保护模式阶段测试

在这里插入图片描述

第一题代码

说说思路吧,如果给出的线性地址+读取的长度没有超过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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值