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/injection | |
| 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/injection')
| -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 |
4 files changed, 181 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> { |