Zoom Icon

Armadillo5 x64 Unpacking

From UIC

Armadillo v5 x64 basic unpacking

Contents


Infos
Author: Pnluck
Email: Pnluck@virgilio.it
Website: http://pnluck.netsons.org
Date: 03/03/2008 (dd/mm/yyyy)
Level: Slightly hard
Language: English Image:Flag_English.gif
Comments:

Della serie alla tv c'è il grande fratello :(, ma per fortuna che c'è il Rev e la Radio trasmette il rock!!



Introduction

Armadillo is one of the most popular executable protectors, and it's one of the few that support PE+ executables.


Tools

Ida: I used this debugger
Explorer Suite: Task Explorer and CFF Explorer
Attached file: Unpackme, Security.dll and ItRebuilder demo


Tutorial infos

We're going to unpack the windows calc.exe protected by Armadillo with basic protection options.
Before reading this tutorial you should know how x64 architecture works: I advise you to read these articles:
Everything You Need To Know To Start Programming 64-Bit Windows Systems
Moving to Windows x64

I'm so impatient to write the first (I believe) unpacking tutorial on x64 executable in the RCE scene =)


Essay

A look inside the Armadillo Loader

Let's disasm the file with IDA: the EP of the loader is a normal Visual C++ EP, IDA actually recognises the WinMain at: 0x000000010001F000. We are looking for the Armadillo MainProc:

.text1:000000010001F3E9                 call    Call_Armadillo_MainProc
.text1:000000010001F3EE                 mov     [rsp+68h+var_48], eax
.text1:000000010001F3F2                 cmp     [rsp+68h+var_48], 0
.text1:000000010001F3F7                 jnz     loc_10001F48E

This call has another call inside it, that leads us to the real Armadillo_MainProc RVA_Section_EntryPoint + 000283A0 (00000001000283A0).
We notice a first check that uses a Mutex: this checks if the process is already running

.text1:000000010002849F                 mov     eax, cs:dword_10005F65C ; dd 0F7CA92B1h
.text1:00000001000284A5                 mov     ecx, cs:dword_10005F618 ; dd 0DEAF1A85h
.text1:00000001000284AB                 xor     ecx, eax
.text1:00000001000284AD                 mov     eax, ecx
.text1:00000001000284AF                 xor     eax, cs:dword_10005F66C ; dd 47D5D8D9h
.text1:00000001000284B5                 mov     r8d, eax ; eax = 6EB050EDh
.text1:00000001000284B8                 lea     rdx, aRn08x     ; "RN%08X"
.text1:00000001000284BF                 lea     rcx, [rsp+798h+WindowName] ; char *
.text1:00000001000284C4                 call    sprintf
.text1:00000001000284C9                 lea     r8, [rsp+798h+WindowName] ; lpName
.text1:00000001000284CE                 xor     edx, edx        ; bInitialOwner
.text1:00000001000284D0                 xor     ecx, ecx        ; lpMutexAttributes
.text1:00000001000284D2                 call    cs:CreateMutexA
.text1:00000001000284D8                 mov     [rsp+798h+hMutex], rax
.text1:00000001000284E0                 cmp     [rsp+798h+hMutex], 0
.text1:00000001000284E9                 jz      loc_100028645

If this check is passed the execution proceeds, and we reach this interesting code:

.text1:000000010002888B                 call    Work_with_Dll
.text1:0000000100028890                 mov     [rsp+798h+var_618], eax
.text1:0000000100028897                 xor     ecx, ecx
.text1:0000000100028899                 call    LoadRegisterServiceProcessApi
.text1:000000010002889E                 xor     ecx, ecx        ; int (__stdcall *)(unsigned __int64)
.text1:00000001000288A0                 call    ?_set_new_handler@@YAP6AH_K@ZP6AH0@Z@Z ; _set_new_handler(int (*)(unsigned __int64))
.text1:00000001000288A5                 cmp     [rsp+798h+var_618], 1
.text1:00000001000288AD                 jnz     short loc_1000288C3

What is the Work_with_Dll thing? Well it's a loader function that loads in memory a packed dll (Security.dll), that is embedded in the executable: it is the core of the Armadillo protection.

