代码注入,通过页表 PML4 注入恶意载荷。
这只是一个页表注入技术的概念验证,用于向任意用户进程注入恶意代码。
在 Windows(以及某些现代操作系统)上,每个进程都有自己的 PML4,也称为目录表基址。因此,进程 A 无法在不使用 API 的情况下访问进程 B。但如果我们能够注入任意的 PML4 条目呢?当然,PML4 条目会指向对应物理地址的条目,PDP、PD 和 PT,与后台进程完全相同。
为了向目标进程注入恶意的 PML4 条目,我们需要有一个实际驻留的页面(物理内存)来支撑该恶意 PML4 条目。因此,该驻留页面实际上必须是驻留的,否则系统会崩溃或变得不稳定,因为在 MMU 转换为物理地址的过程中,MMU 期望的内容不存在,而且 Windows 内存管理器也没有任何预期的内容。
让我们看看后台进程和目标进程的缓冲区。在这种情况下,缓冲区分别是:
0x1A45F8100000x6EA45F810000在进入下一步之前,有些人可能会觉得第二个地址 (0x6EA45F810000) 看起来很奇怪,因为我们通常通过 malloc 或 VirtualAlloc 分配缓冲区,虚拟地址应该类似 0x17C7CAC0000、0x23BE9D80000、0x19FE76F0000 或类似的形式。这是因为恶意的 PML4 条目不涉及 Windows 的内存管理器,也不受其管理。当然,Windows 64 位进程中的任何虚拟地址都可能在一个用户内存范围内拥有任意值。
所以,如果我们查看这两个地址...
0: kd> .process ffff9803d8037080
Implicit process is now ffff9803`d8037080
0: kd> db 0x6EA45F810000 l2
00006ea4`5f810000 4d 5a MZ
0: kd> !vtop 7968b000 0x6EA45F810000
Amd64VtoP: Virt 00006ea45f810000, pagedir 000000007968b000
Amd64VtoP: PML4E 000000007968b6e8
Amd64VtoP: PDPE 000000005849b488
Amd64VtoP: PDE 0000000059e9c7e0
Amd64VtoP: PTE 000000003251d080
Amd64VtoP: Mapped phys 0000000014306000
Virtual address 6ea45f810000 translates to physical address 14306000.
0: kd> .process ffff9803d9f6b080
Implicit process is now ffff9803`d9f6b080
0: kd> db 0x1A45F810000 l2
000001a4`5f810000 4d 5a MZ
0: kd> !vtop 564f6000 0x1A45F810000
Amd64VtoP: Virt 000001a45f810000, pagedir 00000000564f6000
Amd64VtoP: PML4E 00000000564f6018
Amd64VtoP: PDPE 000000005849b488
Amd64VtoP: PDE 0000000059e9c7e0
Amd64VtoP: PTE 000000003251d080
Amd64VtoP: Mapped phys 0000000014306000
Virtual address 1a45f810000 translates to physical address 14306000.
两个地址都对应完全相同的页表条目:PDP、PD、PT 以及一个物理地址。因此,如果我们修改后台进程的缓冲区,目标进程的缓冲区也会随之改变。这与 Windows 上的共享内存非常相似,但区别在于目标进程上的内存区域永远不会出现在其任何 VAD 条目中。但另一方面,如果后台进程的缓冲区被释放,那么目标进程对应的缓冲区也会被释放,但目标进程的页表条目却没有被清理,这意味着内存管理器会导致 bugcheck MEMORY_MANAGEMENT,或者触发更严重的 CPU 三重故障。
这种技术存在严重的稳定性问题,正如我所说,注入的恶意 PML4 条目不涉及 Windows 内存管理器或内核。而且无法保证后台进程会在目标进程终止之前一直存在,或者当后台进程终止时,目标进程能够清除恶意 PML4 条目。
MIT 版权归 Kento Oki <[email protected]>
源代码中可能包含外部内容,这些内容归其版权人所有。