Detours 原始碼閱讀筆記

2021-06-30 16:40:09 字數 3042 閱讀 9809

detour庫

1. 原始碼

detour庫很小,直接編譯成lib比較好,在用到的**中做靜態鏈結。

detours 3.0加入的新的功能:

支援x64的api hook,包括 amd64 和 ia64兩套

支援所有的windows處理器(包括arm)

不再依賴detoured.dll

列舉pe匯入表,匯出表的api,確定函式指標引用的模組

原始碼結構:

disasm.cpp / detours  / detours.h 共同構成了detours基本功能

modules.cpp 提供了遍歷pe檔案的api

image.cpp / creatwth.cpp / uimports.cpp 用於構建新的pe檔案,新增.detours 節 

編譯:直接在vs中建立乙個lib工程,然後將原始檔匯入即可(uimports.cpp 除外)。

注: uimports.cpp 被 include進了 creatwth.cpp 中了,如果加入到工程,就會提示編譯錯誤。

其實detours的工作比較簡單,但是要做乙個健壯的庫,還是不太容易的。

自己感覺detours比較困難的幾個點難點:

1. 給出乙個位址,判斷能否hook

不能hook jmp指令,否則trampline **會有問題

2. **段的判斷:

需要trampline 幾個位元組,不能在hook時將指令截斷

3. trampline部分 位址重定位的問題

這就需要識別出被搬走**中的位址,並進行修改

2和3是乙個問題,就是要能夠識別指令,其實就是解析cpu的 opcode

detours api的作用,以及內部做的工作:

long winapi detourtransactionbegin(void);

鎖住detour庫,並將trampline的所有塊變為可讀可寫可執行,方便後面向trampline塊中寫入。

long winapi detourtransactionabort(void);

恢復所有的 operation(一次可以有多個operation),修改trampline塊為執行屬性,並恢復所有執行緒執行

long winapi detourtransactioncommit(void);

首先恢復hook或插入hook,對執行到trampline的執行緒進行調整,flush icache保證**更新到快取,讓cpu執行新的指令,

修改trampline塊組執行屬性,恢復所有執行緒

long winapi detourtransactioncommitex(pvoid **pppfailedpointer);

同上long winapi detourupdatethread(handle hthread);

掛起指定控制代碼指定的執行緒

long winapi detourattach(pvoid *pppointer, pvoid pdetour);

尋找可以hook的位址(當前位址可能無法hook),分配trampline塊,並且確定trampline中的拷貝的指令位元組數,加入操作(operation)列表

long winapi detourattachex(pvoid *pppointer, pvoid pdetour, pdetour_trampoline *pprealtrampoline, pvoid *pprealtarget, pvoid *pprealdetour);

同上long winapi detourdetach(pvoid *pppointer, pvoid pdetour);

與attach逆向的操作,建立乙個operation,指明為remove hook的操作,將要恢復的hook的trampline掛入operation中。

3. detours需要注意的地方:

1. detourtransactionbegin()方法

每個hook如果只做了一次,在多執行緒情況下可能出現hook失敗的情況。

// only one transaction is allowed at a time.

if (s_npendingthreadid != 0)

// make sure only one thread can start a transaction.

if (interlockedcompareexchange(&s_npendingthreadid, (long)getcurrentthreadid(), 0) != 0)

如果兩個執行緒同時執行到了 detourtransactionbegin的起始位置,同時向下執行,肯定有乙個執行緒會 return error_invalid_operation; 。

2. detourupdatethread() 方法

這個函式是掛起指定控制代碼的執行緒,只留下執行hook的執行緒。

所以要遍歷當前程序中的所有的執行緒,逐一執行這個函式。

3. 如果攔截函式在dll中,那麼絕大多數情況下不能在unhook之後解除安裝這個dll,或者解除安裝存在造成崩潰的危險。

因為某些執行緒的呼叫堆疊中可能還包含hook函式,這時解除安裝掉dll,呼叫堆疊返回到hook函式時記憶體位置已經不是合法的**了。

4. 有一些非常短的目標函式無法hook。

jmp指令需要占用一定空間,有些函式太過短小,甚至不夠jmp指令的長度,沒有辦法hook,(比如ntdll!dbgbreakpoint函式)

4. 示例:

#include #include "detours.h"

#pragma comment(lib, "detours.lib")

static int (winapi * old_messageboxw)(hwnd hwnd, lpcwstr lptext, lpcwstr lpcaption, uint utype) = messageboxw;

int winapi new_messageboxw(hwnd hwnd, lpcwstr lptext, lpcwstr lpcation, uint utype)

void hook()

void unhook()

void main()

閱讀筆記 fsnotify原始碼閱讀

fsnotify的github位址是 fsnotify是乙個資料夾監控應用。可以使用建立乙個watcher來對某個資料夾進行監控 檔案目錄很簡單,實際就兩個程式檔案,fsnotify.go 和 各平台的fsnotify go 後乙個檔案是各個不同平台的實現 example test.go中給的是最簡...

《原始碼閱讀》原始碼閱讀技巧,原始碼閱讀工具

檢視某個類的完整繼承關係 選中類的名稱,然後按f4 quick type hierarchy quick type hierarchy可以顯示出類的繼承結構,包括它的父類和子類 supertype hierarchy supertype hierarchy可以顯示出類的繼承和實現結構,包括它的父類和...

redis原始碼閱讀筆記

在redis中乙個資料庫結構體是這樣的 每個dict是乙個hash表 typedef struct redisdb redisdb dict欄位中存放以key值為鍵,以value指標為值的hash表項dict根據型別的不同分為如下幾種 1 字串 string 操作 set key value get...