.text1:0000000100026F90                 sub     rsp, 148h
.text1:0000000100026F97                 mov     eax, cs:dword_10005F674
.text1:0000000100026F9D                 mov     ecx, cs:dword_10005F690
.text1:0000000100026FA3                 xor     ecx, eax
.text1:0000000100026FA5                 mov     eax, ecx
.text1:0000000100026FA7                 xor     eax, cs:dword_10005F63C
.text1:0000000100026FAD                 and     eax, 3
.text1:0000000100026FB0                 movzx   ecx, ax
.text1:0000000100026FB3                 call    sub_10002B110
.text1:0000000100026FB8                 call    FindSignatureOfPackedDll
.text1:0000000100026FBD                 mov     [rsp+148h+SectionWithSignature_VA], rax
.text1:0000000100026FC5                 cmp     [rsp+148h+SectionWithSignature_VA], 0
.text1:0000000100026FCE                 jnz     short loc_100026FE1

FindSignatureOfPackedDll finds the first section of the executable image that begins with "PRDATA00".
Let's continue the analysis...

.text1:0000000100027074                 mov     [rsp+148h+hWnd], 0
.text1:0000000100027080                 movzx   r8d, [rsp+148h+var_B8] ; char
.text1:0000000100027089                 lea     rdx, [rsp+148h+hWnd] ; __int64
.text1:0000000100027091                 mov     rcx, [rsp+148h+MemAddrOfDll] ; void *
.text1:0000000100027099                 call    MemExtractDll
.text1:000000010002709E                 mov     [rsp+148h+MemAddrOfDll], rax
.text1:00000001000270A6                 cmp     [rsp+148h+MemAddrOfDll], 0
.text1:00000001000270AF                 jnz     short loc_1000270B8
.text1:00000001000270B1                 xor     eax, eax
.text1:00000001000270B3                 jmp     loc_1000273D3
.text1:00000001000270B8 ;
.text1:00000001000270B8
.text1:00000001000270B8 loc_1000270B8:                          ; CODE XREF: Work_with_Dll+11F�j
.text1:00000001000270B8                 mov     rcx, [rsp+148h+MemAddrOfDll] ; void *
.text1:00000001000270C0                 call    DllLoader
.text1:00000001000270C5                 mov     [rsp+148h+MemAddrOfDll], rax
.text1:00000001000270CD                 cmp     [rsp+148h+MemAddrOfDll], 0
.text1:00000001000270D6                 jnz     short loc_1000270DF

MemExtractDll extracts in memory the packed dll. DllLoad is a LoadLibrary-like function: it tries to load the dll at the correct ImageBase, then loads the ImportTable, calculates Relocations, and saves the entrypoint address in a variable.

mov     rax, [rsp+0D8h+NtOptionalHeader]
mov     eax, [rax+10h] ;Address of Entry Point
mov     rcx, [rsp+0D8h+MemorySpaceVirtualAlloc]
add     rcx, rax
mov     rax, rcx
mov     cs:ptrDllEntryPoint, rax

Actually after call DllLoader there's this:

.text1:00000001000270DF
.text1:00000001000270DF loc_1000270DF:                          ; CODE XREF: Work_with_Dll+146�j
.text1:00000001000270DF                 xor     r8d, r8d
.text1:00000001000270E2                 mov     edx, 1
.text1:00000001000270E7                 mov     rcx, cs:ImageBaseDll
.text1:00000001000270EE                 call    cs:ptrDllEntryPoint ; call some function
.text1:00000001000270F4                 test    eax, eax
.text1:00000001000270F6                 jnz     short loc_100027109

So I dumped the dll with Task Explorer to analyse it.
Now, on with the Work_with_Dll function:

