Log in

View Full Version : PEB ProcessHeaps element


Shub-nigurrath
July 14th, 2006, 10:33
Hi all,
I found this code around which is used to implement an antidebugging trick, but I cannot find any information about it, about the structure of the memory pointed by the ProcessHeaps element, once the PEB is accessed

Anyone having infos about it?

Code:

//Access the PEB+0x18 which is the ProcessHeap, is a DWORD
DWORD dwProcessHeap;
if (!ReadProcessMemory(hproc, (LPVOID)(RVApeb + 0x18), &dwProcessHeap, 4, &numread) || numread != 4)
return FALSE;

DWORD dwBeingDebugged;
if (!ReadProcessMemory(hproc, (LPVOID)(dwProcessHeap + 0x10), &dwBeingDebugged, 4, &numread) || numread != 4)
return FALSE;

dwBeingDebugged=0;
if (!WriteProcessMemory(hproc, (LPVOID)(dwProcessHeap + 0x10), &dwBeingDebugged, 4, &numread) || numread != 4)
return FALSE;

blabberer
July 14th, 2006, 11:35
hi shub,

its called forceflag some thing not much documentation available but you can look for a plugin to ollydbg called evancense which is where i saw this forceflag being nulled
if you use windbg then you can use !heap !heap -v 1 dd ##### to check out the results

Code:

0:000> !heap
Index Address Name Debugging options enabled
1: 00140000 tail checking free checking validate parameters
2: 00240000 tail checking free checking validate parameters
3: 00250000 tail checking free checking validate parameters
0:000> !heap -v 1
Index Address Name Debugging options enabled
1: 00140000
Segment at 00140000 to 00240000 (00003000 bytes committed)
Flags: 50000062
ForceFlags: 40000060
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 000000c9
Max. Allocation Size: 7ffdefff
Lock Variable at: 00140608
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 00140050
UCR FreeList: 00140598
FreeList Usage: 00000000 00000000 00000000 00000000
FreeList[ 00 ] at 00140178: 001429c0 . 001429c0 (1 block )
0:000> dd 140000
00140000 000000c8 0000016b eeffeeff 50000062
00140010 40000060 0000fe00 00100000 00002000
00140020 00000200 00002000 000000c9 7ffdefff
00140030 06080001 00000000 00000000 00000000
00140040 00000000 00140598 00000017 fffffff8
00140050 00140050 00140050 00140640 00000000
00140060 00000000 00000000 00000000 00000000
00140070 00000000 00000000 00000000 00000000

and if you do
cmd.exe --> set _NO_DEBUG_HEAP =1 -->
enter -->
windbg and do a !heap again you will see force flags are null

0:000> !heap
Index Address Name Debugging options enabled
1: 00140000
2: 00240000
3: 00250000
0:000> !heap -v 1
Index Address Name Debugging options enabled
1: 00140000
Segment at 00140000 to 00240000 (00004000 bytes committed)
Flags: 00000002
ForceFlags: 00000000
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 000001fe
Max. Allocation Size: 7ffdefff
Lock Variable at: 00140608
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 00140050
UCR FreeList: 00140598
FreeList Usage: 00000000 00000000 00000000 00000000
FreeList[ 00 ] at 00140178: 00143018 . 00143018 (1 block )
0:000> dd 140000
00140000 000000c8 000001a1 eeffeeff 00000002
00140010 00000000 0000fe00 00100000 00002000
00140020 00000200 00002000 000001fe 7ffdefff
00140030 06080001 00000000 00000000 00000000
00140040 00000000 00140598 0000000f fffffff8
00140050 00140050 00140050 00140640 00000000
00140060 00000000 00000000 00000000 00000000
00140070 00000000 00000000 00000000 00000000


Maximus
July 14th, 2006, 14:03
when you are debugging at r3, windows uses a 'debug' form of heap allocation function calls instead of the standard ones. So, debuggee can check this to discover if it is debugged or not. You can nullify this behaviour with a flag, however -so debugging won't be detectable this way. Don't think olly does this, but.

Shub-nigurrath
July 15th, 2006, 00:33
indeed I have not found any documentation about this flags, seems like something only windbg knows :-D
Your informations are relevant, thanks.

Kayaker
July 17th, 2006, 23:38
Hi all,

I was poking around with this a bit and noticed another debugger detection method somewhat similar and associated with the Peb->ProcessHeap.ForceFlags check.

btw, Those ForceFlags flag values of 40000060h may correspond to:

