8.3 NtGlobalFlag

发布时间 2023-09-26 12:26:13作者: lyshark

NtGlobalFlag 是一个Windows内核全局标记,在Windows调试方案中经常用到。这个标记定义了一组系统的调试参数,包括启用或禁用调试技术的开关、造成崩溃的错误代码和处理方式等等。通过改变这个标记,可以在运行时设置和禁用不同的调试技术和错误处理方式,比如调试器只能访问当前进程、只允许用户模式调试、启用特定的错误处理方式等等。但由于NtGlobalFlag标记是内核全局标记,其改变会影响整个系统的行为,需要谨慎处理。

利用该标记反调试,首先定位dt -rv ntdll!_TEB找到TEB结构并通过TEB找到PEB结构,然后找到+0x068 NtGlobalFlag,这个位置的NtGlobalFlag类似于BeingDebugged,如果是调试状态NtGlobalFlag的值会是0x70,所以可以判断这个标志是否为0x70来判断程序是否被调试了,首先我们来使用汇编代码解决。

#include <stdio.h>
#include <windows.h>

// 返回调试状态
BOOL IsDebug()
{
    DWORD Debug = 0;
    __asm
    {
        mov eax, fs:[0x18]       // TEB基地址
        mov eax, [eax + 0x30]    // 找到PEB
        mov eax, [eax + 0x68]    // 找打 NtGlobalFlag
        mov Debug, eax           // 取出值
    }

    if (Debug == 112)
    {
        return TRUE;
    }

    return FALSE;
}

int main(int argc, char * argv[])
{

    if (IsDebug)
    {
        printf("[-] 程序正在被调试 \n");
    }
    else
    {
        printf("[*] 程序正常 \n");
    }

    system("pause");
    return 0;
}

当然除了使用纯汇编实现反调试外,我们也可以使用NativeAPI中的ZwQueryInformationProcess()这个函数来读取到程序中的PET数据,然后判断PebBase+0x68是否等于70,由于这个函数并没有公开,所以在使用时应该自行声明一下结构类型。

#include <stdio.h>
#include <windows.h>
#include <winternl.h>

// 声明该函数
typedef NTSTATUS(NTAPI *typedef_ZwQueryInformationProcess)(
    IN HANDLE ProcessHandle,
    IN PROCESSINFOCLASS ProcessInformationClass,
    OUT PVOID ProcessInformation,
    IN ULONG ProcessInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    );

// 调试状态检测
BOOL IsDebug()
{
    HANDLE hProcess = NULL;
    DWORD ProcessId = 0;
    PROCESS_BASIC_INFORMATION Pbi;
    typedef_ZwQueryInformationProcess pZwQueryInformationProcess = NULL;
    ProcessId = GetCurrentProcessId();
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);

    if (hProcess != NULL)
    {
        HMODULE hModule = LoadLibrary("ntdll.dll");
        pZwQueryInformationProcess = (typedef_ZwQueryInformationProcess)GetProcAddress(hModule, "ZwQueryInformationProcess");

        NTSTATUS Status = pZwQueryInformationProcess(hProcess, ProcessBasicInformation, &Pbi,sizeof(PROCESS_BASIC_INFORMATION), NULL);
        if (NT_SUCCESS(Status))
        {
            DWORD ByteRead = 0;
            WORD NtGlobalFlag = 0;
            ULONG PebBase = (ULONG)Pbi.PebBaseAddress;

            // 读取调试标志并判断
            if (ReadProcessMemory(hProcess, (LPCVOID)(PebBase + 0x68), &NtGlobalFlag, 2, &ByteRead) && ByteRead == 2)
            {
                if (NtGlobalFlag == 0x70)
                {
                    return TRUE;
                }
            }
        }
        CloseHandle(hProcess);
    }

    return FALSE;
}

int main(int argc, char * argv[])
{
    if (IsDebug() == TRUE)
    {
        printf("[-] 进程正在被调试 \n");
    }
    else
    {
        printf("[*] 程序正常 \n");
    }

    system("pause");
    return 0;
}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/e45d84be.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!