第一步:IDA查看這個函數的交叉引用,看到PspAlloCateThread 調用了該函數算法
二. 繼續查看有誰調用了PspAllocateThread 這個函數函數
看到了一個導出函數 NtCreateUserProcess ,思路就是 NtCreateUserProcess --> PspAllocateThread --> PspUserThreadStartup 這樣子就能找到 PspUserThreadStartup 函數的地址spa
記錄一下特徵碼 這裏我在 NtCreateUserProcess 調用 PspAllocateThread 的call 附加尋找特徵碼 ,我尋找的特徵碼是 94 24 18 01 其實這種特徵碼不靠譜 但這個函數很小並且從函數頭到調用的位置只出現一次code
這裏順便記錄一下 94這個字節 距離真正調用call 相差 9 個字節 。blog
接下來尋找 PspAllocateThread 調用 PspUserThreadStartup 附加的特徵碼,8B 86 10 06 這裏距離 lea r8,PspUserThreadStartup 相差16個字節class
接下來編寫一個函數暴力枚舉出來引用
PVOID GetPspUserThreadStartup2(ULONG64 函數地址, 暴力掃描* 信息, UCHAR 特徵碼[]) { if (!MmIsAddressValid(&函數地址)) { return 0; } INT code1 = NULL; ULONG64 addr = NULL; ULONG64 返回地址 = NULL; for (size_t i = 0; i < 0x1BF8CA; i++) { if (memcmp((PVOID)(函數地址 + i), 特徵碼, 信息->特徵碼長度) == 0) { addr = 函數地址 + i + 信息->特徵碼距離函數地址偏移; 信息->偏移 = __insn_len_x86((PVOID)addr, __b64); //信息->偏移 能夠理解爲地址的彙編長度 好比 0x123456 E8 01 這個0x123456地址長度就是 2 for (int i = 信息->偏移; i >= 4; i--) { if (i == 4) { 信息->偏移 = 信息->偏移 - i; //這裏算法能夠計算出函數調用位置的後四字節 break; } } memcpy(&code1, (PVOID)(addr + 信息->偏移), 4); //這裏拷貝 調用的位置後四個字節 好比上面看到的 call PspAllocateThread E8 0D 4E 0C 00 這裏須要拿到後四個字節計算函數真正地址 計算公式 函數真正地址=當前地址+後四字節地址+地址長度 函數地址 = (addr + code1 + __insn_len_x86((PVOID)addr, __b64)); 返回地址 = 函數地址; break; } } return (PVOID)返回地址; }
使用方法,能夠定義一個結構體方法
上面GetFUnaddr 是 NtcreateUserProcess 在SSDT中的編號 獲取它在SSDT中的地址獲取im
結果:call