一个程序被ring3调试器调试时,有很多的调试特征可以检测,本论坛也有专门的帖子详细论述,但有个非常根本的标志ring3也是可以检测的比较少人提及,那就是_EPROCESS.DebugPort。DebugPort对于ring3调试器来说非常重要,没有它正常的ring3调试是无法进行的。当然要检测这个标志的前提是程序能够读取ring0内存,在XP以上的系统有个非常简单的方法就是使用ZwSystemDebugControl的SysDbgReadVirtualMemory方法,我们也可以mapphysicalmemory来操作。检测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的另外一个地方,比如我使用+0x070CreateTime,它是纪录进程创建时间的,进程创建之后,在进程退出前系统不会对它进行任何修改,而且我们修改后对系统或进程没有任何影响。这样我们可以把上面的代码改成这样
        8b8970000000    mov     ecx,dword ptr [ecx+070h]//指向CreateTime,实际的DebugPort已经被移到这里
     只需要修改一个字节,非常简单。
    当然这种方法最麻烦的地方就是定位引用到DebugPort的函数(本人仅仅针对不同的XP系统制作特征码都累到吐血),这些函数都是不导出的,如果是特定系统,最简单的方法就是WinDbg->uf*** 直接找地址硬编码,只需要几分钟时间。
    
代码:

  1. BOOLEAN InitHackAddress() 
  2.   _SEH_TRY 
  3.   { 
  4.    g_KernelBase = GetKernelBaseAndSize( &g_KernelSize );       
  5.    g_HackPspCreateProcess = SearchHackPspCreateProcess(&g_NopPspCreateProcess.Address ); 
  6.     g_HackKiDispatchException =SearchKiDispatchException( g_KernelBase,g_KernelSize );   
  7.    g_HackDbgkpQueueMessage = SearchDbgkpQueueMessage( g_KernelBase,g_KernelSize); 
  8.     g_HackDbgkCreateThread = SearchDbgkCreateThread(g_KernelBase,g_KernelSize );     
  9.     SearchDbgkNotifyRoutine(g_KernelBase,g_KernelSize ); 
  10.     g_HackPspExitThread =SearchPspExitThread();   
  11.     g_HackMmCreatePeb = SearchMmCreatePeb(g_HackPspCreateProcess ); 
  12.     SearchDbgkpSetProcessDebugObject(g_KernelBase,g_KernelSize ); 
  13.     if( g_HackDbgkpSetProcessDebugObject[3]) 
  14.       g_HackDbgkpMarkProcessPeb = SearchDbgkpMarkProcessPeb(g_HackDbgkpSetProcessDebugObject[3] ) ; 
  15.      
  16.     if(g_NopPspCreateProcess.Address != 0 ){ 
  17.       RtlFillMemory(g_NopPspCreateProcess.NopCode,sizeof(g_NopPspCreateProcess.NopCode),0x90 ); 
  18.       g_NopPspCreateProcess.Size = 9; 
  19.       RtlCopyMemory(g_NopPspCreateProcess.OrigCode,(PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.Size); 
  20.     } 
  21.     if( g_NopDbgkForwardException.Address != 0 ){       
  22.      RtlFillMemory(g_NopDbgkForwardException.NopCode,sizeof(g_NopDbgkForwardException.NopCode),0x90); 
  23.       RtlCopyMemory(g_NopDbgkForwardException.OrigCode,(PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.Size); 
  24.     } 
  25.     if( g_NopDbgkExitThread.Address != 0 ){       
  26.       RtlFillMemory(g_NopDbgkExitThread.NopCode,sizeof(g_NopDbgkExitThread.NopCode),0x90 ); 
  27.      RtlCopyMemory(g_NopDbgkExitThread.OrigCode,(PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.Size); 
  28.     } 
  29.     if( g_NopDbgkExitProcess.Address != 0 ){ 
  30.       RtlFillMemory(g_NopDbgkExitProcess.NopCode,sizeof(g_NopDbgkExitProcess.NopCode),0x90); 
  31.       RtlCopyMemory(g_NopDbgkExitProcess.OrigCode,(PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.Size); 
  32.     } 
  33.     if( g_NopDbgkMapViewOfSection.Address != 0){ 
  34.       RtlFillMemory(g_NopDbgkMapViewOfSection.NopCode,sizeof(g_NopDbgkMapViewOfSection.NopCode),0x90); 
  35.       RtlCopyMemory(g_NopDbgkMapViewOfSection.OrigCode,(PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.Size); 
  36.     } 
  37.     if( g_NopDbgkUnMapViewOfSection.Address != 0 ){ 
  38.       RtlFillMemory(g_NopDbgkUnMapViewOfSection.NopCode,sizeof(g_NopDbgkUnMapViewOfSection.NopCode),0x90); 
  39.       RtlCopyMemory(g_NopDbgkUnMapViewOfSection.OrigCode,(PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.Size); 
  40.     }      
  41.      
  42.      
  43.   } 
  44.   _SEH_HANDLER 
  45.   {     
  46.    DbgPrint( "InitHackAddress Exception!\n" ); 
  47.   } 
  48.   return ( g_HackPspCreateProcess != 0 && 
  49.         g_HackKiDispatchException != 0 && 
  50.        g_HackDbgkForwardException!= 0 && 
  51.        g_HackDbgkpQueueMessage != 0 &&  
  52.       g_NopPspCreateProcess.Address != 0 && 
  53.       g_NopDbgkForwardException.Address != 0 && 
  54.       g_HackDbgkCreateThread != 0 && 
  55.        g_HackDbgkExitThread != 0&& 
  56.        g_NopDbgkExitThread.Address != 0 && 
  57.       g_HackDbgkExitProcess != 0 && 
  58.        g_NopDbgkExitProcess.Address !=0 && 
  59.        g_HackDbgkMapViewOfSection != 0 && 
  60.       g_NopDbgkMapViewOfSection.Address != 0 && 
  61.       g_HackDbgkUnMapViewOfSection != 0 && 
  62.       g_NopDbgkUnMapViewOfSection.Address != 0 && 
  63.       g_HackPspExitThread != 0 && 
  64.        g_HackMmCreatePeb != 0&& 
  65.        g_HackDbgkpSetProcessDebugObject[0] != 0&& 
  66.        g_HackDbgkpSetProcessDebugObject[1] != 0&& 
  67.        g_HackDbgkpSetProcessDebugObject[2] != 0&& 
  68.        g_HackDbgkpSetProcessDebugObject[3] != 0&& 
  69.        g_HackDbgkpMarkProcessPeb != 0); 

代码:

  1. //修改已经运行进程的DebugPort位置 
  2. BOOLEAN ChangeProcessDebugPort(BOOLEAN Hide ) 
  3.   ULONG eProcess = (ULONG)PsInitialSystemProcess; 
  4. PLIST_ENTRY pListHead,pListWalk; 
  5.   ULONG DebugObject; 
  6.   if( !g_bIsAddressStartup ){ 
  7.     return FALSE; 
  8.   } 
  9.   pListHead = (PLIST_ENTRY)( eProcess + ACTIVE_LINKS_OFFSET ); 
  10.   pListWalk= pListHead; 
  11.   _SEH_TRY 
  12.   {     
  13.     do
  14.       if( pListWalk == NULL || eProcess== 0 ) 
  15.         break
  16.       eProcess = ( (ULONG)pListWalk - ACTIVE_LINKS_OFFSET );     
  17.       if( Hide ){ 
  18.         DebugObject = *(ULONG*)( eProcess + DEBUG_PORT_OFFSET ); 
  19.        *(ULONG*)( eProcess + CREATE_TIME_OFFSET ) = DebugObject; 
  20.         *(ULONG*)(eProcess + DEBUG_PORT_OFFSET ) = 0; 
  21.       }else
  22.         DebugObject = *(ULONG*)( eProcess + CREATE_TIME_OFFSET ); 
  23.        *(ULONG*)( eProcess + DEBUG_PORT_OFFSET ) = DebugObject; 
  24.       } 
  25.       pListWalk = pListWalk->Flink; 
  26.     }while( pListWalk != pListHead ); 
  27.   } 
  28.   _SEH_HANDLER 
  29.   { 
  30.     DbgPrint( "ChangeProcessDebugPortexception!\n" ); 
  31.   } 
  32.    
  33.   return TRUE; 
  34. 代码: 
  35. BOOLEANModifyDebugFunction() 
  36.   if( !g_bIsAddressStartup ){ 
  37.     returnFALSE; 
  38.   } 
  39.   __asm{ 
  40.     cli 
  41.     mov  eax,cr0 
  42.     and  eax,not 10000h 
  43.    mov  cr0,eax 
  44.   } 
  45.   *(ULONG*)g_HackPspCreateProcess = CREATE_TIME_OFFSET; 
  46. *(ULONG*)g_HackKiDispatchException = CREATE_TIME_OFFSET; 
  47. *(ULONG*)g_HackDbgkForwardException = CREATE_TIME_OFFSET; 
  48. *(ULONG*)g_HackDbgkpQueueMessage = CREATE_TIME_OFFSET; 
  49. *(ULONG*)g_HackDbgkCreateThread = CREATE_TIME_OFFSET; 
  50. *(ULONG*)g_HackDbgkExitThread = CREATE_TIME_OFFSET; 
  51. *(ULONG*)g_HackDbgkExitProcess = CREATE_TIME_OFFSET; 
  52. *(ULONG*)g_HackDbgkMapViewOfSection = CREATE_TIME_OFFSET; 
  53. *(ULONG*)g_HackDbgkUnMapViewOfSection = CREATE_TIME_OFFSET; 
  54. *(ULONG*)g_HackPspExitThread = CREATE_TIME_OFFSET; 
  55. *(ULONG*)g_HackDbgkpMarkProcessPeb = CREATE_TIME_OFFSET; 
  56. *(ULONG*)g_HackMmCreatePeb = CREATE_TIME_OFFSET; 
  57. *(ULONG*)g_HackDbgkpSetProcessDebugObject[0] = CREATE_TIME_OFFSET; 
  58. *(ULONG*)g_HackDbgkpSetProcessDebugObject[1] = CREATE_TIME_OFFSET; 
  59. *(ULONG*)g_HackDbgkpSetProcessDebugObject[2] = CREATE_TIME_OFFSET; 
  60. *(ULONG*)g_HackDbgkpSetProcessDebugObject[3] = CREATE_TIME_OFFSET; 
  61.      
  62.   RtlCopyMemory((PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.NopCode,g_NopPspCreateProcess.Size); 
  63.   RtlCopyMemory((PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.NopCode,g_NopDbgkForwardException.Size); 
  64.   RtlCopyMemory((PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.NopCode,g_NopDbgkExitThread.Size); 
  65.   RtlCopyMemory((PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.NopCode,g_NopDbgkExitProcess.Size); 
  66.   RtlCopyMemory((PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.NopCode,g_NopDbgkMapViewOfSection.Size); 
  67.   RtlCopyMemory((PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.NopCode,g_NopDbgkUnMapViewOfSection.Size); 
  68.   __asm{ 
  69.     mov  eax,cr0 
  70.     or   eax,10000h 
  71.     mov cr0,eax 
  72.     sti 
  73.   } 
  74.   return TRUE; 
  75. BOOLEAN WriteBackDebugFunction() 
  76.   if( !g_bIsAddressStartup ){ 
  77.    return FALSE; 
  78.   } 
  79.   __asm{ 
  80.     cli 
  81.     mov  eax,cr0 
  82.     and  eax,not 10000h 
  83.    mov  cr0,eax 
  84.   } 
  85.   *(ULONG*)g_HackPspCreateProcess = DEBUG_PORT_OFFSET; 
  86. *(ULONG*)g_HackKiDispatchException = DEBUG_PORT_OFFSET; 
  87. *(ULONG*)g_HackDbgkForwardException = DEBUG_PORT_OFFSET; 
  88. *(ULONG*)g_HackDbgkpQueueMessage = DEBUG_PORT_OFFSET; 
  89. *(ULONG*)g_HackDbgkCreateThread = DEBUG_PORT_OFFSET; 
  90. *(ULONG*)g_HackDbgkExitThread = DEBUG_PORT_OFFSET; 
  91. *(ULONG*)g_HackDbgkExitProcess = DEBUG_PORT_OFFSET; 
  92. *(ULONG*)g_HackDbgkMapViewOfSection = DEBUG_PORT_OFFSET; 
  93. *(ULONG*)g_HackDbgkUnMapViewOfSection = DEBUG_PORT_OFFSET; 
  94. *(ULONG*)g_HackPspExitThread = DEBUG_PORT_OFFSET; 
  95. *(ULONG*)g_HackDbgkpMarkProcessPeb = DEBUG_PORT_OFFSET; 
  96. *(ULONG*)g_HackMmCreatePeb = DEBUG_PORT_OFFSET; 
  97. *(ULONG*)g_HackDbgkpSetProcessDebugObject[0] = DEBUG_PORT_OFFSET; 
  98. *(ULONG*)g_HackDbgkpSetProcessDebugObject[1] = DEBUG_PORT_OFFSET; 
  99. *(ULONG*)g_HackDbgkpSetProcessDebugObject[2] = DEBUG_PORT_OFFSET; 
  100. *(ULONG*)g_HackDbgkpSetProcessDebugObject[3] = DEBUG_PORT_OFFSET; 
  101.   RtlCopyMemory((PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.OrigCode,g_NopPspCreateProcess.Size); 
  102.   RtlCopyMemory((PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.OrigCode,g_NopDbgkForwardException.Size); 
  103.   RtlCopyMemory((PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.OrigCode,g_NopDbgkExitThread.Size); 
  104.   RtlCopyMemory((PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.OrigCode,g_NopDbgkExitProcess.Size); 
  105.   RtlCopyMemory((PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.OrigCode,g_NopDbgkMapViewOfSection.Size); 
  106.   RtlCopyMemory((PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.OrigCode,g_NopDbgkUnMapViewOfSection.Size); 
  107.   __asm{ 
  108.     mov  eax,cr0 
  109.     or   eax,10000h 
  110.     mov cr0,eax 
  111.     sti 
  112.   } 
  113.   return TRUE; 

    我想再嗦一下,上面代码大家看到很多函数有个NOPCode,这个实际上是对付线程PS_CROSS_THREAD_FLAGS_HIDEFROMDBG的,NOP掉相关地方后,就算线程被设置为ThreadHideFromDebugger也无法阻挡调试器接收调试信息。