章节介绍
- Win7 x86 设置2-9-9-12分页.
- windows与Intel管理物理页规则,以及Windows内存分区.
- 2-9-9-12分页规则及其由来.
- 通过线性地址查找对应物理地址.
- 共享内存实现原理.
- 0地址访问错误缘故起因,常量区无法修改缘故起因,高2G内存R3访问失败起因于物理页属性限制.
- PDPTE,PDE,PTE属性探测,基址探测(MmIsAddressValid).
- 代码示例0线性地址挂物理页,0线性地址实现SHELLCODE,R3通过门读取任意线性地址...
0.Win7 x86设置2-9-9-12分页
CMD:关闭指令(开启10-10-12分页) bcdedit /set pae ForceDisable bcdedit /set nx AlwaysOff 开启指令(开启2-9-9-12分页)bcdedit /set pae forceEnablebcdedit /set nx OptIn 分页内核文件目录: C:\Windows\System32
x86下每个进程都有虚拟4GB内存空间(x86下线性地址宽度为32位4字节,2^32为4GB(线性地址有4G但未必都能访问 高2G内存为全部进程共享)),x86下虚拟地址划分为:
内存区范围空指针赋值区0x00000000 - 0x0000FFFF用户模式区 0x00010000 - 0x7FFEFFFF64KB禁入区0x7FFF0000 - 0x7FFFFFFF内核0x80000000 - 0xFFFFFFFFintel amd规定一个最小物理页为4KB(一个物理页4096byte遍历每一个字节2^12这也就是分页最后12由来)
Windows规定一个最小物理页为64KB.
1.2-9-9-12分页规则
x86下每个进程有4GB线性地址空间,但是有些地址无法访问,这是由于线性地址对应物理地址为空大概对应物理页属性限制.物理地址MOV EAX, DWORD PTR DS:[0x12345678]有效地址: 0x12345678线性地址: DS.BASE + 0x12345678物理地址: 2-9-9-12分页 通过高31-30位定位PDPTE,通过29-21位定位PDE,通过20-12位定位PTE,通过PTE指向基址 + 11-00位定位页内偏移每个进程都有一个CR3(CR3是一个寄存器,每个核心一个) CR3指向一个物理页(4KB),2-9-9-12分页模式下CR3指向PDPT分页规则物理页: 4KB(4096BYTE)09: PDE(8BYTE),物理页(4KB),一张物理页可以存储 4096 / 8 (512),要遍历每一个PDE 2^909: PTE(8BYTE),物理页(4KB),一张物理页可以存储 4096 / 8 (512),要遍历每一个PTE 2^912: 物理页(4KB),要遍历每一个字节 2^1202: PDPTE(8BYTE)32位剩余2位 2^2(4)一共4个PDPTE2-9-9-12线性地址上限: 4 * 512 * 512 * 4096 4GB2-9-9-12物理地址上限: 2^36(物理地址宽度) 64GB同一进程内相同物理页 MOV EAX, DWORD PTR DS:[0x12345FFF] MOV EAX, DWORD PTR DS:[0x12345EEE] 线性地址前20位(PDPTE PDE PTE)决定在哪张物理页,后12位(OFFSET)决定页内偏移 PTE规则PTE可以没有物理页,且只能对应一个物理页.多个PTE也可以指向同一个物理页. 1.1 通过线性地址查找对应物理地址
#include #include int main(){ DWORD num = 0x64; printf("numaddr -> 0x%08x numdata -> 0x%08x \r\n",&num, num); system("pause"); printf("numaddr -> 0x%08x numdata -> 0x%08x \r\n",&num, num); system("pause"); return 0;}
有效地址为: 0x0012ff44
线性地址为: 0x0012ff44 + SS.Base(0)
线性地址转换为二进制: 0000 0000 0001 0010 1111 1111 0100 0100
2: 00 0h PDPTE
9: 0 0000 0000 000h PDE
9: 1 0010 1111 12fh PTE
12: 1111 0100 0100 f44h OFFSET
通过Windbg手动查看:
1).通过!process 0 0查找进程CR3
DirBase = Cr3 = PDPT.Base = 0x7ea04440
*2).查找PDPTE(巨细8字节)(PDPT(页目录指针表基址) + PDPTI(页目录指针项索引) 8)**
!dq(8Byte方式)查看物理地址
*3).查找PDE(巨细8字节)(PDT(页目录表基址) + PDI(页目录项索引) 8)**
查找需要将PDPTE后12位抹除(为PDPTE属性)
*4).查找PTE(巨细8字节)(PTT(页表基址) + PTI(页表项索引) 8)**
查找需要将PDE后12位抹除(为PDE属性)
5).查找线性地址对应物理地址(Physical Page + offset)
查找需要将PTE后12位抹除(为PTE属性)
6).修改物理页数据(!ed指令)
1.2 申请内存挂物理页过程
#include #include int main(){ PVOID lp = VirtualAlloc(NULL,0x64,MEM_COMMIT,PAGE_EXECUTE_READWRITE); if (!lp) { printf("VirtualAlloc Fail \r\n"); getchar(); } printf("mem addr -> 0x%08x \r\n",lp); system("pause"); memset(lp,0xFF,4); system("pause"); return 0;}
有效地址为: 0x00150000
线性地址为: 0x00150000 + SS.Base(0)
线性地址转换为二进制: 0000 0000 0001 0101 0000 0000 0000 0000
2: 00 0h PDPTE
9: 0 0000 0000 000h PDE
9: 1 0101 0000 150h PTE
12: 0000 0000 0000 000h OFFSET
通过Windbg手动查看:
1).通过!process 0 0 查找进程CR3
DirBase = Cr3 = PDPT.Base = 0x7ea04440
*2).查找PDPTE(巨细8字节)(PDPT(页目录指针表基址) + PDPTI(页目录指针项索引) 8)**
!dq(8Byte方式)查看物理地址
*3).查找PDE(巨细8字节)(PDT(页目录表基址) + PDI(页目录项索引) 8)**
查找需要将PDPTE后12位抹除(为PDPTE属性)
*4).查找PTE(巨细8字节)(PTT(页表基址) + PTI(页表项索引) 8)**
查找需要将PDE后12位抹除(为PDE属性)
5).实行初始化内存代码
*6).查找PTE(巨细8字节)(PTT(页表基址) + PTI(页表项索引) 8)**
查找需要将PDE后12位抹除(为PDE属性)
7).查找线性地址对应物理地址(Physical Page + offset)
查找需要将PTE后12位抹除(为PTE属性)
使用virtualalloc函数在申请内存成功情况下如果不初始化将不会被挂有效物理页
1.3 什么是共享内存?(多个线性地址共用一个或多个物理页)
进程A代码
#include #include int main(){ int num = 1; printf("numaddr -> 0x%08x numdata -> 0x%08x \r\n",&num , num); system("pause"); printf("numaddr -> 0x%08x numdata -> 0x%08x \r\n",&num , num); system("pause"); return 0;}进程B代码
#include #include int main(){ system("pause"); printf("0data -> 0x%08x \r\n",*(LPDWORD)(0 + 0xf44)); *(LPDWORD)(0 + 0xf44) = 0xffffffff; system("pause"); return 0;}1).打开进程A查看变量所对应物理地址
2).打开进程B给0线性地址挂物理页
3).实行进程B剩余代码
4).实行进程A剩余代码
进程B代码实行后将会同时修改进程A变量数据,由于此时指向同一张物理页且页内偏移相同
数据被成功修改
2.2-9-9-12分页PDE PTE属性探测
测试代码使用内核函数MmIsAddressValid实现原理后文将分析
如果代码实行后不生效TLB(后需章节介绍)没有刷新,切换进程或打开新进程后在运行
2.1 P位
P = 1 有效的物理页
P = 0 无效的物理页
#include #include DWORD g_Data = 0x12345678;DWORD g_offs = (DWORD)&g_Data & 0xFFF;DWORD g_PDE = 0;DWORD g_PTE = 0;_declspec(naked) VOID ChangePTEAttribute(){ __asm { //获取线性地址 lea ecx, g_Data //获取PDE mov eax, ecx shr eax, 0x12 and eax, 0x3FF8 sub eax, 0x3FA00000 mov eax, [eax] mov g_PDE, eax //PDE->P test al, 1 jz END //获取PTE mov eax, ecx shr eax, 0x9 and eax, 0x7FFFF8 sub eax, 0x40000000 mov eax, [eax] mov g_PTE, eax //PTE->P test al, 1 jz END //获取线性地址 mov ecx, 0 //PTE mov eax, ecx shr eax, 0x9 and eax, 0x7FFFF8 sub eax, 0x40000000 mov edx, g_PTE mov [eax], edxEND: iretd }}int main(){ printf("INTERRUPT ADDR [0x%08x] \n",ChangePTEAttribute); printf("ADDR [0x%08x] DATA [0x%08x] OFFS [0x%03x] \n",&g_Data, g_Data, g_offs); system("Pause"); __asm { //通过停止门给0线性地址挂物理页 //eq 80b99500 0040ee00`00081005 INT 0x20 } *(LPDWORD)(0 + g_offs) = 0xFFFFFFFF; printf("ADDR [0x%08x] DATA [0x%08x] OFFS [0x%03x] \n",&g_Data, g_Data, g_offs); system("Pause"); return 0;}
变量地址为:0x00412030 转换为二进制 0000 0000 0100 0001 0010 0000 0011 0000
按照2-9-9-12分页格式转换:
2: 00 0h PDPTE
9: 0 0000 0010 002h PDE
9: 0 0001 0010 012h PTE
12: 0000 0011 0000 030h OFFSET
通过Windbg手动查看:
1).通过!process 0 0查看进程CR3
DirBase = Cr3 = PDPT.Base = 0x7eb54460
*2).查找PDPTE(巨细8字节)(PDPT(页目录指针表基址) + PDPTI(页目录指针项索引) 8)**
!dq(8Byte方式)查看物理地址
*3).查找PDE(巨细8字节)(PDT(页目录表基址) + PDI(页目录项索引) 8)**
查找需要将PDPTE后12位抹除(为PDPTE属性)
*4).查找PTE(巨细8字节)(PTT(页表基址) + PTI(页表项索引) 8)**
查找需要将PDE后12位抹除(为PDE属性)
5).查找线性地址对应物理地址(Physical Page + offset)
查找需要将PTE后12位抹除(为PTE属性)
变量线性地址0x00412030对应物理地址为:#055491030
0线性地址默认不可访问是由于没有挂有效物理地址
上述代码实行完毕后将0线性地址对应物理地址改为变量所对应物理地址,即0线性地址此时存在有效物理页
2.2 R/W位
R/W = 0 只读
R/W = 1 可读可写
#include #include CHAR* Data = "HHHHHH";DWORD g_PDE = 0;DWORD g_PTE = 0;_declspec(naked) VOID ChangePTEAttribute(){ __asm { //获取线性地址 mov ecx, Data //获取PDE mov eax, ecx shr eax, 0x12 and eax, 0x3FF8 sub eax, 0x3FA00000 mov eax, [eax] mov g_PDE, eax //PDE->P test al, 1 jz END //获取PTE mov eax, ecx shr eax, 0x9 and eax, 0x7FFFF8 sub eax, 0x40000000 mov edx, [eax] mov g_PTE, edx //PTE->P test dl, 1 jz END //修改R/W位 or dl, 2 mov [eax], edx mov g_PTE, edxEND: iretd }}int main(){ printf("INTERRUPT ADDR [0x%08x] \n",ChangePTEAttribute); printf("DATA [%s] %08x\n",Data,&Data[0]); system("Pause"); __asm { //通过停止门修改页属性 //eq 80b99500 0040ee00`00081005 INT 0x20 } Data[0] = 'A'; printf("DATA [%s] PDE [0x%08x] PTE [0x%08x] \n",Data, g_PDE,g_PTE); system("Pause"); return 0;}
变量地址为:0x0041010C 转换为二进制 0000 0000 0100 0001 0000 0001 0000 1100
按照2-9-9-12分页格式转换:
2: 00 0h PDPTE
9: 0 0000 0010 002h PDE
9: 0 0001 0000 010h PTE
12: 0001 0000 1100 10Ch OFFSET
通过Windbg手动查看:
1).通过!process 0 0查看进程CR3
DirBase = Cr3 = PDPT.Base = 0x7eb54560
*2).查找PDPTE(巨细8字节)(PDPT(页目录指针表基址) + PDPTI(页目录指针项索引) 8)**
!dq(8Byte方式)查看物理地址
*3).查找PDE(巨细8字节)(PDT(页目录表基址) + PDI(页目录项索引) 8)**
查找需要将PDPTE后12位抹除(为PDPTE属性)
*4).查找PTE(巨细8字节)(PTT(页表基址) + PTI(页表项索引) 8)**
查找需要将PDE后12位抹除(为PDE属性)
5).查找线性地址对应物理地址(Physical Page + offset)
查找需要将PTE后12位抹除(为PTE属性)
变量线性地址0x0041010C对应物理地址为:#04c01310c
常量字符串不可以修改是由于物理页属性限制修改R/W位即可改写
2.3 U/S位
U/S = 0 特权用户
U/S = 1 平凡用户
2G以上是内核才能访问的缘故起因是U/S位的设置问题,如果将内核的某个页设置为1就可以在R3访问了.
0 1 2是系统环可以访问系统页和用户页0环是特权级环1, 2环固然不是特权级环 但是是系统环 3环是用户环 可以访问用户页.
#include #include DWORD g_PDE = 0;DWORD g_PTE = 0;_declspec(naked) VOID ChangePTEAttribute(){ __asm { //获取线性地址 mov ecx, 0x80b99008 //获取PDE mov eax, ecx shr eax, 0x12 and eax, 0x3FF8 sub eax, 0x3FA00000 mov edx, [eax] test dl, 1 jz END or dl, 4 mov [eax], edx mov g_PDE, edx //获取PTE mov eax, ecx shr eax, 0x9 and eax, 0x7FFFF8 sub eax, 0x40000000 mov edx, [eax] test dl, 1 jz END //全局页修改G位 and edx, 0xFFFFFEFF //修改U/S位 or dl, 4 mov [eax], edx mov g_PTE, edxEND: iretd }}int main(){ printf("INTERRUPT ADDR [0x%08x] \n",ChangePTEAttribute); system("Pause"); __asm { //通过停止门提权修改页属性 //eq 80b99500 0040ee00`00081005 INT 0x20 } printf("PDE [0x%08x] PTE [0x%08x] \n",g_PDE,g_PTE); printf("DATA [0x%08x] \n",*(LPDWORD)0x80b99008); system("Pause"); return 0;} 线性地址为:0x80b99008 转换为二进制 1000 0000 1011 1001 1001 0000 0000 1000
按照2-9-9-12分页格式转换:
2: 10 2h PDPTE
9: 0 0000 0101 005h PDE
9: 1 1001 1001 199h PTE
12: 0000 0000 1000 008h OFFSET
通过Windbg手动查看:
1).通过!process 0 0查看进程CR3
DirBase = Cr3 = PDPT.Base = 0x7eb54280
*2).查找PDPTE(巨细8字节)(PDPT(页目录指针表基址) + PDPTI(页目录指针项索引) 8)**
!dq(8Byte方式)查看物理地址
*3).查找PDE(巨细8字节)(PDT(页目录表基址) + PDI(页目录项索引) 8)**
查找需要将PDPTE后12位抹除(为PDPTE属性)
*4).查找PTE(巨细8字节)(PTT(页表基址) + PTI(页表项索引) 8)**
查找需要将PDE后12位抹除(为PDE属性)
5).查找线性地址对应物理地址(Physical Page + offset)
查找需要将PTE后12位抹除(为PTE属性)
线性地址0x80b99008对应物理地址为:#b99008
应用层不可以访问高2G内存是由于物理页属性限制修改U/S位即可改写
2.4 PS位
只对PDE有意义
PS = 0 指向PTE
PS = 1 没有PTE 直接指向物理页 低21位是页内偏移 大页(2 ^ 21)2MB
2.5 A位
A = 0 未访问(读大概写)
A = 1 已访问(读大概写)
2.6 D位
D = 0 没有被写过
D = 1 被写过
2.7 XD位
段的属性有可读、可写和可实行页的属性有可读、可写当RET实行返回的时候,如果我修改堆栈里面的数据指向一个我提前预备好的数据(把数据当作代码来实行,漏洞都是依赖这点,比如SQL注入也是)所以,Intel就做了硬件保护,做了一个不可实行位,XD=1时。那么你的软件溢出了也没有关系,即使你的EIP蹦到了危险的“数据区”,也是不可以实行的!在PAE分页模式下,PDE与PTE的最高位为XD/NX位. 3.PDT PTT基址
2-9-9-12分页模式1.页表被映射到了从0xC0000000到0xC07FFFFF的8M地址空间(4(PDT) * 512(PTE) * 4096)2.在这1024个表中有一张特殊的表:页目录表3.页目录被映射到了0xC0600000开始处的16K地址空间0xc0600000 指向页目录表(PDT)0xc0000000 指向第一张页表(PTT)页目录表着实是一张特殊的页表,它是第0x600张页表。页目录表中每项PTE都指向一张页表,其中第0x600项指向了页目录表自己PDPI(PDPE INDEX) PDI(PDE INDEX) PTI(PTE INDEX)访问页目录表的公式:0xC0600000 + PDPI * 4KB + PDI * 8访问页表的公式:0xC0000000 + PDPI * 2MB + PDI * 4KB + PTI * 84.MmIsAddressValid(Win7 x86 2-9-9-12)
.text:00411717 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress).text:00411717 public _MmIsAddressValid@4.text:00411717 _MmIsAddressValid@4 proc near ; CODE XREF: IopIsAddressRangeValid(x,x)+31↑p.text:00411717 ; sub_4C9A84+13↓p ....text:00411717.text:00411717 VirtualAddress = dword ptr 8.text:00411717.text:00411717 8B FF mov edi, edi ; 热补丁.text:00411719 55 push ebp.text:0041171A 8B EC mov ebp, esp ; 提拔栈底.text:0041171C 8B 55 08 mov edx, [ebp+VirtualAddress] ; edx = 线性地址(Param).text:0041171F E8 84 33 0A 00 call _MiIsAddressValid@8 ; MiIsAddressValid(x,x).text:00411724 5D pop ebp ; 恢复栈底.text:00411725 C2 04 00 retn 4 ; 返回.text:00411725 _MmIsAddressValid@4 endp.text:004B4AA8 ; __stdcall MiIsAddressValid(x, x).text:004B4AA8 _MiIsAddressValid@8 proc near ; CODE XREF: MiMakeSystemAddressValidSystemWs(x,x)+E↑p.text:004B4AA8 ; MiMakeSystemAddressValidSystemWs(x,x)+10C↑p ....text:004B4AA8.text:004B4AA8 var_8 = dword ptr -8.text:004B4AA8 var_4 = dword ptr -4.text:004B4AA8.text:004B4AA8 8B FF mov edi, edi ; 热补丁.text:004B4AAA 55 push ebp.text:004B4AAB 8B EC mov ebp, esp ; 提拔栈底.text:004B4AAD 51 push ecx.text:004B4AAE 51 push ecx ; 保存寄存器数据.text:004B4AAF 8B C2 mov eax, edx ; eax = 线性地址.text:004B4AB1 C1 E8 12 shr eax, 12h ; eax 右移 18位.text:004B4AB4 25 F8 3F 00 00 and eax, 3FF8h ; (eax >> 0x12) & 0x3FF8(0011 1111 1111 1000) == PDPTI * 4KB + PDI * 8.text:004B4AB9 2D 00 00 A0 3F sub eax, 3FA00000h ; sub 0x3FA00000 = add 0xC0600000.text:004B4AB9 ; 0xC0600000是页目录表被映射的起始线性地址.text:004B4ABE 8B 08 mov ecx, [eax] ; 取出PDE低4字节数据存入ecx.text:004B4AC0 8B 40 04 mov eax, [eax+4] ; 取出PDE高4字节数据存入eax.text:004B4AC3 89 45 FC mov [ebp-4], eax ; 将PDE高4字节数据存储在局部变量ebp - 4 中.text:004B4AC6 8B C1 mov eax, ecx ; PDE低4字节(大部分属性位在低12位)放入eax.text:004B4AC8 83 E0 01 and eax, 1 ; 与运算判定P位是否为1.text:004B4ACB 6A 00 push 0.text:004B4ACD 89 45 F8 mov [ebp-8], eax.text:004B4AD0 58 pop eax.text:004B4AD1 74 04 jz short loc_4B4AD7 ; P位为0无效页跳转返回.text:004B4AD3 85 C0 test eax, eax.text:004B4AD5 74 04 jz short loc_4B4ADB.text:004B4AD7.text:004B4AD7 loc_4B4AD7: ; CODE XREF: MiIsAddressValid(x,x)+29↑j.text:004B4AD7 32 C0 xor al, al ; 清空al.text:004B4AD9 C9 leave ; mov esp, ebp.text:004B4AD9 ; pop ebp.text:004B4ADA C3 retn ; 返回.text:004B4ADB ; ---------------------------------------------------------------------------.text:004B4ADB.text:004B4ADB loc_4B4ADB: ; CODE XREF: MiIsAddressValid(x,x)+2D↑j.text:004B4ADB 56 push esi ; 保留寄存器数据.text:004B4ADC BE 80 00 00 00 mov esi, 80h ; '?' ; esi = 0x80.text:004B4AE1 23 CE and ecx, esi ; PDE低4字节与0x80进行与运算 判定是否是大页.text:004B4AE3 6A 00 push 0.text:004B4AE5 89 4D F8 mov [ebp-8], ecx.text:004B4AE8 58 pop eax.text:004B4AE9 74 04 jz short loc_4B4AEF ; 小页跳转.text:004B4AEB 85 C0 test eax, eax.text:004B4AED 74 3C jz short loc_4B4B2B ; 大页跳转返回.text:004B4AEF.text:004B4AEF loc_4B4AEF: ; CODE XREF: MiIsAddressValid(x,x)+41↑j.text:004B4AEF C1 EA 09 shr edx, 9 ; edx 右移 9 位.text:004B4AF2 81 E2 F8 FF 7F 00 and edx, 7FFFF8h ; (edx >> 9) & 0x7FFFF8(0111 1111 1111 1111 1111 1000) = PDPTI * 2MB + PDI * 4KB + PTI * 8.text:004B4AF8 8B 8A 04 00 00 C0 mov ecx, [edx-3FFFFFFCh] ; 获取PTE高4字节数据存入ecx.text:004B4AF8 ; sub 0x3FFFFFFC = add 0xC0000004.text:004B4AFE 81 EA 00 00 00 40 sub edx, 40000000h.text:004B4B04 8B 02 mov eax, [edx] ; 获取PTE低4字节数据存入edx.text:004B4B04 ; sub 0x40000000 = add 0xC0000000.text:004B4B04 ; 0xC0000000是页表被映射的起始线性地址.text:004B4B06 89 4D FC mov [ebp-4], ecx.text:004B4B09 8B C8 mov ecx, eax ; ecx = PTE低4字节数据.text:004B4B0B 83 E1 01 and ecx, 1 ; 判定PTE.P位是否为1.text:004B4B0E 6A 00 push 0.text:004B4B10 89 4D F8 mov [ebp-8], ecx.text:004B4B13 59 pop ecx.text:004B4B14 74 11 jz short loc_4B4B27 ; P = 0 无效页跳转返回.text:004B4B16 85 C9 test ecx, ecx.text:004B4B18 75 0D jnz short loc_4B4B27.text:004B4B1A 23 C6 and eax, esi ; esi = 0x80 与PTE低4字节进行与运算判定PAT位.text:004B4B1C 51 push ecx.text:004B4B1D 89 45 F8 mov [ebp-8], eax.text:004B4B20 58 pop eax.text:004B4B21 74 08 jz short loc_4B4B2B ; PAT = 0跳转返回.text:004B4B23 85 C0 test eax, eax.text:004B4B25 75 04 jnz short loc_4B4B2B.text:004B4B27.text:004B4B27 loc_4B4B27: ; CODE XREF: MiIsAddressValid(x,x)+6C↑j.text:004B4B27 ; MiIsAddressValid(x,x)+70↑j.text:004B4B27 32 C0 xor al, al ; 清空al.text:004B4B29 EB 02 jmp short loc_4B4B2D.text:004B4B2B ; ---------------------------------------------------------------------------.text:004B4B2B.text:004B4B2B loc_4B4B2B: ; CODE XREF: MiIsAddressValid(x,x)+45↑j.text:004B4B2B ; MiIsAddressValid(x,x)+79↑j ....text:004B4B2B B0 01 mov al, 1 ; al置1.text:004B4B2D.text:004B4B2D loc_4B4B2D: ; CODE XREF: MiIsAddressValid(x,x)+81↑j.text:004B4B2D 5E pop esi ; 恢复esi寄存器数据.text:004B4B2E C9 leave ; mov esp, ebp.text:004B4B2E ; pop ebp.text:004B4B2F C3 retn ; 返回.text:004B4B2F _MiIsAddressValid@8 endp5.代码示例
5.1 0线性地址挂物理页
#include #include //PDE PTEDWORD dwCodePDE = 0;DWORD dwCodePTE = 0;DWORD dwZeroPDE = 0;DWORD dwZeroPTE = 0;//PAGELPDWORD g_lp = NULL;VOID _declspec(naked)Fun(){ __asm { //CODE PAGE mov ecx, g_lp //PDE mov eax, ecx shr eax, 0x12 and eax, 0x3FF8 sub eax, 0x3FA00000 mov eax, [eax] mov dwCodePDE, eax //PTE shr ecx, 0x9 and ecx,0x7FFFF8 sub ecx,0x40000000 mov ecx, [ecx] mov dwCodePTE, ecx //0 PAGE xor ecx, ecx //PDE mov eax, ecx shr eax, 0x12 and eax, 0x3FF8 sub eax, 0x3FA00000 mov edx, eax mov eax, [eax] mov dwZeroPDE, eax and eax, eax jnz FLAG mov eax, edx mov edx, dwCodePDE mov [eax], edxFLAG: //PTE shr ecx, 0x9 and ecx, 0x7FFFF8 sub ecx, 0x40000000 mov edx, dwCodePTE mov [ecx], edx mov dwZeroPTE, edx retf }}int main(){ //PAGE g_lp = (LPDWORD)VirtualAlloc(NULL,0x100,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE); if (!g_lp) { MessageBox(NULL,"VirtualAlloc Fail !","ERROR",MB_OK|MB_ICONERROR); exit(0); } g_lp[0] = 0x12345678; printf("dwVar Addr = %08x Data = %08x PDPI = %x PDI = %x PTE = %x Offset = %x \n", g_lp, g_lp[0], ((DWORD)g_lp >> 30) & 0x3, ((DWORD)g_lp >> 21) & 0x1FF, ((DWORD)g_lp >> 12) & 0x1FF, ((DWORD)g_lp) & 0xFFF); printf("Function Addr = %08x \n",Fun); system("Pause"); //CALL GATE CHAR calldata[6] = {0,0,0,0,0x48,0}; __asm { call fword ptr [calldata] } *(LPDWORD)0 = 0xFFFFFFFF; printf("CODE PDE = %08X PTE = %08X \n",dwCodePDE, dwCodePTE); printf("ZERO PDE = %08X PTE = %08X \n",dwZeroPDE, dwZeroPTE); printf("Data = %08x \n",g_lp[0]); system("Pause"); return 0;}
5.2 读取任意线性地址指定长度
#include #include //ADDRDWORD dwAddr;DWORD dwReadLen;//PDE PTE ATTRITUBEDWORD dwPDE[0x1000];DWORD dwPTE[0x1000];//Data BufferBYTE szData[0x1000];//Continue FlagDWORD dwFlag;//asmVOID _declspec(naked)GetAddrData(){ __asm { //SAVE DATA pushad pushfd //Stack Save Info mov eax, dwAddr mov [esp - 0x4], eax mov eax, dwReadLen mov [esp - 0x8], eax mov eax, 0 mov [esp - 0xC], eax lea eax, dwPDE mov [esp - 0x10], eax lea eax, dwPTE mov [esp - 0x14], eax lea eax, szData mov [esp - 0x18], eaxSTAR: //Get Addr mov ecx, [esp - 0x4] mov eax, [esp - 0xC] add ecx, eax //PDE mov eax, ecx shr eax, 0x12 and eax, 0x3FF8 sub eax, 0x3FA00000 mov eax, [eax] //SAVE PDE mov edx, [esp - 0x10] mov ebx, [esp - 0xC] mov [edx + ebx * 4], eax //CHECK PDE mov ebx, eax and ebx, 0x1 JZ END mov ebx, eax and ebx, 0x2 jz END //PTE mov eax, ecx shr eax, 0x9 and eax, 0x7FFFF8 sub eax, 0x40000000 mov eax, [eax] //SAVE PTE mov edx, [esp - 0x14] mov ebx, [esp - 0xC] mov [edx + ebx * 4], eax //CHECK PTE mov ebx, eax and ebx, 0x1 JZ END mov ebx, eax and ebx, 0x2 jz END //Check Over GetData mov ecx, [esp - 0x4] mov eax, [esp - 0xC] add ecx, eax mov al, byte ptr [ecx] mov edx, [esp - 0x18] mov ebx, [esp - 0xC] mov [edx + ebx * 1], alEND: //INC Index mov eax, [esp - 0xC] add eax, 1 mov [esp - 0xC], eax //DEC ReadLength and Check mov eax, [esp - 0x8] sub eax, 1 mov [esp - 0x8], eax and eax, eax jnz STAR //LOAD DATA popfd popad //RETF EIP CS ESP SS retf }}int main(){ //Global Descriptor Insert Data WIN7X86 printf("Descriptor %04xEC00`0008%04x \n",HIWORD(GetAddrData),LOWORD(GetAddrData)); system("Pause"); //Entry while (0x1F) { //Clean and Init system("cls"); memset(dwPDE,0,sizeof(dwPDE[0]) * (sizeof(dwPDE) / sizeof(dwPDE[0]))); memset(dwPTE,0,sizeof(dwPTE[0]) * (sizeof(dwPTE) / sizeof(dwPTE[0]))); memset(szData,0,sizeof(szData[0]) * (sizeof(szData) / sizeof(szData[0]))); BYTE dwTest[10] = {0}; printf("%08x \n",dwTest); for (int j = 0; j < 10; j++) { dwTest[j] = j; } printf("Please Input Address(HEX) : "); scanf("%x",&dwAddr); printf("Please Input Readlen(DEC) : "); scanf("%d",&dwReadLen); //Output Info printf("Addr [0x%08x] Readlength [%d] \n",dwAddr,dwReadLen); //CALL GATE CHAR calldata[6] = {0,0,0,0,0x48,0}; __asm { call fword ptr [calldata] } //Output Data printf("\n"); for (int i = 0; i < dwReadLen; i++) { printf("Addr [0x%08x] PDE [0x%08x] PTE[0x%08x] Data[0x%02x] \n",dwAddr + i, dwPDE, dwPTE, szData); } printf("\n"); //Continue or Exit printf("Continue / Exit [1/0] : "); scanf("%d",&dwFlag); if (!dwFlag) { exit(0); } } return 0;}
5.3 使用0x1000线性地址输出页数据
#include #include //PAGELPDWORD g_lp = NULL;DWORD dwPDE;DWORD dwPTE;DWORD dwAdd;//Load PDE PTEVOID _declspec(naked)Fun(){ __asm { //SAVE DATA pushad pushfd //Get addr mov ecx, g_lp //PDE mov eax, ecx shr eax, 0x12 and eax, 0x3FF8 sub eax, 0x3FA00000 mov eax, [eax] mov dwPDE, eax //PTE mov eax, ecx shr eax, 0x9 and eax, 0x7FFFF8 sub eax, 0x40000000 mov eax, [eax] mov dwPTE, eax //Get 0x1000 mov ecx, 0x1000 //PDE mov eax, ecx shr eax, 0x12 and eax, 0x3FF8 sub eax, 0x3FA00000 mov edx, eax mov eax, [eax] and eax, 0x1 JNZ FLAG mov eax, edx mov edx, dwPDE mov [eax], edxFLAG: //PTE mov eax, ecx shr eax, 0x9 and eax, 0x7FFFF8 sub eax, 0x40000000 mov edx, dwPTE mov [eax], edx //LOAD DATA popfd popad //RET retf }}int main(){ //virtual Page g_lp = (LPDWORD)VirtualAlloc(NULL,sizeof(DWORD) * 100,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE); if (!g_lp) { MessageBox(NULL,"VirtualAlloc Fail ! ","ERROR",MB_OK|MB_ICONERROR); exit(0); } //intit for (int i = 0; i < 100; i++) { g_lp = (DWORD)&g_lp; } dwAdd = 0x1000; dwPDE = 0; dwPTE = 0; printf("Descriptor %04xEC00`0008%04x \n",HIWORD(Fun), LOWORD(Fun)); system("Pause"); system("cls"); //CALL GATE CHAR calldata[6] = {0,0,0,0,0x48,0}; __asm { call fword ptr [calldata] } printf("Addr [0x%08x] PDE[0x%08x] PTE[0x%08x] \n\n", DWORD(g_lp), dwPDE, dwPTE); for (int j = 0; j < 100; j++) { printf("Addr [0x%08x] PDE[0x%08x] PTE[0x%08x] Data [0x%08x]\n",0x1000 + j * 4,dwPDE,dwPTE,*(LPDWORD)(0x1000 + j * 4)); } system("Pause"); return 0;}
5.4 0线性地址实行SHELLCODE
#include #include LPVOID g_lp = NULL;DWORD g_PTE = 0;CHAR szData[] = { 0x6a,0x0,0x6a,0x0,0x6a,0x0,0x6a,0x0,//PUSH 0 0xb8,0x0,0x0,0x0,0x0, //MOV EAX, XXXXXXXX 0xFF,0xd0, //CALL EAX 0xC3 //RET};_declspec(naked)VOID Fun(){ __asm { //获取线性地址 mov ecx, g_lp //获取PTE mov eax, ecx shr eax, 0x9 and eax, 0x7FFFF8 sub eax, 0x40000000 mov eax, [eax] mov g_PTE, eax //0 PAGE xor ecx, ecx //设置PTE shr ecx, 0x9 and ecx, 0x7FFFF8 sub ecx, 0x40000000 mov edx, g_PTE mov [ecx], edx iretd }}int main(){ //SHELLCODE *(LPDWORD)&szData[9] = (DWORD)MessageBox; //GETPAGEDATA g_lp = VirtualAlloc(NULL,0x64,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE); //INITMEM memset(g_lp,0,0x64); memcpy(g_lp,szData,sizeof(szData)); //SET 0ADDR PTE printf("FUNADDR [0x%08x] \n",Fun); system("pause"); __asm { //eq 80b99500 0040ee00`00081000 INT 0x20 } printf("PTE [0x%08x] \n",g_PTE); __asm { mov eax, 0 call eax } system("pause"); return 0;}
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |