ARMADILLO


 

           ARMADILLO - Manually unpacking

 **** by Zilot ****

November 27, 2003


This tutorial should be appendix on Crusader's tutorial on Armadillo unpacking. This doesn't mean I have to add something on his observation because something was wrong there, not at all. When he wrote tut, there was version 2.60 of Armadillo, and in the mean time they improved a little bit protector, so there are several new things here, not covered by Crusader's tut . Second reason I wrote this is Olly Debugger Armadillo tuts invasion. Good looking pictures, with Olly screens shoots, may leave impression how Olly debugger becomes   better that Soft-Ice, and newbies will use rather it than SI, especially those who never did serious unpacking before. So Olly is not better, and Soft-Ice is absolute king in our profession. I hope next lines will convince readers in my claim. 


Tools used: 

 

Target :


Packer Improvements


 

 

 

New versions of Armadillo have some obfuscated part injected into code. This is done to avoid easy code analyses with disassemblers (IDA, Wdasm etc....). So if you see something like:

 

 

 

.text:005BFF74 9C pushf
.text:005BFF75 60 pusha
..................

..................
.text:005BFFA6 61 popa
.text:005BFFA7 9D popf

 

 

 

it means that. First registers are placed on stack, and some dumb jumps are executed, with registers altering all that time. After popf registers and flags are like before and execution is continued as usually. Conclusion is that this part serves to nothing, and is here to screw disassembler during code analyses. You can nop such parts (this can be done in memory, when SI breaks), just to be more readable. 

 

 


Defeating copy-mem II


 

 

 

This part is more or less similar to Crusader's explanation. Obfuscations made this part slightly difficult for analyzing. First of all we must find code where packer calls decryption, and after encryption. This can be done by WriteProcessMemory API intercepting (be carefully with breakpoint placing, because Armadillo will detect bpx break points on WriteProcessMemory, so the best way is to  break on GetVersion on the beginning, and to place bpmb  WriteProcessMemory x, immediately after GetVersion break). When you do that, wait on third WriteProcessMemory occurence, (first two times he writes something to process we are not interested). So on third occurence press F12, after that F12 again and you will see something like this:

 

 

 

.text:005C1563  6A 00                     push 0
.text:005C1565  8B 4D 0C               mov ecx, [ebp+0Ch]
.text:005C1568  51                           push ecx
.text:005C1569  8B 55 08                 mov edx, [ebp+8]
.text:005C156C  52                          push edx
.text:005C156D  E8 47 03 00 00      call loc_5C18B9
.text:005C1572   83 C4 0C              add esp, 0Ch      <====  AFTER F12 TWO TIMES YOU'LL FIND YOURSELF HERE   

 

 

 

On this place he is calling decryption/encryption (005C18B9) routine with parameters to do decryption. So this is decryption procedure. More difficult part is to find encryption procedure. As it is explained in Crusader's tut there is maximum of decrypted pages that Armadillo allows to be in memory, if number exceeds that critical value he will do their encryption. In this case during program loading that critical value will not be reached and that routine will not be executed. We must find that routine, because when we force packer to unpack all pages we will hit critical value and our job will fail. After some looking around I succeeded to find that that routine. To be honest I searched file by signature. Here is that encryption routine:

 

 

 


.text:005C17FA  8B 04 8A                         mov eax, [edx+ecx*4]
.text:005C17FD  99                                    cdq
.text:005C17FE   B9 1C 00 00 00               mov ecx, 1Ch
.text:005C1803   F7 F9                               idiv ecx
.text:005C1805   8B CA                              mov ecx, edx
.text:005C1807   D3 EF                              shr edi, cl
.text:005C1809   83 E7 0F                          and edi, 0Fh
.text:005C180C   03 F7                              add esi, edi
.text:005C180E   8B 15 44 C0 5E 00         mov edx, dword_5EC044
.text:005C1814   8D 04 B2                         lea eax, [edx+esi*4]
text:005C1817    50                                    push eax
.text:005C1818   8B 0D 58 C0 5E 00         mov ecx, dword_5EC058
.text:005C181E   8B 15 5C C0 5E 00         mov edx, dword_5EC05C
.text:005C1824   8B 04 8A                         mov eax, [edx+ecx*4]
.text:005C1827   50                                    push eax
.text:005C1828   E8 8C 00 00 00               call loc_5C18B9  <==== HERE HE CALLS DECRYPTION/ENCRYPTION ROUTINE
.text:005C182D  83 C4 0C                         add esp, 0Ch

 

 

 

