Contribute  :  Web Resources  :  Past Polls  :  Site Statistics  :  Downloads  :  Forum  
    BiW ReversingThe challenge is yours    
 Welcome to BiW Reversing
 Friday, April 03 2020 @ 07:58 AM CEST

Manually Skinning Armadillo 2.61



*** Armadillo – MANUALLY skinning the mutant ***

***** ***** by crUsAdEr ***** ****

This tutorial aims to discuss about Armadillo 2.61 protection and how to MANUALLY remove the armadillo protection layer! Hopefully this will demonstrate some manual unpacking techniques that have been forgotten as crackers get more and more dependent on tools.

TOOLS used :
IDA 4.15
Soft Ice on Win2k SP3
LordPE Deluxe

Targets : Get Right 5.0 beta 1


Armadillo 2.61 just released with a few new features that make it slightly more interesting to reverse. The fact that Armadillo debugs its own protected program make it harder for us, crackers to debug the target but the good side is that Armadillo code is not obfuscated or encrypted in anyway so we can disassemble the protection layer and study it in IDA.

i)All code snippets in this tutorial are taken from IDA disassembly, beside the IAT redirection part, code snippets in other parts of this tutorial can be found at the same address in IDA if you can obtain the same version of “getright.exe” file.

ii) Throughout this essay, I used variable names like “d ebp+someName” to make it easier for readers to follow, when you are in sice, you have to type out the actual value, for example “d enp+FFFFFAE0”.

iii)Armadillo protected programs starts 2 process, the protecting layer debugs the protected target so I shall refer to the debugger as “server” and the debugee as “client”.

iv) Also note that IAT redirection on WIN9x is different from winNT/2k/XP so this essay only discuss IAT redirection on win2k though you can find the redirection routine on win9x in a similar way!

(Finally, please READ those threads in Fravia board about Armadillo protection and also make SURE you have a solid understanding of PE format as it is essential to rebuild a working PE image!)

1. Defeating copy-mem II

OK, I hope you have already known what copy-mem II is and what it does. Standard routine, to find OEP do "bpx SetProcessWorkingSetSize"
Once sice break, check it that sice is in Get Right context, if not then press F5 till sice breaks in Get Right context. Then press F12 and trace with F10 for a few instructions till you see a "call edi", stop there and note down the value of edi. That is OEP. Remove all breakpoint and "bpx WriteProcessMemory". Press F5, once sice breaks press F12 twice you will be at the usual decrypting routine of Armadillo that you have seen in previous version of Armadillo.

005E03FF 6A 00                       push 0                  ; flag to indicate Decrypt if 0
                                                             ; if flag is 1 then encrypt
005E0401 8B 4D 0C                    mov ecx, [ebp+key_address]
005E0404 51                          push ecx
005E0405 8B 55 08                    mov edx, [ebp+block_no]
005E0408 52                          push edx
005E0409 E8 76 01 00 00              call Decrypt_Encrypt
005E040E 83 C4 0C                    add esp, 0Ch    ; YOU SHOULD LAND HERE!!!!

Try looping around these instructions to force it to decrypt all code section and you will get garbage because now each memory block of 1000h bytes has a diff decrypt key. So we will have to find the decrypt key generation routine.
Trace a bit more down you will see this :

0044E421 A1 88 9A 45 00              mov eax, ds:block_count 
0044E426 83 C0 01                    add eax, 1                      ; increment decrypted memory block
0044E429 A3 88 9A 45 00              mov ds:block_count, eax         ; in process counter
0044E470                             mov edx, ds:block_count         ; compare number if decrypted blocks
0044E476 3B 15 70 66 45 00           cmp edx, ds:max_number_of_decrypted_block ; with maximum no. allowed
0044E47C 0F 8E FA 00 00 00           jle ok                    

As you can guess, Armadillo store number of memory block already decrypted to make sure that not all blocks are decrypted in memory at anytime. If you do a “bpm max_number_of_decrypted_block” you will see that Armadillo calculates this value from text code section size divide by 1000h (number of memory blocks) then divide by 2. Here we now have 2 ways, patch the jump to make sure it always jump or we can change the value at ds:max_number_of_decrypted_block to 1000h, something big!!!!
Once done, press F12 we will be in the middle of Debug loop of the Armadillo "server".

0044D697                         LOOP:                         ; Start looping here to force 
0044D697 8B 8D 2C FA FF FF           mov ecx, [ebp+mem_block]  ; decrypt the whole code section
0044D69D 3B 0D 84 9A 45 00           cmp ecx, ds:text_section_size
0044D6A3 0F 8D C7 00 00 00           jge continue_1         ;change to "jmp eip", infinite loop when finished
0044D6A9 8B 95 9C FA FF FF           mov edx, [ebp+trap_flag_not_set_flag]
0044D6AF 81 E2 FF 00 00 00           and edx, 0FFh           ;armadillo set trap flag at the beginning of
0044D6B5 85 D2                       test edx, edx           ;its debug loop to check if it is being traced
0044D6B7 0F 84 A9 00 00 00           jz  continue_ok         ; and it is checking for the flag now!
0044D6BD 6A 00                       push 0                    ; instruct to decrypt code
0044D6BF 8B B5 2C FA FF FF           mov esi, [ebp+mem_block]
0044D6C5 C1 E6 04                    shl esi, 4                      ; 
0044D6C8 8B 85 2C FA FF FF           mov eax, [ebp+mem_block]
                                      ; Decrypt key Generation
0044D73F 83 E7 0F                    and edi, 0Fh                    ; codes removed but u can refer to IDA
0044D742 03 F7                       add esi, edi                    ; disassembly
0044D744 8B 15 74 9A 45 00           mov edx, ds:key_address_table
0044D74A 8D 04 B2                    lea eax, [edx+esi*4]
0044D74D 50                          push eax
0044D74E 8B 8D 2C FA FF FF           mov ecx, [ebp+mem_block]
0044D754 51                          push ecx
0044D755 E8 86 0B 00 00              call Decrypt_codes        ; push crypt_flag
0044D755                                                       ; push key_add
0044D755                                                       ; push memaddress
0044D75A 83 C4 0C                    add esp, 0Ch            ;YOU SHOULD LAND HERE!!!!
0044D75D 25 FF 00 00 00              and eax, 0FFh
0044D762 85 C0                       test eax, eax             ; here patch to increment the mem block
0044D762                                                       ; value to force decrypting the next block
0044D764 74 0A                       jz  short bad_jump            ; then jump to LOOP0067B0E8                   

Now we can see how Armadillo generates keys for each memory block and passed it to the Decrypt_codes routine. Also, we can understand why Armadillo exit silently if we single step on the "server-debugger" code. Here, we shall make the big loop containing the key generation routine to force armadillo decrypt the whole code section. At address 44D75D do

a eip
inc dword ptr [ebp+mem_block]
jmp LOOP:44D697

Then we edit the value at "ebp+mem_block" to 0 (tell Armadillo to start decrypting from first memory block), and set the end point at 44D6A3 by changing the instruction there to "jge 46D6A3". Here Armadillo is checking if the mem block is above the code section, we simply put an infinite loop there. Let the program runs on, wait a while and then fire up LordPE to make a full image dump. If LordPE reports "Can't grab memory" then you probably did something wrong and Armadillo hasn’t fully decrypted the code section. Once this is done, we can proceed to rebuild IAT.

2. Rebuild Import data

Open the packed file with LordPE and study the section header, you will notice import data should be in section .idata! Why? Because the name already say it... and you can also double check by open the file in Hex Workshop and go to that section offset, you will see scattering words like "kernel32.dll" and "user32.dll" etc... Import data should be there!

Our task is to find the API redirection routine, study it and based on this routine to rebuild our Import.

To find the IAT redirection routine, use "addr" command of sice to get into the context of the protected (client) program then
bpm IAT_address W (Once break, disable this breakpoint)
bpx GetProcAddress (Once break, disable this breakpoint)
F12 twice and we should be here now

