调试标志

系统表中的特殊标志(驻留在进程内存中并由操作系统设置)可以用来指示进程正在调试。可以通过使用特定的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. if (pfnNtQueryInformationProcess)
  14. {
  15. DWORD dwProcessDebugPort, dwReturned;
  16. NTSTATUS status = pfnNtQueryInformationProcess(
  17. GetCurrentProcess(),
  18. ProcessDebugPort,
  19. &dwProcessDebugPort,
  20. sizeof(DWORD),
  21. &dwReturned);
  22. if (NT_SUCCESS(status) && (-1 == dwProcessDebugPort))
  23. ExitProcess(-1);
  24. }
  25. }

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。可以使用未记录的类ProcessDebugFlags0x1f)检索此字段的逆值。因此,如果返回值为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

调试开始时,将创建一个称为“调试对象”的内核对象。可以通过使用未记录的ProcessDebugObjectHandle0x1e)类来查询此句柄的值。


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.3.4 ProcessBasicInformation

ProcessInformationClass值为0,检索指向可用于确定指定进程是否正在调试的PEB结构的指针,以及系统用于标识指定进程的唯一值。
使用CheckRemoteDebuggerPresentGetProcessId 函数来获取此信息。

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类返回两个标志的值:KdDebuggerEnabled的人,和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. status = NtQuerySystemInformation(
  11. (SYSTEM_INFORMATION_CLASS)SystemKernelDebuggerInformation,
  12. &SystemInfo,
  13. sizeof(SystemInfo),
  14. NULL);
  15. return SUCCEEDED(status)
  16. ? (SystemInfo.DebuggerEnabled && !SystemInfo.DebuggerNotPresent)
  17. : false;
  18. }

缓解措施

  • 对于IsDebuggerPresent():将流程环境块(PEB)的正在调试标志设置为0。
  • 对于CheckRemoteDebuggerPresent()NtQueryInformationProcess()
    由于CheckRemoteDebuggerPresent()调用NtQueryInformationProcess(),唯一的方法是挂接NtQueryInformationProcess()并在返回缓冲区中设置以下值:
    • 如果是ProcessDebugPort查询,则为0(或-1以外的任何值)。
    • 如果是ProcessDebugFlags查询,则为非零值。
    • 如果是ProcessDebugObjectHandle查询,则为0 。
  • 使用RtlQueryProcessHeapInformation()RtlQueryProcessDebugInformation()NtQuerySystemInformation()函数减轻这些检查的唯一方法是钩住它们并修改返回的值:
    • RTL_PROCESS_HEAPS :: HeapInformation :: Heaps [0] :: FlagsHEAP_GROWABLE
      RtlQueryProcessHeapInformation()RtlQueryProcessDebugInformation()
    • 如果是SystemKernelDebuggerInformation查询,则NtQuerySystemInformation()函数的SYSTEM_KERNEL_DEBUGGER_INFORMATION :: DebuggerEnabled设置为0,
      SYSTEM_KERNEL_DEBUGGER_INFORMATION :: DebuggerNotPresent设置为1 。

2.手动检查

以下方法用于验证系统结构中的调试标志。他们无需使用特殊的调试API函数即可手动检查进程内存。

2.1. PEB!BeingDebugged标志

此方法只是不调用IsDebuggerPresent()即可检查PEB的BeingDebugged标志的另一种方法。


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进程环境块(在Windows32位偏移0x68、64位偏移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版本。这些字段是FlagsForceFlags

FlagsForceFlags的值通常分别设置为HEAP_GROWABLE0


如果存在调试器,则在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及更高版本上,如果存在调试器,则“标志”字段将设置为以下标志的组合:

  • 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位为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作为调试器,则可以选择各种Anti-Debug插件,例如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作为调试器,则可以选择各种Anti-Debug插件,例如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

对于堆标志:

Flags值设置为HEAP_GROWABLE,并将ForceFlags值设置为0。这可以通过DLL注入来完成。如果使用OllyDbg或x32 / 64dbg作为调试器,则可以选择各种Anti-Debug插件,例如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;

对于堆保护:

在堆之后手动修补12个字节(32位)或20个字节(64位)。hookkernel32!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;