__out PVOID ProcessInformation, __in ULONG ProcessInformationLength, __out_opt PULONG ReturnLength ); 第三个参数PROCESS_BASIC_INFORMATION结构定义 如下: typedef struct _PROCESS_BASIC_INFORMATION { PVOID Reserved1; PPEB PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; } PROCESS_BASIC_INFORMATION; 第二个参数PebBaseAddress指向一个PEB结构。 除了通过系统API的方式来获得PEB的信息之外,还可以 通过系统寄存器中线程的结构来获得进程信息。PEB存储在另 一个名为线程环境块(Thread Environment Block)TEB的结构之 中,位于TEB结构的偏移0x30h处。TEB中保存着线程相关的 数据,一个进程所有的线程都以堆栈的方式存放,每4KB为一 个完整的TEB。在Windows XP sp2以前的系统版本中,TEB存 储在0x7FFDE000开始的内存中,以后的版本中,这个地址采取 了随机化处理的方法。寄存器FS:0指向当前线程的TEB结构, TEB结构的偏移18h处是一个反身指针,因此用FS: [18h]来找 TEB更加准确。在TEB偏移30h处,指向了线程所在进程的结 构PEB,因此通过下面的代码也可以找到PEB: mov eax, fs:[18h] mov eax, [eax+30h] 深入了解TEB和PEB结构,我们可以利用这些结构里面 的信息来检查当前进程是否被调试器所调试。 第一个检测标志是BeingDebugged。在PEB结构中,偏 移2h处的BeingDebugged变量可以说明当前进程是否处于调 试器之下工作。如果BeingDebugged标志被设置了,则表明当前进程处于调试中。 使用下面的内联汇编代码来找到BeingDebugged: BOOL MyIsDebuggerPresent(VOID) { __asm{ Mov eax, fs:[0x30] //在位于TEB偏移30h处获得PEB地址 Movzx eax, byte ptr [eax+2] //获得PEB偏移2h处BeingDebugged值 } } 第二个检测标志是NtGlobleFlag。PEB结构的68h偏移处 是NtGlobleFlag,当前程序被调试时,NtGlobleFlag=70h,其 他情况下不是,因此可以利用这个标志来判断当前进程是否处 于调试下,相关测试函数如下: BOOL MyIsDebuggerPresentEx(VIOD) { __asm{ Move ax, fs:[0x30] Mov eax, [eax+0x68] And eax, 0x70 } } 第三个检测标志是Heap中的Flags和ForceFlags。PEB 结构的偏移18h处指向Heap结构。HEAP结构定义如下: typedef struct _HEAP { HEAP_ENTRY Entry; ULONG SegmentSignature; ULONG SegmentFlags; LIST_ENTRY SegmentListEntry; PHEAP Heap; PVOID BaseAddress; ULONG NumberOfPages; …… } HEAP, *PHEAP; 正常情况下,系统为进程创建第一个堆时,会将它 的Flags(偏移0x0C)和ForceFlags(偏移0x10h)分别设 为2(HEAP_GROWABLE)和0,在调试状态下,这两个标 志通常被设置成为50000062h(取决于NtGlobalFlag)和 40000060h。因此可以利用这两个标志来进行检测(位于PEB 结构的18h处): BOOL CheckHeapFlags(VOID) { __asm { mov eax, fs:[0x30] mov eax, [eax+0x18] cmp dword ptr [eax+0x0C], 2 jne __debugger_detected cmp dword ptr [eax+0x10], 0 jne __debugger_detected xor eax, eax __debugger_detected: } } 另外,还可以通过DebugObject是否存在来检测调试器。 调试器与被调试程序建立关系有两种途径,在创建进程时设 置DEBUG_PROCESS,或者调用DebugActiveProcess附加到 某个已运行的进程上。 调试器创建一个DebugObject,并且存储在 NtCurrentTeb()->DbgSs Reserved[1] , 保存了DebugObject的句柄。 若一个进程的DbgSs Reserved[1] 不为NULL,则该进程为一个 用户态的调试器的进程。 得到DbgSs Reserved[1] 的方法: mov eax, dword ptr fs:[18] ;DbgUiGetThreadDebugObject mov eax, dword ptr [eax+F24] ;Get F24 使用函数ZwQueryObject查询所有对象的类型,若发现名 |