DebugPort: CheckRemoteDebuggerPresent()/NtQueryInformationProcess()

DebugPort: CheckRemoteDebuggerPresent()/NtQueryInformationProcess()

        Kernel32!CheckRemoteDebuggerPresent()是另一个可以用于确定是否有调试器被附加到进程的API。这个API内部调用了ntdll!NtQueryInformationProcess(),调用时ProcessInformationclass参数为ProcessDebugPort(7)。而NtQueryInformationProcess()检索内核结构EPROCESS5DebugPort成员。非0DebugPort成员意味着进程正在被用户模式的调试器调试。如果是这样的话,ProcessInformation将被置为0xFFFFFFFF,否则ProcessInformation将被置为0

Kernel32!CheckRemoteDebuggerPresent()接受2个参数,第1个参数是进程句柄,第2个参数是一个指向boolean变量的指针,如果进程被调试,该变量将包含TRUE返回值。

BOOL CheckRemoteDebuggerPresent(

HANDLE      hProcess,

PBOOL      pbDebuggerPresent

)

ntdll!NtQueryInformationProcess()5个参数。为了检测调试器的存在,需要将ProcessInformationclass参数设为ProcessDebugPort(7)

NTSTATUS   NTAPI             NtQueryInformationProcess(

HANDLE                           ProcessHandle,

PROCESSINFOCLASS            ProcessInformationClass,

PVOID                             ProcessInformation,

ULONG                             ProcessInformationLength,

PULONG                     ReturnLength

)

示例

下面的例子显示了如何调用CheckRemoteDebuggerPresent()NtQueryInformationProcess()来检测当前进程是否被调试:

; using Kernel32!CheckRemoteDebuggerPresent()

lea            eax,[.bDebuggerPresent]

push              eax                          ;pbDebuggerPresent

push       0xffffffff                                ;hProcess

call               [CheckRemoteDebuggerPresent]

cmp            dword [.bDebuggerPresent],0

jne            .debugger_found

 

; using ntdll!NtQueryInformationProcess(ProcessDebugPort)

lea            eax,[.dwReturnLen]

push              eax                          ;ReturnLength

push              4                              ;ProcessInformationLength

lea            eax,[.dwDebugPort]

push              eax                          ;ProcessInformation

push             ProcessDebugPort          ;ProcessInformationClass(7)

push            0xffffffff                   ;ProcessHandle

call               [NtQueryInformationProcess]

cmp            dword [.dwDebugPort],0

jne               .debugger_found

对策

一种方法是在NtQueryInformationProcess()返回的地方设置断点,当这个断点被断下来后,将ProcessInformation补丁为0下面是自动执行这个方法的ollyscript示例:

var                bp_NtQueryInformationProcess

 

// set a breakpoint handler

eob             bp_handler_NtQueryInformationProcess

 

// set a breakpoint where NtQueryInformationProcess returns

gpa             "NtQueryInformationProcess","ntdll.dll"

find       $RESULT,#C21400#//retn 14

mov       bp_NtQueryInformationProcess,$RESULT

bphws             bp_NtQueryInformationProcess,"X"

run

 

bp_handler_NtQueryInformationProcess:

 

//ProcessInformationClass == ProcessDebugPort?

cmp              [esp+8],7

jne               bp_handler_NtQueryInformationProcess_continue

 

//patch ProcessInformation to 0

mov       patch_addr,[esp+c]

mov       [patch_addr],0

 

// clear breakpoint

bphwc             bp_NtQueryInformationProcess

 

bp_handler_NtQueryInformationProcess_continue:

run

Olly Advanced插件有一个patch NtQueryInformationProcess()的选项,这个补丁涉及注入一段代码来操纵NtQueryInformationProcess()的返回值。

-------------------------------------------------------------------------
以下由Coderui修改整理,在VC 6.0下调试通过(部分关键代码)。
编写日期:2008年05月31日
联系邮箱:coderui@163.com
作者博客:http://hi.baidu.com/coderui

void DebugPort()
{
 DWORD bDebuggerPresent;
 FARPROC MyCheckRemoteDebuggerPresent;
 
 MyCheckRemoteDebuggerPresent = (FARPROC)GetProcAddress(GetModuleHandle("Kernel32"), "CheckRemoteDebuggerPresent");
 
 __asm
 {
    lea   eax,dword ptr [bDebuggerPresent];
    push eax;pbDebuggerPresent;
    push 0xffffffff;hProcess;
    call ds:[MyCheckRemoteDebuggerPresent];
    cmp   dword ptr [bDebuggerPresent],0;
    jz   Coderui;
    push 0;
    call [exit];
 
 Coderui:
 }
 
 DWORD dwReturnLen;
 DWORD dwDebugPort;
 DWORD ProcessDebugPort = 7;
 
 FARPROC MyNtQueryInformationProcess;
 
 MyNtQueryInformationProcess = (FARPROC)GetProcAddress(GetModuleHandle("ntdll"), "NtQueryInformationProcess");
 
 __asm
 {
    ; using ntdll!NtQueryInformationProcess(ProcessDebugPort)
    lea   eax,dword ptr [dwReturnLen];
    push eax;     //ReturnLength
    push 4;      //ProcessInformationLength
    lea   eax,dword ptr [dwDebugPort];
    push eax;     //ProcessInformation
    push ProcessDebugPort; //ProcessInformationClass(7)
    push 0xffffffff;    //ProcessHandle
    call [MyNtQueryInformationProcess];
    cmp   dword ptr [dwDebugPort],0;
    jz   Coderuirui;
    push 0;
    call [exit];
 
 Coderuirui:
 }
}