Hide your DebugPort in ring0

標 題: 【原創】Hide your DebugPort in ring0
作 者: wowelf
時 間: 2009-01-26,11:00
鏈 接: http://bbs.pediy.com/showthread.php?t=80971

一個程序被ring3調試器調試時,有很多的調試特徵可以檢測,本論壇也有專門的帖子詳細論述,但有個非常根本的標誌ring3也是可以檢測的比較少人提及,那就是_EPROCESS.DebugPort。DebugPort對於ring3調試器來說非常重要,沒有它正常的ring3調試是無法進行的。當然要檢測這個標誌的前提是程序能夠讀取ring0內存,在XP以上的系統有個非常簡單的方法就是使用ZwSystemDebugControl的SysDbgReadVirtualMemory方法,我們也可以map physicalmemory來操作。檢測DebugPort之前首先要得到進程的eprocess地址,這可以通過ZwQuerySystemInformation的SystemHandleInformation方法得到,也可以直接搜索ring0內存的eprocess結構。

   對於ring3直接檢測DebugPort,我們可以通過禁止該進程訪問ring0內存來對付,但是目標一旦使用驅動來檢測,那麼就非常麻煩了。下面介紹一種隱藏_EPROCESS.DebugPort的方法,這種方法的基本思路是,將一個正常被調試進程的DebugPort置零後,修正所有受影響的函數,使我們的調試器能夠正常進行。這些函數如下:
    PspCreateProcess、MmCreatePeb 進程創建,設置DebugPort
    DbgkCreateThread 發送線程或者進程創建的調試信息
    KiDispatchException、DbgkForwardException和DbgkpQueueMessage 發送異常調試信息
    PspExitThread、DbgkExitThread和DbgkExitProcess 發送線程退出、進程退出的調試信息
    DbgkMapViewOfSection和DbgkUnMapViewOfSection 發送映像裝載卸載調試信息
    DbgkpSetProcessDebugObject和DbgkpMarkProcessPeb 當調試器附加進程時設置DebugPort   

     這類函數非常多的,如果都HOOK處理的話,那太恐怖了,這裏使用一個非常簡單的辦法:偷龍轉鳳。我們看系統訪問DebugPort的代碼都是這樣的(XP)
         8b89bc000000    mov     ecx,dword ptr [ecx+0BCh] //0BCh就是DebugPort的偏移

     我們可以把DebugPort轉移到_EPROCESS的另外一個地方,比如我使用+0x070 CreateTime,它是紀錄進程創建時間的,進程創建之後,在進程退出前系統不會對它進行任何修改,而且我們修改後對系統或進程沒有任何影響。這樣我們可以把上面的代碼改成這樣
         8b8970000000    mov     ecx,dword ptr [ecx+070h] //指向CreateTime,實際的DebugPort已經被移到這裏
     只需要修改一個字節,非常簡單。

     當然這種方法最麻煩的地方就是定位引用到DebugPort的函數(本人僅僅針對不同的XP系統製作特徵碼都累到吐血),這些函數都是不導出的,如果是特定系統,最簡單的方法就是WinDbg->uf *** 直接找地址硬編碼,只需要幾分鐘時間。

 

