HOOK SwapContext 枚舉隱藏進程(學習筆記4)

來源:互聯網
上載者:User
 作 者: bzhkl
時 間: 2008-12-11,12:01
鏈 接: http://bbs.pediy.com/showthread.php?t=78464

以前想檢測一個被隱藏的進程 後來用暴力枚舉的方法解決了 但是HOOK SwapContext沒有看到有完整的代碼 所以搜集了點網上有用的模組 自己整合實現了下 確定支援XP3, XP2沒測試 應該也能支援 
附完整工程代碼

痛點:是得到SwapContext地址 還有一些細節問題~
原理:KiSwapContext調用SwapContext時候 ESI存放的是要換進線程的上下文 EDI存放的是要換出線程的上下文 然後截獲ESI 即換進的ETHREAD 得到相應的EPROCESS 然後搜集
缺點:對系統效能影響非常大,因為系統線程調度很頻繁, wrk的KiSwapContext用彙編寫的就能體現出來對效率的要求高~.

另外有個有趣的問題 
KiSwapContext 是fastcall調用方式  就是通過ECX EDX傳 多出的按STDCALL傳
WRK 是這樣注釋的 
; BOOLEAN
; KiSwapContext (
;    IN PKTHREAD OldThread
;    IN PKTHREAD NewThread
;    )
但是看下 WRK中的代碼 
        mov     edi, ecx                ; set old thread address
        mov     esi, edx                ; set next thread address
        movzx   ecx, byte ptr [edi].ThWaitirql ; set APC interrupt bypass disable
        call    SwapContext             ; swap context
 發現的確是兩個參數

用WINDBG看 
80545975 8bf1            mov     esi,ecx
80545977 8bbb24010000    mov     edi,dword ptr [ebx+124h]
8054597d 89b324010000    mov     dword ptr [ebx+124h],esi
80545983 8a4f58          mov     cl,byte ptr [edi+58h]
80545986 e8f5000000      call    nt!SwapContext (80545a80)
發現KiSwapContext 是一個參數, esi是要換進的線程上下文 是通過ECX (第一個參數得到)  edi 則不是
所以結論 KiSwapContext的參數現在是一個了,也許我WRK沒更新 老版本。。

WRK KiSwapContext 代碼
cPublicFastCall KiSwapContext, 2
.fpo (0, 0, 0, 4, 1, 0)

;
; N.B. The following registers MUST be saved such that ebp is saved last.
;      This is done so the debugger can find the saved ebp for a thread
;      that is not currently in the running state.
;

        sub     esp, 4*4
        mov     [esp+12], ebx           ; save registers
        mov     [esp+8], esi            ;
        mov     [esp+4], edi            ;
        mov     [esp+0], ebp            ;
        mov     ebx, PCR[PcSelfPcr]     ; set address of PCR
        mov     edi, ecx                ; set old thread address
        mov     esi, edx                ; set next thread address
        movzx   ecx, byte ptr [edi].ThWaitirql ; set APC interrupt bypass disable

        call    SwapContext             ; swap context
        mov     ebp, [esp+0]            ; restore registers
        mov     edi, [esp+4]            ;
        mov     esi, [esp+8]            ;
        mov     ebx, [esp+12]           ;
        add     esp, 4*4                ;
        fstRET  KiSwapContext           ;

fstENDP KiSwapContext

windbg得到的 KiSwapContext 代碼
lkd> uf KiSwapContext
nt!KiSwapContext:
8054595c 83ec10          sub     esp,10h
8054595f 895c240c        mov     dword ptr [esp+0Ch],ebx
80545963 89742408        mov     dword ptr [esp+8],esi
80545967 897c2404        mov     dword ptr [esp+4],edi
8054596b 892c24          mov     dword ptr [esp],ebp
8054596e 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch]
80545975 8bf1            mov     esi,ecx
80545977 8bbb24010000    mov     edi,dword ptr [ebx+124h]
8054597d 89b324010000    mov     dword ptr [ebx+124h],esi
80545983 8a4f58          mov     cl,byte ptr [edi+58h]
80545986 e8f5000000      call    nt!SwapContext (80545a80)
8054598b 8b2c24          mov     ebp,dword ptr [esp]
8054598e 8b7c2404        mov     edi,dword ptr [esp+4]
80545992 8b742408        mov     esi,dword ptr [esp+8]
80545996 8b5c240c        mov     ebx,dword ptr [esp+0Ch]
8054599a 83c410          add     esp,10h
8054599d c3              ret

驅動運行後的效果是:   

