From 5f0eb2bf34c102d5b66cdd5e3d7c4bdd5b30f87d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 19 Aug 2024 17:06:03 +0200 Subject: [PATCH] Progress --- src/emulator/main.cpp | 178 ++++++++++++++++++++++++++++++-- src/emulator/resources/icon.ico | Bin 12479 -> 5072 bytes 2 files changed, 171 insertions(+), 7 deletions(-) diff --git a/src/emulator/main.cpp b/src/emulator/main.cpp index 9ad243a5..f432b9ce 100644 --- a/src/emulator/main.cpp +++ b/src/emulator/main.cpp @@ -62,6 +62,16 @@ namespace return this->address_; } + uint64_t size() const + { + return sizeof(T); + } + + uint64_t end() const + { + return this->value() + this->size(); + } + T* ptr() const { return reinterpret_cast(this->address_); @@ -113,12 +123,10 @@ namespace { } - template - unicorn_object reserve() + uint64_t reserve(const uint64_t count, const uint64_t alignment = 1) { - const auto alignment = alignof(T); const auto potential_start = align_up(this->active_address_, alignment); - const auto potential_end = potential_start + sizeof(T); + const auto potential_end = potential_start + count; const auto total_end = this->address_ + this->size_; if (potential_end > total_end) @@ -128,9 +136,43 @@ namespace this->active_address_ = potential_end; + return potential_start; + } + + template + unicorn_object reserve() + { + const auto potential_start = this->reserve(sizeof(T), alignof(T)); return unicorn_object(*this->uc_, potential_start); } + void make_unicode_string(UNICODE_STRING& result, const std::wstring_view str) + { + constexpr auto element_size = sizeof(str[0]); + constexpr auto required_alignment = alignof(decltype(str[0])); + const auto total_length = str.size() * element_size; + + const auto string_buffer = this->reserve(total_length, required_alignment); + + e(uc_mem_write(*this->uc_, string_buffer, str.data(), total_length)); + + result.Buffer = reinterpret_cast(string_buffer); + result.Length = static_cast(total_length); + result.MaximumLength = result.Length; + } + + unicorn_object make_unicode_string(const std::wstring_view str) + { + const auto unicode_string = this->reserve(); + + unicode_string.access([&](UNICODE_STRING& unicode_str) + { + this->make_unicode_string(unicode_str, str); + }); + + return unicode_string; + } + private: const unicorn* uc_{}; const uint64_t address_{}; @@ -170,6 +212,14 @@ namespace }; } + if (type == UC_HOOK_MEM_READ) + { + handler = +[](uc_engine*, const uc_mem_type /*type*/, const uint64_t address, const int size, + const int64_t /*value*/, void* user_data) + { + (*static_cast(user_data))(address, size); + }; + } e(uc_hook_add(*this->uc_, &this->hook_, type, handler, this->function_.get(), begin, end, args...)); } @@ -421,9 +471,18 @@ namespace { peb.ImageBaseAddress = nullptr; //peb.Ldr = context.ldr.ptr(); + peb.ProcessHeap = nullptr; + peb.ProcessHeaps = nullptr; peb.ProcessParameters = context.process_params.ptr(); }); + context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS& proc_params) + { + proc_params.Flags = 0x6001; + gs.make_unicode_string(proc_params.ImagePathName, L"C:\\Users\\mauri\\Desktop\\ConsoleApplication6.exe"); + gs.make_unicode_string(proc_params.CommandLine, L"C:\\Users\\mauri\\Desktop\\ConsoleApplication6.exe"); + }); + /*context.ldr.access([&](PEB_LDR_DATA& ldr) { ldr.InLoadOrderModuleList.Flink = &context.ldr.ptr()->InLoadOrderModuleList; @@ -559,6 +618,11 @@ namespace uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); } + void handle_NtOpenKey(const unicorn& uc) + { + uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); + } + void handle_NtCreateEvent(const unicorn& uc, process_context& context) { const unicorn_object event_handle{uc, uc.reg(UC_X86_REG_R10)}; @@ -641,6 +705,12 @@ namespace const auto system_information_length = uc.reg(UC_X86_REG_R8D); const unicorn_object return_length{uc, uc.reg(UC_X86_REG_R9)}; + if (info_class == SystemFlushInformation) + { + uc.reg(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED); + return; + } + if (info_class != SystemBasicInformation) { printf("Unsupported system info class: %X\n", info_class); @@ -678,6 +748,44 @@ namespace uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); } + void handle_NtQueryProcessInformation(const unicorn& uc, const process_context& context) + { + const auto process_handle = uc.reg(UC_X86_REG_R10); + const auto info_class = uc.reg(UC_X86_REG_EDX); + const auto process_information = uc.reg(UC_X86_REG_R8); + const auto process_information_length = uc.reg(UC_X86_REG_R9D); + const unicorn_object return_length{uc, uc.read_stack(5)}; + + if (process_handle != ~0ULL) + { + uc.reg(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED); + return; + } + + if (info_class != ProcessCookie) + { + printf("Unsupported process info class: %X\n", info_class); + uc.stop(); + return; + } + + if (return_length) + { + return_length.write(sizeof(uint32_t)); + } + + if (process_information_length != sizeof(uint32_t)) + { + uc.reg(UC_X86_REG_RAX, STATUS_BUFFER_OVERFLOW); + return; + } + + const unicorn_object info{uc, process_information}; + info.write(0x01234567); + + uc.reg(UC_X86_REG_RAX, STATUS_SUCCESS); + } + void handle_NtProtectVirtualMemory(const unicorn& uc) { const auto process_handle = uc.reg(UC_X86_REG_R10); @@ -730,6 +838,32 @@ namespace (void)entry1; (void)entry2; + std::vector export_hooks{}; + + + std::unordered_map export_remap{}; + for (const auto& exp : context.ntdll.exports) + { + export_remap.try_emplace(exp.second, exp.first); + } + + for (const auto& exp : export_remap) + { + auto name = exp.second; + unicorn_hook hook(uc, UC_HOOK_CODE, exp.first, exp.first, + [n = std::move(name)](const unicorn& uc, const uint64_t address, const uint32_t) + { + printf("Executing function: %s (%llX)\n", n.c_str(), address); + + if (n == "RtlImageNtHeaderEx") + { + printf("Base: %llX\n", uc.reg(UC_X86_REG_RDX)); + } + }); + + export_hooks.emplace_back(std::move(hook)); + } + unicorn_hook hook(uc, UC_HOOK_INSN, 0, std::numeric_limits::max(), [&](const unicorn&, const uint64_t address, const uint32_t /*size*/) { @@ -741,6 +875,12 @@ namespace { switch (syscall_id) { + case 0x12: + handle_NtOpenKey(uc); + break; + case 0x19: + handle_NtQueryProcessInformation(uc, context); + break; case 0x23: handle_NtQueryVirtualMemory(uc, context); break; @@ -772,10 +912,34 @@ namespace } }, UC_X86_INS_SYSCALL); - unicorn_hook hook2(uc, UC_HOOK_CODE, 0, std::numeric_limits::max(), - [](const unicorn&, const uint64_t address, const uint32_t /*size*/) + unicorn_hook hook3(uc, UC_HOOK_MEM_READ, context.peb.value(), context.peb.end(), + [&](const unicorn&, const uint64_t address, const uint32_t /*size*/) { - printf("Inst: %llX\n", address); + printf("Read: %llX - %llX\n", address, address - context.peb.value()); + }); + + unicorn_hook hook4(uc, UC_HOOK_MEM_READ, context.process_params.value(), context.process_params.end(), + [&](const unicorn&, const uint64_t address, const uint32_t /*size*/) + { + printf("Read2: %llX - %llX\n", address, address - context.process_params.value()); + }); + + + unicorn_hook hook2(uc, UC_HOOK_CODE, 0, std::numeric_limits::max(), + [](const unicorn& uc, const uint64_t address, const uint32_t /*size*/) + { + /*static bool hit = false; + if (address == 0x01800D46DD) + { + hit = true; + }*/ + + //if (hit) + { + printf("Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX\n", address, + uc.reg(UC_X86_REG_RAX), uc.reg(UC_X86_REG_RBX), uc.reg(UC_X86_REG_RCX), + uc.reg(UC_X86_REG_RDX)); + } }); const auto err = uc_emu_start(uc, entry1, 0, 0, 0); diff --git a/src/emulator/resources/icon.ico b/src/emulator/resources/icon.ico index 2df456da05cd6c47addf5d5ab11098fd6be44bec..b4afb19bf6e0a5ed68896c8e8ddb6c26805835d9 100644 GIT binary patch literal 5072 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