.text1:0000000100027109 loc_100027109:                          ; CODE XREF: Work_with_Dll+166�j
.text1:0000000100027109                 lea     rdx, aSetfunctionadd ; "SetFunctionAddresses"
.text1:0000000100027110                 mov     rcx, cs:ImageBaseDll ; __int64
.text1:0000000100027117                 call    LoadFunctionFromDll ; an LoadLibrary-like function
.text1:000000010002711C                 mov     [rsp+148h+SetFunctionAddress_VA], rax
.text1:0000000100027124                 mov     eax, cs:dword_10005F620
.text1:000000010002712A                 mov     ecx, cs:dword_10005F660
.text1:0000000100027130                 xor     ecx, eax
.text1:0000000100027132                 mov     eax, ecx
.text1:0000000100027134                 xor     eax, cs:dword_10005F674
.text1:000000010002713A                 xor     eax, cs:dword_10005F640
.text1:0000000100027140                 lea     rcx, [rsp+148h+dll_anProc3]
.text1:0000000100027148                 mov     [rsp+148h+var_C8], rcx
.text1:0000000100027150                 lea     rcx, [rsp+148h+dll_OEProc_]
.text1:0000000100027158                 mov     [rsp+148h+var_D0], rcx
.text1:000000010002715D                 lea     rcx, [rsp+148h+Dll_UnpackExeProc]
.text1:0000000100027165                 mov     [rsp+148h+var_D8], rcx
.text1:000000010002716A                 mov     [rsp+148h+var_E0], eax
.text1:000000010002716E                 lea     rax, loc_10002B960
.text1:0000000100027175                 mov     [rsp+148h+Proc_10002b690], rax
.text1:000000010002717A                 lea     rax, loc_10002B950
.text1:0000000100027181                 mov     [rsp+148h+var_F0], rax
.text1:0000000100027186                 lea     rax, loc_10002B890
.text1:000000010002718D                 mov     [rsp+148h+var_F8], rax
.text1:0000000100027192                 lea     rax, Proc9
.text1:0000000100027199                 mov     [rsp+148h+var_100], rax
.text1:000000010002719E                 lea     rax, Proc8
.text1:00000001000271A5                 mov     [rsp+148h+var_108], rax
.text1:00000001000271AA                 lea     rax, Proc7
.text1:00000001000271B1                 mov     [rsp+148h+var_110], rax
.text1:00000001000271B6                 lea     rax, Proc6
.text1:00000001000271BD                 mov     [rsp+148h+var_118], rax
.text1:00000001000271C2                 lea     rax, Proc5
.text1:00000001000271C9                 mov     [rsp+148h+var_120], rax
.text1:00000001000271CE                 lea     rax, Proc4
.text1:00000001000271D5                 mov     [rsp+148h+var_128], rax
.text1:00000001000271DA                 lea     r9, Proc3
.text1:00000001000271E1                 lea     r8, Proc2
.text1:00000001000271E8                 lea     rdx, loc_10002A790
.text1:00000001000271EF                 mov     rcx, cs:hInstance
.text1:00000001000271F6                 call    [rsp+148h+SetFunctionAddress_VA] ; interesting!!
.text1:00000001000271FD                 mov     rax, [rsp+148h+Dll_UnpackExeProc]
.text1:0000000100027205                 mov     [rsp+148h+Dll_UnpackExeProc_], rax
.text1:000000010002720D                 mov     rax, [rsp+148h+dll_OEProc_]
.text1:0000000100027215                 mov     cs:dll_OEProc, rax
.text1:000000010002721C                 mov     rax, [rsp+148h+dll_anProc3]
.text1:0000000100027224                 mov     cs:Dll_AnProc3_, rax
.text1:000000010002722B                 mov     [rsp+148h+var_B4], 0
.text1:0000000100027236                 movzx   eax, [rsp+148h+var_B8]
.text1:000000010002723E                 test    eax, eax
.text1:0000000100027240                 jz      short loc_100027253

What does the Security.SetFunctionAddress routine do?

.text:000000018002F660 SetFunctionAddresses proc near    
.text:000000018002F660                 mov     [rsp+arg_18], r9
.text:000000018002F665                 mov     [rsp+arg_10], r8
.text:000000018002F66A                 mov     [rsp+arg_8], rdx
.text:000000018002F66F                 mov     [rsp+arg_0], rcx
.text:000000018002F674                 sub     rsp, 28h
.text:000000018002F678                 movzx   eax, cs:ThisFunctionWasUsed
.text:000000018002F67F                 test    eax, eax
.text:000000018002F681                 jnz     loc_18002F79F
...
; un-important code for the unpacking
...
.text:000000018002F755
.text:000000018002F755 loc_18002F755:                          ; CODE XREF: SetFunctionAddresses+C9�j
.text:000000018002F755                 mov     eax, [rsp+28h+arg_68]
.text:000000018002F75C                 mov     cs:Val_7FD3BD7F, eax
.text:000000018002F762                 mov     rax, [rsp+28h+arg_70]
.text:000000018002F76A                 lea     rcx, UnpackExeProc
.text:000000018002F771                 mov     [rax], rcx
.text:000000018002F774                 mov     rax, [rsp+28h+arg_78]
.text:000000018002F77C                 lea     rcx, OEProc
.text:000000018002F783                 mov     [rax], rcx
.text:000000018002F786                 mov     rax, [rsp+28h+arg_80]
.text:000000018002F78E                 lea     rcx, An_Proc_3
.text:000000018002F795                 mov     [rax], rcx
.text:000000018002F798                 mov     cs:ThisFunctionWasUsed, 1
.text:000000018002F79F
.text:000000018002F79F loc_18002F79F:                          ; CODE XREF: SetFunctionAddresses+21�j
.text:000000018002F79F                 add     rsp, 28h
.text:000000018002F7A3                 retn
.text:000000018002F7A3 SetFunctionAddresses endp

