現(xiàn)在根據(jù)實(shí)例來(lái)配合,現(xiàn)在要得到NtOpenProcess的內(nèi)存地址
用 winDebug 得到 SSDT這個(gè)表的首地址是 0x80505480

進(jìn)入這個(gè)地址看看里面的內(nèi)容是什么

0: kd> dd poi[KeServiceDescriptorTable]
地址 0 1 2 3
80505480 805a565c 805f243e 805f5c74 805f2470
4 5 6 7
80505490 805f5cae 805f24a6 805f5cf2 805f5d36
8 9 10 11
805054a0 80616d1e 80617a60 805ed83c 805ed494
805054b0 805d5bae 805d5b5e 80617344 805b6fe2
805054c0 80616960 805a9ae6 805b15f6 805d7672
805054d0 8050289c 80617a52 80577b0a 80539c34
805054e0 8060ff2e 805bd55c 805f61ae 80624cf0
805054f0 805fa6c2 805a5d4a 80624f44 805a55fc
看到 0x80505480 這個(gè)地址存的第0個(gè)地址是 0x805A565C
用 Kerne Detective 這個(gè)工具看看這個(gè)是什么API

第0個(gè)是NtAcceptConnectPort 這個(gè)API
可以看到 WinDebug 得到的數(shù)據(jù) 和 KD 一樣
用工具可以很容易找到SSDT的基地址 和 索引號(hào)以及NtAPI的內(nèi)存地址
用編程實(shí)現(xiàn) (精華):
要檢查 SSDT 指定的NtAPI有沒(méi)有被HOOK 就要先 獲取到現(xiàn)在的NtAPI地址、獲取原來(lái)的NtAPI的內(nèi)存地址,然后將兩個(gè)地址相比較即可。
獲取現(xiàn)在NtAPI的內(nèi)存地址的具體流程
首先應(yīng)該得到SSDT的首地址 即 基址
然后將ServiceTableBase 的內(nèi)存首地址+索引號(hào)*4 得到存儲(chǔ)著相應(yīng)索引號(hào)內(nèi)核NtAPI現(xiàn)在的內(nèi)存地址的地址(ServiceTableBase的偏移地址)
讀取該地址得到現(xiàn)在的NtAPI內(nèi)存地址
獲取原來(lái)的NtAPI的內(nèi)存地址的具體流程
通過(guò) MmGetSystemRoutineAddress 可以得到原來(lái)的NtAPI 地址
主要是 獲取現(xiàn)在的NtAPI比較費(fèi)心思去理解,只要理解了這個(gè)流程,也就理解了SSDT表的結(jié)構(gòu)了。
看看下面的代碼以及注釋就能理解SSDT表的結(jié)構(gòu)了
左邊是用KD工具得到 NOtOpenProcess 內(nèi)存地址 右邊是用WinDebug得到

下圖是通過(guò)編程得到 NtOpenProcess 內(nèi)存地址:

代碼:
ypedef struct _ServiceDescriptorTable {
PVOID ServiceTableBase; //System Service Dispatch Table 的基地址
PVOID ServiceCounterTable;
//包含著SSDT 中每個(gè)服務(wù)被調(diào)用次數(shù)的計(jì)數(shù)器。這個(gè)計(jì)數(shù)器一般由sysenter 更新。
unsigned int NumberOfServices;//由ServiceTableBase 描述的服務(wù)的數(shù)目。
PVOID ParamTableBase; //包含每個(gè)系統(tǒng)服務(wù)參數(shù)字節(jié)數(shù)表的基地址-系統(tǒng)服務(wù)參數(shù)表
}*PServiceDescriptorTable;
extern PServiceDescriptorTable KeServiceDescriptorTable;
ULONG GetNt_CurAddr() //獲取當(dāng)前SSDT_NtOpenProcess的現(xiàn)在地址
{
LONG *SSDT_Adr,SSDT_NtOpenProcess_Cur_Addr,t_addr;
KdPrint(("驅(qū)動(dòng)成功被加載中.............................\n\n"));
KdPrint(("********************** 計(jì)算現(xiàn)在的地址**********************\n\n"));
//讀取SSDT表中索引值為x7A的函數(shù)
//poi(poi(KeServiceDescriptorTable)+0x7a*4)
t_addr=(LONG)KeServiceDescriptorTable->ServiceTableBase; // 得到ServiceTableBase 的地址
KdPrint(("[得到ServiceTableBase 的基址] \n當(dāng)前ServiceTableBase地址為0x%X \n\n",t_addr));
// 將該地址里面的內(nèi)容+ 索引號(hào)* 4 就能得到相應(yīng)索引號(hào)內(nèi)核NtAPI現(xiàn)在的內(nèi)存地址0x7A為NtOpenProcess在SSDT的索引
SSDT_Adr=(PLONG)(t_addr+0x7A*4);
KdPrint(("[將ServiceTableBase 的內(nèi)存首地址+索引號(hào)*4 \n得到存儲(chǔ)著相應(yīng)索引號(hào)內(nèi)核NtAPI現(xiàn)在的內(nèi)存地址的地址(ServiceTableBase的偏移地址)]\n"));
KdPrint(("SSDT首地址0x%X + 0x7A * 4= 0x%X 這個(gè)地址0x%X 存儲(chǔ)著索引號(hào)為0x7A 的NtOpenProcess內(nèi)存地址\n\n", t_addr, SSDT_Adr, SSDT_Adr));
SSDT_NtOpenProcess_Cur_Addr=*SSDT_Adr;
KdPrint(("[讀取0x%X 得到NtOpenProcess 函數(shù)現(xiàn)在的內(nèi)存地址] 現(xiàn)在的NtOpenProcess 內(nèi)存地址為0x%X \n\n",SSDT_Adr, SSDT_NtOpenProcess_Cur_Addr));
KdPrint(("********************** 計(jì)算完畢***************************\n\n"));
// 匯編
/*
__asm
{ int 3
push ebx
push eax
mov ebx,KeServiceDescriptorTable
mov ebx,[ebx] //表的基地址 取 KeServiceDescriptorTable 的地址 t_addr=(LONG)KeServiceDescriptorTable->ServiceTableBase;
mov eax,0x7a
shl eax,2//0x7A*4 //imul eax,eax,4//shl eax,2
add ebx,eax//[KeServiceDescriptorTable]+0x7A*4
mov ebx,[ebx] // SSDT_NtOpenProcess_Cur_Addr=*SSDT_Adr; // 取出該地址中存儲(chǔ)的NtOpenProcess 函數(shù)的地址
mov SSDT_NtOpenProcess_Cur_Addr,ebx
pop eax
pop ebx
}
*/
return SSDT_NtOpenProcess_Cur_Addr; // 將獲得的地址返回
}
ULONG GetNt_OldAddr()
{
UNICODE_STRING Old_NtOpenProcess;
ULONG Old_Addr;
KdPrint(("********************** 計(jì)算原來(lái)的地址**********************\n\n"));
RtlInitUnicodeString(&Old_NtOpenProcess,L"NtOpenProcess");
Old_Addr=(ULONG)MmGetSystemRoutineAddress(&Old_NtOpenProcess);//取得NtOpenProcess的地址
KdPrint(("用MmGetSystemRoutineAddress 取得原來(lái)NtOpenProcess 的地址為0x%X\n\n",Old_Addr));
KdPrint(("********************** 計(jì)算完畢****************************\n\n"));
return Old_Addr;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING B) //TYPEDEF LONG NTSTATUS
{
ULONG cur,old;
cur=GetNt_CurAddr();// 得到現(xiàn)在的NtAPI 地址
old=GetNt_OldAddr();// 得到原來(lái)的NtAPI 地址
if (cur!=old)
KdPrint(("NtOpenProcess被HOOK了"));
else
KdPrint(("NtOpenProcess 沒(méi)有被HOOK"));
}