白皮书中 page-fault error code:

shadowWalker 原理:

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

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

相关:

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

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

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

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

    • 所以我们接管。

  • 只接管 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 ;代码如上;

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

  • 创建一个假页面:

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

*(DWORD *)K_FAKE_PTEO = PTE (0x405000)[0];
*(DWORD *)K_FAKE_PTE1 = PTE (0x405000)[1];
  • 处理之后不能直接退出;得手动平 error code 这个栈位;因为中断系统只平默认的5个。

  • 接管处理:

    • 代码执行异常:

    • 读写异常接管:

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

  • 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 \n", i++, g_pEIP, g_pExceptPvn);
break;
}
printf("%d   : BF: %p AF:%p \n", 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\n", 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...\n");
// 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");



}

18_ShadowWalker的更多相关文章

随机推荐

  1. 代码编译与反编译 (.py文件与.pyc文件互转)

    # 将.py文件转化为.pyc文件,实现代码隐藏的需要,转化后的.pyc文件将在当前目录的__pycache__文件夹下. # .pyc文件的使用与.py文件的使用相同. .py -> .pyc ...

  2. LLppdd has a dream!

    LLppdd has a dream Time Limit: 3 s Memory Limit: 256 MB 题目背景 LLppdd经过他充满坎坷的初三后,他的成绩也充满了坎坷. 临近中考了,他希望 ...

  3. 每天一个Linux常用命令 ls命令

    ls:列出目录中的内容 -l  显示详细信息 -a 显示所有文件,包括隐藏文件 -i  显示inode -t :依时间排序,而不是用档名. -r :将排序结果反向输出,例如:原本档名由小到大,反向则为 ...

  4. 高德地图的权限Activity代码

    /** * */package com.amap.location.demo; import java.lang.reflect.Method;import java.util.ArrayList;i ...

  5. Java中udp/tcp的发送和接收

    InetAddress UDP例程: 发送数据: 接收数据: 结果: TCP例程: 发送数据: 接收数据: 结果:

  6. Debug - SpringBoot - Error starting ApplicationContext. To display the auto-configuration report re-runyour application

    Error log 2019-12-07 22:33:03.959 ERROR 3760 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : ** ...

  7. 暴力——cf1202C

    直接去考虑细节很多,不如暴力做 即在四个方向到达最远前向反方向走一步,答案肯定是从这四种情况+不多走里出的 #include<bits/stdc++.h> using namespace ...

  8. [ZJOI2011]看电影(组合数学/打表+高精)

    Description 到了难得的假期,小白班上组织大家去看电影.但由于假期里看电影的人太多,很难做到让全班看上同一场电影,最后大家在一个偏僻的小胡同里找到了一家电影院.但这家电影院分配座位的方式很特 ...

  9. CSS:CSS 媒体类型

    ylbtech-CSS:CSS 媒体类型 1.返回顶部 1. CSS 媒体类型 媒体类型允许你指定文件将如何在不同媒体呈现.该文件可以以不同的方式显示在屏幕上,在纸张上,或听觉浏览器等等. 媒体类型 ...

  10. Openstack组件部署 — Nova_Install and configure a compute node

    目录 目录 前文列表 Prerequisites 先决条件 Install and configure a compute node Install the packages Edit the etc ...