在 IDT 表中的e 號 處理 是 頁面異常處理; 若是 咱們 hook 掉 這個回調函數;那麼就能得到所有的頁面異常;再經過 cr3 對比 捕獲指定的 cr3 (進程)的信息;最後再共享的區域將數據輸出;而後測試程序獲取該本身的頁面異常信息;web
在 c 的時候注意將使用的寄存器(這裏是eax)先保存起來;注意 經過棧保存 eax的話注意 相關進入中斷後和棧相關的數據,就會和esp 的相對偏移產生變化。ide
此程序 主要是 中斷進入 內核;而後讀取數據;看時候有新的和本身有關的異常頁面信息;這樣函數
// 9_頁面異常.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
// 定義一些內核地址宏;用來保存當前程序相關數據(cr3)
// * 當前是否已經提交 cr3,變爲準備接收異常狀態
// esp * 異常代碼
// esp - 4 * 異常地址 eip(產生異常的代碼地址)
// cr3 * 異常程序cr3
// cr2 * 異常地址(產生頁面異常頁中的虛擬地址)
// * 是否有新的異常
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\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;
}
}
}
// 9_頁面異常_過濾獲取目標異常信息.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
// 定義一些內核地址宏;用來保存當前程序相關數據(cr3)
// * 當前是否已經提交 cr3,變爲準備接收異常狀態
// esp * 異常代碼
// esp - 4 * 異常地址 eip(產生異常的代碼地址)
// cr3 * 異常程序cr3
// cr2 * 異常地址(產生頁面異常頁中的虛擬地址)
// * 是否有新的異常
// * Hook 代碼所在
// * 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");
}