雪飘风过 发表于 2020-7-16 11:25:17

内核学习-保护模式阶段性检测

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();
}

觞夜 发表于 2020-7-20 00:58:09

超棒的哇,学习了。

ywb_qh 发表于 2020-8-5 09:10:41

用心讨论,共获提升!
页: [1]
查看完整版本: 内核学习-保护模式阶段性检测