10006622 39 3D E8 C7 01 10           cmp dll_handle_table, edi ; check if pointer is 0 because edi = 0 here
10006628 B8 E8 C7 01 10              mov eax, offset dll_handle_table        ; here is the Table listing
1000662D 74 0C                       jz  short no_special_IAT                ; special DLL and their handles
1000662F                                                             ; the APIs in these DLL will be redirected
1000662F                         loop:                         
1000662F 3B 48 08                    cmp ecx, [eax+8]          ; is dll handle same as handle listed
10006632 74 1B                       jz  short special_dll     
10006634 83 C0 0C                    add eax, 0Ch              ; next dll on the table
10006637 39 38                       cmp [eax], edi
10006639 75 F4                       jnz short loop            
1000663B                         no_special_IAT:               ; Get API address normally, no redirection!!!
1000663B                             push dword ptr [ebp+0Ch]  ; lpProcName
1000663E FF 75 08                    push [ebp+dll_handle]     ; int
10006641 E8 41 00 00 00              call GetProcAddr
10006646 59                          pop ecx                 WE SHOULD LAND HERE!!!!
10006647 59                          pop ecx
1000664F                         ; ---------------------------------------------------------------------------
1000664F                         special_dll:                 
1000664F 8B 40 04                    mov eax, [eax+4]          ; get Special IAT table
10006652 3B C7                       cmp eax, edi              ; if eax = 0
10006654 74 E5                       jz  short no_special_IAT
10006656 39 78 08                    cmp [eax+8], edi
10006659 8B F0                       mov esi, eax              ; esi points to start of special API
1000665B 74 DE                       jz  short no_special_IAT  ; name table… these APIs will be redirected
1000665D                         API_name_check_loop:         
1000665D 66 3B DF                    cmp bx, di
10006660 74 06                       jz  short loc_10006668
10006662 66 3B 5E 04                 cmp bx, [esi+4]
10006666 EB 0E                       jmp short loc_10006676
10006668                         loc_10006668:                
10006668 FF 36                       push dword ptr [esi]    ; The API name in special API table
1000666A FF 75 0C                    push dword ptr [ebp+0Ch]        ; our API name
1000666D E8 8E 2B 01 00              call StringCompare
10006672 59                          pop ecx
10006673 59                          pop ecx
10006674 85 C0                       test eax, eax           ; if API name is found on the table
10006676                                                     ; jump to Redirect_API_now
10006676                         loc_10006676:                
10006676 74 0A                       jz  short Redirect_API_now    
10006678 83 C6 10                    add esi, 10h            ; if not, update pointer on table to next API
1000667B 39 7E 08                    cmp [esi+8], edi        ; Is there anymore API on the table?
1000667E 75 DD                       jnz short API_name_check_loop ; if Yes then loop back to check this API
10006680 EB B9                       jmp short no_special_IAT        ; else go ahead and find API address normally
10006682                         ; ---------------------------------------------------------------------------
10006682                         Redirect_API_now:               
10006682 8B 46 08                    mov eax, [esi+8]          ; eax = redirected API address
10006685 EB C1                       jmp short end_routine00A4A496                   load_next_dl_import:               

The dll_handle_Table looks like this :

1001C7E8 18 C8 01 10                 dd offset strKernel32_dll ; "kernel32.dll"
1001C7EC A8 C4 01 10                 dd offset kernel32_API_table
1001C7F0 00 00 00 00             kernel32_handle dd 0      
1001C7F4 0C C8 01 10                 dd offset strUser32_dll   ; "user32.dll"
1001C7F8 C8 C7 01 10                 dd offset User32_API_table
1001C7FC 00 00 00 00             User32_handle dd 0

The kernel32_API_table looks like this :