搜集到的進程是
0x81FE7768   svchost.exe 
0x81EC6478   alg.exe 
0x81F5E990   svchost.exe 
0x81FE83E0   DrvLoader.exe 
0x81CA7020   taskmgr.exe 
0x81595D70   VMwareService.e 
0x815C6608   VMwareTray.exe 
0x815D9C08   svchost.exe 
0x8159C528   ctfmon.exe 
0x8158EB60   VisualTaskTips. 
0x815E5DA0   winlogon.exe 
0x81E96418   DrvLoader.exe 
0x815F8BD8   lsass.exe 
0x81FE5020   MSDEV.EXE 
0x81EC0B28   mdm.exe 
0x81EE0500   explorer.exe 
0x81F13020   MSDEV.EXE 
0x815523A8   DBGVIEW.EXE 
0x81F74020   csrss.exe 
0x821507C0   System 
0x82009830   VMwareUser.exe 
0x81F66DA0   services.exe 
0x81F07B88   svchost.exe 

搜集到的進程肯定是不全的 因為有的進程在休息 沒有線程調度發生 也就沒有搜集到= = 

下面是主要代碼

DWORD gThreadsProcessOffset =0x220;    // ETHREAD 在 EPROCESS位移
/*

+0x218 TopLevelIrp      : Uint4B
+0x21c DeviceToVerify   : Ptr32 _DEVICE_OBJECT
+0x220 ThreadsProcess   : Ptr32 _EPROCESS
*/

ULONG ProcessNameOffset = 0x174;      // 進程對應的檔案名稱 在 EPROCESS位移
/*
+0x170 Session          : Ptr32 Void
+0x174 ImageFileName    : [16] UChar
+0x184 JobLinks         : _LIST_ENTRY
*/

PProcessList wLastItem = NULL;        
int BeTerminate = 0;                  //1 表示線程必須要停止  3表示線程不是PENDING狀態  0表示線程可以正常運行

void _stdcall CollectProcess(PEPROCESS pEPROCESS)  // 搜集EPROCESS
{
  if (!IsAdded(wLastItem, pEPROCESS)) AddItem(&wLastItem, pEPROCESS);
  return;
}

void __stdcall ThreadCollect(PUCHAR pEthread)   //根據ETHREAD得到EPROCESS 並調用CollectProcess來搜集
{
  PEPROCESS pEprocess = *(PEPROCESS *)(pEthread + gThreadsProcessOffset);
  if (pEprocess) CollectProcess(pEprocess);
  return;
}

DWORD outPEthread = 0;
void __stdcall ProcessData(DWORD pInEthread, DWORD pOutEthread)
{
  DWORD pid, eprocess;
  char * pname;
  if (MmIsAddressValid(PVOID(pInEthread+0x220)) )    // 這裡以及下面要判斷是不是一個真正
的 Ethread 結構體 有時好像調用SwapContext傳進來的不是 Ethread 結構體 然後就藍屏 具體沒有深究 加個判斷就不藍了~
  {
    eprocess = *(DWORD*)(pInEthread+0x220);
    
    if (MmIsAddressValid(PVOID(eprocess) ) )
    {
      ThreadCollect((PUCHAR)pInEthread);
    }
    
  }
}

PBYTE GoBackAddr = NULL;
PBYTE ChangAddr = NULL;

DWORD CallContextOffset = 0;

__declspec(naked) VOID HookSwap()

  _asm 
  {
    pushad
      pushfd
      cli
  }

  _asm
  {
       // EDI 是換出的線程上下文
         push edi
      //ESI 是換入的線程上下文
      push esi
      call ProcessData   //搜集進程
  }
  
  _asm 
  {  
    sti
      popfd
      popad
  }
  _asm jmp DWORD PTR[GoBackAddr]
}

/*
得到SwapContext地址的原理是
用PsLookupThreadByThreadId得到Idle System的KTHREAD
res=(PCHAR)(Thread->Tcb.KernelStack);
SwapAddr=*(DWORD *)(res+0x08);
*/
PCHAR GetSwapAddr()
{
  PCHAR res = 0;
  NTSTATUS  Status;
  PETHREAD Thread;
  
  if (*NtBuildNumber <= 2195)
    Status = PsLookupThreadByThreadId((PVOID)4, &(PETHREAD)Thread);
  else
    Status = PsLookupThreadByThreadId((PVOID)8, &(PETHREAD)Thread);
  
  if (NT_SUCCESS(Status))
  {
    if (MmIsAddressValid(Thread))
    {
      res = (PCHAR)(Thread->Tcb.KernelStack);

    }
    if (MmIsAddressValid(res+8))
    {
      _asm
      {
        mov eax,res
          add eax,8
          mov eax,[eax]
          mov res,eax
      }
    }
    else
    {
      res = 0;
      return NULL;
    }
  }
  _asm
  {
    mov eax,res
      sub eax,5
      mov ChangAddr,eax
      mov edx,[eax+1]
      mov CallContextOffset,edx
      add eax,edx
      add eax,5
      mov GoBackAddr,eax
      mov res,eax
  }
  return res;
}

