0x001 实验环境
xp3
2-9-9-12 分页环境
0x002 时间代码
// 20180327_01.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
DWORD zero, one, two;
__declspec(naked)
void MountPageOnNull() {
__asm {
push ebp
mov ebp, esp
sub esp, 0x100
push ebx
push esi
push edi
}
DWORD* pPTE; // 保存目标线性地址的 PTE 线性地址
DWORD* pNullPTE; // 0 地址的 PTE 线性地址
pNullPTE = (DWORD*)0xc0000000;
// 挂上 0x50000000 所在位置
pPTE = (DWORD*)(0xc0000000 + ((0x50000000 >> 9) & 0x7ffff8));
*pNullPTE = *pPTE;
zero = *(DWORD*)0;
// 挂上 0x60000000 所在位置
pPTE = (DWORD*)(0xc0000000 + ((0x60000000 >> 9) & 0x7ffff8));
*pNullPTE = *pPTE;
one = *(DWORD*)0;
// 刷新 TLB
__asm {
mov eax, cr3
mov cr3, eax
}
// 再次读取 0 地址位置的数据
two = *(DWORD*)0;
__asm {
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
iretd
}
}
// 外壳包裹函数
__declspec(naked)
void MyMountPageOnNull() {
__asm {
int 0x20
ret
}
}
int main(int argc, char* argv[])
{
DWORD* x = (DWORD*)VirtualAlloc((LPVOID)0x50000000, 4, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
DWORD* y = (DWORD*)VirtualAlloc((LPVOID)0x60000000, 4, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
*x = 0x12345678;
*y = 0x87654321;
if (x != (DWORD*)0x50000000 || y != (DWORD*)0x60000000) {
printf("Error alloc!\n");
return -1;
}
MyMountPageOnNull();
printf("1. 读 0 地址数据:\n");
printf("*NULL = 0x%08x\n\n", zero);
printf("2. 给 0 地址重新挂上物理页\n\n");
printf("3. 重新读取 0 地址数据:\n");
printf("*NULL = 0x%08x\n\n", one);
printf("4. 刷新 TLB \n\n");
printf("5. 再次读取 0 地址数据:\n");
printf("*NULL = 0x%08x\n", two);
return 0;
}
0x003 实验步骤
在 main 函数起始位置下断点,在 VC6.0 中观察到函数 MountPageOnNull的函数地址,在我的环境里是 0x00401030。
构造中断门描述符 0040ee00`00081030
中断到 WinDbg 中去,执行以下命令安装中断门
在 WinDbg 中执行命令g
回到 xp 系统中。
继续执行 VC6.0 中的程序。
0x004 实验结果