Admiral
November 29th, 2005, 22:03
I couldn't agree more. A tutorial should tell you what to do and why, not just how to do it. Otherwise it isn't a tutorial but a walkthrough.
Allow me to explain the Code-Splicing and IAT-Elimination protections in more detail:
If a software developer
purchases Armadillo from SRT they are allowed to produce what is being called a 'custom build'. All this means is that they can use any/all of Armadillo's antidump protections (namely Code-Splicing, IAT-Elimination and Nanomites) in addition to those available in the public release.
The developer marks certain (sensitive) sections of their code with tags that Armadillo can understand. Then when the target exe (or dll) is packed, Armadillo will apply the appropriate anti-debug techniques in these areas.
The Code-Splicing goes something like this:
The code is disassembled, and several (100-2000 in my experience) blocks of code, generally around 5-18 bytes in length, which contain no 'offensive' opcodes will be targeted. 'Inoffensive' opcodes are MOV, XCHG, XOR etc. - things that change registers but don't access memory, branch or manipulate hardware. Once such a block is identified, Armadillo will pseudo-intelligently add (2-20) opcodes and their inverses among and around the commands such that the code is bloated and deoptimised, but executes identically in all situations.
For example,
PUSH EDX
MOV EAX, EDX
INC EAX
MOV ECX, EAX
POP EDX
may become
XCHG BX, CX
PUSH EDX
INC EDX
DEC EDX
XCHG CX, BX
MOV EAX, EDX
INC EAX
MOV ECX, ECX
MOV ECX, EAX
POP EDX
This code is a fair bit longer and doesn't contain any obviously redundant opcodes (algorithmically), but it will perform exactly the same regardless of the state of the registers and flags.
Once Armadillo has generated such a convolution, it will 'paste' it into a remote area of memory (well outside the PE image, so it can't be easily dumped) and the original code is JMPed to it. Naturally, the remote 'splice' is then JMPed back to where the code should resume. Hence the target will execute through this without a hitch, albeit somewhat slower.
I have identified a few recurring themes with this protection:
-= The spliced code (almost) always lies in a remote block of size 0x20000 and resides at an address ending in four zeros: xxx0000.
-= Only certain combinations of opcodes are susceptible to splicing. As I said before, any JMPs, Jccs, CALLs, OUTs, SYSENTERs etc. will not be affected.
-= There are only twenty or so different redundant opcode patterns employed by the bloating process, so they can be removed heuristically.
And this promise is justified by my software. Download ArmInline, let it loose on a live process (after telling it where the source and remote splice address ranges are) and it will, one-by-one, remove all redundant opcodes from a splice and WriteProcessMemory the result back into where it should be. This does rely on the compiler not generating any redundant code of its own, but that hasn't proven to be a problem as yet. Give it a try. It certainly beats dumping an extra 0x20000 bytes and writing an inline patch.
As for the IAT Elimination, this one is a bit simpler:
After unpacking the CODE section and the IAT (intact), Armadillo will immediately proceed to 'shuffling' the entries in the IAT, along with a few random dwords. The result is an IAT that is 2-3 times as long, containing many invalid entries, but every API function is still in there (somewhere). As well as doing this, it will memcpy the entire IAT to a higher memory page and destroy the original. While doing this, Armadillo remembers where everything ended up, so it then proceeds to search through the CODE section (using its own 'relocation table', I believe) and it overwrites any references to the IAT and redirects them to where they should be (a few memory-access tricks are also used). Again, once this is done, the target app is completely unaware of any changes made, but the reverse-engineer can't use ImpRec to grab the IAT because it is no longer a continuous chunk separated by null dwords.
This protection is slightly easier to defeat. All that needs to be done (once one knows the range of the 'new' IAT) is to search the CODE section for any references to potential API functions (i.e. those within the given range) be that by a CALL DWORD PTR, JMP DWORD PTR, PUSH DWORD PTR, or a MOV DWORD PTR, produce a list of all referenced functions, order them by DLL (which takes a little bit of doing if you're ReadProcessMemorying unknown DLL addresses), produce a new set of thunks and hence a new IAT, WriteProcessMemory it into place and redirect all those jumps back (ideally into the DATA section). Now ImpRec can be used successfully. Of course, this is nigh on impossible to do by hand, but in two evenings work I produced some code to do it automatically. As you've probably guessed, IAT-Elimination is also supported by ArmInline, so I'm sure you can put it to good use,
sigint33.
I think that about covers it. I'm just glad that nobody mentioned Nanomites or we'd be here all day (My Nanomites recovery tool is far more involved and a detailed explanation would take up a post twice this size

).
I hope this helps.
Regards
Admiral