第一题代码
说说思路吧,如果给出的线性地址+读取的长度没有超过0x1000。那么这种情况很好处理,判断PDE和PTE的p都为1就行了
如果超过了1页,把线性地址加上0x1000那么这个值肯定就对应下一个物理页了。再次判断一下PDE和PTE的p位,注意下细节就好了。
// readPageAttr.cpp : 定义控制台应用程序的入口点。
//调用门描述符 eq 8003f048 0041ec00`00081087
#include "stdafx.h"
#include <Windows.h>
DWORD dwPDT_Index=0;
DWORD dwPTT_Index=0;
DWORD dwPageIndex=0;
DWORD result=0;
bool bRead=false; //地址是否可读标志 true为可正常读
void CallGate();
void _declspec(naked) test()
{
_asm
{
push 0x30
pop fs
pushad
pushfd
xor eax,eax
mov bRead,al
//PDE=0xc0300000+PDI*4
mov eax,0xc0300000
//dwPDT_Index=PDI
mov ecx,dwPDT_Index
shl ecx,2
//eax=PED的指针
add eax,ecx
//读出pde的值
mov ebx,[eax]
//保存在全局变量PDE
//判断PDE的p位是否为1
test ebx,0x1
jz end
//解析PTE 0xc0000000+PDI*4096+PTI*4
//在上面已经移了2位 再左移10位就是4096
shl ecx,10
//eax=PTI
mov eax,dwPTT_Index
shl eax,2
//ebx=PTE的指针
mov ebx,0xc0000000
add ebx,eax
add ebx,ecx
mov ebx,[ebx]
//判断PTE的p位
test ebx,0x1
jz end
//设置bRead为1
xor eax,eax
mov al,0x1
mov bRead,al
end: popfd
popad
retf
}
}
void ParsePage(DWORD dwAddr)
{
//10 10 12分页模式
//获取PDT索引
dwPDT_Index=(dwAddr>>22);
//获取PTT的索引
dwPTT_Index=((dwAddr<<10)>>22);
dwPageIndex=(dwAddr&0xfff);
printf("dwPTT_Index=%x",dwPTT_Index);
CallGate();
}
void CallGate()
{
char buffer[6]={0};
*(DWORD*)&buffer[0]=0;
*(WORD*)&buffer[4]=0x4b;
_asm
{
call fword ptr [buffer]
push 0x3b
pop fs
}
}
bool ReadMemory(OUT void*buffer,IN DWORD dwAddr,IN DWORD
dwlength)
{
//自己制定分页方式 10 10 12
//页不存在,要提示不能报错
//如果dwAddr+dwLength>0x1000则发生跨页,需要检查两个页
printf("dwAddr=%x",dwAddr);
if((dwAddr&0xfff+dwlength)>0x1000)
{
//判断是否可读
ParsePage(dwAddr);
if (bRead)
{
//如果该物理页可读,则判断下一个物理页 该线性地址+0x1000
//就肯定是下一个物理页了
ParsePage((dwAddr+0x1000));
if (bRead)
{
//到这里说明是两个物理页都是可读的,读取值
memcpy_s(buffer,dwlength,(DWORD*)dwAddr,dwlength);
return true;
}
}
}
else
{
ParsePage(dwAddr);
if (bRead)
{
//到这里说明是两个物理页都是可读的,读取值
memcpy_s(buffer,dwlength,(DWORD*)dwAddr,dwlength);
return true;
}
}
return false;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD buf[100]={0};
printf("调用门地址:%x\n",test);
int *p=(int *)0x11ffc;
*p=0x12345678;
BOOL bRet=ReadMemory(buf,0x11ffc,4);
if (bRet)
{
for(int i=0;i<1;i++){
printf("\n 内存读取成功\n buf[%d]=%x",i,buf[i]);
}
}
else
{
printf("内存读取失败");
}
getchar();
return 0;
}
第二题:
**记录一下,两道题肝了我5个小时,还好做出来了 **
// protect2.cpp : 定义控制台应用程序的入口点。
//调用门描述符 eq 8003f048 0041ec00`00081087
#include "stdafx.h"
#include<windows.h>
DWORD dwPDT_Index=0;
DWORD dwPTT_Index=0;
DWORD dwPageIndex=0;
DWORD dwPDE;
DWORD dwPTE;
void CallGate()
{
char buffer[6]={0};
*(DWORD*)&buffer[0]=0;
*(WORD*)&buffer[4]=0x4b;
_asm
{
call fword ptr [buffer]
push 0x3b
pop fs
}
}
void _declspec(naked) test()
{
_asm
{
push 0x30
pop fs
pushad
pushfd
//PDE=0xc0300000+PDI*4
mov eax,0xc0300000
//dwPDT_Index=PDI
mov ecx,dwPDT_Index
shl ecx,2
//eax=PED的指针
add eax,ecx
//读出pde的值
mov eax,[eax]
mov dwPDE,eax
//解析PTE 0xc0000000+PDI*4096+PTI*4
//在上面已经移了2位 再左移10位就是4096
shl ecx,10
//eax=PTI
mov eax,dwPTT_Index
shl eax,2
//ebx=PTE的指针
mov ebx,0xc0000000
add ebx,eax
add ebx,ecx
mov ebx,[ebx]
and ebx,0xfffff000
or ebx,0x067
mov dwPTE,ebx
//找出0x1000的PDE
mov eax,0x1000
shr eax,20
and eax,0xffc
mov ecx,eax //用ecx来保存PDI
add eax,0xc0300000
int 3
//找到PDE
mov ebx,[eax]
//判断 如果无效 则挂一个PDE
test ebx,0
jnz s
mov ebx,dwPDE
mov [eax],ebx
s: mov eax,0x1000
shl eax,10
shr eax,20
//计算 PTI*4
and eax,0xffc
//计算PDI*4096
shl ecx,12
mov ebx,0xc0000000
add ebx,eax
add ebx,ecx
mov eax,dwPTE
mov [ebx],eax
popfd
popad
retf
}
}
void ParsePage(DWORD dwAddr)
{
//10 10 12分页模式
//获取PDT索引
dwPDT_Index=(dwAddr>>22);
//获取PTT的索引
dwPTT_Index=((dwAddr<<10)>>22);
dwPageIndex=(dwAddr&0xfff);
printf("dwPTT_Index=%x\n",dwPTT_Index);
CallGate();
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD* dwAddr=(DWORD*)VirtualAlloc(0,0x1000,MEM_COMMIT,PAGE_READWRITE);
DWORD *p=dwAddr;
printf("test=%x dwAddr=%x\n",test,(DWORD)dwAddr);
for (int i=0;i<100;i++)
{
*p=(DWORD)p;
p++;
}
ParsePage((DWORD)dwAddr);
//3:定义一个指针,指向0x1000 使用指针打印出数组的值。
dwAddr=(DWORD*)0x1000;
for (int i=0;i<100;i++)
{
printf("test=%x\n",*dwAddr);
dwAddr++;
}
getchar();
return 0;
}