zoukankan      html  css  js  c++  java
  • 17_页面异常接管

    页面异常捕获过滤:

    原理:

    在 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;

    // 0x401040
    void __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 ", g_bNewExpt);
    if (g_bNewExpt == 0x1)
    {
    printf("new error ***cr3: %p -- eip: %p -- errorcode:%p -- pfvn:%p ", 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 -- 0x401040
    void __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


  • 相关阅读:
    JMETER(七) 后置处理器
    JMETER(六) 前置处理器
    JMETER(四) 配置元件
    QNET网络测试工具
    修改exe程序图标
    自解压捆绑文件钓鱼
    BigIP Cookie 解码获取真实IP (python2)
    关于windowspwnsafeseh的理解简单随笔
    bilibili动画下载视频批量改名(python)
    好用!网页模板网站
  • 原文地址:https://www.cnblogs.com/leibso-cy/p/11719276.html
Copyright © 2011-2022 走看看