HEAP_TAIL_CHECKING_ENABLED equ 00000020h
HEAP_FREE_CHECKING_ENABLED equ 00000040h

though I can't find a corresponding one for the 40000000h.


The other way of detecting a ring3 debugger is using Peb->NtGlobalFlag. This has probably been used before since it's kind of apparent but anyway...Here is the detection method first of all as inline asm:

Code:

/*******************************************************
Test debugger detection via PEB NtGlobalFlag
*******************************************************/

// Simple inline asm implementation

_asm{
mov eax, fs:[0x18] // TEB
mov eax, [eax+0x30] // PEB
mov eax, [eax+0x68] // Peb->NtGlobalFlag

test eax, 0x70 // FLG_HEAP_ENABLE_FREE_CHECK |
// FLG_HEAP_ENABLE_TAIL_CHECK |
// FLG_HEAP_VALIDATE_PARAMETERS
jz nodebugger
}

MessageBox(NULL, "Debugger Found via PEB NtGlobalFlag", "Busted", NULL);

nodebugger:


The *reason* this works can be exposed by examining ntdll!LdrInitializeThunk. LdrInitializeThunk is the loader initialization routine that is executed as a usermode APC by PspUserThreadStartup and is the first usermode code to execute on process startup.

In Softice at least you can set a global breakpoint on this function and trace its execution when you change external parameters. One of the first things LdrInitializeThunk does is to check any registry settings under
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<program name>]

It does this using several calls to LdrQueryImageFileExecutionOptions with different string values:

Code:

(ReactOS define)
LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
IN PCWSTR ValueName,
IN ULONG Type,
OUT PVOID Buffer,
IN ULONG BufferSize,
OUT PULONG ReturnedLength OPTIONAL)


One of the calls is to check for GlobalFlag settings and it sets the Peb->NtGlobalFlag field accordingly. Now, here's the critical part in terms of the debugger detection and is outlined in the following code:

If there are NO previously defined values for "GlobalFlag" under the registry Image File Execution Options,
AND there is a debugger attached as set under Peb->BeingDebugged,
then Peb->NtGlobalFlag will automatically be filled with the following flag values:

#define FLG_HEAP_ENABLE_TAIL_CHECK 0x00000010
#define FLG_HEAP_ENABLE_FREE_CHECK 0x00000020
#define FLG_HEAP_VALIDATE_PARAMETERS 0x00000040

Here is the ntdll!LdrInitializeThunk code which defines that (Win2Ksp4):

Code:

:77F83A03 lea eax, [PEB+68h] ; Peb->NtGlobalFlag
:77F83A06 push ebx ; NULL (ReturnedLength)
:77F83A07 push esi ; 0x04 (BufferSize)
:77F83A08 push eax ; return buffer Peb->NtGlobalFlag
:77F83A09 push esi ; 0x04 (REG_SZ)
:77F83A0A push offset aGlobalflag ; "GlobalFlag"
:77F83A0F lea eax, [ebp+Peb.UserProcessParameters.ImagePathName]
:77F83A12 push eax ; Unicode ImageName
:77F83A13 call LdrQueryImageFileExecutionOptions ;

; If successful, i.e. an entry for "GlobalFlag" is found, returns 0
; If entry not found, returns 0x0C0000034 STATUS_OBJECT_NAME_NOT_FOUND
;
:77F83A18 cmp eax, ebx
:77F83A1A jge short loc_77F83A25

:77F83A1C cmp [PEB+2], bl ; if (Peb->BeingDebugged)
:77F83A1F jnz @set_Peb.NtGlobalFlag

:77F83A25 loc_77F83A25: ; CODE XREF: LdrInitializeThunk-10D8
:77F83A25 mov eax, [PEB+68h]
:77F83A28 test eax, 2000000h ; FLG_HEAP_PAGE_ALLOCS
:77F83A2D jnz @checkPageHeapflags

...

; OR NtGlobalFlag value with these 3 flags

:77F99C6E @set_Peb.NtGlobalFlag: ; CODE XREF: LdrInitializeThunk-10D3
:77F99C6E or dword ptr [PEB+68h], 70h
; FLG_HEAP_ENABLE_FREE_CHECK | // 0x10
; FLG_HEAP_ENABLE_TAIL_CHECK | // 0x20
; FLG_HEAP_VALIDATE_PARAMETERS // 0x40
:77F99C72 jmp loc_77F83A25


:77F99C77 @checkPageHeapflags: ; CODE XREF: LdrInitializeThunk-10C5
:77F99C77 and ax, 670Fh
...