On this place he is calling decryption/encryption (005C18B9) routine with parameters to do encryption. So this is encryption procedure. How to find it in the future if signature method fail. When you find decryption routine (in our case 005C1563) remember the address of decryption/encryption (005C18B9), put bpmb 005C18B9 x  if (*esp!=005C1572 ) after forcing protector to decrypt all pages. Why this ? on stack after reaching 005C18B9 is return address, because we want to know place where this routine is called because encryption, we must avoid every break because decryption. After breaking you'll see 005C182D (of course afterr dd esp). 

 

Now we must find why this call (005C1828) is executed at all. If you scroll up for a while you'll see this:

 

 

 

.text:005C16E2  8B 15 58 C0 5E 00        mov edx, dword_5EC058
.text:005C16E8  3B 15 94 66 5E 00         cmp edx,  dword_5E6694    
.text:005C16EE  0F 8E BC 01 00 00        jle loc_5C18B0

 

 

 

Here is magic place where Armadillo is checking for decrypted pages. Location dword_5E6694 comprise maximum of decrypted pages, and if current number is greater that allowed jle loc_5C18B0 will not be executed and we will have encryption. This location (005C16EE ) is essential in making loop. So you maus find this place and remember its address, if you fail in this step everything will go to hell. LordPe will not grab process memory. 

 

 

Now comes part with locating place to make infinite loop for whole client code decryption. I found it by searching code signatures. 

 


.text:005BF30E  8B 8D D8 F5 FF FF                  mov ecx, [ebp-0A28h]
.text:005BF314  3B 0D 54 C0 5E 00                   cmp ecx, dword_5EC054
.text:005BF31A  0F 8D 2F 02 00 00                   jge loc_5BF54F
.text:005BF320  8B 95 48 F6 FF FF                   mov edx, [ebp-9B8h]
.text:005BF326  81 E2 FF 00 00 00                    and edx, 0FFh
.text:005BF32C  85 D2                                       test edx, edx
.text:005BF32E  0F 84 AD 00 00 00                   jz loc_5BF3E1
...........................................................................................................

...........................................................................................................

...........................................................................................................
.text:005BF3C1  8D 04 B2                                  lea eax, [edx+esi*4]
.text:005BF3C4  50                                             push eax
.text:005BF3C5  8B 8D D8 F5 FF FF                 mov ecx, [ebp-0A28h]
.text:005BF3CB  51                                             push ecx
.text:005BF3CC  E8 62 1D 00 00                        call loc_5C1133
.text:005BF3D1  83 C4 0C                                  add esp, 0Ch
.text:005BF3D4  25 FF 00 00 00                         and eax, 0FFh

 

 

 

What is going on here is already  explained in Crusader tutorial. I'll clarify steps you must do after finding this place. Our start location is 005BF301, and our end location is 005BF3D4. First of all this is starting place of all your unpacking job. Everything I described above is to find critical places, to find it you'll use IDA, Soft-Ice, and will start and quit program several time. When you find all of this places you'll put bpx GetVersion in Soft-Ice, run program double clicking on desktop icon, break once on GetVersion to get into Trojan Remover context and do next:

 

 

 

Now you have to run LordPe. Do it and you'll find two same processes in process list. Look the bottom of  processes list, you'll se LordPe, and two of Trojan Remover processes. You have to dump younger one, because he is created after server process is started. If you get "Can't grab process memory" something went wrong, you have to repeat steps. 

 

Have one advice for you. Because locking process your comp might become very slow, so open Task Manager (Ctrl+Alt+Delete) and reduce both Trojan Remover processes priority to low. This will increase your comp speed. 

 

Have nothing more to add about dumping, this should be all. 

 

Good Luck !!!!!!!

 

 


Rebuild Import data


 

