Heap Flags
About Heap flags¶
Heap flags contains two flags initialized with NtGlobalFlag: Flags and ForceFlags. The values of these two fields will not only be affected by the debugger, but also by the windows version, the location of the fields. Also depends on the version of windows.
- Flags field:
- In 32-bit Windows NT, Windows 2000 and Windows XP,
Flagsis at the0x0Coffset of the heap. On 32-bit Windows Vista and newer systems, it is located at the offset of0x40. - In 64-bit Windows XP, the
Flagsfield is at the0x14offset of the heap, and on 64-bit Windows Vista and newer systems, it is at the0x70offset. - ForceFlags field:
- In 32-bit Windows NT, Windows 2000 and Windows XP,
ForceFlagsis located at the0x10offset of the heap. On 32-bit Windows Vista and newer systems, it is located at the offset of0x44. - In 64-bit Windows XP, the
ForceFlagsfield is at the0x18offset of the heap, and on 64-bit Windows Vista and newer systems, it is at the0x74offset.
In all versions of Windows, the value of the Flags field is normally set to HEAP_GROWABLE(2), and the ForceFlags field is normally set to 0. However for a 32-bit process (64-bit programs are not There will be troubles. Both of these default values depend on the [subsystem] of its host process (https://msdn.microsoft.com/en-us/library/ms933120.aspx) Version (this does not refer to the Linux subsystem such as win10). Only when subsystem is in 3.51 and higher, the default value of the field is as described above. If it is in 3.10-3.50 Between, the two fields of HEAP_CREATE_ALIGN_16 (0x10000) will be set. If the version is lower than 3.10, then this program file will not be run at all.
If an operation sets the values of the Flags and ForgeFlags fields to 2 and 0, respectively, but does not check the subsystem version, then it can be indicated that the action is to hide the debugger. .
When the debugger is present, under the Windows NT, Windows 2000 and 32-bit Windows XP systems, the Flags field will set the following flags:
HEAP_GROWABLE (2)
HEAP_TAIL_CHECKING_ENABLED (0x20)
HEAP_FREE_CHECKING_ENABLED (0x40)
HEAP_SKIP_VALIDATION_CHECKS (0x10000000)
HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)
On the 64-bit Windows XP system, Windows Vista and newer system versions, the Flags field will set the following flags (less HEAP_SKIP_VALIDATION_CHECKS (0x10000000)):
HEAP_GROWABLE (2)
HEAP_TAIL_CHECKING_ENABLED (0x20)
HEAP_FREE_CHECKING_ENABLED (0x40)
HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)
For the ForgeFlags field, the following flags are normally set:
HEAP_TAIL_CHECKING_ENABLED (0x20)
HEAP_FREE_CHECKING_ENABLED (0x40)
HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)
Because of the relationship of the NtGlobalFlag flag, heap will also set some flag bits.
- If the
FLG_HEAP_ENABLE_TAIL_CHECKflag is set in theNtGlobalFlagfield, theHEAP_TAIL_CHECKING_ENABLEDflag will be set in theheapfield. - If the
FLG_HEAP_ENABLE_FREE_CHECKflag is set in theNtGlobalFlagfield, theFLG_HEAP_ENABLE_FREE_CHECKflag will be set in theheapfield. - If the
FLG_HEAP_VALIDATE_PARAMETERSflag is set in theNtGlobalFlagfield, theHEAP_VALIDATE_PARAMETERS_ENABLEDflag will be set in theheapfield (theHEAP_CREATE_ALIGN_16 (0x10000) will also be set inWindows NTandWindows 2000`. Sign).
heap flags is also the same as NtGlobalFlag in the previous section, but it is subject to the registry HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ <filename>Location's PageHeapFlags" key control.
Get the heap location¶
There are several ways to know the location of the heap. One of the methods is the GetProcessHeap() function of kernel32. Of course, you can also use the following 32-bit assembly code to detect the 32-bit environment (there are actually some shells to avoid). Use this api function to directly query PEB):
mov eax, fs:[30h] ;Process Environment Block
mov eax, [eax+18h] ;get process heap base
Or use the following 64-bit code to detect a 64-bit environment
push 60h
pop rsi
gs:lodsq ;Process Environment Block
mov eax, [rax+30h] ;get process heap base
Or use the following 32-bit code to detect a 64-bit environment
mov eax, fs:[30h] ;Process Environment Block
;64-bit Process Environment Block
;follows 32-bit Process Environment Block
mov eax, [eax+1030h] ;get process heap base
The other method is to use the GetProcessHeaps() function of kernel32. In fact, it is simply transferred to the ntdll RtlGetProcessHeaps() function, which returns an array of the heap belonging to the current process. The first heap of the array is the same as the GetProcessHeap() function of kernel32.
This process can be implemented with 32-bit code detection for 32-bit windows environments:
push 30h
pop how
fs:lodsd ;Process Environment Block
;get process heaps list base
mov how, [how + eax + 5ch]
lodsd
As above, the code for detecting 64-bit windows environment with 64-bit code is:
push 60h
pop rsi
gs:lodsq ;Process Environment Block
;get process heaps list base
mov esi, [rsi * 2 + rax + 20h]
lodsd
Or use a 32-bit code to detect a 64-bit window environment:
mov eax, fs:[30h] ;Process Environment Block
;64-bit Process Environment Block
;follows 32-bit Process Environment Block
mov esi, [eax+10f0h] ;get process heaps list base
lodsd
Detect Flags field¶
So obviously, we can detect the debuggers from the flags of Flags and ForgeFlags.
First look at the detection code of the Flags field, use a 32-bit code to detect the 32-bit windows environment, and the subsystem version is between 3.10-3.50:
call GetVersion
cmp al, 6
cc
sbb ebx, ebx
and ebx, 34h
mov eax, fs:[30h] ;Process Environment Block
mov eax, [eax+18h] ;get process heap base
mov eax, [eax+ebx+0ch] ;Flags
;neither HEAP_CREATE_ALIGN_16
;nor HEAP_SKIP_VALIDATION_CHECKS
and eax, 0effeffffh
;HEAP_GROWABLE
;+ HEAP_TAIL_CHECKING_ENABLED
;+ HEAP_FREE_CHECKING_ENABLED
;+ HEAP_VALIDATE_PARAMETERS_ENABLED
cmp eax, 40000062h
je being_debugged
The 32-bit code detects the 32-bit windows environment, and the subsystem is 3.51 and higher:
call GetVersion
cmp al, 6
cc
sbb ebx, ebx
and ebx, 34h
mov eax, fs:[30h] ;Process Environment Block
mov eax, [eax+18h] ;get process heap base
mov eax, [eax+ebx+0ch] ;Flags
;not HEAP_SKIP_VALIDATION_CHECKS
bswap eax
and al, 0efh
;HEAP_GROWABLE
;+ HEAP_TAIL_CHECKING_ENABLED
;+ HEAP_FREE_CHECKING_ENABLED
;+ HEAP_VALIDATE_PARAMETERS_ENABLED
;reversed by bswap
cmp eax, 62000040h
je being_debugged
64-bit code detects 64-bit windows environments (64-bit processes don't have to be bothered by the subsystem version):
push 60h
pop rsi
gs:lodsq ;Process Environment Block
mov ebx, [rax+30h] ;get process heap base
call GetVersion
cmp al, 6
as rax, rax
and al, 0a4h
;HEAP_GROWABLE
;+ HEAP_TAIL_CHECKING_ENABLED
;+ HEAP_FREE_CHECKING_ENABLED
;+ HEAP_VALIDATE_PARAMETERS_ENABLED
cmp d [rbx+rax+70h], 40000062h ;Flags
je being_debugged
Detect 64-bit windows environment with 32-bit code:
push 30h
pop eax
mov ebx, fs:[eax] ;Process Environment Block
;64-bit Process Environment Block
;follows 32-bit Process Environment Block
mov ah, 10h
mov ebx, [ebx+eax] ;get process heap base
call GetVersion
cmp al, 6
sbb eax, eax
and al, 0a4h
;Flags
;HEAP_GROWABLE
;+ HEAP_TAIL_CHECKING_ENABLED
;+ HEAP_FREE_CHECKING_ENABLED
;+ HEAP_VALIDATE_PARAMETERS_ENABLED
cmp [ebx+eax+70h], 40000062h
je being_debugged
If you get this value directly through the NtMajorVersion field of the KUSER_SHARED_DATA structure (located at the offset of 0x7ffe026c in 2G user space) (this value can be obtained on all 32-bit/64-bit versions of Windows), you can further confuse The GetVersion() function call operation of kernel32.
Detecting ForgeFlags field¶
Of course, another method is to detect the ForgeFlags field. The following is a 32-bit code detection for a 32-bit Windows environment. The subsystem version is between 3.10-3.50:
call GetVersion
cmp al, 6
cc
sbb ebx, ebx
and ebx, 34h
mov eax, fs:[30h] ;Process Environment Block
mov eax, [eax+18h] ;get process heap base
mov eax, [eax+ebx+10h] ;ForceFlags
;not HEAP_CREATE_ALIGN_16
btr eax, 10h
;HEAP_TAIL_CHECKING_ENABLED
;+ HEAP_FREE_CHECKING_ENABLED
;+ HEAP_VALIDATE_PARAMETERS_ENABLED
cmp eax, 40000060h
je being_debugged
The 32-bit code detects the 32-bit windows environment, and the subsystem is 3.51 and higher:
call GetVersion
cmp al, 6
cc
sbb ebx, ebx
and ebx, 34h
mov eax, fs:[30h] ;Process Environment Block
mov eax, [eax+18h] ;get process heap base
;ForceFlags
;HEAP_TAIL_CHECKING_ENABLED
;+ HEAP_FREE_CHECKING_ENABLED
;+ HEAP_VALIDATE_PARAMETERS_ENABLED
cmp [eax+ebx+10h], 40000060h
je being_debugged
64-bit code detects 64-bit windows environments (64-bit processes don't have to be bothered by the subsystem version):
push 60h
pop rsi
gs:lodsq ;Process Environment Block
mov ebx, [rax+30h] ;get process heap base
call GetVersion
cmp al, 6
as rax, rax
and al, 0a4h
;ForceFlags
;HEAP_TAIL_CHECKING_ENABLED
;+ HEAP_FREE_CHECKING_ENABLED
;+ HEAP_VALIDATE_PARAMETERS_ENABLED
cmp d [rbx+rax+74h], 40000060h
je being_debugged
Detect 64-bit windows environment with 32-bit code:
call GetVersion
cmp al, 6
push 30h
pop eax
mov ebx, fs:[eax] ;Process Environment Block
;64-bit Process Environment Block
;follows 32-bit Process Environment Block
mov ah, 10h
mov ebx, [ebx+eax] ;get process heap base
sbb eax, eax
and al, 0a4h
;ForceFlags
;HEAP_TAIL_CHECKING_ENABLED
;+ HEAP_FREE_CHECKING_ENABLED
;+ HEAP_VALIDATE_PARAMETERS_ENABLED
cmp [ebx+eax+74h], 40000060h
je being_debugged
Reference link¶
本页面的全部内容在 CC BY-NC-SA 4.0 协议之条款下提供,附加条款亦可能应用。