题目1:
给定一个线性地址,和长度,读取内容:(运行环境XP)
目前:
可以修该页权限,获得PDE,PTE值,支持跨页检测,以及跨页设置页属性10-10-12)
后续:
补充读取内容 和 2-9-9-12分页模式,跨多页检测
题目要求:
int ReadMemory(OUT BYTE* buffer,IN DWORD dwAddr,IN DWORD dwLeght)
要求:
1)可以自己指定分页方式.
2)页不存在,要提示,不能报错.
3)可以正确读取数据.
实现代码之前 务必使用windbg实现中断提权
kd> eq 8003f500 0040ee00`00081000
实现代码
//release版本 以及 项目属性中选固定基址
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
DWORD g_tmp=0,page_flag =0;
int flag = 0,pde = 0,pte = 0,ppte = 0;
DWORD dwAddr = 0,dwLeght= 0;
DWORD PDI,PTI,OFSET,PDI1,LPTE,LPPTE,LPDE;
//0x401000
void __declspec(naked) ReadMemory() //蓝色字体是告诉编译器函数代码自己去写,不需要编译器添加任何汇编代码
{
__asm
{
mov edx,g_tmp
cmp edx,0
je P1
cmp edx,3
je P2
cmp edx,1
je P2
jmp P3
P2: mov ebx,pte
mov ecx,pde
or ebx,4
or ecx,4
mov eax,LPTE
mov dword ptr ds:[eax],ebx
mov eax,LPDE
mov dword ptr ds:[eax],ecx
mov ecx,ppte
or ecx,4
mov eax,LPPTE
mov dword ptr ds:[eax],ecx
cmp edx,1
je P1
P3: mov ebx,pte
mov ecx,pde
or ebx,2
or ecx,2
mov eax,LPTE
mov dword ptr ds:[eax],ebx
mov eax,LPDE
mov dword ptr ds:[eax],ecx
mov ecx,ppte
or ecx,2
mov eax,LPPTE
mov dword ptr ds:[eax],ecx
P1:
//判断PDE是否为0
mov eax,0xC0300000
add eax,PDI1
mov LPDE,eax
mov eax,dword ptr ds:[eax]
cmp eax,0
jne L1
mov eax,3
mov flag,eax
jmp L2
L1:
//判断PTE是否为0
mov pde,eax
mov eax,0xc0000000
add eax,PDI
add eax,PTI
mov LPTE,eax
mov LPPTE,eax
mov eax,dword ptr ds:[eax]
mov pte ,eax
mov eax,LPPTE
add eax,4
mov LPPTE,eax
mov eax,dword ptr ds:[eax]
mov ppte ,eax
L2:
iretd
}
}
void go()
{
__asm int 0x20 //触发异常
}
int main()
{
int a = 0x123456;
BYTE* buffer = a;
//scanf("%d",&dwLeght);
printf("自带常量线性地址:%p\n\n\n",&a);
printf("请输入目标地址:\n");
scanf("%x",&dwAddr);
printf("请输入读取长度:\n");
scanf("%x",&dwLeght);
PDI = dwAddr>>22;
PTI = (dwAddr<<10)>>22;
OFSET = dwAddr&0x0FFF;
if((dwLeght+OFSET)>=1024)
{
printf("读取数据的跨页存储!\n");
page_flag = 1;
}
printf("PDI:%x\n",PDI);
printf("PTI:%x\n",PTI);
printf("OFFSET:%x\n",OFSET);
PDI1 = PDI*4;
PDI*=0x1000;
PTI*=4;
if((DWORD)ReadMemory !=0x401000)
{
printf("wrong addr:%p",ReadMemory);
exit(-1);
}
RNG:
go();//产生20中断,触发我们塞入20中断地址的函数。
if(pde == 0|| pte ==0)
{
printf("该页未被挂载!");
return 0;
}
printf("%p\n",&a);
printf("PDE:%x\n",pde);
printf("PTE:%x\n",pte);
if(page_flag == 1 && ppte!=0)
{
printf("下页PTE:%x\n",ppte);
}
else if(ppte == 0)
{
printf("下页PTE为NULL,读取数据范围错误! exitting!");
return 0;
}
printf("是否操作该物理页?\n");
printf("1.yes 2.no\n");
scanf("%d",&flag);
if(flag == 2)
return 1;
else if(flag == 1)
{
printf("1.增加普通用户操作权限 \n");
printf("2.增加写权限\n");
printf("3.成年人的选择!\n");
scanf("%d",&g_tmp);
goto RNG;
}
else
printf("输入错误,exitting!.");
}
题目2
2.申请长度为100的DWORD的数组,且每项用该项的地址初始化;把这个数组所在的物理页挂到0x1000的地址上;
定义一个指针,指向0x1000这个页里的数组所在的地址,用0x1000这个页的线性地址打印出这数组的值;
目前:
完成
后续:
题目要求:
要求:
数组所在的物理页,是同一个物理页;
windbg跟上面一样的 命令
实现代码
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<winbase.h>
int pde = 0,pte = 0,g_tmp = 0;
DWORD dwAddr = 0,dwLeght= 0;
DWORD PDI,PTI,OFSET,PDI1;
//0x401000
void __declspec(naked) ReadMemory() //蓝色字体是告诉编译器函数代码自己去写,不需要编译器添加任何汇编代码
{
__asm
{
mov eax,0xc0300000
add eax,PDI1
mov eax,dword ptr ds:[eax]
mov pde,eax
mov eax,0xC0000000
add eax,PDI
add eax,PTI
mov eax,dword ptr ds:[eax]
mov pte,eax
mov eax,0xC0300000
mov ebx,pde
mov dword ptr ds:[eax],ebx
mov eax,0xc0000000
add eax,0x4
mov ebx,pte
mov dword ptr ds:[eax],ebx
iretd
}
}
void go()
{
__asm int 0x20 //触发异常
}
int main()
{
int i =0;
DWORD *p1000=NULL;
DWORD *str=NULL;
DWORD dwAddr;
if(&ReadMemory != 0x401000)
{
printf("Error,ReadMemoryAddr:%p",&ReadMemory);
}
//固定大小申请空间,保证数组空间在同一物理页
str = VirtualAlloc(0,1024,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
printf("当前数组线性地址:%p\n",str);
//数组赋值
for(i=0;i<100;i++)
{
str[i] = &str[i];
}
//拆分线性地址
dwAddr = str;
PDI = dwAddr>>22;
PTI = (dwAddr<<10)>>22;
OFSET = dwAddr&0x0FFF;
PDI1 = PDI*4;
PDI*=0x1000;
PTI*=4;
printf("PDI:%p PTI:%p OFFSET:%p \n",PDI,PTI,OFSET);
go();
printf("挂载完成! 输入任意数字 显示0x1000线性地址内容:\n");
scanf("%d",&g_tmp);
p1000 = 0x1000;
for(i=0;i<100;i++)
{
printf("%p ",p1000[i]);
}
system("pause");
return 1;
}