• Welcome to Valhalla Legends Archive.
 

How to get around GetProcessHeap in dllmain

Started by warz, November 13, 2006, 07:34 PM

Previous topic - Next topic

warz

I've encountered a problem while implementing my own call to checkrevision. There's a loop within the function, infact, the loop looks like so (with some of my commenting)....


.text:0040165B CheckFilesLoop:                         ; CODE XREF: CheckRevision+F1j
.text:0040165B                 mov     eax, [esi]      ; Loop 1 - EAX becomes base addr of lockdown
.text:0040165B                                         ; Loop 2 - EAX becomes base addr of starcraft.exe
.text:0040165B                                         ; Loop 3 - EAX becomes base addr of storm.dll
.text:0040165B                                         ; Loop 4 - EAX becomes base addr of battle.snp
.text:0040165B                                         ; Loop 5 - EAX becomes base addr of pplug114 (0 for now)
.text:0040165B                                         ;
.text:0040165D                 cmp     eax, ebx        ; EBX = 0
.text:0040165F                 jz      short loc_401670 ; Jump if no base addr (loop 5 we jump)
.text:0040165F                                         ;
.text:00401661                 push    eax             ; Loop 1 - Push lockdown base addr
.text:00401661                                         ; Loop 2 - Push sc.exe base addr
.text:00401661                                         ; Loop 3 - Push storm base addr
.text:00401661                                         ; Loop 4 - Push battle base addr
.text:00401662                 lea     eax, [ebp+var_108]
.text:00401668                 push    eax             ; Loop 1 - Push ptr to value (00000200)
.text:00401668                                         ; Loop 2 - Push ptr to modified value (00332200)
.text:00401668                                         ; Loop 3 - Push ptr to modified value (01782200)
.text:00401668                                         ; Loop 4 - Push ptr to modified value (01AC2200)
.text:00401668                                         ;
.text:00401669                 call    BeginExeCheck   ; The value 200h pointed to by arg1 is replaced
.text:00401669                                         ; by 32200h after call. EAX holds 1 on success.
.text:00401669                                         ; EDX holds 150608h, which points to 00 C5 97 7C.
.text:00401669                                         ; Produces a SHA1 digest at arg2+8, and extends
.text:00401669                                         ; recursively past.
.text:0040166E                 pop     ecx
.text:0040166F                 pop     ecx             ; Loop 1 - ECX holds lockdown base addr again
.text:0040166F                                         ; Loop 2 - ECX holds sc.exe base addr again
.text:0040166F                                         ; Loop 3 - ECX holds storm base addr again
.text:0040166F                                         ; Loop 4 - ECX holds battle base addr again
.text:00401670
.text:00401670 loc_401670:                             ; CODE XREF: CheckRevision+CEj
.text:00401670                 add     edi, 4          ; Loop 1 - EDI is 0, and ends up being 4
.text:00401670                                         ; Loop 2 - EDI is 4, and ends up being 8
.text:00401670                                         ; Loop 3 - EDI is 8, and ends up being C
.text:00401670                                         ; Loop 4 - EDI is C, and ends up being 10
.text:00401670                                         ; Loop 5 - EDI is 10, and ends up being 14
.text:00401670                                         ;
.text:00401673                 mov     eax, edi        ; Loop 1 - EAX = 4
.text:00401673                                         ; Loop 2 - EAX = 8
.text:00401673                                         ; Loop 3 - EAX = C
.text:00401673                                         ; Loop 4 - EAX = 10
.text:00401673                                         ; Loop 5 - EAX = 14
.text:00401673                                         ;
.text:00401675                 sar     eax, 2          ; Loop 1 - EAX becomes 1
.text:00401675                                         ; Loop 2 - EAX becomes 2
.text:00401675                                         ; Loop 3 - EAX becomes 3
.text:00401675                                         ; Loop 4 - EAX becomes 4
.text:00401675                                         ; Loop 5 - EAX becomes 5
.text:00401675                                         ;
.text:00401678                 add     esi, 4          ; Loop 1 - ESI becomes 038C4004
.text:00401678                                         ; Loop 2 - ESI becomes 038C4008
.text:00401678                                         ; Loop 3 - ESI becomes 038C400C
.text:00401678                                         ; Loop 4 - ESI becomes 038C4010
.text:00401678                                         ; Loop 5 - ESI becomes 038C4014
.text:00401678                                         ;
.text:0040167B                 cmp     ds:off_4030B8[eax*4], ebx ; Loop 1 - Check for sc.exe base addr
.text:0040167B                                         ; Loop 2 - Check for storm base addr
.text:0040167B                                         ; Loop 3 - Check for battle base addr
.text:0040167B                                         ; Loop 4 - Check for pplug114 base addr
.text:0040167B                                         ; Loop 5 - No more files to check
.text:0040167B                                         ;
.text:00401682                 jnz     short CheckFilesLoop ; Loop 1 - Jump is taken
.text:00401682                                         ; Loop 2 - Jump is taken
.text:00401682                                         ; Loop 3 - Jump is taken
.text:00401682                                         ; Loop 4 - Jump is taken
.text:00401682                                         ; Loop 5 - Jump is not taken.. done!
.text:00401684


... this loop grabs pointers to the base addresses of the main game files from a global variable. The problem is, I think, is that checkrevision's dllmain function now calls GetProcessHeap, and stores it in a global hHeap variable. This is the variable that is read from when "; Loop 2 - EAX becomes base addr of starcraft.exe".

When my test application calls checkrevision, the ptr returned points to the same base address, but is not a ptr to sc.exe (like it should be). So, when this loops reads from the hHeap variable, it grabs a different value than it requires for success. Somewhere within the BeginExeCheck function I have there, there is a 20-byte (looks like SHA1, but havent found any calls to SHA1Update, so it must be loading the address of SHA1Update into a register and then calling it) result being produced. The only values passed to the function are the ptr to the game files base addr, and a ptr to a dword value being generated as this loop progresses. So I have reason to believe the resulting 20-byte value, as well as the dword value, are based on the address passed to the BeginExeCheck function. I should also note, that these values stay the same - provided the same 'value string' and same dll #.

My question is - is there any way to fool this loop into grabbing the base address of the loaded starcraft.exe, instead of my main application? One thing I had in mind was to manually edit that value in memory prior to calling checkrevision, and hook HeapAlloc, etc, to allocate proper space (they read from the hHeap variable created by dllmain), but this seems a little too much. It's also not very safe. Who knows where this variable is referenced.

I can't hook in the middle of this loop because there's no exported ordinal, and the addresses change from dll to dll. So, how to get this loop to read from sc.exe, instead of my calling test app?

warz

Looks like I was looking at the wrong data ptr. It's reading from ESI. ESI holds a ptr to the beginning of the data segment. The first few values in the data segment are our necessary pointers.