diff options
| author | auth12 <[email protected]> | 2020-07-27 16:29:29 -0700 |
|---|---|---|
| committer | auth12 <[email protected]> | 2020-07-27 16:29:29 -0700 |
| commit | 9354a3bd08b63fd5f79f47f186876d3f3611828a (patch) | |
| tree | ec7e2d524f61e710c53fd5a45df4faf8a3565d9d /client/src | |
| parent | Fixed support for colored text. (diff) | |
| download | loader-9354a3bd08b63fd5f79f47f186876d3f3611828a.tar.xz loader-9354a3bd08b63fd5f79f47f186876d3f3611828a.zip | |
Imported modules are now manual mapped.
Diffstat (limited to 'client/src')
| -rw-r--r-- | client/src/injection/mapper.cpp | 9 | ||||
| -rw-r--r-- | client/src/injection/pe.h | 146 | ||||
| -rw-r--r-- | client/src/injection/process.cpp | 74 | ||||
| -rw-r--r-- | client/src/injection/process.h | 2 | ||||
| -rw-r--r-- | client/src/main.cpp | 1 | ||||
| -rw-r--r-- | client/src/util/apiset.cpp | 32 | ||||
| -rw-r--r-- | client/src/util/apiset.h | 21 | ||||
| -rw-r--r-- | client/src/util/native.h | 32 |
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); |