练习代码实现10-10-12的0线性地址挂物理页
前言:这篇记录通过代码实现挂物理页的实现
前面学习了页目录基址和页表基址,这里再通过用代码实现挂物理页来理解巩固这两个知识点
#练习通过代码挂物理页
老师在这集中主要就是让我们有个思路,后面会实践,我把我的想法写出来
既然C0300000线性地址中能够找到相关的PDT和PTT,所以肯定需要用到C0300000,为什么不用CR3?CR3是给CPU用的,它是物理地址,在代码中是不能直接用的
那么访问C0300000肯定需要通过门提权或者修改页的U/S位来实现,接着就是如何访问PDE和PTE了
首先PDE肯定好访问和修改,因为C0300000指向的物理页
这条指令就是能够实现修改第几个的PDE -> mov dword ptr ds:[0xC0300000+N*4],要修改PDE的值
然后接着就是修改第几个PTE,mov dword ptr ds:[第几个的PDE的地址 & FFFFF000 + 相关的偏移],要修改的PTE的值
掌握了这两个地址0xC0300000和0xC0000000,就掌握了一个进程所有的物理内存读写权限。
公式总结
1、访问页目录表中第PDI个PDE的公式:0xC0300000 + PDI*4
2、访问页表中第PDI个PDE中的第PTI个PTE公式:0xC0000000 + PDI*4096 + PTI*4
知识点:
PDI:就是在10-10-12分页模式中的PDE的索引
PTI:就是在10-10-12分页模式中的PTI的索引
代码实现0线性地址挂物理页
C0300000
->
1100 0000 00 *4 -> C00
11 0000 0000 *4 -> C00
000
C0000000
->
1100 0000 00 *4 -> C00
00 0000 0000 -> 0
000 -> 0
实现过程:
1、eq 8003f048 0040EC03 00081005 ,进行调用门提权(有坑),改用中断门提权
2、提权之后,对0的线性地址进行挂上可读写的物理页即可
这里会有疑惑点,要让0线性地址的PDE和PTE去填充什么好呢?这里我通过VirtualAllow来申请线性地址,然后拆分该线性地址取得相关的PDE和PTE,用这个PDE和PTE来覆盖0线性地址的PDE和PTE
测试代码如下
#include<windows.h>
#include<stdio.h>
DWORD* getPDE(DWORD addr)
{
DWORD PDI = addr>>22;
DWORD PTI = (addr>>12) & 0x000003FF;
return (DWORD*)(0xC0300000 + PDI * 4);
}
DWORD* getPTE(DWORD addr)
{
DWORD PDI = addr>>22;
DWORD PTI = (addr>>12)&0x000003FF;
return (DWORD*)(0xC0000000 + PDI * 0x1000 + PTI * 4);
}
DWORD iAddr;
__declspec(naked) void test()
{
__asm
{
push ebp;
mov ebp, esp;
sub esp,0x1000;
pushad;
pushfd;
push fs;
}
*getPDE(0) = *getPDE(iAddr);
*getPTE(0) = *getPTE(iAddr);
__asm
{
//int 3;
pop fs;
popfd;
popad;
add esp,0x1000;
mov esp,ebp;
pop ebp;
iretd;
}
}
int main()
{
iAddr = (DWORD)VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_READWRITE);
memset((DWORD*)iAddr,0,0x1000);
printf("virtualAlloc addr: %x\n", iAddr);
printf("test addr: %x\n", test);
__asm
{
int 0x20;
}
// test r/w
*(DWORD*)0 = 0x12345678;
printf("%x\n", *(DWORD*)0);
return 0;
}
坑点,我一开始用的是CALL调用门提权,我调试发现CALL压入的ESP和SS寄存器都消失了,所以就算代码写的是对的,同样也会蓝屏,原因不知道

接着我看了别人的文章,别人是通过中断门提权的,我发现同样的代码,我改了中断门就可以了
eq 8003f500 0040EE00 00081005(省略了反引号)


浙公网安备 33010602011771号