This function saves in some variables the addresses of the functions that unpack the executable and are used to call the OEP of the executable.
Let's return to Work_with_Dll: after some useless code (useless to us), there's an interesting call:

.text1:0000000100027348                 mov     rax, [rsp+148h+var_18]
.text1:0000000100027350                 mov     [rsp+148h+ExeImgBase], rax
.text1:0000000100027358                 mov     eax, cs:dword_10005F5F0
.text1:000000010002735E                 mov     [rsp+148h+var_30], eax
.text1:0000000100027365                 mov     [rsp+148h+var_2C], 0FFFFFFFFh
.text1:0000000100027370                 lea     rcx, [rsp+148h+var_78]
.text1:0000000100027378                 call    [rsp+148h+Dll_UnpackExeProc_]; another interesting function!!
.text1:000000010002737F                 mov     [rsp+148h+var_A0], eax
.text1:0000000100027386                 cmp     [rsp+148h+var_2C], 0FFFFFFFFh
.text1:000000010002738E                 jz      short loc_10002739F

Security.UnpackExecutable calls a function that executes some antidebug controls, and then calls other functions that implement these protections: Debug-Blocker, Copymem II, Nanomites, Import table elimination, Import redirection, Code Splicing etc...
After that we exit from Word_With_Dll and come back to Armadillo_MainProc. In the end there's the call to OEProc

.text1:00000001000288B6                 call    cs:dll_OEProc

Now we can see what Security.OEProc (at 0000000180060610) does:

.... un-useful to us ;)
.text:000000018006080F                 call    rax ; call executable OEP
.text:0000000180060811                 mov     [rsp+58h+var_38], eax
.text:0000000180060815                 jmp     exit
..... un-useful to us ;)
.text:0000000180060853                 mov     rcx, [rcx+10h]
.text:0000000180060857                 call    rax ; call executable OEP

That two "call rax" are used to call the real OEP of the executable, that (in this case) is:

.text:0000000100018CD0                 mov     rax, rsp ; OEP
.text:0000000100018CD3                 sub     rsp, 0C8h
.text:0000000100018CDA                 mov     [rax+18h], rbx
.text:0000000100018CDE                 mov     [rax+20h], rdi

Now we must talk briefly about IT: the IAT of the dumped file is not correct at all as you can see from this log:

0) RVA: 1000 value: 7ff7ff04f20 Import: ADVAPI32.dll.RegOpenKeyExA
1) RVA: 1008 value: 7ff7ff0b100 Import: ADVAPI32.dll.RegCloseKey
2) RVA: 1010 value: 7ff7ff03ef0 Import: ADVAPI32.dll.RegQueryValueExA
3) RVA: 1018 value: 1eda720
4) RVA: 1020 value: 7ff7fc92a90 Import: GDI32.dll.SetBkColor
5) RVA: 1028 value: 7ff7fc92b70 Import: GDI32.dll.SetTextColor
6) RVA: 1030 value: 7ff7fc92d40 Import: GDI32.dll.SetBkMode
7) RVA: 1038 value: 1eda560
8) RVA: 1040 value: 1eda850
9) RVA: 1048 value: 1ed8f80
....

Many API addresses were replaced by Security.dll functions: some useful, some not.
Useless functions were inserted in place of null qwords: an example is 1eda720