代碼:
BOOLEAN InitHackAddress()
{
  _SEH_TRY
  {
    g_KernelBase = GetKernelBaseAndSize( &g_KernelSize );      
    g_HackPspCreateProcess = SearchHackPspCreateProcess( &g_NopPspCreateProcess.Address );
    g_HackKiDispatchException = SearchKiDispatchException( g_KernelBase,g_KernelSize );  
    g_HackDbgkpQueueMessage = SearchDbgkpQueueMessage( g_KernelBase,g_KernelSize );
    g_HackDbgkCreateThread = SearchDbgkCreateThread( g_KernelBase,g_KernelSize );    
    SearchDbgkNotifyRoutine( g_KernelBase,g_KernelSize );
    g_HackPspExitThread = SearchPspExitThread();  
    g_HackMmCreatePeb = SearchMmCreatePeb( g_HackPspCreateProcess );
    SearchDbgkpSetProcessDebugObject( g_KernelBase,g_KernelSize );
    if( g_HackDbgkpSetProcessDebugObject[3] )
      g_HackDbgkpMarkProcessPeb = SearchDbgkpMarkProcessPeb( g_HackDbgkpSetProcessDebugObject[3] ) ;
    
    if( g_NopPspCreateProcess.Address != 0 ){
      RtlFillMemory( g_NopPspCreateProcess.NopCode,sizeof(g_NopPspCreateProcess.NopCode),0x90 ); 
      g_NopPspCreateProcess.Size = 9;
      RtlCopyMemory( g_NopPspCreateProcess.OrigCode,(PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.Size );
    }

    if( g_NopDbgkForwardException.Address != 0 ){      
      RtlFillMemory( g_NopDbgkForwardException.NopCode,sizeof(g_NopDbgkForwardException.NopCode),0x90 );
      RtlCopyMemory( g_NopDbgkForwardException.OrigCode,(PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.Size );
    }

    if( g_NopDbgkExitThread.Address != 0 ){      
      RtlFillMemory( g_NopDbgkExitThread.NopCode,sizeof(g_NopDbgkExitThread.NopCode),0x90 );
      RtlCopyMemory( g_NopDbgkExitThread.OrigCode,(PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.Size );
    }

    if( g_NopDbgkExitProcess.Address != 0 ){
      RtlFillMemory( g_NopDbgkExitProcess.NopCode,sizeof(g_NopDbgkExitProcess.NopCode),0x90 );
      RtlCopyMemory( g_NopDbgkExitProcess.OrigCode,(PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.Size );
    }

    if( g_NopDbgkMapViewOfSection.Address != 0){
      RtlFillMemory( g_NopDbgkMapViewOfSection.NopCode,sizeof(g_NopDbgkMapViewOfSection.NopCode),0x90 );
      RtlCopyMemory( g_NopDbgkMapViewOfSection.OrigCode,(PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.Size );
    }

    if( g_NopDbgkUnMapViewOfSection.Address != 0 ){
      RtlFillMemory( g_NopDbgkUnMapViewOfSection.NopCode,sizeof(g_NopDbgkUnMapViewOfSection.NopCode),0x90 );
      RtlCopyMemory( g_NopDbgkUnMapViewOfSection.OrigCode,(PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.Size );
    }     
    
    
  }
  _SEH_HANDLER
  {    
    DbgPrint( "InitHackAddress Exception!/n" );
  }

  return ( g_HackPspCreateProcess != 0 &&
         g_HackKiDispatchException != 0 &&
       g_HackDbgkForwardException != 0 &&
       g_HackDbgkpQueueMessage != 0 && 
       g_NopPspCreateProcess.Address != 0 &&
       g_NopDbgkForwardException.Address != 0 &&
       g_HackDbgkCreateThread != 0 &&
       g_HackDbgkExitThread != 0 &&
       g_NopDbgkExitThread.Address != 0 &&
       g_HackDbgkExitProcess != 0 &&
       g_NopDbgkExitProcess.Address != 0 &&
       g_HackDbgkMapViewOfSection != 0 &&
       g_NopDbgkMapViewOfSection.Address != 0 &&
       g_HackDbgkUnMapViewOfSection != 0 &&
       g_NopDbgkUnMapViewOfSection.Address != 0 &&
       g_HackPspExitThread != 0 &&
       g_HackMmCreatePeb != 0 &&
       g_HackDbgkpSetProcessDebugObject[0] != 0 &&
       g_HackDbgkpSetProcessDebugObject[1] != 0 &&
       g_HackDbgkpSetProcessDebugObject[2] != 0 &&
       g_HackDbgkpSetProcessDebugObject[3] != 0 &&
       g_HackDbgkpMarkProcessPeb != 0 );
}
代碼:
//修改已經運行進程的DebugPort位置
BOOLEAN ChangeProcessDebugPort( BOOLEAN Hide )
{
  ULONG eProcess = (ULONG)PsInitialSystemProcess;
  PLIST_ENTRY pListHead,pListWalk;
  ULONG DebugObject;

  if( !g_bIsAddressStartup ){
    return FALSE;
  }

  pListHead = (PLIST_ENTRY)( eProcess + ACTIVE_LINKS_OFFSET );
  pListWalk = pListHead;

  _SEH_TRY
  {    
    do{
      if( pListWalk == NULL || eProcess == 0 )
        break;

      eProcess = ( (ULONG)pListWalk - ACTIVE_LINKS_OFFSET );    

      if( Hide ){

        DebugObject = *(ULONG*)( eProcess + DEBUG_PORT_OFFSET );
        *(ULONG*)( eProcess + CREATE_TIME_OFFSET ) = DebugObject;
        *(ULONG*)( eProcess + DEBUG_PORT_OFFSET ) = 0;

      }else{

        DebugObject = *(ULONG*)( eProcess + CREATE_TIME_OFFSET );
        *(ULONG*)( eProcess + DEBUG_PORT_OFFSET ) = DebugObject;
      }

      pListWalk = pListWalk->Flink;

    }while( pListWalk != pListHead );

  }
  _SEH_HANDLER
  {
    DbgPrint( "ChangeProcessDebugPort exception!/n" );
  }
  
  return TRUE;
}
代碼:
BOOLEAN ModifyDebugFunction()
{
  if( !g_bIsAddressStartup ){
    return FALSE;
  }

  __asm{
    cli
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }

  *(ULONG*)g_HackPspCreateProcess = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackKiDispatchException = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkForwardException = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkpQueueMessage = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkCreateThread = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkExitThread = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkExitProcess = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkMapViewOfSection = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkUnMapViewOfSection = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackPspExitThread = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkpMarkProcessPeb = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackMmCreatePeb = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkpSetProcessDebugObject[0] = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkpSetProcessDebugObject[1] = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkpSetProcessDebugObject[2] = CREATE_TIME_OFFSET;
  *(ULONG*)g_HackDbgkpSetProcessDebugObject[3] = CREATE_TIME_OFFSET;
    

  RtlCopyMemory( (PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.NopCode,g_NopPspCreateProcess.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.NopCode,g_NopDbgkForwardException.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.NopCode,g_NopDbgkExitThread.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.NopCode,g_NopDbgkExitProcess.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.NopCode,g_NopDbgkMapViewOfSection.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.NopCode,g_NopDbgkUnMapViewOfSection.Size );

  __asm{
    mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }

  return TRUE;

}

BOOLEAN WriteBackDebugFunction()
{
  if( !g_bIsAddressStartup ){
    return FALSE;
  }

  __asm{
    cli
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }

  *(ULONG*)g_HackPspCreateProcess = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackKiDispatchException = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkForwardException = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkpQueueMessage = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkCreateThread = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkExitThread = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkExitProcess = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkMapViewOfSection = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkUnMapViewOfSection = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackPspExitThread = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkpMarkProcessPeb = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackMmCreatePeb = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkpSetProcessDebugObject[0] = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkpSetProcessDebugObject[1] = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkpSetProcessDebugObject[2] = DEBUG_PORT_OFFSET;
  *(ULONG*)g_HackDbgkpSetProcessDebugObject[3] = DEBUG_PORT_OFFSET;

  RtlCopyMemory( (PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.OrigCode,g_NopPspCreateProcess.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.OrigCode,g_NopDbgkForwardException.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.OrigCode,g_NopDbgkExitThread.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.OrigCode,g_NopDbgkExitProcess.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.OrigCode,g_NopDbgkMapViewOfSection.Size );
  RtlCopyMemory( (PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.OrigCode,g_NopDbgkUnMapViewOfSection.Size );

  __asm{
    mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }

  return TRUE;
}

     我想再囉嗦一下,上面代碼大家看到很多函數有個NOPCode,這個實際上是對付線程PS_CROSS_THREAD_FLAGS_HIDEFROMDBG的,NOP掉相關地方後,就算線程被設置爲ThreadHideFromDebugger也無法阻擋調試器接收調試信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章