Nothing new here. First you have to find some API address used by client process, i.e ShowWindow. When client process (that what you see when program show his window) is opened put bpx ShowWindow and press for example help, or something that will show you window. When SI pops up instead pbx put bpmb eip x, so do bc*, and type bpmb eip x. After this SI will break again, but you will have calling address reference bc* again and put that calling address bpmb, so you'll do bpmb Calling_Address x. In that way SI will break next time on that calling address. When you are there (it is usually jmp [xxxxxxxx], or call [xxxxxxxx], you have to find xxxxxxxx address. Type code on and read instructon bytes in reverse order, and xxxxxxxx address will be infront of you. Then remember this address, and restart program, again break in Trojan Remover context with GetVersion, clear all break points (bc*), and type bpmb xxxxxxxx w, (xxxxxxxx is what you have remembered). And you'll break in IAT space updating. Trace a little bit, and will se what Crusader mentioned, there are 2 different APIs regular and redirected. I found condition for redirection was on E4B466. When you find this restart program and put bpmb E4B466 x when you are in Trojan Remover context. When SI breaks patch this jz with jmp. Be carefull there is CRC in high memory. There are two ways, leave to be caught on CRC, but when get screen about that don't close program, run ImpRec and rebuild IAT, all APIs should be resolved. There will be some redirections on boundaries between libraries, just cut them (show invalid thunks, and then press cut thunks in ImpRec), second approach to avoid CRC is to put bpmb Last_Writen_APIAddress w, and to wait SI to pop-up, after that you have to restore E4B466 instruction.

 

This is everything about IAT.

 

Good Luck !!!!!!!!!!!!

 

 


Nanomites


 

 

This is part where biggest changes has been accomplished since Crusader time. As in Crusader's case there are 4 tables for getting right jump. First of them is address table, second is jump type table, third is instructions length table, and forth is table of distances where to jump. But some of these tables are different.

 

Because all of this I recoded Crusader's utility for nanomite fixing. And add once more for jump distances decrypting. So there are 2 utilities together. Why two ?. Maybe the decryption way will be changed, so then you'll have to repair just that utility. 

 

How to find all those 5 tables (4 standard + key table). Put bpx on GetThreadContext. After break press F12, scroll down for a while and you'll see next:

 

 

 

.text:005C0010    8B 85 6C EC FF FF                          mov eax, [ebp-1394h]
.text:005C0016    89 85 B0 EB FF FF                           mov [ebp-1450h], eax                Here in eax is address just behind occured int 3
.text:005C001C   C7 85 AC EB FF FF 00 00 00 00      mov dword ptr [ebp-1454h], 0
.text:005C0026   8B 0D 74 C0 5E 00                            mov ecx, dword_5EC074           Here in ecx is address table length (B06 in dwords) 

.text:005C0032   8B 95 AC EB FF FF                           mov edx, [ebp-1454h]               
.text:005C0038   3B 95 84 EE FF FF                            cmp edx, [ebp-117Ch]
.text:005C003E   7D 54                                                 jge short loc_5C0094                When find address of interrupt he will proceed to 5C0094
.text:005C0040  8B 85 84 EE FF FF                              mov eax, [ebp-117Ch]
.text:005C0046  2B 85 AC EB FF FF                            sub eax, [ebp-1454h]
.text:005C004C  99                                                        cdq
.text:005C004D  2B C2                                                  sub eax, edx
.text:005C004F  D1 F8                                                   sar eax, 1
.text:005C0051  8B 8D AC EB FF FF                            mov ecx, [ebp-1454h]
.text:005C0057  03 C8                                                    add ecx, eax
.text:005C0059  89 8D A8 EB FF FF                             mov [ebp-1458h], ecx
.text:005C005F  8B 95 A8 EB FF FF                             mov edx, [ebp-1458h]
.text:005C0065  A1 18 C0 5E 00                                   mov eax, dword_5EC018 <==  ADDRESS TABLE START IN EAX

---------------------------------------

---------------------------------------

.text:005C0094  60                                                         pusha

 

 

 

At  005C0094 you'll have in eax int 3 displacement in address table. You don't have to remember this. Now when he found jump address he will try to find jump type in jump type table.

 

For address jump table I got next values:

 

 

After some tracing below 5C0094, you'll find where he is checking for jump type. Something like: 

 

 

 