.text:000000018003A720 MyFakeNull2     proc near               ; CODE XREF: sub_18003A760+4�p
.text:000000018003A720                                         ; DATA XREF: FuckingProc+22AF�o ...
.text:000000018003A720                 sub     rsp, 28h
.text:000000018003A724                 call    MyFakeNull4 ;Recursive function
.text:000000018003A729                 add     rsp, 28h
.text:000000018003A72D                 retn
.text:000000018003A72D MyFakeNull2     endp

Others, the useful ones, replace -as I said- the real APIs: look at 1eda850:

.text:000000018003A850 MyLoadLibraryA  proc near                                                    
.text:000000018003A850                 mov     [rsp+lpLibFileName], rcx
.text:000000018003A855                 sub     rsp, 38h
.text:000000018003A859                 mov     rcx, [rsp+38h+lpLibFileName]
.text:000000018003A85E                 call    sub_180039D70
.text:000000018003A863                 mov     [rsp+38h+var_18], rax
.text:000000018003A868                 cmp     [rsp+38h+var_18], 0
.text:000000018003A86E                 jnz     short loc_18003A8D0
.text:000000018003A870                 xor     edx, edx
.text:000000018003A872                 lea     rcx, MyImgBase
.text:000000018003A879                 call    sub_18003E9B0
.text:000000018003A87E                 xor     edx, edx
.text:000000018003A880                 lea     rcx, MyImgBase
.text:000000018003A887                 call    sub_18003E990
.text:000000018003A88C                 test    rax, rax
.text:000000018003A88F                 jz      short Call_LoadLibrabry
.text:000000018003A891                 xor     edx, edx
.text:000000018003A893                 lea     rcx, MyImgBase
.text:000000018003A89A                 call    sub_18003E990
.text:000000018003A89F                 mov     [rsp+38h+var_10], rax
.text:000000018003A8A4                 mov     rcx, [rsp+38h+lpLibFileName]
.text:000000018003A8A9                 call    [rsp+38h+var_10]
.text:000000018003A8AD                 mov     [rsp+38h+var_18], rax
.text:000000018003A8B2                 jmp     short loc_18003A8C4
.text:000000018003A8B4
.text:000000018003A8B4 Call_LoadLibrabry:                        
.text:000000018003A8B4                 mov     rcx, [rsp+38h+lpLibFileName] ; lpLibFileName
.text:000000018003A8B9                 call    cs:LoadLibraryA
.text:000000018003A8BF                 mov     [rsp+38h+var_18], rax
.text:000000018003A8C4
.text:000000018003A8C4 loc_18003A8C4:                          
.text:000000018003A8C4                 mov     dl, 1
.text:000000018003A8C6                 mov     rcx, [rsp+38h+var_18]
.text:000000018003A8CB                 call    sub_180039210
.text:000000018003A8D0
.text:000000018003A8D0 loc_18003A8D0:  
.text:000000018003A8D0                 mov     rax, [rsp+38h+var_18]
.text:000000018003A8D5                 add     rsp, 38h
.text:000000018003A8D9                 retn
.text:000000018003A8D9 MyLoadLibraryA  endp

Many Security.dll functions are inserted into the IAT, and act as wrappers of real APIs. They are used to replace null qword as many functions that call CreateProcess or CreateFile: in this case, you should decide if it is an api wrapper or a null qword.
That's all you need to know in order to be able to unpack ;)

Armadillo Unpacking

After that short introduction to the Armadillo loader, we can make a running dump.
Set a bp at 00000001000288B6, and step until a "call rax", and then press step into: we are at the OEP, who is at 00018CD0(RVA).
Now we can dump the process with Task Explorer, don't close the debugger or the debuggee!.
Open the dump file with CFF Explorer and delete the following from the Section Table: text1, pdata2 and rsrc.
After that we can null the IAT Directory, and we must change the .text section flags: select "Is executable", "is writable", "is readable".
Extract from the attached file ItRebuilder.exe (it's an IT Rebuilder built ad-hoc for this target) copy it into the same directory of the dumped file and run it. Enter the name of the dump, the entrypoint RVA and wait for the message "The file was successfully rebuilt".
Run the dumped file, does it work? Yeahh it works!! ;)

Pn[L]uck


Note Finali

Thx to Ntoskrnl, Que, Evilcry, ZaiRoN, Quake2, Ermes, 0x87k, Locu, Evo, StarzBoy (indian friend of mine), and everyone who I met ops also Pincopall, Active85k e DrWatson (me li stavo a scordà, nun sia mai :P)


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.