DebugPort: CheckRemoteDebuggerPresent()/NtQueryInformationProcess()
Kernel32!CheckRemoteDebuggerPresent()是另一个可以用于确定是否有调试器被附加到进程的API。这个API内部调用了ntdll!NtQueryInformationProcess(),调用时ProcessInformationclass参数为ProcessDebugPort(7)。而NtQueryInformationProcess()检索内核结构EPROCESS5的DebugPort成员。非0的DebugPort成员意味着进程正在被用户模式的调试器调试。如果是这样的话,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:
}
}