.text:005C012F  8D 8D B4 EB FF FF                   lea ecx, [ebp-144Ch]
.text:005C0135  51                                                push ecx
.text:005C0136  8B 15 24 C0 5E 00                     mov edx, dword_5EC024  <==  JUMP TYPE TABLE START IN EDX
.text:005C013C  03 95 AC EB FF FF                   add edx, [ebp-1454h]
.text:005C0142  8A 02                                          mov al, [edx]
.text:005C0144  50                                                push eax
.text:005C0145  E8 0B 28 00 00                           call loc_5C2955
.text:005C014A  83 C4 08                                    add esp, 8
.text:005C014D  25 FF 00 00 00                          and eax, 0FFh
.text:005C0152  85 C0                                          test eax, eax
.text:005C0154  0F 84 84 00 00 00                      jz loc_5C01DE  <==  if eax = 0 go to on not jump, whether if eax = 1 go to on jump 

 

 

For  jump type table I got next values:

 

 

Call at 005C0145 is place where protector calculates jump type (from table on AAD360 he gets just coded info about that)  and as a result in eax we will get whether jump will happen or not (for example if we have jz xxxxxxxx, and if zero flag is set in eax on 005C0152  we will have eax = 1, if zero flag is not set we will have eax = 0). So you can put bpmb 005C0154 x  if (eax = = 0) and when break tracing will lead you to the place where protector calculate how long is jump instruction decoded in call at 005C2955, because it is decided that jump will not be executed. So protector has to update eip of client process as bytes forward as jump instruction is long. In this case you'll find something like this:

 

 

 

.text:005C0212  8B 15 2C C0 5E 00            mov edx, dword_5EC02C<==  JUMP LENGTH TABLE START IN EDX
.text:005C0218  03 95 AC EB FF FF           add edx, [ebp-1454h]
.text:005C021E  33 C0                                 xor eax, eax
.text:005C0220  8A 02                                 mov al, [edx]
.text:005C0222  8B 8D 6C EC FF FF          mov ecx, [ebp-1394h]
.text:005C0228  03 C8                                 add ecx, eax
.text:005C022A 89 8D 6C EC FF FF           mov [ebp-1394h], ecx

 

 

For  jump instruction  length table I got next values:

 

 

Ok, when you find this clear previou break point and put next  bpmb 005C0154 x  if (eax = = 1), in this case you'll break at 005C0154 when jump will happen. After some tracing through obfuscation you'll hit next:

 

 

 

.text:005C0180  8B 85 AC EB FF FF                   mov eax, [ebp-1454h]  ;       Jump displacement is in eax (its relative value in address table)
.text:005C0186  33 D2                                          xor edx, edx
.text:005C0188  B9 10 00 00 00                           mov ecx, 10h
.text:005C018D  F7 F1                                         div ecx
.text:005C018F  8B 85 AC EB FF FF                   mov eax, [ebp-1454h]
.text:005C0195  8B 0D 14 C0 5E 00                    mov ecx, dword_5EC014  <==  JUMP CRYPTED DISTANCES  TABLE START IN 
.text:005C019B  8B 04 81                                     mov eax, [ecx+eax*4]                                                    ECX
.text:005C019E  33 84 95 98 EE FF FF                xor eax, [ebp+edx*4-1168h]<==  JUMP KEY  TABLE START  (EBP-1168 h)
.text:005C01A5  8B 8D 6C EC FF FF                  mov ecx, [ebp-1394h]
.text:005C01AB  03 C8                                        add ecx, eax
.text:005C01AD  89 8D 6C EC FF FF                 mov [ebp-1394h], ecx

 

 

This is the most interesting place with tables. Here is where stuff differs from described in Crusader's tut. What's going here. Jump distance table is crypted and there is key how to decrypt that. First on 005C018D jump relative displacement in address table is divided with 10h (reminder can be less or equal to 0Fh, can be 00h, 01h, 02h, ................. 0Ch, 0Dh, 0Eh, 0Fh). Then on 005C019B crypted distance of our jump is placed in eax, after that on 005C019E it is being decrypted. If you look better 005C019E, there is ebp+edx*4-1168h, edx is reminder after division, and ebp-1168h is start of key table. So you have to remember this address, and its length is 10h dwords (4x10h in bytes). Can't be less or bigger because whole decryption procedure. 

 

 

For  jump crypted distances table I got next values: 

 

 

 

For  jump key  table I got next values: 

 

 

 

 