By examining the above code you can see one simple way to bypass a debugger check based on Peb->NtGlobalFlag, make sure there IS an existing entry for

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\program.exe]
"GlobalFlag"=""

Note that there doesn't have to be any value for "GlobalFlag", just the presence of the string is enough.

By itself this isn't too significant, BUT for some reason the presence of a "GlobalFlag" entry ALSO bypasses the Peb->ProcessHeap.ForceFlags debugger check trick as well. This is why I said above that these two detection methods are somewhat associated.

In terms of an Olly plugin one could either add a "Global Flag" registry entry for the target program *before* it is loaded, this will take care of both debugger checks, or of course simply wipe out the Peb fields after loading if you don't need them active.

I was going to attach a small test project but there's enough info here for anyone who wants to do it. For reference here is a complete listing of all the possible GlobalFlag settings (Peb->NtGlobalFlag) which I put together from two different sources:

Code:

// NtGlobalFlag flags

#define FLG_STOP_ON_EXCEPTION 0x00000001
#define FLG_SHOW_LDR_SNAPS 0x00000002
#define FLG_DEBUG_INITIAL_COMMAND 0x00000004
#define FLG_STOP_ON_HUNG_GUI 0x00000008
#define FLG_HEAP_ENABLE_TAIL_CHECK 0x00000010
#define FLG_HEAP_ENABLE_FREE_CHECK 0x00000020
#define FLG_HEAP_VALIDATE_PARAMETERS 0x00000040
#define FLG_HEAP_VALIDATE_ALL 0x00000080
#define FLG_POOL_ENABLE_TAIL_CHECK 0x00000100
#define FLG_POOL_ENABLE_FREE_CHECK 0x00000200
#define FLG_POOL_ENABLE_TAGGING 0x00000400
#define FLG_HEAP_ENABLE_TAGGING 0x00000800
#define FLG_USER_STACK_TRACE_DB 0x00001000
#define FLG_KERNEL_STACK_TRACE_DB 0x00002000
#define FLG_MAINTAIN_OBJECT_TYPELIST 0x00004000
#define FLG_HEAP_ENABLE_TAG_BY_DLL 0x00008000
#define FLG_IGNORE_DEBUG_PRIV 0x00010000
#define FLG_ENABLE_CSRDEBUG 0x00020000
#define FLG_ENABLE_KDEBUG_SYMBOL_LOAD 0x00040000
#define FLG_DISABLE_PAGE_KERNEL_STACKS 0x00080000
#define FLG_HEAP_ENABLE_CALL_TRACING 0x00100000
#define FLG_HEAP_DISABLE_COALESCING 0x00200000
#define FLG_VALID_BITS 0x003FFFFF
#define FLG_ENABLE_CLOSE_EXCEPTION 0x00400000
#define FLG_ENABLE_EXCEPTION_LOGGING 0x00800000
#define FLG_ENABLE_HANDLE_TYPE_TAGGING 0x01000000
#define FLG_HEAP_PAGE_ALLOCS 0x02000000
#define FLG_DEBUG_WINLOGON 0x04000000
#define FLG_ENABLE_DBGPRINT_BUFFERING 0x08000000
#define FLG_EARLY_CRITICAL_SECTION_EVT 0x10000000
#define FLG_DISABLE_DLL_VERIFICATION 0x80000000


For fun here is one possible C++ implementation of the Peb->NtGlobalFlag debugger check:

Code:

// A more formal C++ implementation of the same trick

NTSTATUS ntstatus;
HMODULE hNtDll;
PPEB Peb;

NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess;
PROCESS_BASIC_INFORMATION ProcessInfo;
ULONG ReturnLength;

///////////////////////////////////////////////////////

