Flag: Tornado!
Hurricane!
|
|
Topic created on: September 10, 2007 14:35 CDT by lafkuku .
Well I'm still kind of new to reversing, been working on this stuff for about 6ish months. I ran into this anti-debugging trick in a crackme. The trick is posted on this site under the reference library. However it doesn�t give much information on why this works. Other than once it detects memory allocated and sees a library referenced it knows a debugger exists.
(link: http://www.openrce.org/reference_library/anti_reversing_view/33/Ring3%20Debugger%20Detection%20via%20LDR_MODULE/)
I've looked all over the net trying to find references to this to understand; with no luck (maybe I�m using the wrong keywords?). Specifically why the memory is allocated in the LDR_Module when a ring 3 debugger is present and why not when one isn�t. I was hoping someone could point in the right direction or explain it a little.
Also, any generic methodology on how a script might be written to bypass this trick would also be helpful (or a link to a resource explaining it). I can do it manually once located in the binary, however, I�m curious what the approach would be if you wanted to automate it.
John
Why don't you post the link to the crackme, and some of us can take a look.
|
> jms: Why don\'t you post the link to the crackme, and some of us can take a look.
Well the problem isnt in the crackme, I can get around the anti-debugging trick easily by setting flags etc. And the anti debugging trick is implemented exactly how the link in the reference section of this site describes it (under references->anti-reversing->ring 3 dection via LRD_Module)
I�m curious on how/why this particular type of anti-debugging trick works. More specifically why detection is possible due to the LDR_Module structure be initialized and why is it initialized during debugging and not when the target isn�t being debugged.
But for reference here is a snippet of the anti-debugging trick used in the crackme, which is virtually the same as the one I mentioned above except what happens after detection.
004010CD . 33F6 XOR ESI,ESI
004010CF . 57 PUSH EDI
004010D0 . 8BF9 MOV EDI,ECX
004010D2 . 8975 EC MOV DWORD PTR SS:[EBP-14],ESI
004010D5 . 8975 F0 MOV DWORD PTR SS:[EBP-10],ESI
004010D8 . 50 PUSH EAX
004010D9 . 64:A1 30000000 MOV EAX,DWORD PTR FS:[30] ;Grabs the PEB struct
004010DF 8B40 0C MOV EAX,DWORD PTR DS:[EAX+C] ;Goes to the PPEB_LDR_Data struct
004010E2 40 INC EAX ;linear search though address space 1 byte at a time
004010E3 FF45 F0 INC DWORD PTR SS:[EBP-10]
004010E6 . 817D F0 000500>CMP DWORD PTR SS:[EBP-10],500 ;if we checked 500 bytes and no lib found
004010ED 74 0F JE SHORT Crackme1.004010FE ;jump to passed code
004010EF . 8138 EEFEEEFE CMP DWORD PTR DS:[EAX],FEEEFEEE ;Checking for an initilized lib
004010F5 .^75 EB JNZ SHORT Crackme1.004010E2 ;jump to start of loop
004010F7 C745 EC 010000>MOV DWORD PTR SS:[EBP-14],1 ;if found set bool to true
004010FE > 58 POP EAX
004010FF . 3975 EC CMP DWORD PTR SS:[EBP-14],ESI ;esi = 0
00401102 . 74 21 JE SHORT Crackme1.00401125 ;jump to notBeingDebugged code or drop to fail and screw up the EIP, throwing AV exception
edit* added a comma and fixed a comment
|
Well it would be useful to have the binary, as I could script something in ImmunityDebugger that would show how to automagically bypass this. Email me @ jms @ bughunter.ca
|
Hi
I believe the trick is based on the difference in heap allocations between release and debug (or under a debugger) versions, and the call to RtlAllocateHeap when the PEB_LDR_DATA structure is created. A slightly larger heap allocation than requested is made, which includes the 0xFEEEFEEE at the end for whatever reason.
PEB_LDR_DATA is allocated in ntdll!LdrpInitializeProcess as can be seen in the following:
:7C921ABC _LdrpInitializeProcess@20 proc near ; CODE XREF: _LdrpInitialize(x,x,x)+88CE
...
:7C921B36 mov eax, large fs:18h ; TEB
:7C921B3C mov ebx, [eax+30h] ; PEB
:7C921B3F lea edi, [ebx+8] ; PEB.ImageBaseAddress
:7C921B42 push dword ptr [edi]
:7C921B44 call _RtlImageNtHeader@4 ; RtlImageNtHeader(x)
...
:7C921D7F xor esi, esi
...
:7C92202B push 28h
:7C92202D pop edi
:7C92202E push edi
:7C92202F add eax, 40000h
:7C922034 push eax
:7C922035 push _LdrpHeap
:7C92203B call _RtlAllocateHeap@12 ; RtlAllocateHeap(x,x,x)
:7C922040 cmp eax, esi
:7C922042 mov [ebx+0Ch], eax ; PEB_LDR_DATA allocated
:7C922045 jz loc_7C93E932
:7C92204B
:7C92204B loc_7C92204B: ; CODE XREF: LdrpInitializeProcess(x,x,x,x,x)+1CEAEj
:7C92204B mov eax, [ebx+0Ch]
:7C92204E mov [eax+_PEB_LDR_DATA.Length], edi
:7C922050 mov eax, [ebx+0Ch]
:7C922053 mov [eax+_PEB_LDR_DATA.Initialized], 1
:7C922057 mov eax, [ebx+0Ch]
:7C92205A mov [eax+_PEB_LDR_DATA.SsHandle], esi
:7C92205D mov eax, [ebx+0Ch]
:7C922060 mov [eax+_PEB_LDR_DATA.EntryInProgress], esi
:7C922063 mov eax, [ebx+0Ch]
:7C922066 add eax, 0Ch
:7C922069 mov [eax+LIST_ENTRY.Blink], eax ; PEB_LDR_DATA.InLoadOrderModuleList
:7C92206C mov [eax+LIST_ENTRY.Flink], eax
:7C92206E mov eax, [ebx+0Ch]
:7C922071 add eax, 14h
:7C922074 mov [eax+LIST_ENTRY.Blink], eax ; PEB_LDR_DATA.InMemoryOrderModuleList
:7C922077 mov [eax+LIST_ENTRY.Flink], eax
:7C922079 mov eax, [ebx+0Ch]
:7C92207C add eax, 1Ch
:7C92207F mov [eax+LIST_ENTRY.Blink], eax ; PEB_LDR_DATA.InInitializationOrderModuleList
:7C922082 mov [eax+LIST_ENTRY.Flink], eax
:7C922084 push dword ptr [ebx+8]
:7C922087 call _LdrpAllocateDataTableEntry@4 ; LdrpAllocateDataTableEntry(x)
...
If you trace into the PEB_LDR_DATA RtlAllocateHeap when a process is starting under a debugger you will see it call RtlDebugAllocateHeap. The 0xFEEEFEEE that the antidebug technique detects can be easily seen using Softice for example. Start notepad, Ctrl-D into Softice, change the address context to notepad and put a breakpoint on 7C92203B call _RtlAllocateHeap. Then start another instance of notepad under OllyDbg and it should break. Step over the mem allocation call and you can see the effect.
Kayaker
|
Thanks kayaker,
Thats what i kinda figure out after a few more hours of research into the area. I've written a small ID script which scans through and removes the FEEEFEEE added into the allocation. Could be better though, it's just something i put together to test this.
From what i gather the FEEEFEEE is added in order to allow the debugger keep track of the heap for the purpose of freeing (Could be completely wrong here). So I dont know if this method inadvertently adds a memory leak. But here is what i came up with, which seems to work with no errors.
If anyone else has any more insight into exactly what's up with the FEEEFEEE string let me know i'd be very thankful.
def ldrModDefeat(imm):
searchLong = 0xeefeeefe
ldrModPtr = imm.getPEBaddress() + 0x0c
ldrMod = imm.readLong(ldrModPtr)
i = 0
while i < 5000:
d = str2int32(imm.readMemory(ldrMod + i, 8))
i += 1
if d == searchLong:
imm.writeLong(ldrMod + i, 0x00000000)
|
After some googling...
Wikipedia article: "0xFEEEFEEE : Used by Microsoft's HeapFree() to mark freed heap memory"
Memory Debug Codes:
"Windows NT memory codes
0xABABABAB - Memory following a block allocated by LocalAlloc().
0xBAADF00D - "Bad Food". This is memory allocated via LocalAlloc( LMEM_FIXED, ... ). It is memory that has been allocated but not yet written to.
0xFEEEFEEE - OS fill heap memory, which was marked for usage, but wasn't allocated by HeapAlloc() or LocalAlloc(). Or that memory just has been freed by HeapFree()."
Win32 Debug CRT Heap Internals:
"HeapFree() will be called to return the block to the win32 heap. This causes the block to be overwritten with the win32 heap's "freed memory" pattern, which is 0xFEEEFEEE"
So it seems the case is that if the debugger is running, a special implementation of the heap allocation functions will be called, and that's what the trick checks for.
|
Another anti-debug test is to check NtGlobalFlags in the PEB to see if it equals 70h (FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS)
I have the feeling that FLG_HEAP_ENABLE_FREE_CHECK is strongly related to the usage of 0xFEEEFEEE. Haven't tested it myself tho.
In this nice article a couple of ways of overcoming the check are given.
|
Note: Registration is required to post to the forums.
|
|
|
There are 31,319 total registered users.
|
|