天天看點

驅動中擷取PsActiveProcessHead變量位址的五種方法

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函數。

驅動中擷取PsActiveProcessHead變量位址的五種方法
驅動中擷取PsActiveProcessHead變量位址的五種方法
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。

驅動中擷取PsActiveProcessHead變量位址的五種方法
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。

驅動中擷取PsActiveProcessHead變量位址的五種方法
驅動中擷取PsActiveProcessHead變量位址的五種方法
驅動中擷取PsActiveProcessHead變量位址的五種方法
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;
}      

繼續閱讀