17_页面异常接管

谁说胖子不能爱 提交于 2019-12-01 22:38:00

页面异常捕获过滤:

原理:

在 IDT 表中的e 号 处理 是 页面异常处理; 如果 我们 hook 掉 这个回调函数;那么就能获得全部的页面异常;再通过 cr3 对比 捕获指定的 cr3 (进程)的信息;最后再共享的区域将数据输出;然后测试程序获取该自己的页面异常信息;

实验中 容易出现的错误:

在 c 的时候注意将使用的寄存器(这里是eax)先保存起来;注意 通过栈保存 eax的话注意 相关进入中断后和栈相关的数据,就会和esp 的相对偏移产生变化。

测试程序代码.c:

此程序 主要是 中断进入 内核;然后读取数据;看时候有新的和自己有关的异常页面信息;这样

// 9_页面异常.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//​#include "pch.h"#include <stdio.h>#include<stdlib.h>#include<Windows.h>// 定义一些内核地址宏;用来保存当前程序相关数据(cr3)#define K_BOOL_READY   0x8003f3f0    // * 当前是否已经提交 cr3,变为准备接收异常状态#define K_ESP        0x8003f3f4    // esp     * 异常代码 #defineK_ESP_NEG4    0x8003f3f8    // esp - 4   * 异常地址 eip(产生异常的代码地址)#define K_TARGET_CR30x8003f3ec    // cr3       * 异常程序cr3#define K_CR2        0x8003f3e8    // cr2       * 异常地址(产生页面异常页中的虚拟地址)#define K_BOOL_NEW_EXPT 0x8003f3e4    // * 是否有新的异常​​DWORD g_bReady = FALSE;DWORD g_bNewExpt = FALSE;​DWORD g_pEIP = 0;DWORD g_pExceptPvn = 0;DWORD g_iCr3 = 0;DWORD g_iErrCode = -1;​// 0x401040void __declspec(naked) IdtEntry(){__asm mov eax, ds:[K_BOOL_READY];__asm mov g_bReady, eax;__asm{    mov eax, cr3;    mov cr3, eax;}if (g_bReady != 1){        // 第一次运行还没有提交CR3数据:    __asm    {        mov eax, cr3;        mov ds : [K_TARGET_CR3], eax;        // 提交完成的标识。        mov eax, 0x1;        mov ds : [K_BOOL_READY], eax;        // 重置新异常信号;        mov eax, 0x0;        mov ds : [K_BOOL_NEW_EXPT], eax;        iretd;    }}else{    // 已经提交 cr3 开始接收异常数据:​    // ----* 检测是否有新的异常需要接收;    __asm mov eax, dword ptr ds : [K_BOOL_NEW_EXPT];    __asm mov g_bNewExpt, eax;    if (g_bNewExpt == 0x1)    {        // 如果 有新的异常        __asm        {            // 获取异常信息 --》 到本地全局,以便输出            mov eax, dword ptr ds : [K_ESP_NEG4];            mov g_pEIP, eax;            mov eax, dword ptr ds : [K_CR2];            mov g_pExceptPvn, eax;            mov eax, dword ptr ds : [K_TARGET_CR3];            mov g_iCr3, eax;            mov eax, dword ptr ds : [K_ESP];            mov g_iErrCode, eax;            // 接收之后 重置新异常信号;            mov eax, 0x0;            mov ds : [K_BOOL_NEW_EXPT], eax;        }            }​    __asm    {        mov eax, cr3;        mov cr3, eax;        iretd;    }}}​​void _declspec(naked) go(){__asm{    int 0x20;    ret;}}​​int main(){if ((DWORD)IdtEntry != 0x401040){    printf("Func addres is wrong !!");    Sleep(5000);    system("pause");    exit(-1);}while (1){    go();    //printf("%d\n", g_bNewExpt);    if (g_bNewExpt == 0x1)    {        printf("new error ***cr3: %p -- eip: %p -- errorcode:%p -- pfvn:%p\n", g_iCr3, g_pEIP, g_iErrCode, g_pExceptPvn);        g_bNewExpt = 0;    }​}​    }​

Hook IDT_E 回调函数 且 通过识别cr3 将相关信息过滤到 共识的共享数据区域 .c :

