在windows平台做逆向、外掛等,經常需要調用很多未導出的內核函數,怎么方便、快速查找了?可以先用IDA等工具查看硬編碼,再根據硬編碼定位到需要調用的函數。整個思路大致如下:
1、先查找目標模塊
遍歷模塊的方式有多種。既然通過驅動在內核編程,這里選擇遍歷driverObject的DriverSection字段來遍歷內核所有模塊,核心代碼如下:
1 /* 2 可以用來動態查找內核模塊的基址,后續用於: 3 1、PTE\PDE等base計算 4 2、其他函數、變量精確位置的計算(IDA靜態分析只能查到偏移) 5 */ 6 PVOID FindMould(PDRIVER_OBJECT pDriverObject, PWCHAR moudName, PULONG pSize) 7 { 8 // 從PDRIVER_OBJECT獲取DriverSection,便可獲得驅動模塊鏈表 9 PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; 10 // 開始遍歷雙向鏈表 11 PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData; 12 do 13 { 14 if ((0 < pDriverData->BaseDllName.Length) || 15 (0 < pDriverData->FullDllName.Length)) 16 { 17 // 顯示 18 DbgPrint("BaseDllName=%ws,\tDllBase=0x%p,\tSizeOfImage=0x%X,\tFullDllName=%ws\n", 19 pDriverData->BaseDllName.Buffer, pDriverData->DllBase, 20 pDriverData->SizeOfImage, pDriverData->FullDllName.Buffer); 21 //BaseDllName.Buffer是PWCH,也就是寬字符串,所以自己定義的moudName也要是PWCHAR類型 22 if (!_stricmp(moudName, (PCHAR)pDriverData->BaseDllName.Buffer)) 23 { 24 DbgPrint("find target : BaseDllName=%ws,\tDllBase=0x%p,\tSizeOfImage=0x%X,\tFullDllName=%ws\n", 25 pDriverData->BaseDllName.Buffer, pDriverData->DllBase, 26 pDriverData->SizeOfImage, pDriverData->FullDllName.Buffer); 27 *pSize = pDriverData->SizeOfImage; 28 return pDriverData->DllBase; 29 } 30 31 } 32 // 下一個 33 pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverData->InLoadOrderLinks.Flink; 34 35 } while (pFirstDriverData != pDriverData); 36 37 return NULL; 38 }
傳入driverObject、模塊名稱,得到模塊基址(返回值)和模塊長度(參數);
2、得到模塊基址后,再進一步根據特征碼查找目標函數:
1 PVOID FindFun(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength) 2 { 3 PVOID pDestAddr = NULL; 4 PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr; 5 PUCHAR pEndAddr = pBeginAddr + ulSearchLength; 6 PUCHAR i = NULL; 7 ULONG j = 0; 8 9 for (i = pBeginAddr; i <= pEndAddr; i++) 10 { 11 // 遍歷特征碼 12 for (j = 0; j < ulSpecialCodeLength; j++) 13 { 14 // 判斷地址是否有效 ntoskrnl.exe有時地址無效,藍屏報錯:PAGE FAULED IN NONPAGED AREA 15 if (FALSE == MmIsAddressValid((PVOID)(i + j))) 16 { 17 break; 18 } 19 // 匹配特征碼 20 if (*(PUCHAR)(i + j) != pSpecialCode[j]) 21 { 22 break; 23 } 24 } 25 // 匹配成功 26 if (j >= ulSpecialCodeLength) 27 { 28 pDestAddr = (PVOID)i; 29 break; 30 } 31 } 32 33 return pDestAddr; 34 }
這里特征碼搜索可以繼續改進,比如用正則做模糊匹配~~~
3、用法舉例:強行殺死線程時,需要調用 PspTerminateThreadByPointer 函數,但此函數並未導出,可以通過IDA查看匯編代碼,也可以在windbg通過U PspTerminateThreadByPointer,如下:
kd> u nt!PspTerminateThreadByPointer
nt!PspTerminateThreadByPointer:
fffff803`d01c6210 48895c2408 mov qword ptr [rsp+8],rbx
fffff803`d01c6215 48896c2410 mov qword ptr [rsp+10h],rbp
fffff803`d01c621a 4889742418 mov qword ptr [rsp+18h],rsi
fffff803`d01c621f 57 push rdi
fffff803`d01c6220 4883ec30 sub rsp,30h
fffff803`d01c6224 8b81d0060000 mov eax,dword ptr [rcx+6D0h]
fffff803`d01c622a 418ae8 mov bpl,r8b
fffff803`d01c622d 488bb920020000 mov rdi,qword ptr [rcx+220h]
由於大多數函數剛開始都是初始化堆棧代碼,這里特征碼重合度較高,為了避免找到其他函數,建議從稍微靠后幾行代碼處提取特征碼,比如這里從第7行開始提取 418ae8488bb920020000 10個字節,找到后再減去26字節就回到了PspTerminateThreadByPointer入口;
1 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath) 2 { 3 DbgPrint("Enter DriverEntry\n"); 4 5 NTSTATUS status = STATUS_SUCCESS; 6 pDriverObject->DriverUnload = DriverUnload; 7 for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) 8 { 9 pDriverObject->MajorFunction[i] = DriverDefaultHandle; 10 } 11 12 ULONG mouldSize = 0; 13 PWCHAR mouldName = L"ntkrnlmp.exe"; 14 PVOID mouldBase = FindMould(pDriverObject, mouldName, &mouldSize); 15 16 17 DbgPrint("mould name = %ws ; mould base = 0x%p; mould size = 0x%X\n", mouldName, mouldBase, mouldSize); 18 19 UCHAR pSpecialCode[256] = { 0 }; 20 /*418ae8488bb920020000*/ 21 pSpecialCode[0] = 0x41; 22 pSpecialCode[1] = 0x8a; 23 pSpecialCode[2] = 0xe8; 24 pSpecialCode[3] = 0x48; 25 pSpecialCode[4] = 0x8b; 26 pSpecialCode[5] = 0xb9; 27 pSpecialCode[6] = 0x20; 28 pSpecialCode[7] = 0x02; 29 pSpecialCode[8] = 0x00; 30 pSpecialCode[9] = 0x00; 31 32 PVOID FunAddress = FindFun(mouldBase, mouldSize, pSpecialCode, 4); 33 DbgPrint("Finally function address = 0x%p;\n", FunAddress-26); 34 35 return status; 36 }