设为首页收藏本站
查看: 8324|回复: 1

[原创] [翻译]反调试:调试标志寄存器

[复制链接]
  • TA的每日心情
    开心
    2022-1-9 18:41
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2021-9-12 15:26:44 | 显示全部楼层 |阅读模式
    备注
    原文地址:https://anti-debug.checkpoint.com/techniques/debug-flags.html
    原文标题:Anti-Debug: Debug Flags
    更新日期:2021年9月12日
    此文后期:根据自身所学进行内容扩充
    因自身技术有限,只能尽自身所能翻译国外技术文章,供大家学习,若有不当或可完善的地方,希望可以指出,用于共同完善这篇文章。

    目录
    • 调试标志寄存器
    • 1. 使用Win32 API
    • 1.1. IsDebuggerPresent()
    • 1.2. CheckRemoteDebuggerPresent()
    • 1.3. NtQueryInformationProcess()
    • 1.3.1. ProcessDebugPort进程调试端口
    • 1.3.2. ProcessDebugFlags进程调试标志寄存器
    • 1.3.3. ProcessDebugObjectHandle进程调试对象句柄
    • 1.4. RtlQueryProcessHeapInformation()
    • 1.5. RtlQueryProcessDebugInformation()
    • 1.6. NtQuerySystemInformation()
    • 反制措施
    • 2. 手工检查
    • 2.1. PEB!BeingDebugged标志寄存器
    • 2.2. NtGlobalFlag
    • 2.3. 堆标志寄存器
    • 2.4. 堆保护
    • 反制措施



    调试标志寄存器
    系统表中的特殊标志寄存器,即停留在进程内存中的、由操作系统设置的标志寄存器,可以用来指示进程正在被调试。这些标志寄存器的状态可以通过使用特定的API函数或检查内存中的系统表来验证。
    这些技术是恶意软件最常使用的。
    1. 使用Win32 API
    以下技术使用现有的API函数(WinAPI或NativeAPI),这些函数检查进程内存中的系统结构,以寻找表明进程现在正在被调试的特定标志寄存器。

    1.1. IsDebuggerPresent()
    函数kernel32!IsDebuggerPresent()确定当前进程是否被用户模式的调试器如OllyDbg或x64dbg调试。一般来说,该函数只检查进程环境块(PEB)的 BeingDebugged 标志寄存器。
    如果正在调试进程,可以使用以下代码终止进程:
    汇编代码:
    1.     call IsDebuggerPresent   
    2.     test al, al
    3.     jne  being_debugged
    4.     ...
    5. being_debugged:
    6.     push 1
    7.     call ExitProcess
    复制代码

    C/C++ 代码:
    1. if (IsDebuggerPresent())
    2.     ExitProcess(-1);
    复制代码


    1.2. CheckRemoteDebuggerPresent()
    函数kernel32!CheckRemoteDebuggerPresent()检查一个调试器(在同一台机器的不同进程中)是否连接到当前进程。
    C/C++ 代码:
    1. BOOL bDebuggerPresent;
    2. if (TRUE == CheckRemoteDebuggerPresent(GetCurrentProcess(), &bDebuggerPresent) &&
    3.     TRUE == bDebuggerPresent)
    4.     ExitProcess(-1);
    复制代码

    x86 汇编:
    1.     lea eax, bDebuggerPresent]
    2.     push eax
    3.     push -1  ; GetCurrentProcess()
    4.     call CheckRemoteDebuggerPresent
    5.     cmp [bDebuggerPresent], 1
    6.     jz being_debugged
    7.     ...
    8. being_debugged:
    9.     push -1
    10.     call ExitProcess
    复制代码

    x86-64 汇编:
    1.     lea rdx, [bDebuggerPresent]
    2.     mov rcx, -1 ; GetCurrentProcess()
    3.     call CheckRemoteDebuggerPresent
    4.     cmp [bDebuggerPresent], 1
    5.     jz being_debugged
    6.     ...
    7. being_debugged:
    8.     mov ecx, -1
    9.     call ExitProcess
    复制代码


    1.3. NtQueryInformationProcess()
    函数ntdll!NtQueryInformationProcess()可以从一个进程中检索不同种类的信息。它接受一个ProcessInformationClass参数,该参数指定了你想得到的信息,并定义了ProcessInformation参数的输出类型。

    1.3.1. ProcessDebugPort进程调试端口
    可以使用ntdll!NtQueryInformationProcess()来检索进程的调试器端口号。有一个记录在案的类ProcessDebugPort,如果进程正在被调试,它会检索到一个等于0xFFFFFFFF(十进制-1)的DWORD值。
    C/C++ 代码:
    1. typedef NTSTATUS (NTAPI *TNtQueryInformationProcess)(
    2.     IN HANDLE           ProcessHandle,
    3.     IN PROCESSINFOCLASS ProcessInformationClass,
    4.     OUT PVOID           ProcessInformation,
    5.     IN ULONG            ProcessInformationLength,
    6.     OUT PULONG          ReturnLength
    7.     );

    8. HMODULE hNtdll = LoadLibraryA("ntdll.dll");
    9. if (hNtdll)
    10. {
    11.     auto pfnNtQueryInformationProcess = (TNtQueryInformationProcess)GetProcAddress(
    12.         hNtdll, "NtQueryInformationProcess");
    13.    
    14.     if (pfnNtQueryInformationProcess)
    15.     {
    16.         DWORD dwProcessDebugPort, dwReturned;
    17.         NTSTATUS status = pfnNtQueryInformationProcess(
    18.             GetCurrentProcess(),
    19.             ProcessDebugPort,
    20.             &dwProcessDebugPort,
    21.             sizeof(DWORD),
    22.             &dwReturned);

    23.         if (NT_SUCCESS(status) && (-1 == dwProcessDebugPort))
    24.             ExitProcess(-1);
    25.     }
    26. }
    复制代码

    x86 汇编:
    1.     lea eax, [dwReturned]
    2.     push eax ; ReturnLength
    3.     push 4   ; ProcessInformationLength
    4.     lea ecx, [dwProcessDebugPort]
    5.     push ecx ; ProcessInformation
    6.     push 7   ; ProcessInformationClass
    7.     push -1  ; ProcessHandle
    8.     call NtQueryInformationProcess
    9.     inc dword ptr [dwProcessDebugPort]
    10.     jz being_debugged
    11.     ...
    12. being_debugged:
    13.     push -1
    14.     call ExitProcess
    复制代码

    x86-64 汇编:
    1.     lea rcx, [dwReturned]
    2.     push rcx    ; ReturnLength
    3.     mov r9d, 4  ; ProcessInformationLength
    4.     lea r8, [dwProcessDebugPort]
    5.                 ; ProcessInformation
    6.     mov edx, 7  ; ProcessInformationClass
    7.     mov rcx, -1 ; ProcessHandle
    8.     call NtQueryInformationProcess
    9.     cmp dword ptr [dwProcessDebugPort], -1
    10.     jz being_debugged
    11.     ...
    12. being_debugged:
    13.     mov ecx, -1
    14.     call ExitProcess
    复制代码


    1.3.2. ProcessDebugFlags进程调试标志寄存器
    一个叫做EPROCESS的内核结构代表一个进程对象,它包含NoDebugInherit字段。这个字段的反值可以通过一个无文件记录的类ProcessDebugFlags(0x1f)来检索。因此,如果返回值为0,则说明有调试器存在。
    C/C++ 代码:
    1. typedef NTSTATUS(NTAPI *TNtQueryInformationProcess)(
    2.     IN HANDLE           ProcessHandle,
    3.     IN DWORD            ProcessInformationClass,
    4.     OUT PVOID           ProcessInformation,
    5.     IN ULONG            ProcessInformationLength,
    6.     OUT PULONG          ReturnLength
    7.     );

    8. HMODULE hNtdll = LoadLibraryA("ntdll.dll");
    9. if (hNtdll)
    10. {
    11.     auto pfnNtQueryInformationProcess = (TNtQueryInformationProcess)GetProcAddress(
    12.         hNtdll, "NtQueryInformationProcess");

    13.     if (pfnNtQueryInformationProcess)
    14.     {
    15.         DWORD dwProcessDebugFlags, dwReturned;
    16.         const DWORD ProcessDebugFlags = 0x1f;
    17.         NTSTATUS status = pfnNtQueryInformationProcess(
    18.             GetCurrentProcess(),
    19.             ProcessDebugFlags,
    20.             &dwProcessDebugFlags,
    21.             sizeof(DWORD),
    22.             &dwReturned);

    23.         if (NT_SUCCESS(status) && (0 == dwProcessDebugFlags))
    24.             ExitProcess(-1);
    25.     }
    26. }
    复制代码

    x86 汇编:
    1.     lea eax, [dwReturned]
    2.     push eax ; ReturnLength
    3.     push 4   ; ProcessInformationLength
    4.     lea ecx, [dwProcessDebugPort]
    5.     push ecx ; ProcessInformation
    6.     push 1Fh ; ProcessInformationClass
    7.     push -1  ; ProcessHandle
    8.     call NtQueryInformationProcess
    9.     cmp dword ptr [dwProcessDebugPort], 0
    10.     jz being_debugged
    11.     ...
    12. being_debugged:
    13.     push -1
    14.     call ExitProcess
    复制代码

    x86-64 汇编:
    1.     lea rcx, [dwReturned]
    2.     push rcx     ; ReturnLength
    3.     mov r9d, 4   ; ProcessInformationLength
    4.     lea r8, [dwProcessDebugPort]
    5.                  ; ProcessInformation
    6.     mov edx, 1Fh ; ProcessInformationClass
    7.     mov rcx, -1  ; ProcessHandle
    8.     call NtQueryInformationProcess
    9.     cmp dword ptr [dwProcessDebugPort], 0
    10.     jz being_debugged
    11.     ...
    12. being_debugged:
    13.     mov ecx, -1
    14.     call ExitProcess
    复制代码


    1.3.3. ProcessDebugObjectHandle进程调试对象句柄
    当调试开始时,一个叫做 "debug object "的内核对象被创建。可以通过使用无文献记载的ProcessDebugObjectHandle(0x1e)类来查询这个句柄的值。
    C/C++ 代码:
    1. typedef NTSTATUS(NTAPI * TNtQueryInformationProcess)(
    2.     IN HANDLE           ProcessHandle,
    3.     IN DWORD            ProcessInformationClass,
    4.     OUT PVOID           ProcessInformation,
    5.     IN ULONG            ProcessInformationLength,
    6.     OUT PULONG          ReturnLength
    7.     );

    8. HMODULE hNtdll = LoadLibraryA("ntdll.dll");
    9. if (hNtdll)
    10. {
    11.     auto pfnNtQueryInformationProcess = (TNtQueryInformationProcess)GetProcAddress(
    12.         hNtdll, "NtQueryInformationProcess");

    13.     if (pfnNtQueryInformationProcess)
    14.     {
    15.         DWORD dwReturned;
    16.         HANDLE hProcessDebugObject = 0;
    17.         const DWORD ProcessDebugObjectHandle = 0x1e;
    18.         NTSTATUS status = pfnNtQueryInformationProcess(
    19.             GetCurrentProcess(),
    20.             ProcessDebugObjectHandle,
    21.             &hProcessDebugObject,
    22.             sizeof(HANDLE),
    23.             &dwReturned);

    24.         if (NT_SUCCESS(status) && (0 != hProcessDebugObject))
    25.             ExitProcess(-1);
    26.     }
    27. }
    复制代码

    x86 汇编:
    1.     lea eax, [dwReturned]
    2.     push eax ; ReturnLength
    3.     push 4   ; ProcessInformationLength
    4.     lea ecx, [hProcessDebugObject]
    5.     push ecx ; ProcessInformation
    6.     push 1Eh ; ProcessInformationClass
    7.     push -1  ; ProcessHandle
    8.     call NtQueryInformationProcess
    9.     cmp dword ptr [hProcessDebugObject], 0
    10.     jnz being_debugged
    11.     ...
    12. being_debugged:
    13.     push -1
    14.     call ExitProcess
    复制代码

    x86-64 汇编:
    1.     lea rcx, [dwReturned]
    2.     push rcx     ; ReturnLength
    3.     mov r9d, 4   ; ProcessInformationLength
    4.     lea r8, [hProcessDebugObject]
    5.                  ; ProcessInformation
    6.     mov edx, 1Fh ; ProcessInformationClass
    7.     mov rcx, -1  ; ProcessHandle
    8.     call NtQueryInformationProcess
    9.     cmp dword ptr [hProcessDebugObject], 0
    10.     jnz being_debugged
    11.     ...
    12. being_debugged:
    13.     mov ecx, -1
    14.     call ExitProcess
    复制代码


    1.4. RtlQueryProcessHeapInformation()
    ntdll!RtlQueryProcessHeapInformation()函数可以用来从当前进程的进程内存中读取堆标志寄存器。
    C/C++ 代码:
    1. bool Check()
    2. {
    3.     ntdll::PDEBUG_BUFFER pDebugBuffer = ntdll::RtlCreateQueryDebugBuffer(0, FALSE);
    4.     if (!SUCCEEDED(ntdll::RtlQueryProcessHeapInformation((ntdll::PRTL_DEBUG_INFORMATION)pDebugBuffer)))
    5.         return false;

    6.     ULONG dwFlags = ((ntdll::PRTL_PROCESS_HEAPS)pDebugBuffer->HeapInformation)->Heaps[0].Flags;
    7.     return dwFlags & ~HEAP_GROWABLE;
    8. }
    复制代码


    1.5. RtlQueryProcessDebugInformation()
    ntdll!RtlQueryProcessDebugInformation()函数可用于从被请求进程的进程内存中读取某些字段,包括堆标志寄存器。
    C/C++ 代码:
    1. bool Check()
    2. {
    3.     ntdll::PDEBUG_BUFFER pDebugBuffer = ntdll::RtlCreateQueryDebugBuffer(0, FALSE);
    4.     if (!SUCCEEDED(ntdll::RtlQueryProcessDebugInformation(GetCurrentProcessId(), ntdll::PDI_HEAPS | ntdll::PDI_HEAP_BLOCKS, pDebugBuffer)))
    5.         return false;

    6.     ULONG dwFlags = ((ntdll::PRTL_PROCESS_HEAPS)pDebugBuffer->HeapInformation)->Heaps[0].Flags;
    7.     return dwFlags & ~HEAP_GROWABLE;
    8. }
    复制代码

    1.6. NtQuerySystemInformation()
    ntdll!NtQuerySystemInformation()函数接受一个参数,即要查询的信息类别。大多数类都没有被记录下来。这包括SystemKernelDebuggerInformation(0x23)类,它从Windows NT开始就存在了。SystemKernelDebuggerInformation类返回两个标志寄存器的值。al中的KdDebuggerEnabled,和ah中的KdDebuggerNotPresent。因此,如果内核调试器存在,ah中的返回值为零。
    C/C++ 代码:
    1. enum { SystemKernelDebuggerInformation = 0x23 };

    2. typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION {
    3.     BOOLEAN DebuggerEnabled;
    4.     BOOLEAN DebuggerNotPresent;
    5. } SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;

    6. bool Check()
    7. {
    8.     NTSTATUS status;
    9.     SYSTEM_KERNEL_DEBUGGER_INFORMATION SystemInfo;
    10.    
    11.     status = NtQuerySystemInformation(
    12.         (SYSTEM_INFORMATION_CLASS)SystemKernelDebuggerInformation,
    13.         &SystemInfo,
    14.         sizeof(SystemInfo),
    15.         NULL);

    16.     return SUCCEEDED(status)
    17.         ? (SystemInfo.DebuggerEnabled && !SystemInfo.DebuggerNotPresent)
    18.         : false;
    19. }
    复制代码

    反制措施
    • 对于IsDebuggerPresent()。将进程环境块(PEB)的BeingDebugged标志设置为0。 更多信息请参见BeingDebugged 标志寄存器反制措施。
    • 对于CheckRemoteDebuggerPresent()和NtQueryInformationProcess():
      由于CheckRemoteDebuggerPresent()调用NtQueryInformationProcess(),唯一的方法是拦截NtQueryInformationProcess()并在返回缓冲区设置以下值。
      • 如果是ProcessDebugPort查询,则为0(或除-1外的任何值)。
      • 如果是ProcessDebugFlags查询,则为非零值。
      • 在ProcessDebugObjectHandle查询的情况下为0。
    • 用RtlQueryProcessHeapInformation()、RtlQueryProcessDebugInformation()和NtQuerySystemInformation()函数反制这些检查的唯一方法是拦截它们并修改返回值:
      • RTL_PROCESS_HEAPS::HeapInformation::Heaps[0]:标志寄存器改为HEAP_GROWABLE,用于RtlQueryProcessHeapInformation()和RtlQueryProcessDebugInformation()。
      • SYSTEM_KERNEL_DEBUGGER_INFORMATION:ebuggerEnabled为0和系统_KERNEL_DEBUGGER_INFORMATION:ebuggerNotPresent为1。NtQuerySystemInformation()函数在查询SystemKernelDebuggerInformation的情况下。


    2. 手工检查
    以下方法用于验证系统结构中的调试标志。他们手工检查进程的内存,而不使用特殊的调试API函数。
    2.1. PEB!正在调试标志寄存器
    这个方法只是检查PEB的BeingDebugged标志寄存器[的另一种方法,而不需要调用IsDebuggerPresent()。
    32位进程:
    1. mov eax, fs:[30h]
    2. cmp byte ptr [eax+2], 0
    3. jne being_debugged
    复制代码

    64位进程:
    1. mov rax, gs:[60h]
    2. cmp byte ptr [rax+2], 0
    3. jne being_debugged
    复制代码

    WOW64 进程:
    1. mov eax, fs:[30h]
    2. cmp byte ptr [eax+1002h], 0
    复制代码

    C/C++ 代码:
    1. #ifndef _WIN64
    2. PPEB pPeb = (PPEB)__readfsdword(0x30);
    3. #else
    4. PPEB pPeb = (PPEB)__readgsqword(0x60);
    5. #endif // _WIN64

    6. if (pPeb->BeingDebugged)
    7.     goto being_debugged;
    复制代码

    2.2. NtGlobalFlag
    进程环境块的NtGlobalFlag字段(32位Windows的0x68偏移,64位Windows的0xBC)默认为0。附加一个调试器并不改变NtGlobalFlag的值。但是,如果进程是由调试器创建的,则将设置以下标志寄存器:
    • FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
    • FLG_HEAP_ENABLE_FREE_CHECK (0x20)
    • FLG_HEAP_VALIDATE_PARAMETERS (0x40)

    调试器的存在可以通过检查这些标志寄存器的组合来检测。
    32位进程:
    1. mov eax, fs:[30h]
    2. mov al, [eax+68h]
    3. and al, 70h
    4. cmp al, 70h
    5. jz  being_debugged
    复制代码

    64位进程:
    1. mov rax, gs:[60h]
    2. mov al, [rax+BCh]
    3. and al, 70h
    4. cmp al, 70h
    5. jz  being_debugged
    复制代码

    WOW64 进程:
    1. mov eax, fs:[30h]
    2. mov al, [eax+10BCh]
    3. and al, 70h
    4. cmp al, 70h
    5. jz  being_debugged
    复制代码

    C/C++ 代码:
    1. #define FLG_HEAP_ENABLE_TAIL_CHECK   0x10
    2. #define FLG_HEAP_ENABLE_FREE_CHECK   0x20
    3. #define FLG_HEAP_VALIDATE_PARAMETERS 0x40
    4. #define NT_GLOBAL_FLAG_DEBUGGED (FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS)

    5. #ifndef _WIN64
    6. PPEB pPeb = (PPEB)__readfsdword(0x30);
    7. DWORD dwNtGlobalFlag = *(PDWORD)((PBYTE)pPeb + 0x68);
    8. #else
    9. PPEB pPeb = (PPEB)__readgsqword(0x60);
    10. DWORD dwNtGlobalFlag = *(PDWORD)((PBYTE)pPeb + 0xBC);
    11. #endif // _WIN64

    12. if (dwNtGlobalFlag & NT_GLOBAL_FLAG_DEBUGGED)
    13.     goto being_debugged;
    复制代码

    2.3. 堆标志寄存器
    堆包含两个字段,它们会受到调试器存在的影响。具体如何影响,取决于Windows的版本。这些字段是标志寄存器(Flags)和强标志寄存器(ForceFlags)。

    标志寄存器和强标志寄存器的值通常分别设置为HEAP_GROWABLE和0。
    当调试器出现时,在Windows NT、Windows 2000和32位Windows XP上,标志寄存器字段被设置为这些标志寄存器的组合。
    • HEAP_GROWABLE (2)
    • HEAP_TAIL_CHECKING_ENABLED (0x20)
    • HEAP_FREE_CHECKING_ENABLED (0x40)
    • HEAP_SKIP_VALIDATION_CHECKS (0x10000000)
    • HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)

    在64位的Windows XP和Windows Vista及更高版本中,如果有调试器存在,Flags字段会被设置为这些标志寄存器组合:
    • HEAP_GROWABLE (2)
    • HEAP_TAIL_CHECKING_ENABLED (0x20)
    • HEAP_FREE_CHECKING_ENABLED (0x40)
    • HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)

    当调试器出现时,ForceFlags字段被设置为这些标志寄存器的组合:
    • HEAP_TAIL_CHECKING_ENABLED (0x20)
    • HEAP_FREE_CHECKING_ENABLED (0x40)
    • HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)

    C/C++ 代码:
    1. bool Check()
    2. {
    3. #ifndef _WIN64
    4.     PPEB pPeb = (PPEB)__readfsdword(0x30);
    5.     PVOID pHeapBase = !m_bIsWow64
    6.         ? (PVOID)(*(PDWORD_PTR)((PBYTE)pPeb + 0x18))
    7.         : (PVOID)(*(PDWORD_PTR)((PBYTE)pPeb + 0x1030));
    8.     DWORD dwHeapFlagsOffset = IsWindowsVistaOrGreater()
    9.         ? 0x40
    10.         : 0x0C;
    11.     DWORD dwHeapForceFlagsOffset = IsWindowsVistaOrGreater()
    12.         ? 0x44
    13.         : 0x10;
    14. #else
    15.     PPEB pPeb = (PPEB)__readgsqword(0x60);
    16.     PVOID pHeapBase = (PVOID)(*(PDWORD_PTR)((PBYTE)pPeb + 0x30));
    17.     DWORD dwHeapFlagsOffset = IsWindowsVistaOrGreater()
    18.         ? 0x70
    19.         : 0x14;
    20.     DWORD dwHeapForceFlagsOffset = IsWindowsVistaOrGreater()
    21.         ? 0x74
    22.         : 0x18;
    23. #endif // _WIN64

    24.     PDWORD pdwHeapFlags = (PDWORD)((PBYTE)pHeapBase + dwHeapFlagsOffset);
    25.     PDWORD pdwHeapForceFlags = (PDWORD)((PBYTE)pHeapBase + dwHeapForceFlagsOffset);
    26.     return (*pdwHeapFlags & ~HEAP_GROWABLE) || (*pdwHeapForceFlags != 0);
    27. }
    复制代码

    2.3.堆保护
    如果在NtGlobalFlag中设置了HEAP_TAIL_CHECKING_ENABLED标志寄存器,序列0xABABABAB将被附加在所分配的堆块的末端(在32位Windows中为2次,在64位Windows中为4次)。

    如果在NtGlobalFlag中设置了HEAP_FREE_CHECKING_ENABLED标志寄存器,如果需要额外的字节来填充空的空间,直到下一个内存块,那么将附加序列0xFEEEFEEE。
    C/C++ 代码:
    1. bool Check()
    2. {
    3.     PROCESS_HEAP_ENTRY HeapEntry = { 0 };
    4.     do
    5.     {
    6.         if (!HeapWalk(GetProcessHeap(), &HeapEntry))
    7.             return false;
    8.     } while (HeapEntry.wFlags != PROCESS_HEAP_ENTRY_BUSY);

    9.     PVOID pOverlapped = (PBYTE)HeapEntry.lpData + HeapEntry.cbData;
    10.     return ((DWORD)(*(PDWORD)pOverlapped) == 0xABABABAB);
    11. }
    复制代码


    反制措施
    对于PEB!BeingDebugged标志寄存器:
    将BeingDebugged标志设置为0,这可以通过DLL注入完成。如果你使用OllyDbg或x32/64dbg作为调试器,你可以选择各种反调试插件,如ScyllaHide
    1. #ifndef _WIN64
    2. PPEB pPeb = (PPEB)__readfsdword(0x30);
    3. #else
    4. PPEB pPeb = (PPEB)__readgsqword(0x60);
    5. #endif // _WIN64
    6. pPeb->BeingDebugged = 0;
    复制代码

    对于NtGlobalFlag:
    将NtGlobalFlag设置为0,这可以通过DLL注入完成。如果你使用OllyDbg或x32/64dbg作为调试器,你可以选择各种反调试插件,如ScyllaHide
    1. #ifndef _WIN64
    2. PPEB pPeb = (PPEB)__readfsdword(0x30);
    3. *(PDWORD)((PBYTE)pPeb + 0x68) = 0;
    4. #else
    5. PPEB pPeb = (PPEB)__readgsqword(0x60);
    6. *(PDWORD)((PBYTE)pPeb + 0xBC); = 0;
    7. #endif // _WIN64
    复制代码

    对于堆标志寄存器:
    设置标志寄存器值为HEAP_GROWABLE,ForceFlags值为0,这可以通过DLL注入完成。如果你使用OllyDbg或x32/64dbg作为调试器,你可以选择各种反调试插件,如ScyllaHide
    1. #ifndef _WIN64
    2. PPEB pPeb = (PPEB)__readfsdword(0x30);
    3. PVOID pHeapBase = !m_bIsWow64
    4.     ? (PVOID)(*(PDWORD_PTR)((PBYTE)pPeb + 0x18))
    5.     : (PVOID)(*(PDWORD_PTR)((PBYTE)pPeb + 0x1030));
    6. DWORD dwHeapFlagsOffset = IsWindowsVistaOrGreater()
    7.     ? 0x40
    8.     : 0x0C;
    9. DWORD dwHeapForceFlagsOffset = IsWindowsVistaOrGreater()
    10.     ? 0x44
    11.     : 0x10;
    12. #else
    13. PPEB pPeb = (PPEB)__readgsqword(0x60);
    14. PVOID pHeapBase = (PVOID)(*(PDWORD_PTR)((PBYTE)pPeb + 0x30));
    15. DWORD dwHeapFlagsOffset = IsWindowsVistaOrGreater()
    16.     ? 0x70
    17.     : 0x14;
    18. DWORD dwHeapForceFlagsOffset = IsWindowsVistaOrGreater()
    19.     ? 0x74
    20.     : 0x18;
    21. #endif // _WIN64

    22. *(PDWORD)((PBYTE)pHeapBase + dwHeapFlagsOffset) = HEAP_GROWABLE;
    23. *(PDWORD)((PBYTE)pHeapBase + dwHeapForceFlagsOffset) = 0;
    复制代码

    对于堆保护:
    手工修补32位的12字节和64位环境下的20字节的堆。拦截kernel32!HeapAlloc()并在其分配后修补堆。
    1. #ifndef _WIN64
    2. SIZE_T nBytesToPatch = 12;
    3. #else
    4. SIZE_T nBytesToPatch = 20;
    5. #endif // _WIN64

    6. SIZE_T nDwordsToPatch = nBytesToPatch / sizeof(DWORD);
    7. PVOID pHeapEnd = (PBYTE)HeapEntry.lpData + HeapEntry.cbData;
    8. for (SIZE_T offset = 0; offset < nDwordsToPatch; offset++)
    9.     *((PDWORD)pHeapEnd + offset) = 0;
    复制代码

    点评

    支持一下  发表于 2024-10-14 19:31
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    红盟社区--红客联盟 

    Processed in 0.064580 second(s), 25 queries.

    站点统计| 举报| Archiver| 手机版| 黑屋 |   

    备案号:冀ICP备20006029号-1 Powered by HUC © 2001-2021 Comsenz Inc.

    手机扫我进入移动触屏客户端

    关注我们可获取更多热点资讯

    Honor accompaniments. theme macfee

    快速回复 返回顶部 返回列表