zoukankan      html  css  js  c++  java
  • 18_ShadowWalker

    白皮书中 page-fault error code:

    1570607688762

    shadowWalker 原理:

    接管 指定程序 的 执行页面异常、读写页面异常;然后 调用一下正常的 使其出现在快表;然后恢复到假的pte

    ------ 根据白皮书中 的error code 过滤出 执行、读写异常类型

    相关:

    • 将 402000 这个页面通过修改pte 设置为不存在(直接 给 p位置为 0);这样产生异常 我们接管

      • 然后通过 0x10 判断 是否是执行异常;是的话,就将页面给挂上去。

      • 1570610073334

      • 1570615185931

    • 全程接管 读写、执行异常

      • 读写异常 -- 不能交给系统默认处理;因为系统有虚拟地址的管理,他可能以为还没有映射该页面或者可能被置换到磁盘文件等,再次映射;但是还是不是我们想要的正确的。

      • 所以我们接管。

    • 只接管 402000 页面(具体根据项目//后来我的项目是 412000)

      • 因为其他页面也会产生异常;如果想把该程序的都接收,那么得区分出来分别处理,这里我们只处理一个页面就行;原理类似。

    • 利用 TLB 使得瞬间正常,然后又恢复异常状态;不然只接管了一次。

    #define K REAL PTEO 0x8003f3e4
    #define K REAL PTE1 0x8003f3e0
    #define K FAKE PTEO 0x8003f3dc
    #define K FAKE PTE1 0x8003f3d8
    DWORD g esp;
    DWORD 9 esp 4;
    DWORD 9 cr2;
    //0x401000
    void一dec lspec (naked) IdtEntry()
    {
    *(DWORD *)K REAL PTEO = PTE (0x402000)[0];
    *(DWORD *)K REAL PTE1 = PTE(0x402000)[1;
    dasir
    mov eax, cr3
    mov ds:[K TARGET CR3],eax
    }
    _asm {
    iretd
    #pragma code seg(" . my_ code")__ declspec (allocate(".my_ code ")) void gc
    #pragma code seg(".my_ code")_ dectspec (allocate(".my_ code ")) void ma
    vold go() {
    _asm
    int 0x20
    //eq 8003f500 0040ee000081000
    void main()
    • 在被接管得测试程序 一进入 0环 ,就保存 需要接管的 pte ;代码如上;

    • 异常接管后;如果不给页面的话 ;它会一直死循环 页面异常;所以 我们给他假的页面

    • 创建一个假页面:

    1570608936324

    #pragma section("data seg", read, write)
    _declspec(allocate("data seg")) DWORD FakePage[1024]; //405000
    • 再把假页面给 内核;这样 我们在内核接管的时候;可以将这个假页面给请求者。

    1570609102689

    *(DWORD *)K_FAKE_PTEO = PTE (0x405000)[0];
    *(DWORD *)K_FAKE_PTE1 = PTE (0x405000)[1];

    • 处理之后不能直接退出;得手动平 error code 这个栈位;因为中断系统只平默认的5个。

    1570609714118

    • 接管处理:

      • 代码执行异常:

        • 1570610465408

      • 读写异常接管:

        • 同理。。。 只是纠正后用一下;让其快表中;然后恢复到假页面

    • OD 有时能读出; 要完善的话得考虑OD 和内核通讯得路径

    • 程序退出 有可能蓝屏:

      • 原因: 退出得时候;把页面得pte 应该设置成正常得;前面遇到过重复释放问题。程序有虚拟地址管理;程序结束会回收;找pte 物理页面找不到;会出错。

    • 所以在退出程序得时候将pte 修改回来;还可以将钩子卸掉;

      • 还是得C 了 窗口消息函数 然后 将 pte 得修改回来!★ ---- 这个才是i正确得。。。

    代码1 被隐藏目标程序:shadowWalker.cpp

    // 9_页面异常.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //

    #include "pch.h"
    #include <stdio.h>
    #include<stdlib.h>
    #include<Windows.h>

    // 计算 pte 的宏 -- 针对29912
    #define PTE(y) ((DWORD *)(0xc0000000 + ((y>> 12)<< 3)))

    // 定义一些内核地址宏;用来保存当前程序相关数据(cr3)
    #define K_REAL_PTE0     0x8003f3e0 // * 真正得pte 【0】
    #define K_REAL_PTE1     0x8003f3e4       // * 真正得pte 【1】
    // 假页的PTE
    #define K_FAKE_PTE0     0x8003f3d0       // * 假页 pte 【0】
    #define K_FAKE_PTE1   0x8003f3d4 // * 假页 pte 【1】

    // j假
    #define K_TARGET_CR30x8003f3c0 // cr3       * 异常程序cr3



    DWORD g_bReady = FALSE;
    DWORD g_bNewExpt = FALSE;

    DWORD g_pEIP = 0;
    DWORD g_pExceptPvn = 0;
    DWORD g_iCr3 = 0;
    DWORD g_iErrCode = -1;


    void go();
    #pragma section("data_seg",read,write)
    __declspec(allocate("data_seg")) DWORD FakePage[1024] = {0};// 0x41d000
    //#pragma code_seg(".text") __declspec(allocate(".text"))void IdtEntry();

    // 0x401040
    void __declspec(naked) IdtEntry()
    {
    // 注册 int 0x21; -- FixBack() -- 0x401090
    *(DWORD*)0x8003f508 = 0x000810b0;
    *(DWORD*)0x8003f50c = 0x0040ee00;

    // 将pte数据提交
    //__asm int 3;
    *(DWORD*)K_REAL_PTE0 = PTE((DWORD)0x412000)[0];
    *(DWORD*)K_REAL_PTE1 = PTE((DWORD)0x412000)[1];
    *(DWORD*)K_FAKE_PTE0 = PTE((DWORD)0x41d000)[0];
    *(DWORD*)K_FAKE_PTE1 = PTE((DWORD)0x41d000)[1];
    //__asm int 3;
    g_pExceptPvn = PTE(0x412000)[0];
    g_pEIP = *(DWORD*)K_REAL_PTE0;
    PTE(0x412000)[0]= PTE(0x412000)[0]&0xfffffffe;// 关闭 p位 缺页异常!。
    __asm
    {
    // 将当前cr3 数据提交
    mov eax, cr3;
    mov ds : [K_TARGET_CR3], eax;
    //// 提交完成的标识。
    //mov eax, 0x1;
    //mov ds : [K_BOOL_READY], eax;
    iretd;
    }
    }
    void __declspec(naked) FixBack()
    {
    __asm
    {
    //int 3
    mov eax, cr3;
    mov cr3, eax;
    }
    __asm
    {
    invlpg ds : [0x412000];// 书信 TLB
    }
    PTE(0x412000)[0] = *(DWORD*)K_REAL_PTE0;
    //PTE(0x412000)[1] = *(DWORD*)K_REAL_PTE1;

    __asm
    {
    mov eax, ds:[0x412000];
    //int 3;
    push 0x3b;
    pop fs;
    iretd; // 返回。
    }
    }
    // 真实得代码页: 0x412000;五角星 放得位置 决定着 所在得虚拟位置 == 地址
    #pragma code_seg(".my_code") __declspec(allocate(".my_code"))int main();
    #pragma code_seg(".my_code") __declspec(allocate(".my_code"))void go();


    void _declspec(naked) go()
    {
    __asm
    {
    int 0x20;
    ret;
    }
    }



    int main()
    {
    __asm {
    jmp L
    ret// 这里会产生缺页中断 --- 其实这里是对下面的 缺页中断 响应
    //00402005
    L :
    }
    if ((DWORD)IdtEntry != 0x401040)
    {
    printf("wrong addr: %p", IdtEntry);
    printf("wrong addr: %p", FixBack);
    exit(-1);
    }
    FakePage[0] = 0;
    go();
    __asm
    {
    //int 3;
    }
    int i = 0;
    while (1) {
    if (i == 2000)
    {
    __asm
    {
    int 0x21;
    //inc i;

    }
    printf("%d   : BF: %p AF:%p ", i++, g_pEIP, g_pExceptPvn);
    break;
    }
    printf("%d   : BF: %p AF:%p ", i++,g_pEIP,g_pExceptPvn);
    Sleep(1000);// 这里 Sleep完之后;不存在那个TLB 表中了会产生 缺页 中断;

    }
    system(" pause");

    }
    //int main()
    //{
    //if ((DWORD)IdtEntry != 0x401040)
    //{
    // printf("Func addres is wrong !!");
    // Sleep(5000);
    // system("pause");
    // FakePage[0] = 0;
    // exit(-1);
    //}
    //__asm
    //{
    // jmp L;
    // ret;
    //L:
    //}
    //
    //FakePage[0] = 0;// 这里访问一次使得可以 第一次可以不产生异常。
    ////printf("%d ", FakePage[0]);
    //go();
    //int i = 0;
    //while (1)
    //{
    // i++;
    // if (i % 10 != 0)
    // {
    // for (int j = 0; j < i; j++)
    // {
    // printf(".");
    // }
    // Sleep(50);
    // continue;
    // }
    // else
    // {
    // i = 0;
    //
    // printf("runing... ");
    // Sleep(500);
    // system("cls");
    // }
    //
    //}
    //
    //system("pause");
    //}

    代码2:注册和过滤处理目标页面异常消息

    // 9_页面异常_过滤获取目标异常信息.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //

    #include "pch.h"
    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>

    // 计算 pte 的宏 -- 针对29912
    #define PTE(y) ((DWORD *)(0xc0000000 + ((y>> 12)<< 3)))

    // 定义一些内核地址宏;用来保存当前程序相关数据(cr3)
    #define K_REAL_PTE0     0x8003f3e0 // * 真正得pte 【0】
    #define K_REAL_PTE1     0x8003f3e4       // * 真正得pte 【1】
    // 假页的PTE
    #define K_FAKE_PTE0     0x8003f3d0       // * 假页 pte 【0】
    #define K_FAKE_PTE1   0x8003f3d4 // * 假页 pte 【1】

    // j假
    #define K_TARGET_CR30x8003f3c0 // cr3       * 异常程序cr3

    #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



    // 原来的第一句 有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 < 256; g_i++)
    {
    *(BYTE*)(g_p + g_i) = *(byte*)((DWORD)checkAndCap + g_i);
    }

    __asm
    {
    iretd;
    }
    }


    // 0x401040 --
    void _declspec(naked) checkAndCap()
    {
    __asm
    {
    pushad;
    // 判断是否是 目标程序
    mov eax, cr3;   // cr3不能用于比较的 参数
    cmp eax, ds:[K_TARGET_CR3];
    jnz PASS;

    //***** 到这里 说明是新的 目标程序的异常
    // 再过滤指定区段得异常

    mov eax, cr2;
    shr eax, 0xc;
    cmp eax, 0x412;

    jnz PASS;

    // 在这里需要拦截不能交给系统继续处理
    mov eax, [esp + 0x20];// 因为前面push ad ;error code;
    test eax, 0x10;//如果是
    jnz EXEC;
    jmp DATA;
    DATA:
    // 修改PTE 读写操作全部移动到假页;
    }
    PTE(0x412000)[0] =  *((DWORD*)K_FAKE_PTE0);
    //PTE(0x412000)[1] = *((DWORD*)K_FAKE_PTE1);


    __asm
    {
    mov eax, ds:[0x412000];
    };// 使得加入快表-- 这次得异常得以执行;

    PTE(0x412000)[0] = PTE(0x412000)[0] & 0xfffffffe;// 这样使得p位为0;会继续产生异常交给我们接管;
    //PTE(0x412000)[1] = 0;// 这样使得p位为0;会继续产生异常交给我们接管;
    __asm
    {
    jmp DEALED;
    EXEC:
    }
    // 修改pte 将执行操作 移动到真页
    PTE(0x412000)[0] = *(DWORD*)K_REAL_PTE0;
    //PTE(0x412000)[1] = *(DWORD*)K_REAL_PTE1;

    // 调用代码 使得进入 itlb -- 指令快表--使得这次能得以处理
    __asm
    {
    mov eax, 0x00412012;
    call eax;
    }
    // 继续使得p 位 为 0 -- 后面继续产生 缺页 我们接管。
    PTE(0x412000)[0] = PTE(0x412000)[0] & 0xfffffffe;
    //PTE(0x412000)[1] = 0;
    __asm
    {
    DEALED:
    popad;
    add esp, 4;// 因为有一个 errorcode!!;这个得手动平
    iretd;


    PASS:
    popad;
    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 != 0x4010b0)
    {
    printf("CHEC出错了:%p", checkAndCap);
    Sleep(10000);
    exit(-1);
    }
    go();
    system("pause");



    }

  • 相关阅读:
    Springx b 界面
    ETCD 分布式锁实现逻辑
    etcd 集群概述 转
    [转]MySQL性能优化
    Elasticsearch、MongoDB和Hadoop比较
    Mysql导出表格变成科学计数法的解决方案
    记一次laravel框架下的post请求测试
    Mysql语句优化记录
    laravel与MongoDB 的部分实践
    Laravel多数据库连接记录
  • 原文地址:https://www.cnblogs.com/leibso-cy/p/11719281.html
Copyright © 2011-2022 走看看