BOOL  HookSwapFunction(BOOL flag)
{  
  if (flag == TRUE)
  { 
    KIRQL OldIrql=0;
    DWORD NewOffset;//HookSwap-ChangAddr-5;
    _asm
    {
      mov eax,HookSwap
        mov edx,ChangAddr
        sub eax,edx
        sub eax,5
        mov NewOffset,eax
    }

    PAGED_CODE()
      ASSERT(KeGetCurrentIrql()<=DISPATCH_LEVEL);
    KeRaiseIrql(2,&OldIrql);//HIGH_LEVEL
    __asm
    {
      CLI
        MOV   EAX, CR0
        AND   EAX, NOT 10000H  //disable WP bit
        MOV   CR0, EAX
    }
    _asm
    {
      mov eax,ChangAddr
        push NewOffset
        pop dword ptr[eax+1]
        
    }
    
    __asm
    {
      MOV   EAX, CR0
        OR    EAX, 10000H  //enable WP bit
        MOV   CR0, EAX
        STI
    }
    
    
    KeLowerIrql(OldIrql);
    
  }
  //Bug Check 0xD1: DRIVER_IRQL_NOT_LESS_OR_EQUAL
  
  else
  { 
    KIRQL OldIrql=0;
    KeRaiseIrql(2,&OldIrql);///HIGH_LEVEL
    __asm
    {
      CLI
        MOV   EAX, CR0
        AND   EAX, NOT 10000H  //disable WP bit
        MOV   CR0, EAX
    }
    
    _asm
    {
      mov eax,ChangAddr
        push CallContextOffset
        pop dword ptr[eax+1]
    }
    
    
    __asm
    {
      MOV   EAX, CR0
        OR    EAX, 10000H  //enable WP bit
        MOV   CR0, EAX
        STI
    }
    KeLowerIrql(OldIrql);
    //    DbgPrint("HookSwapFunctionFALSE");//jution
  }
  
}

PEPROCESS processObject (PETHREAD ethread) {
  return  (PEPROCESS)(ethread->Tcb.ApcState.Process);
}

void  klisterUnload(IN PDRIVER_OBJECT pDriverObject)
{
  BeTerminate = 1;
  while(BeTerminate != 3)    // = 3時說明建立的線程不是pending狀態且馬上會結束 這時候可以UNLOAD   否則線程在PENDING狀態UNLOADE 會直接藍
  {
      
  }
  
  if (GoBackAddr)//PBYTE GoBackAddr = NULL;
    HookSwapFunction(FALSE);  
}

void showProcess()
{

  PProcessList temp;
  DWORD count = 0;
  PUCHAR pFileName;
   temp = wLastItem;

  while (temp)     //遍曆鏈表
  {  
      if (temp->pEPROCESS)
    {
        count++;
        pFileName = (PUCHAR)((unsigned int)(temp->pEPROCESS) + 0x174);
        DbgPrint("0x%08X   %s /n",(unsigned int)(temp->pEPROCESS), pFileName);
    }
    temp = PProcessList(temp->NextItem);
  }

  DbgPrint("共有%d個進程", count); 
}

void WorkThread(IN PVOID pContext)
{
  LARGE_INTEGER timeout;
  
  while(true)
  {
    if (MmIsAddressValid(&BeTerminate) )    // 因為BeTerminate是在UNLOAD中設定的 可能驅動卸載後 這個變數不能訪問 所以用MmIsAddressValid判斷下 
    {
      if(BeTerminate == 0)
      {
        
        //等待單位是 100ns         //-10作用是轉換成微秒  //2000000微秒=2秒
        timeout = RtlConvertLongToLargeInteger(-10              *    2000000);   
        
        KeDelayExecutionThread(KernelMode, FALSE, &timeout);
        DbgPrint("搜集到的進程是");        
        showProcess();
      }
      else
      {
          BeTerminate = 3;
        PsTerminateSystemThread(STATUS_SUCCESS);
        goto __end;
      }
    }
    else
    {
        BeTerminate = 3;
      PsTerminateSystemThread(STATUS_SUCCESS);
      goto __end;  
    }
  }
__end:;
}

// 驅動程式載入時調用DriverEntry常式
NTSTATUS DriverEntry(
           IN PDRIVER_OBJECT  pDriverObject,
           IN PUNICODE_STRING pRegistryPath
           )
{
  NTSTATUS dwStAtus; 
  HANDLE hThread; 
  
  pDriverObject->DriverUnload=klisterUnload;
  
  dwStAtus = PsCreateSystemThread(&hThread, 
    (ACCESS_MASK)0, 
    NULL, 
    (HANDLE)0, 
    NULL, 
    WorkThread, 
    NULL 
    ); 
    
    
      GetSwapAddr();
      if (GoBackAddr){
      HookSwapFunction(TRUE);
}  
  return STATUS_SUCCESS;
}

上傳的附件

HookSwapContext.rar (2008-12-11 12:01, 105.1 KB, 122 次

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.