Because this I coded small utility (I called it JumpDistance_Decryptor) to decrypt distances table. I used source from Crusader's tut and did some modifications. Everything you have to do is to dump jump crypted distances table and jump key table. Then you have to attach in address fields (BROWSE button) those two tables, and in Decrypted Distances Table field you have to attach same size file as in Crypted Distances Table (that will be out file), the best way to do that is to copy your dumped jump crypted distances table with different name into same place. When you press FIX IT you'll have decypted distances table. You will see values like 00 00 00 00e, 00 00 00 05, etc......Now it looks like described in Crusader's tut.

 

 

If you remember when I described what is new in nanomites managing, I mentioned that protector first takes jumps from original exe, replace them with CCh, and then search whole exe again, and where ever find CCh (whether it is replaced in previous or not) he will update jump address table, and all other 3 tables. So if we don't think in that way and start to recover all CCh places we will screw our dumped_.exe. So I recoded Crusader's tool for fixing nanomites. I added int3 Log address field. What is that ?. Because we don't know which CCh in dumped_.exe is jump which is not, somehow we have to filter CCh addresses. And int3Log is actually CCh addresses filter. So all other 5 fields are same, this one differs, and NanomiteFixer will replace just those CCh addresses which he finds in int3Log file. If you put in int3Log field same file as in address field he will does as in Crusader's way. Now there is a question how to generate int3Log. We have to record all int3 occurences and to dump them to file. Better way in whole this strategy would be to make Armadillo files loader, to work as debugger. And then we don't care about that which CCh is jump which not, I mean loader to work everything that protector does when int3 is reached. But I hadn't time for that. 

 

 

So let's make int3Log.  As you remember on 005C0016  in eax we had address of int3, this is the place where we will redirect our protector work. First where to find space for extra code, in this case it is easy, there are lot pushfd/popfd  pushad/popad pairs with a lot of garbage code between them, so first you can nop such place and then write next I'll show. First of all restart program, break on GetVersion and put bpmb 005C0016  x. When you reach it all stop. Remember 6 bytes of this instruction (89 85 B0 EB FF FF ), now you can nop first pushad till you find popad (included both).  You can start from 005C0094 and finish at 005C00BA, and start from 005C00D5 and finish at 005C012F, we need a lot of space for code I'll describe. So when you are at 005C0016 type, a eip; jmp 005C00D7, but don't execute anything. Now we need some memory space to store our int3Log, so we need to allocate that space, because I couldn't find somewhere in process memory such amount of space. So now type next: 

 

 

a 005C0096

 

 

.text:005C0096  60                            pusha
.text:005C0097  6A 10                      push 10h                         <====   I made mistake here instead 10h put 1000h 
.text:005C0099  6A 00                      push 0
.text:005C009B  E8 7A 90 8D 77     call near ptr 77E9911Ah  <====    GlobalAlloc
.text:005C00A0  50                           push eax
.text:005C00A1  E8 FD CB 8C 77   call near ptr 77E8CCA3h <====    GlobalLock
.text:005C00A6  61                           popa
.text:005C00A7  EB 2E                     jmp short loc_5C00D7

 

 

