内核学习-保护模式阶段性检测
1. 给定一个线性地址,和长度,读取内容;int ReadMemory(OUT BYTE* buffer,IN DWORD dwAddr,IN DWORD dwLeght)
要求:
1) 可以自己指定分页方式。
2) 页不存在,要提示,不能报错。
3) 可以正确读取数据。
#include <windows.h>
#include <stdio.h>
//eq 8003f090 0040EC05`000810
DWORD PTE;
DWORD PDE;
DWORD DwAddr;
DWORD DwLeght;
BYTE* Buff;
BOOL _MAXPage = 0;
BOOL _TockPage = 0;
BOOL _P_Flafge = 0;
BOOL _PAT_Flage = 0;
VOID _declspec(naked) Start()
{
//获取参数
__asm
{
lea eax, dword ptr ds :
mov esi, dword ptr ds :
mov dword ptr ds : ,esi
mov esi, dword ptr ds :
mov dword ptr ds : ,esi
mov esi, dword ptr ds :
mov dword ptr ds : ,esi
mov esi, dword ptr ds :
mov dword ptr ds : ,esi
mov esi, dword ptr ds :
mov dword ptr ds : ,esi
}
__asm
{
mov eax, dword ptr ds :
mov ecx, dword ptr ds :
//检测PDE P位
test cl,0x1
jz Pflage_Nop
//检测PDE PS位
test cl,0x80
jz Nops
//检测是否跨页
mov dword ptr ds : , 0x1
mov eax, dword ptr ds:
and eax,0x00000FFF
mov ecx, dword ptr ds :
add eax,ecx
cmp eax,0x00001000
jns steppage
jmp nosteppage
Nops: //小页
mov eax, dword ptr ds :
mov ecx, dword ptr ds :
//检测PTE P位
test cl,0x1
jz Pflage_Nop
//检测PTE PAT位
test cl,0x80
jnz PatFlage_Code
//检测是否跨页
mov eax, dword ptr ds :
and eax, 0x00000FFF
mov ecx, dword ptr ds :
add eax, ecx
cmp eax, 0x00001000
jns steppage
jmp nosteppage
}
steppage://读取的内存地址跨页执行代码
__asm
{
//每读取1字节就检测P位,防止跨页的线性地址没有物理页导致CPU报错 -- 根据大页还是小页检测
//大页:读取时只检测PDE P位
mov eax, dword ptr ds :
test al,0x1
jz Small_Page_Code
push ebp
mov ebp, esp
sub esp, 0x20
mov dword ptr ss : , 0x0
JMP while_b_F
while_a_F :
mov eax, dword ptr ds :
mov esi, dword ptr ds :
mov edi,eax
add edi,esi
mov ecx,edi
shr ecx,0x12
and ecx,0X3FF8
sub ecx,0X3FA00000
mov dword ptr ss : ,ecx
mov ecx,edi
shr ecx,0x9
and ecx,0x7FFFF8
sub ecx,0x40000000
mov dword ptr ss : ,ecx
mov ecx, dword ptr ds :
mov ecx, dword ptr ds :
test cl,0x1//检测PDE P位
jz _FL
mov eax, dword ptr ds :
mov esi, dword ptr ds :
xor ecx,ecx
mov cl, byte ptr ds :
mov eax, dword ptr ds :
mov byte ptr ds : , cl
mov ecx, dword ptr ds :
add ecx, 0x1
mov dword ptr ds : , ecx
while_b_F :
mov eax, dword ptr ds :
mov ecx, dword ptr ds :
cmp ecx, eax
js while_a_F
jmp _FL
//小页:读取时检测PDE和PTE P位
Small_Page_Code:
push ebp
mov ebp, esp
sub esp, 0x20
mov dword ptr ss : , 0x0
JMP while_b_T
while_a_T :
mov eax, dword ptr ds :
mov esi, dword ptr ds :
mov edi, eax
add edi, esi
mov ecx, edi
shr ecx, 0x12
and ecx, 0X3FF8
sub ecx, 0X3FA00000
mov dword ptr ss : , ecx
mov ecx, edi
shr ecx, 0x9
and ecx, 0x7FFFF8
sub ecx, 0x40000000
mov dword ptr ss : , ecx
mov ecx, dword ptr ds :
mov ecx, dword ptr ds :
test cl, 0x1//检测PDE P位
jz _FL
mov ecx, dword ptr ds :
mov ecx, dword ptr ds :
test cl,0x1 //检测PTE P位
jz _FL
xor ecx,ecx
mov eax, dword ptr ds :
mov esi, dword ptr ds :
mov cl, byte ptr ds :
mov eax, dword ptr ds :
mov byte ptr ds : , cl
mov ecx, dword ptr ds :
add ecx, 0x1
mov dword ptr ds : , ecx
while_b_T :
mov eax, dword ptr ds :
mov ecx, dword ptr ds :
cmp ecx, eax
js while_a_T
_FL:
mov dword ptr ds : , 0x1
mov eax, dword ptr ds :
leave
jmp _Retf
}
nosteppage://读取的内存地址无需跨页执行代码
__asm
{
//直接读取DwLeght个字节到缓冲区
push ebp
mov ebp, esp
sub esp, 0x20
mov dword ptr ss : , 0x0
JMP while_b
while_a :
mov eax, dword ptr ds :
mov esi, dword ptr ds :
mov cl, byte ptr ds :
mov eax, dword ptr ds :
mov byte ptr ds : , cl
mov ecx, dword ptr ds :
add ecx, 0x1
mov dword ptr ds : , ecx
while_b :
mov eax, dword ptr ds :
mov ecx, dword ptr ds :
cmp ecx, eax
js while_a
mov eax, dword ptr ds :
leave
JMP _Retf
}
Pflage_Nop: //P位无效
__asm
{
mov dword ptr ds : ,0x1
xor eax,eax
jmp _Retf
}
PatFlage_Code: //PAT位为1执行代码
__asm
{
mov dword ptr ds : ,0x1
xor eax, eax
jmp _Retf
}
_Retf:
__asm
{
retf 0x14
}
}
DWORD MyReadMemory(OUT BYTE* Buff, IN DWORD DwAddr, IN DWORD DwLeght)
{
unsigned int PDE = DwAddr >> 0X12;
PDE &= 0X3FF8;
PDE -= 0X3FA00000;
unsigned int PTE = DwAddr >> 0x9;
PTE &= 0x7FFFF8;
PTE -= 0X40000000;
BYTE RunCode = { 0 };
RunCode = 0x93;
BOOL RetCode;
__asm
{
push PDE
push PTE
push DwAddr
push DwLeght
push Buff
call fword ptr ds :
mov dword ptr ds : ,eax
}
return RetCode;
}
VOID main()
{
BYTE Buff = { 0 };
CHAR* Str = "Hello 你好?";
DWORD _ReadSize = MyReadMemory(Buff, 0x8003fffe, 4);
printf("是否大页:%X -- 是否跨段:%X -- P位:%XPAT位:%X\r\n", _MAXPage, _TockPage, _P_Flafge, _PAT_Flage);
if (_ReadSize)
{
printf("%X -- %d\r\n", *(DWORD*)Buff,_ReadSize);
}
else
{
printf("读取失败\r\n");
}
getchar();
}2. 申请长度为100的DWORD的数组,且每项用该项的地址初始化;
把这个数组所在的物理页挂到0x1000的地址上;
定义一个指针,指向0x1000这个页里的数组所在的地址,用0x1000这个页的线性地址打印出这数组的值;
要求:
数组所在的物理页,是同一个页;
#include <windows.h>
#include <stdio.h>
VOID _declspec(naked) Start()
{
DWORD Address_1;
DWORD Address_2;
unsigned int _Address_1_PTE;
unsigned int _Address_2_PTE;
__asm
{
mov eax, dword ptr ds :
mov dword ptr ds : , eax
}
Address_2 = 0x1000;
_Address_1_PTE = Address_1 >> 0x9;
_Address_1_PTE &= 0x7FFFF8;
_Address_1_PTE -= 0x40000000;
_Address_2_PTE = Address_2 >> 0x9;
_Address_2_PTE &= 0x7FFFF8;
_Address_2_PTE -= 0x40000000;
__asm
{
mov eax,dword ptr ds :
mov ecx, dword ptr ds :
mov edx, dword ptr ds :
mov dword ptr ds : ,ecx
}
__asm
{
retf 0x4
}
}
//eq 8003f090 0040EC01`00081000
VOID main()
{
DWORD Address = (DWORD)VirtualAlloc(NULL, 400, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
BYTE RunCode = {0};
RunCode = 0x93;
if ((Address & 0x00000FFF) > 0x0)
{
printf("申请内存失败\r\n");
}
else
{
DWORD* Address_p = (DWORD*)Address;
for (DWORD _index = 0; _index < 100; _index++)
{
*(Address_p+_index) = _index;
}
__asm
{
push Address;
call fword ptr ds :
}
DWORD* P = (DWORD*)0X1000;
for (DWORD _index = 0; _index < 100; _index++)
{
printf("%X\r\n",*(P + _index));
}
}
VirtualFree((LPVOID)Address, 400, MEM_DECOMMIT);
getchar();
}
超棒的哇,学习了。 用心讨论,共获提升!
页:
[1]