Log in

View Full Version : Armadillo 2.x/3 DLL stub unpacking


SysCall
May 10th, 2004, 13:29
Hello all,

first post ... congrats to this forum

I have a target that just seems to me like a never ending story

It consists of .exe file and some .dlls.
The exe was packed with armadillo 2.xx? with CopyMem II technique and table destruction.
Though i never encountered armadillo before i was able to unpack the .exe manually and restore IAT+OEP with the help of ollydbg + ricardos tutorial (thanks man) in considerable amout of time.

Well ... the .exe started successfully and the reg dialog popped up.
So i thought easy game ... well was not.
The dialog does not come from the .exe itself but from one of its .dlls

I tried to trace it and later inject a helper dll (containg my nifty code) but failed.
The debugger locked up every time.
Using PeID it said packed with "Armadillo 2.51 - 3.xx DLL Stub".
Well .. seems every binary of this target is packed with armadillo

That problem of this target is, that the init/unpack + dialog code is called from entry itself = DllMain().
This causes the OS loader lock to get locked the whole time which in turn makes it impossible to load any additional code.
(i had to "break on dll load" + breakpoint on entry to trace it)

My idea was to redirect the entry point to an empty one (only saving the instance handle away).
Then i would add a special export to fake DllMain() call from external - this would allow me to inject additional dlls/code without the dreaded OS loader lock (and to quick brute the serial code (its XXXX-XXXX- ... style, 16 bytes num)).

Well it didnt work ... the code seems to unpack itself into some .PDATA000 section and check itself with some checksum code (it reads itself from disk).

I dumped the section to a separate file and it seem to contain some armadillo stuff...
I tried to fix the IAT but it didnt work at all, because some of the code calls back to original .text1 section.
The .PDATAxxxx section is dynamically allocated on heap and i'm not sure of its functionality...

Can someone shed any lights on this? I've searched the forum but did not found any occurences on armadillo dll stub unpacking.
Any hints welcome...

Thank you very much.

nikolatesla20
May 10th, 2004, 16:13
Even tho this teaches you nothing,..

It's been forever since I wrote this, and since Arma no doubt has a new version which breaks it try this for older armas...2.85-3.xx ?

I don't remember which version I made it for.



-nt20

SysCall
May 10th, 2004, 17:15
Hello again

The tool seems to do its work in general - until the loader tries to load the (original?) dll.
It returns with lasterror=6 (invalid handle).
The loader gets the original dll supplied as parameter while its started as debuggee of unpacker.

The log window of the "unpacker" tool outputs this:

LoadLibrary called for xxxxx.dll
arma secu dll base: xxxxxxh (i guess this is the heap-allocated memory block that gets unpacked - i can see PE signature+sections there)
scanning secu dll
scanning secu export table
OEP aquired
setting OEP bp <---- reminder dialog pops up here and the unpacker waits until i press "ok"

IAT decrypt block found at xxxxx
scanning for import redirect..
OEP found xxxxx
protected dll loaded at xxxxh
dll size xxxxxh
dumped file created successfully (its like orginal file size + unpacked sections?)
...

-- imp rebuild stage ---
sanitizing iat, please wait...
dll OEP found: xxxxh
.rdata offset xxxxh
IAT cleaned and ready

The loader error seems to pop up asynchronously/immediately after i press the "ok" button of dialog.

I viewed the modules list of dll loader with process viewer (while its attached by unpacker) and it does not show the original dll.

The calculated OEP of the tool seems ok.
I had manually traced with ollydbg to same point

Any ideas ...

SysCall
May 10th, 2004, 17:57
Another observation ... i debugged your loader (hope you dont mind hehe).

In the LoadLibrary() call where you load the target dll i never see the name of target dll (supplied by commandline) but the loader app name itself.

My "interpretation" to C code of your loaders disassembly:

...
int main( int argc, char* argv[])
{
....

// error here: argv[0]??
HINSTANCE hInst = LoadLibrary( argv[0]);
if( hInst == 0)
{
sprintf( buf, "error loadlibrary, getlasterror returns %d", ::GetLastError());
MessageBox( .... "dll loader error", buf, ...);
}
...
MessageBox( ... "Dllloader", "press ok when done...";

}

Really looks like ::LoadLibrary( argv[0]) instead of ::LoadLibrary( argv[1]) to me ... is this intended?

Or is there another way, the loader gets instructed which dll to load (environment var)?

Regards

nikolatesla20
May 10th, 2004, 21:00
Yes, it "fails" like this on the newer versions of arma, and you are correct, it screws up for some reason by loading the wrong argument, good job debugging

I think at one point I tracked down the cause of the error but I never go around to fixing it 100% , it was a long while ago since I did this code hehe.

The dll I think still gets dumped clean...all you need to do is rebuild the IAT. And that's the only reason the loader waited for you anyway, after the dump it would keep the DLL in mem so you could do the IAT.

So just write down the info for where the IAT is (the offset) and run the original arma protected program and use ImpREC with that info to find the clean imports..use LordPE to get the protected DLL's imagebase, and then apply the IAT offset that the unpacker gave you to ImpREC to search for the clean IAT. This should work. Sorry for the malfunctions, the arma authors do a good job of keeping up with things.

-nt20

SysCall
May 11th, 2004, 00:51
Hello,

Quote:
So just write down the info for where the IAT is (the offset) and run the original arma protected program and use ImpREC with that info to find the clean imports..


i loaded the target in imprec and put in OEP, IAT offset (did auto search on later point, after dismissing reminder dialog).
It find _an_ IAT (the one from "--- import rebuild stag ---" but it seems to me some entries pointing to the dynamically heap unpacked memory block/dll.
They look like stubs:

.rdata offset (given by unpacker and/or auto search of imprec):

rva:xxxx: mod:kernel32.dll ord:xx name:GetVersionExA
rva:xxx4: mod:kernel32.dll ord:xx name:Sleep
rva:xxx8: ptr:00DA87F1 <---- stubs, point to in memory unpacked dll?
rva:xxxC: ptr:00DAxxxx
rva:xx10: mod:kernel32.dll ord:xx nameeviceIoControl
....

The unpacked? dll base is 00DA0000 which seems to correspond with these entries (i found PE signature+sections there).
The protected dll base is 0x10000000 (just like every user created one).

What goes wrong here?

Thanks

addenum:

The dumped file contains the following sections:

.text
.rdata (IAT to be rebuilt?)
.data
.text1
.adata
.idata (the initial IAT of original protected dll?)
.data1 (data seg of arma dll?)
.reloc1
.pdata (the PDATA000 seg)

The .pdata seg starts with signature 'PDATA000',0 and after a few bytes the PE signature can be found (+11 bytes later)

nikolatesla20
May 11th, 2004, 11:53
Ok,

I worked on it this morning, got new version for you to try. It works on my newer arma (3.50???). It was previously coded for 3.20.

Fixed DLLLoader
Fixed CreateProcess call to DLLLoader
Added new arma version

-nt20

SysCall
May 11th, 2004, 15:14
Hello again

I tried your proggy and the loader issue seems fixed.
But the fundamental problem is left ...

It dumps raw dll/sections to disk, starts the loader which loads the protected dll and waits for imprec.

It puts out following:

"*** IAT was not able to be hooked ***
this is probably newer ver of arma... dont have sigs for it.."

OEP found: xxxxh
.rdata offset xxxxh

Lemme try to understand some things... (correct me if im wrong, please)

The protected dll unpacks its .pdata section to dynamically alloc'd memory (heap).
The unpacked stuff itself is the security dll which is a valid PE file in memory.
The protected dll and the security dll "connect" function pointers to each other (SetFunctionAddresses) so one cannot exist without the other.
(i verified this because the protected dll has some public exports, that get called by main .exe later - which in turn call the security functions)
The security dll itself has a public IAT (in memory) and some "secret" function address table where it calls back to protected one.

The security dll verifies the protected dll's integrity by reading the file from disk and use crc like stuff?

Would the following idea sound feasible?

- dump the security dll from memory leaving PE image on disk, record the "public" IAT offsets (where to find OEP of it?) and the secret function table (offsets into protected dll)
- record the offsets of protected dll .rdata entries which go into security dll

- build a new IAT for protected dll, resolving to imports from security dll
(how can i do it while the security dll is a chunk in memory (not visible in module list), imprec wants to select protected dll but not memory chunk?)

One problem remains ... i dont know if the "callback" secret function table is used in any protected dll code (with new OEP)
If so it may be difficult.
Maybe its possible to convert this secret table to some IAT style, resolving the entries (callbacks to protected dll) by OS loader.

Any suggestions ... hints

Regards

SysCall
May 11th, 2004, 15:52
Update ... i got the security dll dumped and fixed (though the initial dump address was < 0x400000 i simply set the image base to unpacked heap base address so all code/data references did match - it worked).

I can now see all imports of its .rdata section fine.
Ollydbg loads it with its loader helper and the DllMain() entry point gets successfully executed.

My next step would be to "connect" the security dll to the protected dll by trying to "reference" the redirected IAT entries to newly created dll.

How can i add a custom (security) dll to imprec?
Injection the addtional dll into loader process space doesnt help, imprec doesnt see it (can't select in import editor).
Before that i have to extend/recreate the export table of security dll (it only contains a single export "SetFunctionAddresses" for now).

Regards

nikolatesla20
May 11th, 2004, 16:08
You don't need this security dll for anything.

I have to say, trying to explain how I go about unpacking this would take some time, and I just don't have it right now at this particular moment.

I'm making some more new sigs

-nt20

nikolatesla20
May 11th, 2004, 16:57
Added Arma 3.60 support

Hmm there are so many versions, I think I 'll come up with a better search method

-nt20

SysCall
May 11th, 2004, 17:32
Hehe .. will try to email the security dll later

I think i've found it ... unfortunately the app expired _just_ at this moment *arrrgg*
When the dialog pops up i set hw bp at projected IAT when the first entry is written, it breaks.
I looked around the code and found one conditional responsible for redirected table entries "destruction".
I nopped it and found it fully restored the IAT (using "dump" -> "display as long" -> "address".
Before i could use PUPE + imprec it was 00:00 and the dialog just displays expired info ...

Someone know where it stores the "installation timestamp" without diggin too deep to repeat that steps again?

Regards

SysCall
May 11th, 2004, 18:05
Quote:
I'm making some more new sigs


Hmm ... i guess you use opcode signatures to find the corresponding IAT build/restore code/conditionals right?

I noticed the following unique pattern/sequence which works for my version
(From the hardware breakpoint accessing instruction within 1000 bytes forward range):

protected .exe = Copymem II + table destr:

xxxxxxxx 83BD 08E7FFFF 0>CMP DWORD PTR SS:[EBP-18F8], 0
xxxxxxxx 75 3F JNZ SHORT 00AFF48F ; -> nop to restore whole table
xxxxxxxx 0FB785 0CE7FFFF MOVZX EAX, WORD PTR SS:[EBP-18F4]

protected .dll stubs + table destr:

same sequence!

cmp dword ss:[ebp-xxxx],0
jnz yyy ; must be nopped
MOVZX EAX, WORD PTR SS:[EBP-zzzz]
TEST EAX, EAX

Maybe there are easier ways ... nopping that conditionals and placing endless loop instruction outside of IAT rebuilder loop (to attach with imprec) worked for me...

Regards

nikolatesla20
May 11th, 2004, 19:07
Quote:
[Originally Posted by SysCall]Hehe .. will try to email the security dll later

I think i've found it ... unfortunately the app expired _just_ at this moment *arrrgg*
When the dialog pops up i set hw bp at projected IAT when the first entry is written, it breaks.
I looked around the code and found one conditional responsible for redirected table entries "destruction".
I nopped it and found it fully restored the IAT (using "dump" -> "display as long" -> "address".
Before i could use PUPE + imprec it was 00:00 and the dialog just displays expired info ...

Someone know where it stores the "installation timestamp" without diggin too deep to repeat that steps again?

Regards


Good work ! Sounds like you have a good handle on debugging !

I usually term it the "magic jump"

You can put in an infinite loop if you really want, if you are doing it manually that will work fine. Nice work.

-nt20

SysCall
May 12th, 2004, 15:19
Hello again

For the sake of completeness...

To fix/track installation "timestamp", i used a native call interface (NCI) tracer, which works thru kernel mode.

(i read somewhere arma effects registry and file monitors so i didnt want to waste unnessary time).

By analyzing the log output i quickly identified the registry portions:

HKLM\Software\Licenses\[all keys]
HKEY_CLASSES_ROOT\CLSID\{xxxxx} (you will find out the specific one hehe...)

It also records some unique items from registry like bios version, date, computer name and from harddisks for example the disk geometry to calculate fingerprint keys.
They get stored into registry and temp file.

To detect clock reversing/forwarding it searches some well known directories for files, mask: "*" (bpx FindNextFile + pFindData + fileattr != DIRECTORY) and compares the file time to system time.
For example if it finds newer ones than system clock .. well thats a short circuit There are other (difference checks) too.

Just make sure the registry stuff is deleted, temp dir cleaned and pay attention to %windir%

Of course all can be verified by either bpx on interesting kernel32 exports or using api tracer (to identify the key apis) or doing deadlist of security dll...

Regards