NtGlobalFlag 字段

一、通过检测 NtGlobalFlag 字段

我们在进行调试的过程中,可以通过两种方法来调试目标程序。第一种方法就是直接附加到一个已经运行的进程,第二种方法就是通过打开一个新的进程来进行调试。

在进程的 PEB 结构中有一个 NtGlobalFlag 字段,该字段是一个 Uint4B 类型的值,包含一系列的标志位,默认值为 0.

在 32 位系统上,NtGlobalFlag 字段位于 PEB 偏移 0x68 处,而在 64 位系统上则在偏移 0xbc 的位置。当我们通过打开一个新的进程来进行调试的时候,由调试器创建的进程会设置以下三个标志位:

FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
FLG_HEAP_ENABLE_FREE_CHECK (0x20)
FLG_HEAP_VALIDATE_PARAMETERS (0x40)

剔除掉 NtGlobalFlag 字段的其他标志位后,其值为 0x70,因此我们可以通过检测该标志位来判断是否目标进程由调试器创建并处于调试状态。

注:这三个标志位被设置只是大概率处于被调试状态,并不包含所有情况,但这个字段常常因为这个目的而被使用。

1 通过汇编程序来检测 NtGlobalFlag 字段

因为 Windows 并没有直接提供检测该字段的函数,因此我们只能通过自己编写汇编代码来对该字段进行检测。

针对 32 位程序的汇编代码

.386
.model flat, c

.code 
Asm_IsDebugged proc
	push ebp    ; 保存 x86 的非易失性寄存器(ebp, ebx, esi, edi)
	mov ebp, esp    ; 在开辟临时栈空间之前需要保存栈顶指针(没有开辟可省略)
	sub esp, 100h    ; 开辟临时栈空间(没有开辟可省略)
	push ebx
	push esi
	push edi

	assume fs:nothing    ; 使用 fs 寄存器
	mov eax, dword ptr fs:[30h]    ; 取得 PEB
	mov eax, dword ptr [eax+68h]    ; 得到 NtGlobalFlag 字段(Uint4B)
	and eax, 70h    ; 掩盖其他位
	cmp eax, 70h    ; 检查 NtGlobalFlag 字段的三个位是否被设置
	setz al    ; 取 ZF 标志位的值给 al
	movzx eax, al    ; 返回值

	pop edi    ; 恢复 x86 的非易失性寄存器(ebp, ebx, esi, edi)
	pop esi
	pop ebx
	add esp, 100h    ; 释放临时栈空间
	mov esp, ebp    ; 恢复栈顶指针
	pop ebp
	ret
Asm_IsDebugged endp
end

针对 64 位程序的汇编代码

.code
Asm_IsDebugged proc
	push rbp    ; 保存 x64 的非易失性寄存器
	push rbx
	push rsi
	push rdi
	push r12
	push r13
	push r14
	push r15
	sub rsp, 100h    ; 开辟临时栈空间(没有开辟可省略)

	mov rax, qword ptr gs:[60h]    ; 取得 PEB
	mov eax, dword ptr [rax+0bch]    ; 得到 NtGlobalFlag 字段(Uint4B)
	and eax, 70h    ; 掩盖其他位
	cmp eax, 70h    ; 检查 NtGlobalFlag 字段的三个位是否被设置
	setz al    ; 取 ZF 标志位的值给 al
	movzx rax, al    ; 返回值

	add rsp, 100h
	pop r15    ; 恢复 x64 的非易失性寄存器
	pop r14
	pop r13
	pop r12
	pop rdi
	pop rsi
	pop rbx
	pop rbp
	ret
Asm_IsDebugged endp
end

上面的汇编代码中定义了一个函数,用于检测该字段的三个标志位是否被设置,接下来我们只需要在主程序中声明并调用即可:

#include <stdio.h>
#include <Windows.h>

extern "C" bool Asm_IsDebugged();

int main()
{
	if (Asm_IsDebugged())
	{
		printf("可能被调试\r\n");
	}
	else
	{
		printf("没有被调试\r\n");
	}

	system("pause");
}

通过调试器打开程序,结果如下:

posted @ 2025-02-12 18:23  lostin9772  阅读(7)  评论(0)    收藏  举报