As I sad, subject of this tutorial is Import Elimination feature. Target for this tutorial is unpackme taken from one KaGra's tutorial and that target has spliced code too, but we will not talk too much about it. It's been explained in previous tutorials along with usual IAT redirection. This version of Armadillo also uses CreateTollhelp32Snapshot API to get all processes and protected file crushes/exits if it finds ollydbg.exe. This is minor anoyance, just rename ollydbg.exe to something else. Also, version of armadillo isn't important, main thing is that our target has IAT elimination feature. Lets see what IAT elimination is.
After you have renamed ollydbg.exe to something else, load target in it. Using CreateThread API find OEP (like in previous tutorials), but do not place bp on first opcode because armadillo will find it and make infinite loop. Place bp on last opcode, run, remove bp and find jump to OEP:
003D7732 FFD7 CALL EDI <----- Jump to OEP!
003D7734 8BD8 MOV EBX,EAX
003D7736 5F POP EDI
003D7737 8BC3 MOV EAX,EBX
003D7739 5E POP ESI
003D773A 5B POP EBX
003D773B C3 RETN
003BD687 PUSH EBP
003BD688 MOV EBP,ESP
003BD68A PUSH ECX
003BD68B PUSH EBX
003BD68C PUSH ESI
003BD68D PUSH EDI
003BD68F MOV EDX,DWORD PTR DS:[3E9218]
003BD695 ADD EDX,64
003BD698 CALL EDX <------------------------- Call to GetTickCount, to fool tools.
003BD69A MOV EDX,DWORD PTR DS:[3E91A4]
003BD6A0 ADD EDX,64
003BD6A3 MOV ECX,5
003BD6A8 CMP BYTE PTR DS:[EDX],0CC <------- Breakpoint check!
003BD6AB JE SHORT 003BD6B4
003BD6AD LOOPD SHORT 003BD6A8
003BD6AF PUSH DWORD PTR SS:[EBP+8]
003BD6B2 CALL EDX <------------------------- Call to GetModuleHandle!!!
003BD6B4 MOV DWORD PTR SS:[EBP-4],EAX
003BD6B8 MOV EAX,DWORD PTR SS:[EBP-4]
003BD6BB POP EDI
003BD6BC POP ESI
003BD6BD POP EBX
003BD6BF RETN 4
Our call leads to emulated import GetModuleHandle. This is usual armadillo emulation which you can see in the first tutorial only here that API call is also allocated in one seperate memory block. So what is IAT elimination? From what I noticed, Armadillo moves whole import table to some allocated memory block far away from our target image. This is making it hard to dump and also prevents ImpREC from getting imports. There is many ways how to repair this and make working dump and we gona see some of them.
2. Repairing IAT elimination
First we need to prevent usual emulation of imports and fix code splicing. Also do not forget to copy-paste PE header when you reach OEP. Idea for fixing IAT elimination is similar to code solicing one. We need to dump redirected IAT section to disk and attach it to our main dump, or we need to inject it somewhere in our main dump just like we did with code splicing. Take a look at the memory after you have reached OEP:
00400000 00001000 IAT_elim Imag R RWE
00401000 00003000 IAT_elim .idata Imag R RWE
00404000 00002000 IAT_elim .text Imag R RWE
00406000 00001000 IAT_elim .data Imag R RWE
00407000 00009000 IAT_elim .bss Imag R RWE
00410000 00001000 IAT_elim IMPORTS Imag R RWE
00411000 00030000 IAT_elim .text1 code Imag R RWE
00441000 00010000 IAT_elim .adata code Imag R RWE
00451000 00020000 IAT_elim .data1 data,imports Imag R RWE
00471000 00030000 IAT_elim .pdata Imag R RWE
004A1000 00002000 IAT_elim .rsrc resources Imag R RWE
.idata , .text , .data , .bss , IMPORTS and .rsc are packed file sections. We will not touch those ones. .text1 , .adata , data1 and .pdata are Armadillo's sections and we can use those for our injecting.
One more thing; in previous tutorials, after we changed that "Magic Jump" for fixing import emulation, our file would crush after finishing with imports. That wasn't problem there, but we can't aford that here and we gona see how to prevent that too. Let's go ;)
2.1 Code Splicing, usual IAT emulation and avoiding crushing
Load target in our olly (change ollydbg.exe to something else xxxx.exe). This version of armadillo doesn't have IsDebuggerPresent or OutputDebugStringA checks. We need to fix Code Splicing and normal import emulation first. Code splicing feature comes first and uses time API from msvctr.dll. We need to place bp on that API but we cannot do it untill that dll isn't loaded in memory. Olly has one nice option in debugging options under events, you can set olly to break on any new dll loading. So go there and select "Break on new module (DLL)" and hit F9 so many times until you see msvctr.dll in module window (I think 5 times). Then uncheck option for break on loading dll's (we don't need it anymore) and place "bp time" in command bar. Hit ENTER and you will break on time API. Remove bp and return to armadillo code (scroll down):
003D2620 CALL DWORD PTR DS:[3DB1A0] ; kernel32.VirtualAlloc
003D2626 MOV DWORD PTR SS:[EBP-1988],EAX <----------- Break here and set EAX=471000!!!
003D262C CMP DWORD PTR SS:[EBP-1988],0
003D2633 JE SHORT 003D2668
003D2635 PUSH 40
003D2637 PUSH 1000
003D263C PUSH DWORD PTR SS:[EBP-1990]
003D2642 PUSH DWORD PTR DS:[3E9230]
003D2648 CALL DWORD PTR DS:[3DB1A0] ; kernel32.VirtualAlloc
003D264E MOV DWORD PTR SS:[EBP-1988],EAX <----------- Break here and set EAX=471000!!!
003D2654 CMP DWORD PTR SS:[EBP-1988],0
003D265B JE SHORT 003D2668
In order to redirect spliced block to our .pdata section, change EAX values to 471000. If you don't remember how and why, then read previous tutorial. Remove all breakpoints that you have and place new "bp _stricmp" in command bar. Hit F9 and you will break there. Armadillo uses this API lot of times but we need to find place where it uses it for API processing. You can speed it up a little; remove bp from begining of the _stricmp API and place it on last opcode, what is RETN. Run and you'll break there. Check registers window:
Do you see that API names? We are in the API checking procedure. You may ask how the hell I know that? Simply, I unpacked bunch of targets before writting this tutorial and got habbit, but this is not general approach. You will need to dig alot when you try some other target. Return to armadillo code now (remove that and all bp's from before). You are at the place where is our familiar API check:
003D474C CMP DWORD PTR DS:[EAX+8],0
003D4750 JE SHORT 003D479A
003D4752 PUSH 100
003D4757 LEA EAX,DWORD PTR SS:[EBP-1E8C]
003D475D PUSH EAX
003D475E MOV EAX,DWORD PTR SS:[EBP-1D8C]
003D4764 PUSH DWORD PTR DS:[EAX]
003D4766 CALL 003B7C43
003D476B ADD ESP,0C
003D476E LEA EAX,DWORD PTR SS:[EBP-1E8C]
003D4774 PUSH EAX
003D4775 PUSH DWORD PTR SS:[EBP-1D84]
003D477B CALL DWORD PTR DS:[3DB330] ; msvcrt._stricmp
003D4781 POP ECX
003D4782 POP ECX
003D4783 TEST EAX,EAX
003D4785 JNZ SHORT 003D4798 <---------------- Change this jump to JMP!!!!
003D4787 MOV EAX,DWORD PTR SS:[EBP-1D8C]
003D478D MOV EAX,DWORD PTR DS:[EAX+8]
003D4790 MOV DWORD PTR SS:[EBP-1D80],EAX
003D4796 JMP SHORT 003D479A
003D4798 JMP SHORT 003D4737
Change that JNZ to JMP for prevention of redirecting imports. Then we need to place bp on some place that is being executed after all imports are passed. I found one such spot, but maybe there is more of them, don't know. Scroll up:
003D4241 TEST EAX,EAX
003D4243 JNZ SHORT 003D424A
003D4245 JMP 003D4986 <------------ Place bp here!!!
That jump will be executed after imports are checked. Place bp there (that must be only one bp in olly) and press F9. You will break there. We have fixed usuall armadillo IAT emulation/redirection, but armadillo dll is being eencrypted/decrypted on the fly so target will crush because we have change some bytes in it. Scroll down where you have changed that jump from JNZ to JMP and reastore back original JNZ. And that's it! Our target will run nice. We fixed spliced code and normall IAT problem and now we can find OEP. You know how, place bp on CreateThread and find that ECX that thorws you to OEP:
Dou you see changes? Our imports are visible but they are in the A90000 block! ImpREC can't fix that, it will give error reading process memory. I will now describe how did I solve this, but first you must copy-paste PE header to get properly dump. Do it and dump target to hard disk. There are lot of approaches to solve problem of IAT Elimination, but basicly they are all similar.
2.2.1 First way, dumping pointers and attaching them to main dump
Ok, this is wery clumsy way how to do it, but this was first thing that fall on my mind. Problem is that you must think what will help ImpREC to recognize imports, unless you want to manually build whole IAT. ImpREC needs to find somewhere in the main exe image values that coresponds to some API's. Those values like 77xxxxxx and simmilar are placed inside A90000 block and ImpREC cannot handle that so you need to copy that values inside our main image. Lucky for us, Armadillo has added lot of its own sections that we don't need anymore so we can copy there our IAT table. IAT for this unpackme is small and you can find it if you follow taht [A99020]; kernel32.GetModuleHandleA in dump window:
00A98FB0 62 A6 3B 00 BC A7 3B 00 7F A6 3B 00 94 56 D4 77 b.;...;...;..V.w
00A98FC0 93 A7 3B 00 19 A6 3B 00 C8 A6 3B 00 25 E2 E7 77 ..;...;...;.%..w
00A98FD0 31 A6 3B 00 84 A6 3B 00 62 A6 3B 00 91 4B E7 77 1.;...;.b.;..K.w
00A98FE0 76 A6 3B 00 78 A6 3B 00 36 A7 3B 00 4D A7 3B 00 v.;.x.;.6.;.M.;.
00A991C0 CC 95 E6 77 33 A7 3B 00 13 A7 3B 00 26 A7 3B 00 ...w3.;...;.&.;.
00A991D0 5F A7 3B 00 78 A6 3B 00 2E 7E D4 77 AB AB AB AB _.;.x.;..~.w....
00A991E0 AB AB AB AB EE FE EE FE 00 00 00 00 00 00 00 00 ................
00A991F0 04 00 53 00 00 07 1F 00 58 AB AB AB AB AB AB AB ..S.....X.......
00A99200 AB FE EE FE EE FE EE FE 00 00 00 00 00 00 00 00 ................
00A99210 06 00 04 00 00 07 1C 00 2C 01 00 00 10 01 00 00 ........,.......
There you will see some 77xxxxxx DWORDS. Armadillo has scattered them inside this block. Binary copy whole block (from A98FB0 to A99210). Now we gonna chose where to paste that. I chose to paste it in .adata section (remember that .pdata is one that hold spliced code block so don't paste there). So I pasted that content in .adata section which start at 441000. Now open ImpREC and attach to our target. Set for OEP = 4000.If you click now "IAT AutoSearch" you will get nothing. That is problem with IAT Elimination. But we can still force ImpREc to find our pasted values. Set in "IAT infos needed" RVA=41000 (.adata start = 441000-400000=41000). For size you must enter some value that you estimate as enough big. 1000 is more than big, enter that and click "Get Imports". Ha, I got 5 invalid modules, and 142 invalid thunks. Click "Show Invalid" and cut all that invalid thunks. You will get 18 modules and 18 imports, one import per module, altough there are lot kernel32 and user32 ones. That is because scattering, but that still makes valid IAT. Fix dump and try to run it... it will crush. That is because pointers point to A90000 block. I will fix that by expanding fixed dump for B00000 bytes and pasting there values from A90000 block.
Open fixed dump in hex editor and add B00000 bytes to the end of file. Then change VirtualSize and RawSize of last section for B00000 bytes (add them) and save changes. My dumped file is now ~11.5 MB in size. Now open that dump in olly, go to 00A98FB0 in dump window and paste there whole that block 00A98FB0-00A99210 and save changes. In CPU window you should see now that pointers shows API values:
Run file and it will work. Problem is that such file will work only indentical systems like one on which target was unpacked, because fixed pointers. Other bad thing is it's size.
2.2.2 Second way - redirecting pointers using OllyScript
This is much better way because we will get dump that will work on all machines and file will be smaller. I hope that you didn't close olly because we will just continue from our OEP. First, fill select whole .idata section and fill it with zeroes. This is not important but I like clear section so I can see what I'm doing there. We sow that our imports look like this:
I wrote small script that will change all CALL DWORD[A9xxxx] API to CALL DWORD[401yyy] API where 401yyy is in .idata section. But consider that if you want to use this script on your computer, you will have to modify it. My script is searching pattern of bytes that corespond to CALL DWORD[A9xxxx] and those bytes are FF15????A900. So my script is searching for opcodes like this:
where x is variable for address. I sugest you to read readme.txt from OllyScrypt plugin because this plugin is very helpfull for unpacking.
There you can clearly see thunks. There is one thunk per API again, it would be too complicated to write script that could put all API values for one dll in one thunk and this is also correct IAT and our dump will work. Now dump again from memory to hard disk.
And now it comes finall step. Open ImpREC, attach to target, enter OEP=4000 and click "IAT AutoSearch", then "Get Imports"and you will get 19 valid functions. Important thing now; UNCHECK "Add new section" and enter there RVA=1000 and then fix dump. Run dumped file and it will work great :) And this file is very small ~200 kb after using LordPE. So we got smal file that works on every machine.
3. Conclusions and final words
The third way to fix IAT problem would be to find where Armadillo is doing redirection. I tried to find that but I had no will to finish it.
I spoted one mistake about spliced code feature in my tutorial. We shouldn't use .pdata section for redirecting spliced block because that section holds some things that armadillo dll/loader uses while unpacking, which continues after we fix splicing. I noticed that when I filled whole that section with zeroes on the fly, my unpackme just crashed. Use .adata section instead because that one holds code that it not longer in use after unpacking loader.
I had couple more things to say, but I'm little tired of all this writing.
Next tutorial will be about Debug Blocker feature.