PsActiveProcessHead的定義:
在windows系統中,所有的活動程序都是連在一起的,構成一個雙連結清單,表頭是全局變量PsActiveProcessHead,當一個程序被建立時,其ActiveProcessList域将被作為節點加入到此連結清單中;當程序被删除時,則從此連結清單中移除,如果windows需要枚舉所有的程序,直接操縱此連結清單即可。
方法一:從KdInitSystem函數位址處寫死搜尋
方法二:從System程序(pid=4)的PEPROCESS位址擷取
方法三:從ntoskrnl.exe的導出變量PsInitialSystemProcess中擷取
方法四:從KPCR中擷取
方法五:調用NtSystemDebugControl函數擷取
注:作業系統 Windows XP SP3
方法一:
系統核心變量KdDebuggerDataBlock是一個KDDEBUGGER_DATA64類型的結構體,結構成員PsActiveProcessHead正是我們所找的位址。可在WinDDK的\inc\api\WDBGEXTS.H檔案中檢視到此結構的定義。
KdInitSystem函數中引用了KdDebuggerDataBlock,而ntoskrnl.exe的導出函數KdEnableDebugger調用了KdInitSystem函數。
ULONG FindPsActiveProcessHead1()
{
//1.從KdEnableDebugger位址找到KdInitSystem位址
//nt!KdEnableDebugger 804f7810
//804f7837 6a00 push 0
//804f7839 6a00 push 0
//804f783b c605ecab558001 mov byte ptr [nt!PoHiberInProgress (8055abec)],1
//804f7842 e8f7951600 call nt!KdInitSystem (80660e3e)
//804f7847 e8649a1600 call nt!KdpRestoreAllBreakpoints (806612b0)
ULONG i;
PCALL_CODE pCall;
PUCHAR pKdInitSystem=NULL;
PUCHAR p=(PUCHAR)GetExportFuncAddress(L"KdEnableDebugger");
KdPrint(("KdEnableDebugger位址=%x\n",p));
if (!p)
{
KdPrint(("擷取KdEnableDebugger位址失敗\n"));
return 0;
}
for (i=0;i<100;i++,p++)
{
if ((*p==0x6a)&&
(*(p+1)==0x00)&&
(*(p+2)==0x6a)&&
(*(p+3)==0x00)&&
(*(p+4)==0xc6)&&
(*(p+5)==0x05)&&
(*(p+0xb)==0xe8)&&
(*(p+0x10)==0xe8) )
{
pCall=(PCALL_CODE)(p+0xb);
pKdInitSystem=p+0xb+pCall->address+5;
KdPrint(("KdInitSystem位址=%x\n",pKdInitSystem));
break;
}
}
if (!pKdInitSystem)
{
KdPrint(("擷取KdInitSystem位址失敗\n"));
return 0;
}
//2.從KdInitSystem位址找到KdDebuggerDataBlock位址
//nt!KdInitSystem 80660e3e
//80660e8e 6890020000 push 290h
//80660e93 68606b5480 push offset nt!KdDebuggerDataBlock (80546b60)
//80660e98 be74926780 mov esi,offset nt!KdpDebuggerDataListHead (80679274)
p=pKdInitSystem;
for (i=0;i<100;i++,p++)
{
if ((*p==0x68)&&
(*(p+5)==0x68)&&
(*(p+0xA)==0xbe))
{
pCall=(PCALL_CODE)(p+5);
KdPrint(("KdDebuggerDataBlock位址=%x\n",pCall->address));
KdPrint(("PsActiveProcessHead位址=%x\n",((PKDDEBUGGER_DATA64)pCall->address)->PsActiveProcessHead));
return ((PKDDEBUGGER_DATA64)pCall->address)->PsActiveProcessHead;
}
}
KdPrint(("擷取KdDebuggerDataBlock位址失敗\n"));
return 0;
}
方法二:PsActiveProcessHead是活動程序連結清單頭,理論上是第二個程序的EPROCESS結構成員ActiveProcessLinks的Blink,最後一個程序的EPROCESS結構成員ActiveProcessLinks的Flink。第二個程序即System程序,程序ID等于4。
NTSTATUS FindPsActiveProcessHead(ULONG *pPsActiveProcessHead)
{
PEPROCESS process;
PLIST_ENTRY pList=NULL;
NTSTATUS status=PsLookupProcessByProcessId((HANDLE)4,&process);
if (!NT_SUCCESS(status))
{
KdPrint(("擷取process失敗\n"));
return status;
}
//xp _EPROCESS +0x088 ActiveProcessLinks : _LIST_ENTRY
pList=(PLIST_ENTRY)((PUCHAR)process+0x88);
KdPrint(("PsActiveProcessHead位址=%x\n",pList->Blink));
*pPsActiveProcessHead=(ULONG)pList->Blink;
ObDereferenceObject(process);
return status;
}
方法三:ntoskrnl.exe導出了一個類型為PEPROCESS結構的變量PsInitialSystemProcess,它指向system程序(PID=4)的EPROCESS。這個方法與上一個方法類似。使用PsInitialSystemProcess在WinDDK中編譯的話有連結ntoskrnl.lib。
ULONG FindPsActiveProcessHead3()
{
ULONG addr=*(PULONG)PsInitialSystemProcess;
//xp _EPROCESS +0x088 ActiveProcessLinks : _LIST_ENTRY
PLIST_ENTRY pList=(PLIST_ENTRY)(addr+0x88);
KdPrint(("PsActiveProcessHead位址=%x\n",pList->Blink));
return (ULONG)pList->Blink;
}
方法四:每個CPU都有個KPCR結構,第一個KPCR結構的位址是固定的0xffdff000。KPCR結構偏移0x034位置的結構成員KdVersionBlock是一個DBGKD_GET_VERSION64類型的指針。此結構同樣在WDBGEXTS.H中有定義。DBGKD_GET_VERSION64結構成員DebuggerDataList其實是KdpDebuggerDataListHead。而KdpDebuggerDataListHead.Flink==KdpDebuggerDataListHead.Blink=KdDebuggerDataBlock。
ULONG FindPsActiveProcessHead4()
{
PLIST_ENTRY pList;
PKDDEBUGGER_DATA64 pKdDebuggerData;
PDBGKD_GET_VERSION64 pKdVersionBlock=(PDBGKD_GET_VERSION64)(*(PULONG)(0xffdff000+0x34));
KdPrint(("擷取到DebuggerDataList位址=%x\n",pKdVersionBlock->DebuggerDataList));
pList=(PLIST_ENTRY)pKdVersionBlock->DebuggerDataList;
KdPrint(("pList->Flink=%x,pList->Blink位址=%x\n",pList->Flink,pList->Blink));
pKdDebuggerData=(PKDDEBUGGER_DATA64)pList->Flink;
KdPrint(("PsActiveProcessHead位址=%x\n",pKdDebuggerData->PsActiveProcessHead));
return pKdDebuggerData->PsActiveProcessHead;
}
方法五:調用SSDT表中的NtSystemDebugControl函數。
ULONG FindPsActiveProcessHead5()
{
PLIST_ENTRY pList;
DBGKD_GET_VERSION64 KdVersionBlock;
PKDDEBUGGER_DATA64 pKdDebuggerData;
ZwSystemDebugControl NtSystemDebugControl;
NtSystemDebugControl=(ZwSystemDebugControl)GetSSDTAddrFromIndex(255);
KdPrint(("NtSystemDebugControl函數位址=%x\n",NtSystemDebugControl));
NtSystemDebugControl(SysDbgSysGetVersion,NULL,0,&KdVersionBlock,sizeof(DBGKD_GET_VERSION64),NULL);
KdPrint(("DebuggerDataList=%x\n",KdVersionBlock.DebuggerDataList));
pList=(PLIST_ENTRY)KdVersionBlock.DebuggerDataList;
KdPrint(("擷取到KdDebuggerDataBlock位址=%x\n",pList->Flink));
pKdDebuggerData=(PKDDEBUGGER_DATA64)pList->Flink;
KdPrint(("PsActiveProcessHead位址=%x\n",pKdDebuggerData->PsActiveProcessHead));
return pKdDebuggerData->PsActiveProcessHead;
}