Physmeme 是一个驱动映射器,它适用于任何形式的物理内存读写。它是高度模块化的代码,允许逆向工程师轻松集成他们自己的易受攻击的驱动程序。如果您能够读取和写入物理内存,您现在只需编写四个函数即可将未签名的驱动程序映射到内核中。
Physmeme 的工作方式与更高级别的kdmapper类似。内联挂钩系统调用,然后调用系统调用,我们可以调用内核中的任何函数。唯一的问题是找到所需系统调用的物理页面。这可以通过简单的计算来完成。给定 ntoskrnl.exe 中导出函数的相对虚拟地址,您可以将虚拟地址与页面大小取模。通常页面是 0x1000 (4096) 字节,但在某些系统上它们可以是 2mb 或 1gb。
在左边你可以看到从 ntoskrnl.exe 的基地址到我们感兴趣的函数的相对虚拟地址。在图像上你可以看到为获得页面偏移量所做的简单计算。此页面偏移量稍后在映射器中用于将字节与物理内存进行比较。现在我们知道了页面偏移量,我们可以开始映射每个物理页面。与其一次做一页,不如一次映射 2mb 可以显着提高速度,这是因为 IOCTL 非常慢。除了一次映射 2mb 之外,为每个物理内存范围创建一个线程会将找到正确物理页面的时间缩短到一秒以下。
//--- for each physical memory range, make a thread to search it
std::vector<std::thread> search_threads;
for (const auto& ranges : util::pmem_ranges)
search_threads.emplace_back(std::thread(
&kernel_ctx::map_syscall,
this,
ranges.first,
ranges.second
));
for (std::thread& search_thread : search_threads)
search_thread.join();
一旦找到系统调用的物理页面并将其映射到我们的进程中,我们就可以在其中安装内联挂钩,然后调用该函数。这引入了一些风险,从补丁保护到竞争条件。尽管如此,发生此类事情的可能性还不足以引起问题,因为字节在几微秒/纳秒内恢复。
template <class T, class... Ts>
std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) const
{
static const auto proc =
GetProcAddress(
syscall_hook.second.data(),
syscall_hook.first.data()
);
hook::make_hook(psyscall_func, addr);
auto result = reinterpret_cast<T>(proc)(args ...);
hook::remove(psyscall_func);
return result;
}
使用此函数,您可以系统调用内核中的任何函数。
为什么你可能会问为什么在kdmapper或drvmapper上使用physmeme 。Physmeme 是高度模块化的代码,易于使用,允许用户在几分钟内集成他们自己的易受攻击的驱动程序。使用physmeme只需对四个函数进行编程。
加载和卸载驱动程序的两个函数。
*
load_drv,加载驱动程序并返回驱动程序句柄。*
unload_drv,关闭驱动程序的句柄,然后卸载它。处理物理内存的两个函数。
*
map_phys,将物理内存映射到当前进程的地址空间。*
unmap_phys,取消映射已映射到当前进程的物理内存。Physmeme 是一个高度模块化、功能完善的映射器,可用于系统地利用数千个已知和未知的驱动程序。读/写任意物理内存的能力非常广泛。从 cpu 风扇速度读取器到 bios 刷新实用程序的任何东西现在都可以轻松地用于映射驱动程序。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。