// 9_页面异常_过滤获取目标异常信息.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//​#include "pch.h"#include<stdio.h>#include<stdlib.h>#include<Windows.h>​// 定义一些内核地址宏;用来保存当前程序相关数据(cr3)#define K_BOOL_READY   0x8003f3f0    // * 当前是否已经提交 cr3,变为准备接收异常状态#define K_ESP        0x8003f3f4    // esp     * 异常代码 #defineK_ESP_NEG4    0x8003f3f8    // esp - 4   * 异常地址 eip(产生异常的代码地址)#define K_TARGET_CR30x8003f3ec    // cr3       * 异常程序cr3#define K_CR2        0x8003f3e8    // cr2       * 异常地址(产生页面异常页中的虚拟地址)#define K_BOOL_NEW_EXPT 0x8003f3e4    // * 是否有新的异常​#define K_HOOK_IDT_E_CODE 0x8003F120      // * Hook 代码所在#define K_HOOK_IDT_E_SRCCODE 0x80541450   // * Hook目标 所在​DWORD g_bReady = FALSE;DWORD g_bNewExpt = FALSE;​DWORD g_pEIP = 0;DWORD g_pExceptPvn = 0;DWORD g_iCr3 = 0;DWORD g_iErrCode = -1;DWORD g_iCurCr3 = 0;​​int  g_i = 0;DWORD g_p = 0;void  checkAndCap();// -- int0x20 -- 0x401040void __declspec(naked) HookIdt_0xe(){// hook __asm{    // 修改写保护 WP    //cli;//将处理器标志寄存器的中断标志位清0 ,不允许中断    mov eax, cr0    and eax, not 0x10000    mov cr0, eax​    mov eax, 0x0;    mov ds : [K_BOOL_READY], eax;​    // 原来的第一句 有7个字节;而我们push ret 只有6个字节 ;扩充到 7个字节 68 20 f1 03 80 C3 90;    // push 0x8003f120;    // ret    // nop     mov al, 0x68;    mov byte ptr ds : [K_HOOK_IDT_E_SRCCODE], al;    mov eax, 0x8003f120;    mov dword ptr ds : [K_HOOK_IDT_E_SRCCODE + 1], eax;    mov ax, 0x90c3;    mov word ptr ds : [K_HOOK_IDT_E_SRCCODE + 5], ax;​        mov eax, cr0    or eax, 0x10000    mov cr0, eax    //sti;//将中断恢复​}​g_i = 0;g_p = K_HOOK_IDT_E_CODE;​// 拷贝hook 代码带内核区for (; g_i < 128; g_i++){    *(BYTE*)(g_p + g_i) = *(byte*)((DWORD)checkAndCap + g_i);}​__asm{    iretd;}}​​// 0x401040  -- void _declspec(naked) checkAndCap(){__asm{    push eax;    // 判断程序是否已经就位    mov eax, ds:[K_BOOL_READY];    cmp eax, 0x1;    jnz END;    // 如果 目标程序 已经提交cr3 那么 就可以开始捕获异常了;    mov eax,cr3;   // cr3不能用于比较的 参数    cmp eax, ds:[K_TARGET_CR3];    jnz END;​    // 来到这一步,表明是目标的异常​    mov eax, [esp + 8]; // 前面push  了一个 eax  我去 浪费时间··· esp + 0x4 --> esp+ 0x8;    mov ds : [K_ESP_NEG4], eax; // eip 异常地址    mov eax, cr2;    mov ds : [K_CR2], eax; // 异常读/写/访 的目标分页地址    mov eax, [esp+4];// esp-->esp +4  因为前面压入了 eax    mov ds : [K_ESP], eax; // 异常代码    // 给新的异常信号    mov eax, 0x1;    mov ds : [K_BOOL_NEW_EXPT], eax;END:    pop eax;    mov  word ptr[esp + 2], 0 // 恢复 原来的执行    push 0x80541457;          // 返回之前hook 的下一句    ret}}​void _declspec(naked) go(){__asm{    int 0x20;    ret;}}int main(){if ((DWORD)HookIdt_0xe != 0x401040){    printf("HOOK出错了:%p", HookIdt_0xe);    Sleep(10000);    exit(-1);}if ((DWORD)checkAndCap != 0x4010c0){    printf("CHEC出错了:%p", checkAndCap);    Sleep(10000);    exit(-1);}go();system("pause");​​​}​

效果展示:

1570606046611


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!