To explain this (when do a eip you'll type just instruction pushad.......popad). We started nopping  from 005C0094 and now we are writting from  005C0096, why ? On 005C0094 we had pushad and there we will put jmp 005C00BA (do it like a 005C0094; jmp 005C00BA) , that's immediately after popad we just nopped. And now what does this code do, GlobalAlloc (to write this in Soft-Ice type call KERNEL32!GlobalAlloc, same for GlobalLock) will arrange some memory space, and will return handle to that space, GlobalLock will return starting memory address of that space in eax, with me it was eax = 00133468  after 005C00A1. Remember this value it is important for next code we will write. So now when you finished with this writing  (everything is stopped still and you are at  005C0016 with your eip) type r eip 005C0096, why to jump in this way, because we will never do this code again, jusy once we will arrange memory space and after we will from 005C0096 go on 005C00D7. Ok now when you are at 005C0096 with F10 execute line by line until you reach 005C00A6, when eip is 005C00A6 remember eax (memory allocated starting address), execute 005C00A7 and when eip is 005C00D7 all stop again. Location 005C00D5 was previously pushad we nopped and now we must put jump here on place after popad it is 005C012F, so when you are at  eip = 005C00D7 type a 005C00D5; jmp 005C012F. 

Now we have to edit code on 005C00D7 to make int3Log, so type next:

 

 

a eip

 

 

.text:005C00D7   60                              pusha
.text:005C00D8   BE 68 34 13 00         mov esi, 133468h
.text:005C00DD  8B 0E                        mov ecx, [esi]
.text:005C00DF   83 F9 00                   cmp ecx, 0
.text:005C00E2   74 0A                        jz short loc_5C00EE              If we don't have that value (we serached whole table) we will append  
.text:005C00E4   3B 04 0E                   cmp eax, [esi+ecx]                 In eax is our int3 address 
.text:005C00E7   74 0C                        jz short loc_5C00F5              If we already have that value we will exit
.text:005C00E9   83 E9 04                    sub ecx, 4
.text:005C00EC  EB F1                        jmp short loc_5C00DF
.text:005C00EE  83 06 04                    add dword ptr [esi], 4
.text:005C00F1  03 36                         add esi, [esi]
.text:005C00F3  89 06                         mov [esi], eax
.text:005C00F5  61                              popa
.text:005C00F6  89 85 B0 EB FF FF   mov [ebp-1450h], eax
.text:005C00FC E9 1B FF FF FF        jmp loc_5C001C

 

 

When you typed all of this ( you are still at 005C00D7) you must do one thing manually, type ed 00133468 and write all zeros there, why to do that, on this location we will keep number of int3 happened during work. Now because some int3 are happening many times it is dumb to have several times same value, so we will search first our int3Log to find if there we already have such address and if don't we will just append at the end of our table that address and update addresses number, if we have we will exit with no addresses  number at  00133468 updating. At 005C00F5 we will restore all registers like before our patch, on 005C00F6 we will execute that what we missed because redirection, and on 005C00FC we will jump to instruction after 005C0016, it is 005C001C. Now clear break points and let program run. When program open main dialog you have to try to do everything with program you can, to scan directories to change options, just everything that program can do to make sure you have passed whole program code and stored all program jumps. But don't exit program. When you did that (program is still running) open LordPe and dump Region with Int3Log (in my case it is location 133468 with size 1000 h) you'll choose protector process because that's where you allocated memory space. Now you have int3Log, you previously dumped all other tables and now open NanomiteFixer (utility I attached) and with browse button attach all tables you dumped, and our dumped_.exe file with fixed IAT. Press FIX IT and all nanomites should be fixed.

If you failed to locate some nanomite, and if experience some bug, just remember what you did to achieve that bug, in Soft-Ice type int3 here on repeat procedure for bug catching and when Soft-Ice pops up remember address immediately after int 3, then you can add that address into int3Log and fix your dumped_.exe again.

There is no limitation how many times you can repeat that. But to avoid that boring job it is better to try all options you can during making patch I described above. Once again there should be better to make Armadillo files loader, maybe someone will write that soon.

 

 

I didn't mentioned how I resolved jump types, it is covered by Crusader's tut (trace in call at 5C2955) I'll just show how many jumps I found (there were just several with this version of armadillo and this program, in nanomite fixer I didn't take care about others, they stayed as Crusader put, if you want do it by yourself)

 

 

 

   Jump Type

Instruction   

JBE
1
7 JB
9
JLE
B JNZ
C JMP
D
JA

E

JZ

 


I didn't say how to find OEP, you can set bpmb SetProcessWorkingSetSize x, after second break in Trojan Remover context put bpmb GetCurrentThreadId x, after first break clear all break points, trace for a while with F10 and will see call edi, in edi is OEP = 582A44h

 

Good Luck !!!!!!!!!

 


One more trick


 

After everything you did dumped_.exe will refuse to run normally. Main screen will appear but cancel, scan buttons remain inactive. After some time will close without your activity. So put bpx GetEnvironmentVariableA and when break in dunmped_.exe context press F12 ,trace with F10 until you return from call  and you will see some check test eax, eax; jnz xxxxxxxx, you have to put jmp. That will happen several times, everywhere you see some branching after return from routine where GetEnvironmentVariableA was invoked, you have to update that jumps. You can compare how original (protected file) does in such situations, and make your dumped_.exe to do same.

 

 


UTILITIES


 

Distance Decryptor                     

 

Nanomite Fixer

 

All Tables

 

Resolved IAT

 

Fixed File (should be all working)


END