parent
3d3a2ebd82
commit
5d8fb3f10d
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,227 @@
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
|
||||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*/
|
||||
|
||||
#include "drv_image.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
|
||||
namespace physmeme
|
||||
{
|
||||
drv_image::drv_image(std::vector<uint8_t> image) : m_image(std::move(image))
|
||||
{
|
||||
m_dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(m_image.data());
|
||||
assert(m_dos_header->e_magic == IMAGE_DOS_SIGNATURE);
|
||||
m_nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS64>((uintptr_t)m_dos_header + m_dos_header->e_lfanew);
|
||||
assert(m_nt_headers->Signature == IMAGE_NT_SIGNATURE);
|
||||
assert(m_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC);
|
||||
m_section_header = reinterpret_cast<IMAGE_SECTION_HEADER*>((uintptr_t)(&m_nt_headers->OptionalHeader) + m_nt_headers->FileHeader.SizeOfOptionalHeader);
|
||||
}
|
||||
|
||||
size_t drv_image::size() const
|
||||
{
|
||||
return m_nt_headers->OptionalHeader.SizeOfImage;
|
||||
}
|
||||
|
||||
uintptr_t drv_image::entry_point() const
|
||||
{
|
||||
return m_nt_headers->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
|
||||
void drv_image::map()
|
||||
{
|
||||
m_image_mapped.clear();
|
||||
m_image_mapped.resize(m_nt_headers->OptionalHeader.SizeOfImage);
|
||||
std::copy_n(m_image.begin(), m_nt_headers->OptionalHeader.SizeOfHeaders, m_image_mapped.begin());
|
||||
|
||||
for (size_t i = 0; i < m_nt_headers->FileHeader.NumberOfSections; ++i)
|
||||
{
|
||||
const auto& section = m_section_header[i];
|
||||
const auto target = (uintptr_t)m_image_mapped.data() + section.VirtualAddress;
|
||||
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);
|
||||
printf("copying [%s] 0x%p -> 0x%p [0x%04X]\n", §ion.Name[0], (void*)source, (void*)target, section.SizeOfRawData);
|
||||
}
|
||||
}
|
||||
|
||||
bool drv_image::process_relocation(uintptr_t image_base_delta, uint16_t data, uint8_t* relocation_base)
|
||||
{
|
||||
#define IMR_RELOFFSET(x) (x & 0xFFF)
|
||||
|
||||
switch (data >> 12 & 0xF)
|
||||
{
|
||||
case IMAGE_REL_BASED_HIGH:
|
||||
{
|
||||
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
|
||||
*raw_address += static_cast<unsigned long>(HIWORD(image_base_delta));
|
||||
break;
|
||||
}
|
||||
case IMAGE_REL_BASED_LOW:
|
||||
{
|
||||
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
|
||||
*raw_address += static_cast<unsigned long>(LOWORD(image_base_delta));
|
||||
break;
|
||||
}
|
||||
case IMAGE_REL_BASED_HIGHLOW:
|
||||
{
|
||||
const auto raw_address = reinterpret_cast<size_t*>(relocation_base + IMR_RELOFFSET(data));
|
||||
*raw_address += static_cast<size_t>(image_base_delta);
|
||||
break;
|
||||
}
|
||||
case IMAGE_REL_BASED_DIR64:
|
||||
{
|
||||
auto UNALIGNED raw_address = reinterpret_cast<DWORD_PTR UNALIGNED*>(relocation_base + IMR_RELOFFSET(data));
|
||||
*raw_address += image_base_delta;
|
||||
break;
|
||||
}
|
||||
case IMAGE_REL_BASED_ABSOLUTE: // No action required
|
||||
case IMAGE_REL_BASED_HIGHADJ: // no action required
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw std::runtime_error("gay relocation!");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
#undef IMR_RELOFFSET
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void drv_image::relocate(uintptr_t base) const
|
||||
{
|
||||
if (m_nt_headers->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
|
||||
return;
|
||||
|
||||
ULONG total_count_bytes;
|
||||
const auto nt_headers = ImageNtHeader((void*)m_image_mapped.data());
|
||||
auto relocation_directory = (PIMAGE_BASE_RELOCATION)::ImageDirectoryEntryToData(nt_headers, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &total_count_bytes);
|
||||
auto image_base_delta = static_cast<uintptr_t>(static_cast<uintptr_t>(base) - (nt_headers->OptionalHeader.ImageBase));
|
||||
auto relocation_size = total_count_bytes;
|
||||
|
||||
// This should check (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) too but lots of drivers do not have it set due to WDK defaults
|
||||
const bool doRelocations = image_base_delta != 0 && relocation_size > 0;
|
||||
|
||||
if (!doRelocations)
|
||||
{
|
||||
printf("no relocations needed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(relocation_directory != nullptr);
|
||||
|
||||
void* relocation_end = reinterpret_cast<uint8_t*>(relocation_directory) + relocation_size;
|
||||
|
||||
while (relocation_directory < relocation_end)
|
||||
{
|
||||
auto relocation_base = ::ImageRvaToVa(nt_headers, (void*)m_image_mapped.data(), relocation_directory->VirtualAddress, nullptr);
|
||||
|
||||
auto num_relocs = (relocation_directory->SizeOfBlock - 8) >> 1;
|
||||
|
||||
auto relocation_data = reinterpret_cast<PWORD>(relocation_directory + 1);
|
||||
|
||||
for (unsigned long i = 0; i < num_relocs; ++i, ++relocation_data)
|
||||
{
|
||||
if (process_relocation(image_base_delta, *relocation_data, (uint8_t*)relocation_base) == FALSE)
|
||||
{
|
||||
printf("failed to relocate!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
relocation_directory = reinterpret_cast<PIMAGE_BASE_RELOCATION>(relocation_data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
__forceinline T* ptr_add(void* base, uintptr_t offset)
|
||||
{
|
||||
return (T*)(uintptr_t)base + offset;
|
||||
}
|
||||
|
||||
void drv_image::fix_imports(const std::function<uintptr_t(std::string_view)> get_module, const std::function<uintptr_t(const char*, const char*)> get_function)
|
||||
{
|
||||
ULONG size;
|
||||
auto import_descriptors = static_cast<PIMAGE_IMPORT_DESCRIPTOR>(::ImageDirectoryEntryToData(m_image.data(), FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size));
|
||||
|
||||
if (import_descriptors == nullptr)
|
||||
{
|
||||
printf("no imports!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (; import_descriptors->Name; import_descriptors++)
|
||||
{
|
||||
IMAGE_THUNK_DATA* image_thunk_data;
|
||||
|
||||
const auto module_name = get_rva<char>(import_descriptors->Name);
|
||||
const auto module_base = get_module(module_name);
|
||||
assert(module_base != 0);
|
||||
|
||||
printf("processing module: %s [0x%I64X]\n", module_name, module_base);
|
||||
|
||||
if (import_descriptors->OriginalFirstThunk)
|
||||
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->OriginalFirstThunk);
|
||||
else
|
||||
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->FirstThunk);
|
||||
auto image_func_data = get_rva<IMAGE_THUNK_DATA64>(import_descriptors->FirstThunk);
|
||||
|
||||
assert(image_thunk_data != nullptr);
|
||||
assert(image_func_data != nullptr);
|
||||
|
||||
for (; image_thunk_data->u1.AddressOfData; image_thunk_data++, image_func_data++)
|
||||
{
|
||||
uintptr_t function_address;
|
||||
const auto ordinal = (image_thunk_data->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0;
|
||||
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);
|
||||
function_address = get_function(module_name, name_of_import);
|
||||
printf("function: %s [0x%I64X]\n", name_of_import, function_address);
|
||||
assert(function_address != 0);
|
||||
image_func_data->u1.Function = function_address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* drv_image::data()
|
||||
{
|
||||
return m_image_mapped.data();
|
||||
}
|
||||
|
||||
size_t drv_image::header_size()
|
||||
{
|
||||
return m_nt_headers->OptionalHeader.SizeOfHeaders;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
|
||||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#define WIN32_NO_STATUS
|
||||
#include <Windows.h>
|
||||
#include <Winternl.h>
|
||||
#undef WIN32_NO_STATUS
|
||||
#include <ntstatus.h>
|
||||
|
||||
#include <functional>
|
||||
#include <DbgHelp.h>
|
||||
#include <variant>
|
||||
|
||||
#pragma comment(lib, "Dbghelp.lib")
|
||||
namespace physmeme
|
||||
{
|
||||
class drv_image
|
||||
{
|
||||
std::vector<uint8_t> m_image;
|
||||
std::vector<uint8_t> m_image_mapped;
|
||||
PIMAGE_DOS_HEADER m_dos_header = nullptr;
|
||||
PIMAGE_NT_HEADERS64 m_nt_headers = nullptr;
|
||||
PIMAGE_SECTION_HEADER m_section_header = nullptr;
|
||||
|
||||
public:
|
||||
explicit drv_image(std::vector<uint8_t> image);
|
||||
size_t size() const;
|
||||
uintptr_t entry_point() const;
|
||||
void map();
|
||||
static bool process_relocation(size_t image_base_delta, uint16_t data, uint8_t* relocation_base);
|
||||
void relocate(uintptr_t base) const;
|
||||
|
||||
template<typename T>
|
||||
__forceinline T* get_rva(const unsigned long offset)
|
||||
{
|
||||
return (T*)::ImageRvaToVa(m_nt_headers, m_image.data(), offset, nullptr);
|
||||
}
|
||||
|
||||
void fix_imports(const std::function<uintptr_t(std::string_view)> get_module, const std::function<uintptr_t(const char*, const char*)> get_function);
|
||||
void* data();
|
||||
size_t header_size();
|
||||
};
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
#include "kernel_ctx.h"
|
||||
|
||||
namespace physmeme
|
||||
{
|
||||
/*
|
||||
Author: xerox
|
||||
Date: 4/19/2020
|
||||
*/
|
||||
kernel_ctx::kernel_ctx()
|
||||
: psyscall_func(NULL), ntoskrnl_buffer(NULL)
|
||||
{
|
||||
nt_rva = reinterpret_cast<std::uint32_t>(
|
||||
util::get_module_export(
|
||||
"ntoskrnl.exe",
|
||||
syscall_hook.first.data(),
|
||||
true
|
||||
));
|
||||
|
||||
nt_page_offset = nt_rva % 0x1000;
|
||||
ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>(LoadLibraryA("C:\\Windows\\System32\\ntoskrnl.exe"));
|
||||
|
||||
#if PHYSMEME_DEBUGGING
|
||||
std::cout << "[+] page offset of " << syscall_hook.first << " is: " << std::hex << nt_page_offset << std::endl;
|
||||
#endif
|
||||
|
||||
std::vector<std::thread> search_threads;
|
||||
//--- for each physical memory range, make a thread to search it
|
||||
for (auto ranges : 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();
|
||||
|
||||
#if PHYSMEME_DEBUGGING
|
||||
std::cout << "[+] psyscall_func: " << std::hex << std::showbase << psyscall_func.load() << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
author: xerox
|
||||
date: 4/18/2020
|
||||
|
||||
finds physical page of a syscall and map it into this process.
|
||||
*/
|
||||
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 = physmeme::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 (!psyscall_func) // keep scanning until its found
|
||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
||||
{
|
||||
psyscall_func.store((void*)page);
|
||||
return;
|
||||
}
|
||||
physmeme::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 = physmeme::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 (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
||||
{
|
||||
psyscall_func.store((void*)page);
|
||||
return;
|
||||
}
|
||||
}
|
||||
physmeme::unmap_phys(page_va, 0x1000 * 512);
|
||||
}
|
||||
}
|
||||
|
||||
// map the remainder and check each page of it
|
||||
auto page_va = physmeme::map_phys(begin + end - remainder + nt_page_offset, remainder);
|
||||
if (page_va)
|
||||
{
|
||||
for (auto page = page_va; page < page_va + remainder; page += 0x1000)
|
||||
{
|
||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
||||
{
|
||||
psyscall_func.store((void*)page);
|
||||
return;
|
||||
}
|
||||
}
|
||||
physmeme::unmap_phys(page_va, remainder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Author: xerox
|
||||
Date: 4/19/2020
|
||||
|
||||
allocate a pool in the kernel (no tag)
|
||||
*/
|
||||
void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type)
|
||||
{
|
||||
static const auto ex_alloc_pool =
|
||||
util::get_module_export(
|
||||
"ntoskrnl.exe",
|
||||
"ExAllocatePool"
|
||||
);
|
||||
if (ex_alloc_pool)
|
||||
return syscall<ExAllocatePool>(ex_alloc_pool, pool_type, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Author: xerox
|
||||
Date: 4/19/2020
|
||||
|
||||
allocate a pool in the kernel with a tag
|
||||
*/
|
||||
void* kernel_ctx::allocate_pool(std::size_t size, ULONG pool_tag, POOL_TYPE pool_type)
|
||||
{
|
||||
static const auto ex_alloc_pool_with_tag =
|
||||
util::get_module_export(
|
||||
"ntoskrnl.exe",
|
||||
"ExAllocatePoolWithTag"
|
||||
);
|
||||
if (ex_alloc_pool_with_tag)
|
||||
return syscall<ExAllocatePoolWithTag>(ex_alloc_pool_with_tag, pool_type, size, pool_tag);
|
||||
}
|
||||
|
||||
/*
|
||||
Author: xerox
|
||||
Date: 4/19/2020
|
||||
|
||||
read kernel memory
|
||||
*/
|
||||
void kernel_ctx::read_kernel(std::uintptr_t addr, void* buffer, std::size_t size)
|
||||
{
|
||||
size_t amount_copied;
|
||||
static const auto mm_copy_memory =
|
||||
util::get_module_export(
|
||||
"ntoskrnl.exe",
|
||||
"MmCopyMemory"
|
||||
);
|
||||
if (mm_copy_memory)
|
||||
syscall<MmCopyMemory>(
|
||||
mm_copy_memory,
|
||||
reinterpret_cast<void*>(buffer),
|
||||
MM_COPY_ADDRESS{ (void*)addr },
|
||||
size,
|
||||
MM_COPY_MEMORY_VIRTUAL,
|
||||
&amount_copied
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
Author: xerox
|
||||
Date: 4/19/2020
|
||||
|
||||
write kernel memory, this doesnt write to read only memory!
|
||||
*/
|
||||
void kernel_ctx::write_kernel(std::uintptr_t addr, void* buffer, std::size_t size)
|
||||
{
|
||||
size_t amount_copied;
|
||||
static const auto mm_copy_memory =
|
||||
util::get_module_export(
|
||||
"ntoskrnl.exe",
|
||||
"MmCopyMemory"
|
||||
);
|
||||
if (mm_copy_memory)
|
||||
syscall<MmCopyMemory>(
|
||||
mm_copy_memory,
|
||||
reinterpret_cast<void*>(addr),
|
||||
MM_COPY_ADDRESS{ buffer },
|
||||
size,
|
||||
MM_COPY_MEMORY_VIRTUAL,
|
||||
&amount_copied
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include "../util/util.hpp"
|
||||
#include "../physmeme/physmeme.hpp"
|
||||
#include "../util/hook.hpp"
|
||||
|
||||
#define PHYSMEME_DEBUGGING 1
|
||||
|
||||
#if PHYSMEME_DEBUGGING
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Author: xerox
|
||||
Date: 4/19/2020
|
||||
|
||||
this namespace contains everything needed to interface with the kernel
|
||||
*/
|
||||
namespace physmeme
|
||||
{
|
||||
class kernel_ctx
|
||||
{
|
||||
public:
|
||||
kernel_ctx();
|
||||
void* allocate_pool(std::size_t size, POOL_TYPE pool_type = NonPagedPool);
|
||||
void* allocate_pool(std::size_t size, ULONG pool_tag = 'MEME', POOL_TYPE pool_type = NonPagedPool);
|
||||
|
||||
void read_kernel(std::uintptr_t addr, void* buffer, std::size_t size);
|
||||
void write_kernel(std::uintptr_t addr, void* buffer, std::size_t size);
|
||||
|
||||
template <class T>
|
||||
T read_kernel(std::uintptr_t addr)
|
||||
{
|
||||
if (!addr)
|
||||
return {};
|
||||
T buffer;
|
||||
read_kernel(addr, &buffer, sizeof(T));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write_kernel(std::uintptr_t addr, const T& data)
|
||||
{
|
||||
if (!addr)
|
||||
return {};
|
||||
write_kernel(addr, &data, sizeof(T));
|
||||
}
|
||||
|
||||
//
|
||||
// use this to call any function in the kernel
|
||||
//
|
||||
template <class T, class ... Ts>
|
||||
PVOID syscall(void* addr, Ts ... args)
|
||||
{
|
||||
auto proc = GetProcAddress(GetModuleHandleA("ntdll.dll"), syscall_hook.first.data());
|
||||
if (!proc || !psyscall_func || !addr)
|
||||
return reinterpret_cast<PVOID>(STATUS_INVALID_PARAMETER);
|
||||
|
||||
hook::make_hook(psyscall_func, addr);
|
||||
PVOID result = reinterpret_cast<PVOID>(reinterpret_cast<T>(proc)(args ...));
|
||||
hook::remove(psyscall_func);
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//
|
||||
// mapping of a syscalls physical memory (for installing hooks)
|
||||
//
|
||||
mutable std::atomic<void*> psyscall_func;
|
||||
|
||||
//
|
||||
// you can edit this how you choose, im hooking NtTraceControl.
|
||||
//
|
||||
const std::pair<std::string_view, std::string_view> syscall_hook = { "NtTraceControl", "ntdll.dll" };
|
||||
|
||||
//
|
||||
// offset of function into a physical page
|
||||
// used for comparing bytes when searching
|
||||
//
|
||||
std::uint16_t nt_page_offset;
|
||||
|
||||
//
|
||||
// rva of nt function we are going to hook
|
||||
//
|
||||
std::uint32_t nt_rva;
|
||||
|
||||
//
|
||||
// base address of ntoskrnl (inside of this process)
|
||||
//
|
||||
const std::uint8_t* ntoskrnl_buffer;
|
||||
};
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "kernel_ctx/kernel_ctx.h"
|
||||
#include "drv_image/drv_image.h"
|
||||
|
||||
/*
|
||||
Author: xerox
|
||||
Date: 4/19/2020
|
||||
*/
|
||||
int __cdecl main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 1)
|
||||
{
|
||||
std::cout << "[-] invalid use, please provide a path to a driver" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> drv_buffer;
|
||||
util::open_binary_file(argv[1], drv_buffer);
|
||||
|
||||
physmeme::drv_image image(drv_buffer);
|
||||
physmeme::kernel_ctx ctx;
|
||||
|
||||
//
|
||||
// lambdas used for fixing driver image
|
||||
//
|
||||
const auto _get_module = [&](std::string_view name)
|
||||
{
|
||||
return util::get_module_base(name.data());
|
||||
};
|
||||
|
||||
const auto _get_export_name = [&](const char* base, const char* name)
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(util::get_module_export(base, name));
|
||||
};
|
||||
|
||||
//
|
||||
// allocate memory in the kernel for the driver
|
||||
//
|
||||
std::uintptr_t pool_base = reinterpret_cast<std::uintptr_t>(ctx.allocate_pool(image.size(), NonPagedPool));
|
||||
std::cout << "[+] allocated " << std::hex << std::showbase << image.size() << " at: " << std::hex << std::showbase << pool_base << std::endl;
|
||||
|
||||
//
|
||||
// fix the driver image
|
||||
//
|
||||
image.fix_imports(_get_module, _get_export_name);
|
||||
std::cout << "[+] fixed imports" << std::endl;
|
||||
image.map();
|
||||
std::cout << "[+] sections mapped in memory" << std::endl;
|
||||
image.relocate(pool_base);
|
||||
std::cout << "[+] relocations fixed" << std::endl;
|
||||
|
||||
//
|
||||
// copy driver into the kernel
|
||||
// this might blue screen if the image takes too long to copy
|
||||
//
|
||||
ctx.write_kernel(pool_base, image.data(), image.size());
|
||||
|
||||
//
|
||||
// call driver entry and pass in base address and size of the driver.
|
||||
//
|
||||
auto entry_point = pool_base + image.entry_point();
|
||||
auto size = image.size();
|
||||
|
||||
auto result = ctx.syscall<DRIVER_INITIALIZE>(reinterpret_cast<void*>(entry_point), pool_base, image.size());
|
||||
std::cout << "[+] driver entry returned: " << std::hex << result << std::endl;
|
||||
physmeme::unload_drv();
|
||||
|
||||
std::cout << "[=] press enter to close" << std::endl;
|
||||
std::cin.get();
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{6578B958-DD53-4BE0-8011-009563919E73}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>physmeme</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="drv_image\drv_image.cpp" />
|
||||
<ClCompile Include="kernel_ctx\kernel_ctx.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="drv_image\drv_image.h" />
|
||||
<ClInclude Include="kernel_ctx\kernel_ctx.h" />
|
||||
<ClInclude Include="physmeme\physmeme.hpp" />
|
||||
<ClInclude Include="util\hook.hpp" />
|
||||
<ClInclude Include="util\nt.hpp" />
|
||||
<ClInclude Include="util\util.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\kernel_ctx">
|
||||
<UniqueIdentifier>{040c8387-476c-4aa5-aa2a-ca30465b41bd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\kernel_ctx">
|
||||
<UniqueIdentifier>{642c89a0-7989-4f5c-ae5a-f71e697abe16}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\physmeme">
|
||||
<UniqueIdentifier>{c4aa2f98-70d4-418e-894d-4e1975e2bad2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\util">
|
||||
<UniqueIdentifier>{4fd2f117-66bb-4f75-af5b-b7e041a4dc48}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\drv_image">
|
||||
<UniqueIdentifier>{161b3714-a6cd-4b7b-a1f1-9b90b1f84aca}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\drv_image">
|
||||
<UniqueIdentifier>{ed9d2db3-acef-42c0-880f-7f95dcca819d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="kernel_ctx\kernel_ctx.cpp">
|
||||
<Filter>Source Files\kernel_ctx</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="drv_image\drv_image.cpp">
|
||||
<Filter>Source Files\drv_image</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="kernel_ctx\kernel_ctx.h">
|
||||
<Filter>Header Files\kernel_ctx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\hook.hpp">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\util.hpp">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\nt.hpp">
|
||||
<Filter>Header Files\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="drv_image\drv_image.h">
|
||||
<Filter>Header Files\drv_image</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="physmeme\physmeme.hpp">
|
||||
<Filter>Header Files\physmeme</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerCommandArguments>C:\Users\interesting\Desktop\hello-world.sys</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LocalDebuggerCommandArguments>C:\Users\interesting\Desktop\hello-world.sys</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerCommandArguments>C:\Users\interesting\Desktop\hello-world.sys</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerCommandArguments>C:\Users\interesting\Desktop\hello-world.sys</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <mutex>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
|
||||
namespace physmeme
|
||||
{
|
||||
//--- 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;
|
||||
})();
|
||||
|
||||
/*
|
||||
please code this function depending on your method of physical read/write.
|
||||
*/
|
||||
static 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 (!is_valid(addr))
|
||||
return NULL;
|
||||
|
||||
static const auto map_phys_ptr =
|
||||
reinterpret_cast<__int64(__fastcall*)(__int64, unsigned)>(
|
||||
GetProcAddress(LoadLibrary("pmdll64.dll"), "MapPhyMem"));
|
||||
return map_phys_ptr ? map_phys_ptr(addr, size) : false;
|
||||
}
|
||||
|
||||
/*
|
||||
please code this function depending on your method of physical read/write.
|
||||
*/
|
||||
static bool unmap_phys(
|
||||
std::uintptr_t addr,
|
||||
std::size_t size
|
||||
)
|
||||
{
|
||||
static const auto unmap_phys_ptr =
|
||||
reinterpret_cast<__int64(*)(__int64, unsigned)>(
|
||||
GetProcAddress(LoadLibrary("pmdll64.dll"), "UnmapPhyMem"));
|
||||
return unmap_phys_ptr ? unmap_phys_ptr(addr, size) : false;
|
||||
}
|
||||
|
||||
/*
|
||||
please code this function depending on your method of physical read/write.
|
||||
*/
|
||||
static HANDLE load_drv()
|
||||
{
|
||||
static const auto load_driver_ptr =
|
||||
reinterpret_cast<__int64(*)()>(
|
||||
GetProcAddress(LoadLibrary("pmdll64.dll"), "LoadPhyMemDriver"));
|
||||
|
||||
if (load_driver_ptr)
|
||||
load_driver_ptr();
|
||||
|
||||
//--- i dont ever use this handle, its just an example of what you should do.
|
||||
return CreateFileA("\\\\.\\PhyMem", 0xC0000000, 3u, 0i64, 3u, 0x80u, 0i64);
|
||||
}
|
||||
|
||||
/*
|
||||
please code this function depending on your method of physical read/write.
|
||||
*/
|
||||
static bool unload_drv()
|
||||
{
|
||||
static const auto unload_driver_ptr =
|
||||
reinterpret_cast<__int64(*)()>(
|
||||
GetProcAddress(LoadLibrary("pmdll64.dll"), "UnloadPhyMemDriver"));
|
||||
return unload_driver_ptr ? unload_driver_ptr() : false;
|
||||
}
|
||||
|
||||
inline HANDLE drv_handle = load_drv();
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <winternl.h>
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
|
||||
#define MM_COPY_MEMORY_PHYSICAL 0x1
|
||||
#define MM_COPY_MEMORY_VIRTUAL 0x2
|
||||
|
||||
constexpr auto PAGE_SIZE = 0x1000;
|
||||
constexpr auto STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
|
||||
|
||||
constexpr auto SystemModuleInformation = 11;
|
||||
constexpr auto SystemHandleInformation = 16;
|
||||
constexpr auto SystemExtendedHandleInformation = 64;
|
||||
|
||||
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 (__fastcall*)(PVOID, MM_COPY_ADDRESS,SIZE_T,ULONG,PSIZE_T);
|
||||
using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(std::uintptr_t, std::size_t);
|
@ -0,0 +1,155 @@
|
||||
#include <Windows.h>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <iterator>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "nt.hpp"
|
||||
|
||||
/*
|
||||
This code stinks, its the worst code in this project and needs to be recoded in a later time.
|
||||
*/
|
||||
namespace util
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
Loading…
Reference in new issue