From 09d0342da61c74b08a95ee284a8b25c742ca89c1 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Thu, 13 May 2021 22:44:43 -0700 Subject: [PATCH] init commit --- xtils.sln | 22 ++ xtils/hello-world-x64.dll | Bin 0 -> 10752 bytes xtils/main.cpp | 52 ++++ xtils/xtils.hpp | 523 ++++++++++++++++++++++++++++++++++++ xtils/xtils.vcxproj | 63 +++++ xtils/xtils.vcxproj.filters | 23 ++ xtils/xtils.vcxproj.user | 4 + 7 files changed, 687 insertions(+) create mode 100644 xtils.sln create mode 100644 xtils/hello-world-x64.dll create mode 100644 xtils/main.cpp create mode 100644 xtils/xtils.hpp create mode 100644 xtils/xtils.vcxproj create mode 100644 xtils/xtils.vcxproj.filters create mode 100644 xtils/xtils.vcxproj.user diff --git a/xtils.sln b/xtils.sln new file mode 100644 index 0000000..d455256 --- /dev/null +++ b/xtils.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30907.101 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xtils", "xtils\xtils.vcxproj", "{47343E59-10B7-4F29-B7A0-561B106F7D0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {47343E59-10B7-4F29-B7A0-561B106F7D0B}.Release|x64.ActiveCfg = Release|x64 + {47343E59-10B7-4F29-B7A0-561B106F7D0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5FCE9B1F-FCF9-4D0A-9B5E-207C218B537E} + EndGlobalSection +EndGlobal diff --git a/xtils/hello-world-x64.dll b/xtils/hello-world-x64.dll new file mode 100644 index 0000000000000000000000000000000000000000..1f6b286f1293924dd762f02734927bee7828e579 GIT binary patch literal 10752 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 +#include +#include "xtils.hpp" + +int __cdecl main(int argc, const char** argv) +{ + auto utils = xtils::um_t::get_instance(); + const auto explorer_pid = + utils->get_pid(L"explorer.exe"); + + const auto explorer_module_base = + utils->get_process_base(utils->get_handle(explorer_pid).get()); + + std::printf("> explorer pid = 0x%x, module base = 0x%p\n", + explorer_pid, explorer_module_base); + + std::map modules; + if (!utils->get_modules(explorer_pid, modules)) + { + std::printf("[!] failed to get modules...\n"); + return -1; + } + + std::printf("> user32.dll base = 0x%p\n", + modules[L"user32.dll"]); + + const auto [notepad_handle, notepad_pid, notepad_base] = + utils->start_exec("C:\\Windows\\System32\\notepad.exe"); + + std::printf("> notepad handle = 0x%x, notepad pid = 0x%x, notepad_base = 0x%p\n", + notepad_handle, notepad_pid, notepad_base); + + const auto module_base = utils->load_lib(notepad_handle, + (std::filesystem::current_path() + .string() + "\\hello-world-x64.dll").c_str()); + + std::printf("> module base = 0x%p\n", module_base); + auto km_utils = xtils::km_t::get_instance(); + + km_utils->each_module( + [](PRTL_PROCESS_MODULE_INFORMATION kmodule_info, const char* module_name) -> bool + { + std::printf("> module name = %s, module base = 0x%p\n", + module_name, kmodule_info->ImageBase); + + return true; + } + ); + + std::printf("> ntoskrnl base = 0x%p\n", km_utils->get_base("ntoskrnl.exe")); +} \ No newline at end of file diff --git a/xtils/xtils.hpp b/xtils/xtils.hpp new file mode 100644 index 0000000..1bb6870 --- /dev/null +++ b/xtils/xtils.hpp @@ -0,0 +1,523 @@ +#pragma once +#define _CRT_SECURE_NO_WARNINGS +#pragma comment(lib, "ntdll.lib") + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define LOG_SIG "[xtils]" +#define LOG(...) \ +{ \ + char buff[256]; \ + snprintf(buff, sizeof buff, LOG_SIG ## __VA_ARGS__); \ + OutputDebugStringA(buff); \ +} + +#define NT_HEADER(x) reinterpret_cast( uint64_t(x) + reinterpret_cast(x)->e_lfanew ) + +typedef struct _RTL_PROCESS_MODULE_INFORMATION +{ + HANDLE Section; + PVOID MappedBase; + PVOID ImageBase; + ULONG ImageSize; + ULONG Flags; + USHORT LoadOrderIndex; + USHORT InitOrderIndex; + USHORT LoadCount; + USHORT OffsetToFileName; + UCHAR FullPathName[256]; +} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION; + +typedef struct _RTL_PROCESS_MODULES +{ + ULONG NumberOfModules; + RTL_PROCESS_MODULE_INFORMATION Modules[1]; +} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES; + + +namespace xtils +{ + using uq_handle = std::unique_ptr; + + class um_t + { + using module_callback_t = std::function; + using module_map_t = std::map; + + public: + static auto get_instance() -> um_t* { static um_t obj; return &obj; } + + auto get_modules(std::uint32_t pid, module_map_t& module_map) -> bool + { + uq_handle snapshot = { CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid), &CloseHandle }; + + if (snapshot.get() == INVALID_HANDLE_VALUE) + return false; + + MODULEENTRY32 module_info = { sizeof MODULEENTRY32 }; + Module32First(snapshot.get(), &module_info); + + // lowercase the module name... + std::for_each(module_info.szModule, + module_info.szModule + wcslen(module_info.szModule) * 2, + [](wchar_t& c) { c = ::towlower(c); }); + + module_map[module_info.szModule] = reinterpret_cast(module_info.modBaseAddr); + + for (Module32First(snapshot.get(), &module_info); Module32Next(snapshot.get(), &module_info);) + { + // lowercase the module name... + std::for_each(module_info.szModule, + module_info.szModule + wcslen(module_info.szModule) * 2, + [](wchar_t& c) { c = ::towlower(c); }); + + module_map[module_info.szModule] = + reinterpret_cast(module_info.modBaseAddr); + } + + return true; + } + + void each_module(std::uint32_t pid, module_callback_t callback) + { + module_map_t module_map; + if (!get_modules(pid, module_map)) + return; + + for (auto& [module_name, module_base] : module_map) + if (!callback(module_name, module_base)) + break; + } + + // https://github.com/PierreCiholas/GetBaseAddress/blob/master/main.cpp#L7 + auto get_process_base(HANDLE proc_handle)->std::uintptr_t + { + HMODULE lph_modules[1024]; + DWORD needed = 0u; + + if (!EnumProcessModules(proc_handle, lph_modules, sizeof(lph_modules), &needed)) + return {}; + + TCHAR mod_name[MAX_PATH]; + if (!GetModuleFileNameEx(proc_handle, lph_modules[0], mod_name, sizeof(mod_name) / sizeof(TCHAR))) + return {}; + + return reinterpret_cast(lph_modules[0]); + } + + auto get_pid(const wchar_t* proc_name) -> std::uint32_t + { + uq_handle snapshot = { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL), &CloseHandle }; + + if (snapshot.get() == INVALID_HANDLE_VALUE) + return {}; + + PROCESSENTRY32W process_entry{ sizeof(PROCESSENTRY32W) }; + Process32FirstW(snapshot.get(), &process_entry); + if (!std::wcscmp(proc_name, process_entry.szExeFile)) + return process_entry.th32ProcessID; + + for (Process32FirstW(snapshot.get(), &process_entry); Process32NextW(snapshot.get(), &process_entry); ) + if (!std::wcscmp(proc_name, process_entry.szExeFile)) + return process_entry.th32ProcessID; + + return {}; + } + + auto get_handle(const wchar_t* proc_name, DWORD access = PROCESS_ALL_ACCESS) -> uq_handle + { + std::uint32_t pid = 0u; + if (!(pid = get_pid(proc_name))) + return { NULL, &CloseHandle }; + + return { OpenProcess(access, FALSE, pid), &CloseHandle }; + } + + auto get_handle(std::uint32_t pid, DWORD access = PROCESS_ALL_ACCESS)->uq_handle + { + if (!pid) return { NULL, &CloseHandle }; + return { OpenProcess(access, FALSE, pid), &CloseHandle }; + } + + auto load_lib(HANDLE proc_handle, const char* dll_path) -> std::uintptr_t + { + const auto dll_path_page = + VirtualAllocEx( + proc_handle, + nullptr, + 0x1000, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE + ); + + if (!dll_path_page) + return {}; + + SIZE_T handled_bytes; + if (!WriteProcessMemory(proc_handle, dll_path_page, + dll_path, strlen(dll_path), &handled_bytes)) + return {}; + + // +6 for string address + // +16 for LoadLibrary address... + unsigned char jmp_code[] = + { + 0x48, 0x83, 0xEC, 0x28, // sub rsp, 0x28 + 0x48, 0xB9, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // mov rcx, &dllpath + 0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // mov rax, &LoadLibraryA + 0xFF, 0xD0, // call rax + 0x48, 0x83, 0xC4, 0x28, // add rsp, 0x28 + 0x48, 0x89, 0x05, 0x01, 0x00, 0x00, 0x00, // mov [rip+1], rax + 0xC3 // ret + }; + + *reinterpret_cast(&jmp_code[6]) = + reinterpret_cast(dll_path_page); + + *reinterpret_cast(&jmp_code[16]) = + reinterpret_cast(&LoadLibraryA); + + const auto jmp_code_page = + VirtualAllocEx( + proc_handle, + nullptr, + 0x1000, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE + ); + + if (!jmp_code_page) + return {}; + + if (!WriteProcessMemory(proc_handle, + jmp_code_page, jmp_code, sizeof jmp_code, &handled_bytes)) + return {}; + + DWORD tid = 0u; + auto thandle = CreateRemoteThread(proc_handle, nullptr, + NULL, (LPTHREAD_START_ROUTINE)jmp_code_page, nullptr, NULL, &tid); + + if (thandle == INVALID_HANDLE_VALUE) + return {}; + + WaitForSingleObject(thandle, INFINITE); + + // read the base address out of the shellcode... + std::uintptr_t module_base = 0u; + if (!ReadProcessMemory(proc_handle, reinterpret_cast( + reinterpret_cast(jmp_code_page) + sizeof jmp_code), + &module_base, sizeof module_base, &handled_bytes)) + return {}; + + return module_base; + } + + auto start_exec(const char* image_path, char* cmdline = nullptr, + bool suspend = false) -> std::tuple + { + STARTUPINFOA info = { sizeof info }; + PROCESS_INFORMATION proc_info; + + if (!CreateProcessA(image_path, cmdline, nullptr, + nullptr, false, + suspend ? CREATE_SUSPENDED | CREATE_NEW_CONSOLE : CREATE_NEW_CONSOLE, + nullptr, nullptr, &info, &proc_info + )) + return { {}, {}, {} }; + + Sleep(1); // sleep just for a tiny amount of time so that get_process_base works... + return { proc_info.hProcess, proc_info.dwProcessId, get_process_base(proc_info.hProcess) }; + } + + std::uintptr_t scan(std::uintptr_t base, std::uint32_t size, const char* pattern, const char* mask) + { + static const auto check_mask = + [&](const char* base, const char* pattern, const char* mask) -> bool + { + for (; *mask; ++base, ++pattern, ++mask) + if (*mask == 'x' && *base != *pattern) + return false; + return true; + }; + + size -= strlen(mask); + for (auto i = 0; i <= size; ++i) + { + void* addr = (void*)&(((char*)base)[i]); + if (check_mask((char*)addr, pattern, mask)) + return reinterpret_cast(addr); + } + return {}; + } + + private: + explicit um_t() {} + }; + + class km_t + { + using kmodule_callback_t = std::function; + public: + static auto get_instance() -> km_t* { static km_t obj; return &obj; }; + auto get_base(const char* drv_name)->std::uintptr_t + { + void* buffer = nullptr; + DWORD buffer_size = NULL; + + auto status = NtQuerySystemInformation( + static_cast(0xB), + buffer, buffer_size, &buffer_size); + + while (status == STATUS_INFO_LENGTH_MISMATCH) + { + VirtualFree(buffer, NULL, MEM_RELEASE); + buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + status = NtQuerySystemInformation( + static_cast(0xB), + buffer, buffer_size, &buffer_size); + } + + if (!NT_SUCCESS(status)) + { + VirtualFree(buffer, NULL, MEM_RELEASE); + return NULL; + } + + const auto modules = static_cast(buffer); + for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) + { + const auto current_module_name = + std::string(reinterpret_cast( + modules->Modules[idx].FullPathName) + + modules->Modules[idx].OffsetToFileName); + + if (!_stricmp(current_module_name.c_str(), drv_name)) + { + const auto result = + reinterpret_cast( + modules->Modules[idx].ImageBase); + + VirtualFree(buffer, NULL, MEM_RELEASE); + return result; + } + } + + VirtualFree(buffer, NULL, MEM_RELEASE); + return NULL; + + } + + void each_module(kmodule_callback_t callback) + { + void* buffer = nullptr; + DWORD buffer_size = NULL; + + auto status = NtQuerySystemInformation( + static_cast(0xB), + buffer, buffer_size, &buffer_size); + + while (status == STATUS_INFO_LENGTH_MISMATCH) + { + VirtualFree(buffer, NULL, MEM_RELEASE); + buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + status = NtQuerySystemInformation( + static_cast(0xB), + buffer, buffer_size, &buffer_size); + } + + if (!NT_SUCCESS(status)) + { + VirtualFree(buffer, NULL, MEM_RELEASE); + return; + } + + const auto modules = static_cast(buffer); + for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) + { + auto full_path = std::string( + reinterpret_cast( + modules->Modules[idx].FullPathName)); + + if (full_path.find("\\SystemRoot\\") != std::string::npos) + full_path.replace(full_path.find("\\SystemRoot\\"), + sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\")); + + else if (full_path.find("\\??\\") != std::string::npos) + full_path.replace(full_path.find("\\??\\"), + sizeof("\\??\\") - 1, ""); + + if (!callback(&modules->Modules[idx], full_path.c_str())) + { + VirtualFree(buffer, NULL, MEM_RELEASE); + return; + } + } + + VirtualFree(buffer, NULL, MEM_RELEASE); + return; + } + + + auto get_export(const char* drv_name, const char* export_name)->std::uintptr_t + { + void* buffer = nullptr; + DWORD buffer_size = NULL; + + NTSTATUS status = NtQuerySystemInformation( + static_cast(0xB), + buffer, + buffer_size, + &buffer_size + ); + + while (status == STATUS_INFO_LENGTH_MISMATCH) + { + VirtualFree(buffer, 0, MEM_RELEASE); + buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + status = NtQuerySystemInformation( + static_cast(0xB), + buffer, + buffer_size, + &buffer_size + ); + } + + if (!NT_SUCCESS(status)) + { + VirtualFree(buffer, 0, MEM_RELEASE); + return NULL; + } + + const auto modules = static_cast(buffer); + for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) + { + // find module and then load library it + const std::string current_module_name = + std::string(reinterpret_cast( + modules->Modules[idx].FullPathName) + + modules->Modules[idx].OffsetToFileName + ); + + if (!_stricmp(current_module_name.c_str(), drv_name)) + { + auto full_path = std::string( + reinterpret_cast( + modules->Modules[idx].FullPathName)); + + full_path.replace(full_path.find("\\SystemRoot\\"), + sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\")); + + const auto module_base = + LoadLibraryExA( + full_path.c_str(), + NULL, + DONT_RESOLVE_DLL_REFERENCES + ); + + const auto image_base = + reinterpret_cast( + modules->Modules[idx].ImageBase); + + // free the RTL_PROCESS_MODULES buffer... + VirtualFree(buffer, NULL, MEM_RELEASE); + + const auto rva = + reinterpret_cast( + GetProcAddress(module_base, export_name)) - + reinterpret_cast(module_base); + + return image_base + rva; + } + } + + VirtualFree(buffer, NULL, MEM_RELEASE); + return NULL; + + } + private: + explicit km_t() {} + }; + + class pe_t + { + using section_callback_t = std::function; + public: + static auto get_instance() -> pe_t* { static pe_t obj; return &obj; } + + // returns an std::vector containing all of the bytes of the section + // and also the RVA from the image base to the beginning of the section... + auto get_section(std::uintptr_t module_base, + const char* section_name) -> std::pair, std::uint32_t> + { + const auto nt_headers = reinterpret_cast( + reinterpret_cast(module_base)->e_lfanew + module_base); + + const auto section_header = + reinterpret_cast( + reinterpret_cast(nt_headers) + sizeof(DWORD) + + sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader); + + for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx) + { + const auto _section_name = + reinterpret_cast( + section_header[idx].Name); + + // sometimes section names are not null terminated... + if (!strncmp(_section_name, section_name, strlen(section_name) - 1)) + { + const auto section_base = + reinterpret_cast( + module_base + section_header[idx].VirtualAddress); + + const auto section_end = + reinterpret_cast( + section_base + section_header[idx].Misc.VirtualSize); + + std::vector section_bin(section_base, section_end); + return { section_bin, section_header[idx].VirtualAddress }; + } + } + + return { {}, {} }; + } + + void each_section(section_callback_t callback, std::uintptr_t module_base) + { + if (!module_base) + return; + + const auto nt_headers = reinterpret_cast( + reinterpret_cast(module_base)->e_lfanew + module_base); + + const auto section_header = + reinterpret_cast( + reinterpret_cast(nt_headers) + sizeof(DWORD) + + sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader); + + for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx) + { + const auto _section_name = + reinterpret_cast( + section_header[idx].Name); + + // keep looping until the callback returns false... + if (!callback(§ion_header[idx], module_base)) + return; + } + } + private: + explicit pe_t() {}; + }; +} \ No newline at end of file diff --git a/xtils/xtils.vcxproj b/xtils/xtils.vcxproj new file mode 100644 index 0000000..78a7dac --- /dev/null +++ b/xtils/xtils.vcxproj @@ -0,0 +1,63 @@ + + + + + Release + x64 + + + + 16.0 + Win32Proj + {47343e59-10b7-4f29-b7a0-561b106f7d0b} + xtils + 10.0 + + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + false + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + Disabled + + + Console + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/xtils/xtils.vcxproj.filters b/xtils/xtils.vcxproj.filters new file mode 100644 index 0000000..4863c55 --- /dev/null +++ b/xtils/xtils.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/xtils/xtils.vcxproj.user b/xtils/xtils.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/xtils/xtils.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file