aboutsummaryrefslogtreecommitdiff
path: root/client/src
diff options
context:
space:
mode:
authorauth12 <[email protected]>2020-07-27 16:29:29 -0700
committerauth12 <[email protected]>2020-07-27 16:29:29 -0700
commit9354a3bd08b63fd5f79f47f186876d3f3611828a (patch)
treeec7e2d524f61e710c53fd5a45df4faf8a3565d9d /client/src
parentFixed support for colored text. (diff)
downloadloader-9354a3bd08b63fd5f79f47f186876d3f3611828a.tar.xz
loader-9354a3bd08b63fd5f79f47f186876d3f3611828a.zip
Imported modules are now manual mapped.
Diffstat (limited to 'client/src')
-rw-r--r--client/src/injection/mapper.cpp9
-rw-r--r--client/src/injection/pe.h146
-rw-r--r--client/src/injection/process.cpp74
-rw-r--r--client/src/injection/process.h2
-rw-r--r--client/src/main.cpp1
-rw-r--r--client/src/util/apiset.cpp32
-rw-r--r--client/src/util/apiset.h21
-rw-r--r--client/src/util/native.h32
8 files changed, 267 insertions, 50 deletions
diff --git a/client/src/injection/mapper.cpp b/client/src/injection/mapper.cpp
index 052dc39..3857948 100644
--- a/client/src/injection/mapper.cpp
+++ b/client/src/injection/mapper.cpp
@@ -44,17 +44,10 @@ void mmap::thread(tcp::client& client) {
nlohmann::json final_imports;
for (auto& [key, value] : imports.items()) {
-
- auto base = proc.load(key);
- if (!base) {
- io::log_error("failed to load {}", key);
- continue;
- }
-
for (auto& i : value) {
auto name = i.get<std::string>();
- final_imports[name] = proc.module_export(base, name);
+ final_imports[name] = proc.module_export(proc.map(key), name);
}
}
imports.clear();
diff --git a/client/src/injection/pe.h b/client/src/injection/pe.h
index 4709872..bf36b41 100644
--- a/client/src/injection/pe.h
+++ b/client/src/injection/pe.h
@@ -1,5 +1,8 @@
#pragma once
+#include <linux-pe/linuxpe>
+
+
namespace pe {
class virtual_image {
@@ -62,4 +65,147 @@ namespace pe {
operator bool() { return m_base != 0; }
};
+ struct import_t {
+ std::string name;
+ uint32_t rva;
+ };
+
+ struct section_t {
+ std::string name;
+ size_t size;
+ uint32_t rva;
+ uint32_t va;
+ };
+
+ template <bool x64 = false>
+ class image {
+ win::image_t<x64>* m_image;
+ std::vector<char> m_buffer;
+
+ std::unordered_map<std::string, std::vector<import_t>> m_imports;
+ std::vector<section_t> m_sections;
+ std::vector<std::pair<uint32_t, win::reloc_entry_t>> m_relocs;
+
+ public:
+ image() = default;
+ image(const std::vector<char>& buf) : m_image{ nullptr } {
+ m_buffer.assign(buf.begin(), buf.end());
+
+ m_image = reinterpret_cast<win::image_t<x64>*>(m_buffer.data());
+ load();
+ }
+
+ void load() {
+ parse_sections();
+ parse_relocs();
+ parse_imports();
+ }
+
+ void parse_sections() {
+ const auto nt = m_image->get_nt_headers();
+ const size_t n = nt->file_header.num_sections;
+
+ for (size_t i = 0; i < n; i++) {
+ auto section = nt->get_section(i);
+ m_sections.emplace_back(section_t{ section->name, section->size_raw_data,
+ section->ptr_raw_data,
+ section->virtual_address });
+ }
+ };
+
+ void parse_relocs() {
+ const auto reloc_dir =
+ m_image->get_directory(win::directory_id::directory_entry_basereloc);
+ if (!reloc_dir) return;
+
+ const auto ptr = m_image->rva_to_ptr(reloc_dir->rva);
+ auto block = reinterpret_cast<win::reloc_block_t*>(ptr);
+
+ while (block->base_rva) {
+ for (size_t i = 0; i < block->num_entries(); ++i) {
+ auto entry = block->entries[i];
+
+ m_relocs.emplace_back(std::make_pair(block->base_rva, entry));
+ }
+ block = block->get_next();
+ }
+ }
+
+ void parse_imports() {
+ const auto import_dir =
+ m_image->get_directory(win::directory_id::directory_entry_import);
+ if (!import_dir) return;
+
+ const auto ptr = m_image->rva_to_ptr(import_dir->rva);
+ auto table = reinterpret_cast<win::import_directory_t*>(ptr);
+
+ for (uint32_t previous_name = 0; previous_name < table->rva_name;
+ previous_name = table->rva_name, ++table) {
+ auto name_ptr = m_image->rva_to_ptr(table->rva_name);
+ auto mod_name = std::string(reinterpret_cast<char*>(name_ptr));
+
+ auto thunk = reinterpret_cast<win::image_thunk_data_t<x64>*>(
+ m_image->rva_to_ptr(table->rva_original_first_thunk));
+
+ auto step = x64 ? sizeof(uint64_t) : sizeof(uint32_t);
+ for (uint32_t index = 0; thunk->address; index += step, ++thunk) {
+ auto named_import = reinterpret_cast<win::image_named_import_t*>(
+ m_image->rva_to_ptr(thunk->address));
+
+ if (!thunk->is_ordinal) {
+ import_t data;
+ data.name = reinterpret_cast<const char*>(named_import->name);
+ data.rva = table->rva_first_thunk + index;
+
+ std::transform(mod_name.begin(), mod_name.end(), mod_name.begin(),
+ ::tolower);
+
+ m_imports[mod_name].emplace_back(std::move(data));
+ }
+ }
+ }
+ }
+
+ void copy(std::vector<char>& out) {
+ const auto nt = m_image->get_nt_headers();
+ const auto n = nt->file_header.num_sections;
+
+ out.resize(nt->optional_header.size_image);
+
+ std::memcpy(&out[0], &m_buffer[0], 4096);
+
+ for (auto& sec : m_sections) {
+ std::memcpy(&out[sec.va], &m_buffer[sec.rva], sec.size);
+ }
+ }
+
+ void relocate(std::vector<char>& image, uintptr_t base) {
+ const auto delta =
+ base - m_image->get_nt_headers()->optional_header.image_base;
+ if (delta > 0) {
+ for (auto& [base_rva, entry] : m_relocs) {
+ if (x64) {
+ if (entry.type == win::rel_based_high_low ||
+ entry.type == win::rel_based_dir64) {
+ *reinterpret_cast<uint64_t*>(image.data() + base_rva +
+ entry.offset) += delta;
+ }
+ continue;
+ }
+
+ if (entry.type == win::rel_based_high_low) {
+ *reinterpret_cast<uint32_t*>(image.data() + base_rva +
+ entry.offset) += delta;
+ }
+ }
+ }
+ }
+
+ const auto operator->() { return m_image; }
+ operator bool() const { return m_image != nullptr; }
+
+ auto& imports() const { return m_imports; }
+ auto& relocs() const { return m_relocs; }
+ auto& sections() const { return m_sections; }
+ };
}; // namespace pe \ No newline at end of file
diff --git a/client/src/injection/process.cpp b/client/src/injection/process.cpp
index 6093bf3..691265c 100644
--- a/client/src/injection/process.cpp
+++ b/client/src/injection/process.cpp
@@ -1,11 +1,12 @@
#include "../include.h"
#include "../util/io.h"
#include "../util/util.h"
+#include "../util/apiset.h"
+#include "pe.h"
#include "process.h"
uintptr_t util::process32::module_export(const uintptr_t base, const std::string_view func) {
if (!base) {
- io::log_error("module {} isnt loaded.", m_name);
return {};
}
@@ -86,7 +87,7 @@ uintptr_t util::process32::module_export(const uintptr_t base, const std::string
std::string fwd_func_name = name_str.substr(delim + 1);
- return module_export(load(fwd_mod_name), fwd_func_name);
+ return module_export(map(fwd_mod_name), fwd_func_name);
}
return proc_addr;
@@ -96,69 +97,60 @@ uintptr_t util::process32::module_export(const uintptr_t base, const std::string
return {};
}
-uintptr_t util::process32::load(const std::string_view mod) {
- auto base = m_modules[mod.data()];
+uintptr_t util::process32::map(const std::string_view module_name) {
+ std::string mod{module_name};
+ g_apiset(mod);
+
+ auto base = m_modules[mod];
if (base) {
return base;
}
- static auto loaddll = module_export(m_modules["ntdll.dll"], "LdrLoadDll");
-
- auto name = allocate(0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-
- std::string path{ "C:\\Windows\\SysWOW64\\" };
- path.append(mod.data());
+ io::log("mapping {}", module_name);
- native::unicode_string_t<uint32_t> ustr = { 0 };
+ std::string path{"C:\\Windows\\SysWOW64\\"};
+ path.append(mod);
- auto wpath = util::multibyte_to_wide(path.data());
- ustr.Buffer = name + sizeof(ustr);
- ustr.MaximumLength = ustr.Length = wpath.size() * sizeof(wchar_t);
-
- if (!write(name, &ustr, sizeof(ustr))) {
- io::log_error("failed to write name.");
+ std::vector<char> local_image;
+ if (!io::read_file(path, local_image)) {
return {};
}
- if (!write(name + sizeof(ustr), wpath.data(), wpath.size() * sizeof(wchar_t))) {
- io::log_error("failed to write path.");
+ pe::image img(local_image);
+
+ if (!img) {
+ io::log_error("failed to init image.");
return {};
}
- static std::vector<uint8_t> shellcode = { 0x55, 0x89, 0xE5, 0x68, 0xEF, 0xBE, 0xAD,
- 0xDE, 0x68, 0xEF, 0xBE, 0xAD, 0xDE, 0x6A, 0x00, 0x6A, 0x00, 0xB8,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0x89, 0xEC, 0x5D, 0xC3 };
- *reinterpret_cast<uint32_t*>(&shellcode[4]) = name + 0x800;
- *reinterpret_cast<uint32_t*>(&shellcode[9]) = name;
- *reinterpret_cast<uint32_t*>(&shellcode[18]) = loaddll;
+ std::vector<char> remote_image;
+ img.copy(remote_image);
- auto code = allocate(shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- if (!write(code, shellcode.data(), shellcode.size())) {
- io::log_error("failed to write shellcode.");
+ base = allocate(remote_image.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (!base) {
return {};
}
- io::log("name : {:x}", name);
- io::log("shellcode : {:x}", code);
+ img.relocate(remote_image, base);
- if (!thread(code)) {
- io::log_error("thread creation failed.");
- return {};
+ for (auto &[mod, funcs] : img.imports()) {
+ for (auto &func : funcs) {
+ auto addr = module_export(map(mod), func.name);
+ //io::log("{}:{}->{:x}", mod, func.name, addr);
+ *reinterpret_cast<uint32_t *>(&remote_image[func.rva]) = addr;
+ }
}
- if (!free(code, shellcode.size())) {
- io::log_error("failed to free shellcode.");
- return {};
- }
+ if (!write(base, remote_image.data(), remote_image.size())) {
+ free(base, remote_image.size());
- if (!free(name, 0x1000)) {
- io::log_error("failed to free name.");
return {};
}
- enum_modules();
+ io::log("{}->{:x}", mod, base);
+ m_modules[mod] = base;
- return m_modules[mod.data()];
+ return base;
}
bool util::fetch_system_data(system_data_t& out) {
diff --git a/client/src/injection/process.h b/client/src/injection/process.h
index 002c399..f397a8a 100644
--- a/client/src/injection/process.h
+++ b/client/src/injection/process.h
@@ -231,7 +231,7 @@ namespace util {
}
uintptr_t module_export(const uintptr_t base, const std::string_view func);
- uintptr_t load(const std::string_view mod);
+ uintptr_t map(const std::string_view module_name);
};
class process64 : public base_process<uint64_t> {
diff --git a/client/src/main.cpp b/client/src/main.cpp
index 0cb08f4..4a11061 100644
--- a/client/src/main.cpp
+++ b/client/src/main.cpp
@@ -6,6 +6,7 @@
#include "injection/process.h"
#include "injection/mapper.h"
#include "hwid/hwid.h"
+#include "util/apiset.h"
int main(int argc, char* argv[]) {
io::log("{:x}", g_syscalls());
diff --git a/client/src/util/apiset.cpp b/client/src/util/apiset.cpp
new file mode 100644
index 0000000..e47fb51
--- /dev/null
+++ b/client/src/util/apiset.cpp
@@ -0,0 +1,32 @@
+#include "../include.h"
+#include "util.h"
+#include "io.h"
+#include "apiset.h"
+
+apiset g_apiset;
+
+apiset::apiset() {
+ auto map = *reinterpret_cast<native::API_SET_NAMESPACE_ARRAY**>(uintptr_t(util::peb()) + 0x68);
+ for (int i = 0; i < map->Count; ++i) {
+ std::wstring wapi_name(255, 0);
+ std::wstring wapi_host(255, 0);
+
+ auto entry = reinterpret_cast<native::API_SET_NAMESPACE_ENTRY*>(uintptr_t(map) + map->End + i * sizeof(native::API_SET_NAMESPACE_ENTRY));
+ auto array = reinterpret_cast<native::API_SET_VALUE_ARRAY*>(uintptr_t(map) + map->Start + entry->Size * sizeof(native::API_SET_VALUE_ARRAY));
+
+ auto byte_map = reinterpret_cast<uint8_t*>(map);
+ std::memcpy(&wapi_name[0], &byte_map[array->NameOffset], array->NameLength);
+
+ auto host = reinterpret_cast<native::API_SET_VALUE_ENTRY*>(&byte_map[array->DataOffset]);
+
+ std::memcpy(&wapi_host[0], &byte_map[host->ValueOffset], host->ValueLength);
+
+ wapi_name.assign(wapi_name.data());
+ wapi_host.assign(wapi_host.data());
+
+ auto api_name = util::wide_to_multibyte(wapi_name);
+ auto api_host = util::wide_to_multibyte(wapi_host);
+
+ m_apimap[api_name] = api_host;
+ }
+} \ No newline at end of file
diff --git a/client/src/util/apiset.h b/client/src/util/apiset.h
new file mode 100644
index 0000000..440dcc0
--- /dev/null
+++ b/client/src/util/apiset.h
@@ -0,0 +1,21 @@
+#pragma once
+
+class apiset {
+ std::unordered_map<std::string, std::string> m_apimap;
+public:
+ apiset();
+
+ void operator()(std::string &mod) {
+ auto it = std::find_if(m_apimap.begin(), m_apimap.end(), [&](const std::pair<std::string, std::string>& pair) {
+ return mod.find(pair.first) != std::string::npos;
+ });
+
+ if (it != m_apimap.end()) {
+ mod = it->second;
+ }
+ }
+
+ auto &map() { return m_apimap; }
+};
+
+extern apiset g_apiset; \ No newline at end of file
diff --git a/client/src/util/native.h b/client/src/util/native.h
index dada567..44b8ab6 100644
--- a/client/src/util/native.h
+++ b/client/src/util/native.h
@@ -340,6 +340,38 @@ namespace native {
SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
+ struct API_SET_VALUE_ENTRY {
+ ULONG Flags;
+ ULONG NameOffset;
+ ULONG NameLength;
+ ULONG ValueOffset;
+ ULONG ValueLength;
+ };
+
+ struct API_SET_VALUE_ARRAY {
+ ULONG Flags;
+ ULONG NameOffset;
+ ULONG Unk;
+ ULONG NameLength;
+ ULONG DataOffset;
+ ULONG Count;
+ };
+
+ struct API_SET_NAMESPACE_ENTRY {
+ ULONG Limit;
+ ULONG Size;
+ };
+
+ struct API_SET_NAMESPACE_ARRAY {
+ ULONG Version;
+ ULONG Size;
+ ULONG Flags;
+ ULONG Count;
+ ULONG Start;
+ ULONG End;
+ ULONG Unk[2];
+ };
+
using NtQuerySystemInformation = NTSTATUS(__stdcall*)(native::SYSTEM_INFORMATION_CLASS, PVOID, SIZE_T, PULONG);
using NtOpenProcess = NTSTATUS(__stdcall*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, CLIENT_ID*);
using NtReadVirtualMemory = NTSTATUS(__stdcall*)(HANDLE, PVOID, PVOID, SIZE_T, PULONG);