hNtDll = GetModuleHandle("ntdll.dll";
if(!hNtDll)
return FALSE;

pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)GetProcAddress(hNtDll, "NtQueryInformationProcess";

if(IsBadCodePtr((FARPROC)pNtQueryInformationProcess))
return FALSE;


ntstatus = pNtQueryInformationProcess(GetCurrentProcess(),
ProcessBasicInformation,
(PVOID)&ProcessInfo,
sizeof(PROCESS_BASIC_INFORMATION),
&ReturnLength);

if(ntstatus != STATUS_SUCCESS)
return FALSE;


Peb = (PPEB) ProcessInfo.PebBaseAddress;

if ( Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK &&
Peb->NtGlobalFlag & FLG_HEAP_ENABLE_FREE_CHECK &&
Peb->NtGlobalFlag & FLG_HEAP_VALIDATE_PARAMETERS)
{

MessageBox(NULL, "Debugger detected via Peb->NtGlobalFlag", NULL, NULL);
}


Cheers,
Kayaker

goggles99
July 18th, 2006, 03:05
Good Thoughts here... a plugin for Olly has been written to address all the above mentioned detection methods.

Quote:
目前该插件可以隐藏如下Anti-Debug检测:
IsDebuggerpresent,NtGlobalFlags,HeapFlags,
ForceFlags,SetDebugPrivilege,OutDebugStringA,
CheckRemoteDebuggerPresent,ZwSetInformationThread,
UnhandledExceptionFilter,Process32Next,
ZwQueryInformationProcess。

HideOD 0.13
http://www.pediy.com/tools/Debuggers/ollydbg/plugin.htm


you can set the ForceFlags back in your own code like this
Quote:
// As most of you know, running a debugger against the vulnerable
// application will change the heap behavior. This can be done
// with the following (which will make the heap behave the same
// whether or not a debugger is attached)
pHeap->Flags = pHeap->ForceFlags = 2;

http://www.cybertech.net/~sh0ksh0k/heap.txt
As far as doing it in a debugged process Too bad HideOD isn't open source...

blabberer
July 18th, 2006, 09:30
hi kayaker

check out this thread

http://www.exetools.com/forum/showthread.php?t=7363

it has the code you describe apart from some other details

btw you cant use NtSetInformationProcess() to set a global flag in remote process there is a KERNEL_VALID_BITS FLAG which prohibits setting some of the gflags with that api also ms gfalgs utility too will fail
though using it inside windbg will let you set the flags -htc -hfc -hpc
heap tail , heap free , heap validate
with !gflag -htc -hfc -hpc because windbgs exts.dll write to a process memory directly

inspite of doing -htc -hpc -hfc in a running process the debug heaps charecteristics remain same because
RtlDebugAllocateHeap() is called only once when ZwCreateProcess() is being run with DEBUG_T##### flags

also windbg will fail if you use -hd commandline option while starting
but it will change the heap behaviour if you do
set = _NO_DEBUG_HEAP = 1 in cmd and run windbg from that command prompt

naides
July 18th, 2006, 10:39
Naive question:

I assume these PEB flags have a REAL functional significance appart from debug detection tricks.
When plugins like HideOD modify the flags in order to hide the debugger presence, what would be the consequences for the App Heap allocation, memory mangement, and other low level module execution functions that read these flags and act accordingly?

blabberer
July 18th, 2006, 11:25
hi naides,

most of these flags are dependent on the process being debugged
and when you run this process out of debugger none of these flags
matter

so whats being done is to simulate something that makes it look like it is running out of debugger

so heap validity checking etc dont happen thats all if you null out these flags

probably some crtfunctions that rely heavily on heapalloc etc will or may report some problems and most of them would be suppressed internally
by _try() catch() blocks it seems

btw windbg natively provides you facility to disable all these flags
while debugging so probably nothing to worry about i think
but thats my opinion not a fact corraborated with any factual data

Kayaker
July 18th, 2006, 12:20
Quote:
[Originally Posted by blabberer]hi kayaker
check out this thread
http://www.exetools.com/forum/showthread.php?t=7363
it has the code you describe apart from some other details


Right you are. I figured the details would be lurking around somewhere else in some other shady corner of the web. That's OK, it's the thrill of the chase that's important, not the final catch.

blabberer
July 18th, 2006, 13:21
sure its the thrill that matters even if you dont catch

i threw that link to get to know why gflag -k fails while gflags -r wont fail
but needs reboot to take effect

fyi gflags from commandline uses the nativeapi NtSetInformationProcess()
while windbg uses openprocess() NtQueryInformationProcess() and WriteProcessMemory()

also you know of a way to debug with ollydbg a cmd.exe that runs windbg from its prompt

for example i need to catch while windbg is spawned from cmd.exe in ollydbg
dead listing of RtlAllocateDebugHeap() in windbg with uf RtlAllocateHeap is painfull

this is where it decides if to allocate debug heap or not

Code:

eax=40000060 ebx=00140000 ecx=00000084 edx=0012fb00 esi=7c9012d6 edi=00000000
eip=7c9105fe esp=0012f8a8 ebp=0012fac8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
ntdll!RtlAllocateHeap+0x2a:
7c9105fe a9600f037d test eax,0x7d030f60

==============

eax=0012f884 ebx=00140000 ecx=40000060 edx=0012fb00 esi=00000000 edi=00140000
eip=7c91b2d6 esp=0012f678 ebp=0012f894 iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!RtlAllocateHeapSlowly+0x2a:
7c91b2d6 f7c100000269 test ecx,0x69020000

eax=0012f884 ebx=00140000 ecx=40000060 edx=0012fb00 esi=00000000 edi=00140000
eip=7c949d02 esp=0012f678 ebp=0012f894 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
ntdll!RtlAllocateHeapSlowly+0x32:
7c949d02 f7c100000010 test ecx,0x10000000

eax=0012f884 ebx=00140000 ecx=40000060 edx=0012fb00 esi=00000000 edi=00140000
eip=7c949d13 esp=0012f66c ebp=0012f894 iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!RtlAllocateHeapSlowly+0x3f:
7c949d13 e8e3380200 call ntdll!RtlDebugAllocateHeap (7c96d5fb)




Shub-nigurrath
July 23rd, 2006, 18:28
thanks to who helped here.

Your comments went directly into a tutorial I'm releasing soon and Kayaker proposed method has been included into the xADT tool released yesterday.

goggles99
July 24th, 2006, 14:49
I have a follow-up question.
I realize that one can change the "ForceFlags" flag back to the not-debugged status, but what about heaps that have already been created? They are already constructed in the differed debug-heap structure. couldn't these heaps be enumerated/recognised from anti-debug code thereby detecting the debugger? What ring-3 debugger could prevent this? At least one heap is created by CreateProcess in ring-0. You would have to hook CreateProcess I suppose, but can this be done in ring-3?

I think that you could enumerate/rebuild/relink all the heaps after resetting "ForceFlags", but would that be a huge hassle?

Corrections/Ideas?
Thanks...

Kayaker
July 24th, 2006, 15:32
Quote:
[Originally Posted by goggles99]I realize that one can change the "ForceFlags" flag back to the not-debugged status, but what about heaps that have already been created?
couldn't these heaps be enumerated/recognised from anti-debug code thereby detecting the debugger?


That's a good point goggles99. I think that's exactly the problem/situation you'd have if you only "zeroed" the ForceFlags PEB field after the process has started. This would only fool a *direct* check of Peb->ProcessHeap.ForceFlags. As you say though, if a debug heap was truly active for a process then there may be other ways to detect that.

As I noted above, if you instead set a "GlobalFlag"="" for a process *before* it is loaded, this *also* clears the Peb->ProcessHeap.ForceFlags field (actually it's never even set). This is what I noticed anyway, but it should be tested in XP as well.

I'm not 100% sure (or even 5% sure) that setting a blank "GlobalFlag"="" completely prevents debug heaps from being used if a debugger is attached, but it does at least seem to prevent Peb->ProcessHeap.ForceFlags from being set. It would take a slightly deeper look at ntdll!LdrInitializeThunk to be sure there wouldn't be any clues left of debug heap usage.

Kayaker

goggles99
July 24th, 2006, 17:21
Thanks Kayaker,
But how do you set/reset the "GlobalFlag" before a single heap is allocated by the target process? (from ring-3) if you start a process as suspended, or wait for the first debugBreak, ther are already heaps that have been created (debug heaps) how can this be prevented?

I think that the "ForceFlags" cannot be changed after the process has created any heaps. The reason is that different API are used to access/release them. If you just switched it after they were created, you'd end up with a "heap of corruption"

RtlDebugCreateHeap
RtlDebugDestroyHeap
RtlDebugAllocateHeap
RtlDebugFreeHeap
RtlDebugSizeHeap
RtlDebugZeroHeap
...

debug counter-parts to

RtlCreateHeap
RtlDestroyHeap
RtlAllocateHeap
RtlFreeHeap
RtlSizeHeap
RtlZeroHeap
...

Thanks

blabberer
July 27th, 2006, 02:23
setting forceflags by changing peb->processheaps will only fool those who try to look explicitly at that flag

it doesnot modify the existing heaps that were either created before or
those that are created after

if you see the windbgs paste i posted you will see
that 140000 is a heap that was created earlier (alive and kicking when you get to the first systembreakboint (ntdll.DbgBreakPoint)

and other heaps just use the flags that were set earlier in that heap

btw if you do a local kernel debugging with /debug enabled via editing boot.ini
or with bootcfg.exe /Debug on /ID ## and reboot

the heaps doesnt seem to have these flags set looks like local kernel debugging doesnt create Debugheaps