1001C4A8 1C CB 01 10                 dd offset strExitprocess ; "ExitProcess"
1001C4AC 00 00 00 00                 dd 0
1001C4B0 77 6C 00 10                 dd offset Fake_ExitProcess      ; if string compare is same, this 
1001C4B4 00 00 00 00                 dd ExitProcess_Address          ; Fake_ExitProcess routine is used!!!
1001C4B8 08 CB 01 10                 dd offset strTerminateprocess ; "TerminateProcess"
1001C4BC 00 00 00 00                 dd 0
1001C4C0 CA 6C 00 10                 dd offset Fake_TerminateProcess
1001C4C4 00 00 00 00                 dd TerminateProcess_Address
1001C4C8 FC CA 01 10                 dd offset strExitthread   ; "ExitThread"
1001C4CC 00 00 00 00                 dd 0
1001C4D0 00 6D 00 10                 dd offset Fake_ExitThread
1001C4D4 00 00 00 00                 dd ExitThread_Address

The User32_API_table looks similar of course!

At this point, if you are lazy, you can simply patch the program to jump over the dll_handle_table scanning part, then our IAT will never be redirected and we can simply run Imprec or Revirgin on the running process to re-build IAT... BUT we are doing everything manually aren’t we :)? So let's trace on. If you press F12 one more time, you will be in the middle Import loading loop,

10010DED FF B5 70 FD FF FF           push [ebp+API_name]
10010DF3 FF B5 94 FD FF FF           push [ebp+dll_handle]
10010DF9 E8 FA 57 FF FF              call Get_API_address
10010DFE 89 85 78 FD FF FF           mov [ebp+API_add], eax  WE SHOULD LAND HERE!!!!
10010E04 83 BD 78 FD FF FF 00        cmp [ebp+API_add], 0
10010E0B 75 38                       jnz short API_add_found
10010E45                       API_add_found :
10010E45 8B 85 80 FD FF FF           mov eax, [ebp+IAT_add]
10010E4B 8B 8D 78 FD FF FF           mov ecx, [ebp+API_add]
10010E51 89 08                       mov [eax], ecx          HERE is where first thunk is updated!!!
10010E53 8B 85 80 FD FF FF           mov eax, [ebp+IAT_add]
10010E59 83 C0 04                    add eax, 4
10010E5C 89 85 80 FD FF FF           mov [ebp+IAT_add], eax

My comments already say it all, put a breakpoint on the Call Get_API_Address then trace around the loop to get the hang of it. Then you will see [ebp+API_name] store the pointer to Import ASCIIs and follow this pointer, you will see a long list of API and DLL names… WOW is this our Import ASCII :)? Make a dump of the whole Table and you will see the dump looking like this :


Study this table we'll see that it start with a DLL name, then the RVA of first thunk corresponding with that DLL, then the number of Import from that DLL and list of all Imports ASCII from that DLL. For example, WIMM.dll first thunk start at 001D519C, (remember reversed order of bytes) and there is one import form this DLL which is PlaySoundA. Kernel32.dll first thunk starts at 1D4B74 and there are 9Fh Imports from kernel32.dll...etc

Moreover if you take a look at the first thunk, by "d eax" when you are at instruction 10010E51 you will notice that the First Thunk is untouched by Armadillo! Which means that we know the original location of ASCII entries of API, however take a look at those location and we see only zeros :( Import ASCII are deleted but hey at least we know where each entry of Import ASCII should be stored.

So now what do we have to do? We need to rebuild Import Table, in other words copy Import ASCII to location where they should be. Time for some patching on the fly! Set a break point "bpm 10010DF3 x" then restart the program. Once it break,

a eip
mov ecx, [ebp+IAT_add] ; get the RVA of Import ASCII
add ecx, 400002h ; calculate VA of Import ASCII by adding image base and 2 is size of HINT
push ecx
call lstrcpy
jmp API_add_found

Yep, I hope you understand what the little inline patch codes do. The next task is stopping Armadillo from destroying our First Thunk, simply NOP the instruction at 10010E51. Finally, press F12 and let Armadillo rebuilt IAT for you :>... once sice break again dump the whole .idata segment.

Of course you will notice that the Import Directory is missing so it is your task to rebuild this directory. I shall leave as an exercise for readers. If you are wondering about Import by ordinal because we can’t copy the Import ASCII like import by name case, don’t worry! Import by ordinal is handled separately by Armadillo (if you scroll up code window in sice for one or two pages, you will see that “Call Get_API_address” is called there as well to handle ordinal cases. However, as I have said, our First Thunk is intact so Ordinals are already stored in First Thunk and as long as we NOP the instruction at 10010E51, our Import by ordinals are preserved!

Note : Another more generic approach would be coding a small utility that reads the Import ASCII dump and insert Import ASCII into our exe dump file and rebuild the Import Directory. This would be usable on all current Armadillo target!!!

3. New int3 tricks

Run the exe now and BOOM, you will get a big message from Windows saying int3 occurs and is not handled. that is the newest trick of Armadillo to prevent dumping. Time to get into sice and IDA to trace again, just look through the Debug loop of the "server" and you will see the int3 handling routine.

0044DAAC 8B 85 38 FA FF FF           mov eax, [ebp+lpDebugEvent]
0044DAB2 81 78 0C 03 00 00 80        cmp dword ptr [eax+0Ch], 80000003h ; ç INT 3 exception code
0044DAB9 0F 85 96 03 00 00           jnz loc_44DE55
0044DABF                         INT3_occur:     
0044DABF 33 C9                       xor ecx, ecx
0044DAC1 8A 0D 6E 9A 45 00           mov cl, ds:int3_feature_installed

Here begins our quest to kill int3. Start tracing from this point, you will see that the "server" reads a block of data from the "client" memory space and divide this into 4 tables and then decrypt this 4 tables into 4 separate virtually allocated memory space. Then the "server" use GetThreadContext to check for location of eip of the "client". This eip is one byte after the location int3 exception occurs! Trace on and we'll see that armadillo performs binary search on Table_1 to find the position of eip. Once eip location in Table_1 found, we are here :

005DFDD5 8D 95 28 F7 FF FF           lea edx, [ebp+Context]
005DFDDB 52                          push edx
005DFDDC A1 58 BA 5E 00              mov eax, ds:table_2
005DFDE1 03 85 20 F7 FF FF           add eax, [ebp+relative_location] ; location in table_1 where eip is found
005DFDE7 8A 08                       mov cl, [eax]
005DFDE9 51                          push ecx
005DFDEA E8 24 12 00 00              call Get_Jump_Type              ; determine which kind of Jump it is
005DFDEF 83 C4 08                    add esp, 8
005DFDF2 25 FF 00 00 00              and eax, 0FFh
005DFDF7 85 C0                       test eax, eax
005DFDF9 74 1C                       jz  short it_is_NOT_a_jump              ;if al = 1 then it is a jump
005DFDFB 8B 95 20 F7 FF FF           mov edx, [ebp+relative_location]        ; if al = 0 then it is not a jump
005DFE01 A1 48 BA 5E 00              mov eax, ds:Table_4
005DFE06 8B 8D E0 F7 FF FF           mov ecx, [ebp+Context.Eip]; add eip with corresponding value in Table_3
005DFE0C 03 0C 90                    add ecx, [eax+edx*4]    ;      relative location = location of eip
005DFE0F 89 8D E0 F7 FF FF           mov [ebp+Context.Eip], ecx ;      in Table 1
005DFE15 EB 1E                       jmp short Update_eip
005DFE17                         ; ---------------------------------------------------------------------------
005DFE17                         it_is_NOT_a_jump:                  
005DFE17 8B 15 5C BA 5E 00           mov edx, ds:Table_3
005DFE1D 03 95 20 F7 FF FF           add edx, [ebp+relative_location] ;set edx to corresponding value in Table_4
005DFE23 33 C0                       xor eax, eax
005DFE25 8A 02                       mov al, [edx]                   ; get distance eip to be moved by
005DFE27 8B 8D E0 F7 FF FF           mov ecx, [ebp+Context.Eip]
005DFE2D 03 C8                       add ecx, eax
005DFE2F 89 8D E0 F7 FF FF           mov [ebp+Context.Eip], ecx              ; update eip
005DFE35                         Update_eip:                  
005DFE35 8D 95 28 F7 FF FF           lea edx, [ebp+Context]
005DFE3B 52                          push edx                  ; lpContext
005DFE3C 8B 85 F4 F9 FF FF           mov eax, [ebp+hThread]
005DFE42 50                          push eax                  ; hThread
005DFE43 FF 15 80 80 5E 00           call ds:SetThreadContext  ; SetThreadContext: 

Basically, Armadillo has replaced some of the jumps (conditional & unconditional) in the original exe with int3 and generate these 4 tables storing information about position, distances of all these jumps. All done during packing time. As you can see, when and int3 occurs in the "client" process, the "server" will check for eip where int3 occurs, look it up in Table_1, once found, the "server" will check corresponding value in table_2 which is what kind of Jump it is at this eip. Then "the server" will check eflags register on “client” context (inside the call Get_Jump_type" routine) to see if the "client" should jump or not. If jump then the "client" eip will be moved by a corresponding value in Table_4 (jump distance), if not then the "client" eip will be moved by a corresponding value in table_3 (length of jump instruction). Take a look into the Get_Jump_Type routine.

005E1046                         jump type 9:                       
005E1046 B0 01                       mov al, 1          ;al always 1 => always jump no matter what
005E1048 E9 AF 01 00 00              jmp end         ;==>> JMP
005E104D                         jump type E:                      
005E104D 8B 55 0C                    mov edx, [ebp+context]
005E1050 8B 82 C0 00 00 00           mov eax, [edx+0C0h]     ; get eflags register
005E1056 83 E0 41                    and eax, 41h            ; check Zero and Carry flag
005E1059 F7 D8                       neg eax                 ; eax is negative if either flag set
005E105B 1B C0                       sbb eax, eax            ; eax = -1 if either flag is set
                                                             ; eax = 0 if neither flag is set
005E105D 40                          inc eax                 ; al = 1 when neither flag set
005E105E E9 99 01 00 00              jmp loc_5E11FC            ; ==> jump when CF=0 and ZF=0 => JA
005E108C                         jump type 4:                       ; CODE XREF: Get_Jump_Type+2Cj
005E108C 8B 55 0C                    mov edx, [ebp+context]
005E108F 8B 82 C0 00 00 00           mov eax, [edx+0C0h]     ; get eflags register
005E1095 25 80 00 00 00              and eax, 80h            ; check Sign Flag
005E109A F7 D8                       neg eax
005E109C 1B C0                       sbb eax, eax
005E109E 40                          inc eax                 ; eax = 0 is S flag set, else eax = 1
005E109F 8B 4D 0C                    mov ecx, [ebp+context]
005E10A2 8B 91 C0 00 00 00           mov edx, [ecx+0C0h]     ; get eflags
005E10A8 81 E2 00 08 00 00           and edx, 800h           ; check Overflow flag
005E10AE F7 DA                       neg edx
005E10B0 1B D2                       sbb edx, edx
005E10B2 42                          inc edx                 ; edx = 0 if O flag set, else edx = 1
005E10B3 33 C9                       xor ecx, ecx
005E10B5 3B C2                       cmp eax, edx            ; compare eax with edx
005E10B7 0F 95 C1                    setnz cl                ; al = 1 if not equal
005E10BA 8A C1                       mov al, cl
005E10BC E9 3B 01 00 00              jmp end                   ; jump if SF != OF  ==>> JL

Yep, all together there are 11h type of jump. Finally, it is out task to fix those int3 so I coded a small utility to scan through Table_1, check each virtual address entry in table_1 with our dump, if the opcode is "CC" then it is out int3, check the corresponding value in Table_2 to determine what kind of jump it is (JNZ or JZ or JMP etc). Then it check table_3 to see how long the jump instruction should be and assign write the correct jump opcodes into our exe dump. Finally, it check the corresponding value in Table_4 which is the distance how far the jump is and update the value in the exe again. Thus, run the protected program, dump the for tables into 4 separate files, (make sure that Table_1 size is same as table_4 size and is 4 times the table_2 and 3 size. Why?). I have attached the masm source code of this little program for your reference.

4. The Final Touch

After fixing int3, the dump still refused to run, exiting with some stupid beeping noise. This got me baffled for a while... tracing doesn’t seem to get me anywhere, double check my int3 patching routine, double check IAT... everything seems fine. I was at my wits end when I decide, hey the Beep sound doesn’t come out when I run the original exe, voila, bpx MessageBeep then press F12 we land here...

00438E03 68 C4 0E 5C 00              push offset strDellatsnisyad ; "DELLATSNISYAD" 
00438E08 8D 4D E4                    lea ecx, [ebp-1Ch]
00438E0B 89 46 6C                    mov [esi+6Ch], eax
00438E0E E8 F4 42 10 00              call ??4CString@@QAEABV0@PBD@Z ; CString::operator=(char const *)
00438E13 8D 4D E4                    lea ecx, [ebp-1Ch]
00438E16 E8 91 46 10 00              call ?MakeReverse@CString@@QAEXXZ ; The name says it all :>
00438E1B 8B 7D E4                    mov edi, [ebp-1Ch]
00438E1E B8 FF 00 00 00              mov eax, 0FFh
00438E23 50                          push eax                  ; nSize
00438E24 50                          push eax
00438E25 8D 4D E8                    lea ecx, [ebp-18h]
00438E28 E8 84 45 10 00              call ?GetBuffer@CString@@QAEPADH@Z ; CString::GetBuffer(int)
00438E2D 50                          push eax                  ; lpBuffer
00438E2E 57                          push edi                  ; lpName
00438E2F FF 15 8C 4C 5D 00           call ds:GetEnvironmentVariableA ; GetEnvironmentVariableA: 
00438E35 85 C0                       test eax, eax           ; check how many days installed :)?
00438E37 6A FF                       push 0FFFFFFFFh
00438E39 8D 4D E8                    lea ecx, [ebp-18h]
00438E3C 75 36                       jnz short GOOD_JUMP     ; if variable not found, BEEP n exit
00438E3E E8 BD 45 10 00              call ?ReleaseBuffer@CString@@QAEXH@Z ; CString::ReleaseBuffer(int)
00438E43 6A 01                       push 1                    ; uType
00438E45 FF 15 64 50 5D 00           call ds:MessageBeep       ; MessageBeep: 
00438E4B 53                          push ebx                  ; 

SO our task is to patch the conditional jump at 438E3C to JMP... play around with the program, like try resuming a download you will received a another beep :

Here is summary of all the patches

438E3C  75               DAYSINSTALLED
4720EE  75               DAYSINSTALLED
4E6B7F  75               ALTUSERNAME               

Now Get Right runs like a baby :>... though I find the downloading really slow. Personally I don’t recommend you to use this download manager :>, so once you crack it uninstall it immediately!

5. The end

That is it, phew. What a long tutorial! I hope you find it useful. I tried my best to explain things but I realise I can’t explain everything in details or else the tutorial will be too long for anyone to bother read it. So if there is any part that you find unclear, drop me a message on fravia board and I will make the appropriate changes.

For the enthusiasts: If you notice that the IAT redirection routine is in some unknown memory space, you can try scrolling up to the beginning of this memory section and you will find a PE header! Check out the image size in the header, put a bpm at the end of the image (to make sure the whole image is loaded in memory) then re-run Get Right, once sice breaks, check that image is fully loaded in memory… dump it and rename it as “arma.dll” you will get a virgin dll that export functions like "LoadProgramInfo", "NukeNow", "CheckNetLicense", "ArmAccess" and "RunUserProgram". Promising enough :>???


This tutorial would not have been possible without the help of all people on Fravia Message Board. So greetz fly out to all my friends on Fravia board and on mirc.

Special greetz to Woody and March^drn (get well soon :)

Last Edited : 7 Nov 2002



What's Related

Story Options

Manually Skinning Armadillo 2.61 | 0 comments | Create New Account
The following comments are owned by whomever posted them. This site is not responsible for what they say.
 Copyright © 2020 BiW Reversing
 All trademarks and copyrights on this page are owned by their respective owners.
Powered By Geeklog 
Created this page in 0.73 seconds