-
2. How beria works
--------------------------------------------------------------------------------
When you run protected target, beria envelope code will start another process from same file. This proces will unpack target in memory. However these two processes depends of each other. First process is called debugger (not "father" like yow will read in most of tutorials) because it monitors actions of second process. Actually it really debugs second one. Second process is called debuggee (often called a "son"), because he is one that is being debugged. Next question would be, what has to be debugged there. The answer is, what ever coder of protector wants. Usually, it is not much. Main purpose of debugger-debuggee is to prevent debugging of application by third person, that means you. How?
Now, I'm not expert so you cannot take my words for absolute truth, but from what I know application in Windows can be debugged by only one debugger (ring 3, I think that desn't rule for ring 0 like SoftICE) at time. That mean we cannot attach to second process and because that, we cannot see what is happening with second process. So that is first issue. This trick is called "Debug Blocker feature" in this kind of protections.
Second one is, that debuggee expect certain actions from debugger. As I sad, what ones, it depends from coder. I will try to explain what beria is doing.
Beria doesn't unpack whole file in memory, only blocks of 1000 bytes when packed application needs it. This is for preventing dumping. For example, second process will try to jump at OEP of file, but there will be no code. So debugge will call debugger process and debugger process will decrypt 1000 bytes code block and place it at that address around OEP in debugge. Then it will return controll to debuggee to continue normall execution of OEP code. If eventually debuggee lands on some address that is again empty, it will again call debugger and this one will again place there another 1000 block of code. Now you get picture, it's just copy-paste thing. This is how armadillo is working, only that armadillo destroys blocks of code after execution which are not nedded at that time. Armadillo decrypts and encrypts code back again. Beria doesn't encrypt code back, so when beria decrypts one block, it stays like that untill the termination of program. This makes unpacking beria little easier.
Second thing what debuggee in beria expects is import execution. This part is interesting and little harder to reverse. Second process, debuggee - now unpacked application, will eventually want to use some API. But beria didn't fill IAT with all API's at the start of unpacked target. Some API's will have to be loaded using LoadLibraryA and GetProcAddres functions. But here two processes will interact. Debuggee will tell to debugger that is needs some API on some offset. Debugger will then look in his table which API should be at that offset and then it will give to debugge DLL name which owns that API and name of that API. Then debuggee will use LoadLibraryA to load DLL in memory, and GetProcAddress to find address of that API in memory. Then it will load that API at offset in IAT where it should be and program will continue with execution.
And that is what beria is doing. Now you can conclude what we have to do to unpack our target. We need to decrypt whole image of application in memory, load all imports and detach processes. Then we need to dump second process file and repair dump. Sounds easy , ha :) Well, we know theory but we need to see what we can do in reall app.
One more thing, the way how we gonna debug applications that debugs itself. We cannot debug second process directly because it is already debugged with its own debugger, but we can debug it indirectly - by controling debugger (the "father"). And that is whole point of double processes.
========>
-
3. Examnig beria code
--------------------------------------------------------------------------------
I sad that debugger and debuggee comunicates with each other. How do they comunicate? The answer is - via exceptions! Yep, you use it all the time when you crack some target, even if you didn't think about that. The most know exception is breakpoint => INT3 => CC ! Debuggee is one that couse some exceptions and beria's debugger proces on a type of exception perform some action. Beria uses three kinds of exceptions:
Exception number Name
80000001 GUARD PAGE VIOLATION
80000003 BREAKPOINT
C0000005 ACCESS VIOLATION
GUARD PAGE VIOLATION:
Like I sad, beria decrypts blocks of 1000 bytes of code when debuggee needs it. Thing is that beria has used VirtualProtectEx function to protect debuggee with PAGE_GUARD parameter. From Win32 API reference we see:
"Pages in the region become guard pages. Any attempt to read from or write to a guard page causes the operating system to raise a STATUS_GUARD_PAGE exception, and turn off the guard page status. Guard pages thus act as a one-shot access alarm."
So when debuggee jump to some offset, like on OEP, it triggers this exception, stops, and from that point debugger takes control. Debugger will then check where exception happend and it going to write there 1000 bytes, also it will remove PAGE_GUARD protection from that block of code so debuggee can work. Then it gives control back to debuggee.
BREAKPOINT:
Do I need to explain this one ? :) Actually all exceptions to the same, they stop debuggee and he waits for debugger to take some action. Again, debugger checks where exception happened and on a base of that it takes some action.
ACCESS VIOLATION:
From API reference; The thread attempted to read from or write to a virtual address for which it does not have the appropriate access. This one is not important for us.
But debugger needs somehow to catch these exceptions from debuggee. For that he uses WaitForDebugEvent and ContinueDebugEvent API's. The WaitForDebugEvent function waits for a debugging event (exception) to occur in a process being debugged. The ContinueDebugEvent function enables a debugger to continue a thread that previously reported a debugging event. These two are main ones. Check API reference and you will find lot of info about debugging. Now we have some basic understanding and we can finally load target in Olly. So load packed.exe and scroll down. This is part of code that controls debuggee:
00401964 /PUSH -1
00401966 |PUSH packed.00404040
0040196B |CALL ESI <--------------- WaitForDebugEvent API catches exceptions from debuggee.
0040196D |TEST EAX,EAX
0040196F |JE packed.00401A19
00401975 |MOV EAX,DWORD PTR DS:[404040]
0040197A |DEC EAX
0040197B |CMP EAX,6
0040197E |JA packed.00401A05
00401984 |JMP DWORD PTR DS:[EAX*4+401AB8]
0040198B |CMP DWORD PTR DS:[40440C],EBP
00401991 |JNZ SHORT packed.00401A05
00401993 |MOV ECX,DWORD PTR DS:[40401C]
00401999 |MOV EDX,DWORD PTR DS:[4043C0]
0040199F |LEA EAX,DWORD PTR SS:[ESP+24]
004019A3 |PUSH EAX ; /pBytesWritten = 0016DCF8
004019A4 |PUSH 1 ; |BytesToWrite = 1
004019A6 |PUSH packed.00403050 ; |Buffer = packed.00403050
004019AB |PUSH ECX ; |Address = 77E757C4
004019AC |PUSH EDX ; |hProcess = 00140608
004019AD |CALL DWORD PTR DS:[<&KERNEL32.WriteProc>; \WriteProcessMemory
004019B3 |JMP SHORT packed.00401A05
004019B5 |MOV EAX,DWORD PTR DS:[40404C]
004019BA |CMP EAX,80000001 <-------------------- Check exception, is it PAGE_GUARD ?
004019BF |JE SHORT packed.004019F3 <------------ If yes, then go to decrypting blocks.
004019C1 |CMP EAX,80000003 <-------------------- Is exception breakpoint ?
004019C6 |JE SHORT packed.004019D7 <------------ Then go to import procedure.
004019C8 |CMP EAX,C0000005 <-------------------- Memory access violation?
004019CD |JNZ SHORT packed.00401A05 <----------- Not debugger problem, return to debuggee.
004019CF |MOV DWORD PTR DS:[4043DC],EBP
004019D5 |JMP SHORT packed.00401A05 <----------- Every else just continues to debuggee.
004019D7 |MOV EAX,DWORD PTR DS:[404064] <------- Here it will jump if exception is breakpoint.
004019DC |MOV ECX,DWORD PTR DS:[404058]
004019E2 |PUSH EAX
004019E3 |MOV EAX,DWORD PTR DS:[404048]
004019E8 |PUSH ECX
004019E9 |CALL packed.00401AE0 <---------------- In this call imports will be processed.
004019EE |ADD ESP,8
004019F1 |JMP SHORT packed.00401A05
004019F3 |MOV EDX,DWORD PTR DS:[404064] <------- If exception is page_guard, here jumps.
004019F9 |MOV EBX,DWORD PTR DS:[404030]
004019FF |PUSH EDX
00401A00 |CALL packed.00402690 <---------------- Call that decrypts and writes 1000 blocks of code.
00401A05 |MOV EAX,DWORD PTR DS:[404048]
00401A0A |MOV ECX,DWORD PTR DS:[404044]
00401A10 |PUSH 10002
00401A15 |PUSH EAX
00401A16 |PUSH ECX
00401A17 |CALL EDI <---------------------------- ContinueDebugEvent gives control back to debuggee.
00401A19 |CMP DWORD PTR DS:[4043DC],EBP
00401A1F \JNZ packed.00401964
WaitForDebugEvent api returns some information of debugging event. One part of that information is what kind of exception coused event and where did that exception occured. On a base of that information beria decides what to do. If exception is breakpoint, it will jump to call where imports are processed (actually there is more things , but it's not all that important). If exception is guard page violation, beria will jump to code where algo for decrypting blocks is. Memory access violations are not debugger job and he will just pass control to debuggee, let him take care of that.
I spend quite some time examning code in order to see how beria works but here I will just generally descrybe main two parts, decrypting blocks and couple words about imports.
Decrypting blocks of code:
If exception is 80000001->PAGE_GUARD , we will jump to algo that decrypts blocks:
004019F3 |> 8B15 64404000 |MOV EDX,DWORD PTR DS:[404064] ; packed.0042ADB4
004019F9 |. 8B1D 30404000 |MOV EBX,DWORD PTR DS:[404030]
004019FF |. 52 |PUSH EDX
00401A00 |. E8 8B0C0000 |CALL packed.00402690
First line shows where exception occured, in this case at 0042ADB4 which is OEP of unpacked file. OEP, because it is a first PAGE_GUARD exception and logic tels you that first opcode that some exe trying to execute is OEP one. Tracing in with F7 we will enter in CALL at 401A00 and continue to this line:
004026CC |. 8B4C83 14 MOV ECX,DWORD PTR DS:[EBX+EAX*4+14] ; packed.0042D000
Address 0042D000 is base of IAT section. I have concluded that later (well I also packed file myself and I know how original was looking ;). Using bp's on WriteProcessMemory you can later see that in that section some API's are written, whole blocks of them so you know that it should be IAT there. Point is that code that missing in main exe is between 401000 and that IAT base 42D000 and it needs to be decrypted. You can trace further to see what is going on after, but I will not descrybe that here simply because tutorial would be too big , plus I don't have strength to write that much. Just hit Ctrl+F9 (run till return) and F7 to return from our decryptor call:
004019F3 |> 8B15 64404000 |MOV EDX,DWORD PTR DS:[404064];packed.0042ADB4
004019F9 |. 8B1D 30404000 |MOV EBX,DWORD PTR DS:[404030]
004019FF |. 52 |PUSH EDX
00401A00 |. E8 8B0C0000 |CALL packed.00402690
00401A05 |> A1 48404000 |MOV EAX,DWORD PTR DS:[404048];Default case of switch 0040197A
You are at the last line above, there beria will call ContinueDebugEvent which will return control to second process after 1000 block of code is decrypted. Here we could make jump that will loop and decrypt all blocks of code from 401000 to 42D000, just address that shows where exception ocured [404064] must be changed every time.
Imports:
Beria is doing trick thing with imports which cannot be fixed on the fly with OllyDbg. Just few words about this. Some imports will be written initialy in the IAT section , but some of them will be loaded when they are needed. Beria will replace lot of imports with pointers to some allocated memory block, in my case 003A0000 one:
0042D0B0 00 00 00 00 00 00 3A 00 01 00 3A 00 02 00 3A 00 ......:...:...:.
0042D0C0 03 00 3A 00 04 00 3A 00 05 00 3A 00 06 00 3A 00 ..:...:...:...:.
0042D0D0 07 00 3A 00 08 00 3A 00 09 00 3A 00 0A 00 3A 00 ..:...:...:...:.
0042D0E0 0B 00 3A 00 0C 00 3A 00 0D 00 3A 00 0E 00 3A 00 ..:...:...:...:.
0042D0F0 0F 00 3A 00 10 00 3A 00 11 00 3A 00 12 00 3A 00 ..:...:...:...:.
0042D100 13 00 3A 00 14 00 3A 00 15 00 3A 00 16 00 3A 00 ..:...:...:...:.
0042D110 17 00 3A 00 18 00 3A 00 19 00 3A 00 1A 00 3A 00 ..:...:...:...:.
You see, pointters to 3A0000, 3A0001, 3A0002,.....,3A0xxx. An there in that section:
003A0000 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0010 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0020 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0030 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0040 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0050 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0060 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0070 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0080 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0090 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A00A0 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A00B0 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A00C0 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A00D0 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A00E0 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A00F0 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0100 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC ................
003A0110 CC CC CC CC CC CC CC 00 00 00 00 00 00 00 00 00 ................
So import will now point to some CC byte which is actually INT3 opcode = breakpoint. With dhis, debuggee will couse breakpoint exception when he needs some import. Debugger process will then take controll. We can see what debugger will do now:
004019D7 |MOV EAX,DWORD PTR DS:[404064]
004019DC |MOV ECX,DWORD PTR DS:[404058] <-- Here you will see where exception occured.
004019E2 |PUSH EAX
004019E3 |MOV EAX,DWORD PTR DS:[404048]
004019E8 |PUSH ECX
004019E9 |CALL packed.00401AE0
004019EE |ADD ESP,8
004019F1 |JMP SHORT packed.00401A05
At above line you will see where exception ocured, in my case it is 003A00C and that is 003A00C-1=003A00B (minus one byte because exception is ocurred when opcode is executed and then eip register already points to next opcode). Placing bp on WriteProcessMemory we can see what is happening next:
It will give to debuggee name of kernel32.dll to some 160000 memory block which is probably buffer:
0012FF30 00402570 /CALL to WriteProcessMemory from packed.0040256A
0012FF34 00000034 |hProcess = 00000034
0012FF38 00160000 |Address = 160000
0012FF3C 00167BA0 |Buffer = 00167BA0 <------------ Follow it in buffer.
0012FF40 0000001A |BytesToWrite = 1A (26.)
0012FF44 0012FF68 \pBytesWritten = 0012FF68
00167BA0 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C kernel32.dll
Then it will write that pointer to address which is probably stack of debuggee (don't know what purpose of this pointer is):
0012FF10 00402162 /CALL to WriteProcessMemory from packed.0040215C
0012FF14 00000034 |hProcess = 00000034
0012FF18 0012FFA0 |Address = 12FFA0
0012FF1C 0012FF44 |Buffer = 0012FF44
0012FF20 00000004 |BytesToWrite = 4
0012FF24 0012FF38 \pBytesWritten = 0012FF38
0012FF44 0C 00 3A 00 ..:.
Then it writes buffer pointer to stack, telling debuggee where is that kernel32.dll name:
0012FF08 00402162 /CALL to WriteProcessMemory from packed.0040215C
0012FF0C 00000034 |hProcess = 00000034
0012FF10 0012FF9C |Address = 12FF9C
0012FF14 0012FF3C |Buffer = 0012FF3C
0012FF18 00000004 |BytesToWrite = 4
0012FF1C 0012FF30 \pBytesWritten = 0012FF30
0012FF3C 00 00 16 00 ....
Then it writes LoadLibraryA API to debuggee stack:
0012FF00 00402162 /CALL to WriteProcessMemory from packed.0040215C
0012FF04 00000034 |hProcess = 00000034
0012FF08 0012FF98 |Address = 12FF98
0012FF0C 0012FF34 |Buffer = 0012FF34
0012FF10 00000004 |BytesToWrite = 4
0012FF14 0012FF28 \pBytesWritten = 0012FF28
0012FF34 B4 D8 E7 77 ...w
Then again that pointer (why? - who cares):
0012FF10 00402162 /CALL to WriteProcessMemory from packed.0040215C
0012FF14 00000034 |hProcess = 00000034
0012FF18 0012FFA0 |Address = 12FFA0
0012FF1C 0012FF44 |Buffer = 0012FF44
0012FF20 00000004 |BytesToWrite = 4
0012FF24 0012FF38 \pBytesWritten = 0012FF38
0012FF44 0C 00 3A 00 ..:.
Then it will give some API name to debuggee:
0012FF30 004024AD /CALL to WriteProcessMemory from packed.004024A7
0012FF34 00000034 |hProcess = 00000034
0012FF38 00160000 |Address = 160000
0012FF3C 00168118 |Buffer = 00168118
0012FF40 00000042 |BytesToWrite = 42 (66.)
0012FF44 0012FF68 \pBytesWritten = 0012FF68
00168118 47 65 74 4D 6F 64 75 6C 65 48 61 6E 64 6C 65 41 GetModuleHandleA
Then again pointer to buffer:
0012FF10 00402162 /CALL to WriteProcessMemory from packed.0040215C
0012FF14 00000034 |hProcess = 00000034
0012FF18 0012FF9C |Address = 12FF9C
0012FF1C 0012FF44 |Buffer = 0012FF44
0012FF20 00000004 |BytesToWrite = 4
0012FF24 0012FF38 \pBytesWritten = 0012FF38
0012FF44 00 00 16 00 ....
Then module handle of some dll (kernel32):
0012FF10 00402162 /CALL to WriteProcessMemory from packed.0040215C
0012FF14 00000034 |hProcess = 00000034
0012FF18 0012FF98 |Address = 12FF98
0012FF1C 0012FF44 |Buffer = 0012FF44
0012FF20 00000004 |BytesToWrite = 4
0012FF24 0012FF38 \pBytesWritten = 0012FF38
0012FF44 00 00 E6 77 ...w
Then GetProcAddress API:
0012FF08 00402162 /CALL to WriteProcessMemory from packed.0040215C
0012FF0C 00000034 |hProcess = 00000034
0012FF10 0012FF94 |Address = 12FF94
0012FF14 0012FF3C |Buffer = 0012FF3C
0012FF18 00000004 |BytesToWrite = 4
0012FF1C 0012FF30 \pBytesWritten= 0012FF30
0012FF3C 85 B2 E7 77 < /FONT > < /FONT >
Ok, to make story short , what is going on?
Debuggee will make INT3 exception when it needs some import. Debugger will then give to debuggee name of dll and API based on address where exception INT3 ocured, and then debuggee will load that dll and API using LoadLibraryA and GetProcAddress API's. This is very good import protection but lucky for us, there is easier way to fix IAT. You will see that later. < /FONT > < /FONT >
And these are most interesting parts in beria. < /FONT >
-
4. Unpacking target
--------------------------------------------------------------------------------
It is time to unpack our target. Next chapters will describe how.
4.1. Finding OEP and decrypting target
--------------------------------------------------------------------------------
We can find OEP very easy and decrypting target isn't hard either. To find OEP, just place bp on next line:
004019F3 |> 8B15 64404000 |MOV EDX,DWORD PTR DS:[404064]
Press F9:
004019F3 |> 8B15 64404000 |MOV EDX,DWORD PTR DS:[404064] ; packed.0042ADB4
OEP = 0042ADB4
Keep tracing with F7 to this line:
004026CC |. 8B4C83 14 MOV ECX,DWORD PTR DS:[EBX+EAX*4+14] ; packed.0042D000
IAT = 42D0000
Code between 401000 and 42D0000 needs to be decrypted. For that, we will inject simple patch code in our target that will decrypt whole that range. Restart and place bp again at next line:
004019F3 |MOV EDX,DWORD PTR DS:[404064] <----- Follow this address in dump and write there 401000=00104000.
004019F9 |MOV EBX,DWORD PTR DS:[404030]
004019FF |PUSH EDX
00401A00 |CALL packed.00402690
00401A05 |MOV EAX,DWORD PTR DS:[404048]
00401A0A |MOV ECX,DWORD PTR DS:[404044]
00401A10 |PUSH 10002
00401A15 |PUSH EAX
00401A16 |PUSH ECX
00401A17 |CALL EDI
00401A19 |CMP DWORD PTR DS:[4043DC],EBP
00401A1F \JNZ packed.00401964
In dump there will be OEP value 0042ADB4, you change it to 401000. Then make next changes:
004019F3 |MOV EDX,DWORD PTR DS:[404064]
004019F9 |MOV EBX,DWORD PTR DS:[404030]
004019FF |PUSH EDX
00401A00 |CALL packed.00402690
00401A05 |ADD DWORD PTR DS:[404064],1000 <------- Add 1000 bytes to go on next block.
00401A0F |CMP DWORD PTR DS:[404064],0042D000 <--- Did we came to IAT base?
00401A19 |JNZ SHORT packed.004019F3 <------------ If not then go decrypt new block.
00401A1B |NOP <---------------------------------- Place bp here and run.
00401A1C |NOP
00401A1D |NOP
00401A1E |NOP
Do all like above and run. When you stop on bp, target is decrypted. Now we need to detach processes. Because page_guard protection, second process will crush. I tried to alter parameters of VirtualProtectEx functions to get non crushing process, but I failed. But I have notice that Windows DrWatson reported crushing right at OEP due 80000001 exception. And then idea fall on my mind. Olly has just-in-time debugging option! That mean we can set olly to be main windows debugger instead DrWatson so when some program crush, olly will popup and not that small ugly message from DrWatson. Go in olly options menu and click on Just-in-time debugging button. There click on "Make olly just-in-time debugger" and "Attach without confirmation", then "done". Good :) Now we need to detach processes. Just inject new inline patch below first one:
004019F3 MOV EDX,DWORD PTR DS:[404064]
004019F9 MOV EBX,DWORD PTR DS:[404030]
004019FF PUSH EDX
00401A00 CALL packed.00402690
00401A05 ADD DWORD PTR DS:[404064],1000
00401A0F CMP DWORD PTR DS:[404064],0042D000
00401A19 JNZ SHORT packed.004019F3
00401A1B PUSH 644 <------------------------ Second process PID. Your is different ofcourse.
00401A20 CALL DebugActiveProcessStop
00401A25 NOP <----------------------------- Place bp here and run.
00401A26 NOP
00401A27 NOP
00401A28 NOP
00401A29 NOP
Your PID will be different. You can get it in the attach window (the grey one). After you press F9, new Olly will popup saying "Bad or unknown format of 32-bit...". Bravo! It worked :) Don't worry for that message, just click OK. Close first olly, we don't need it anymore.
Now, you are probably confused because Olly doesn't shows target code, instead it is in ntdll.dll module. I have noticed that in Delphi programs this can happen, while for C, asm, it will land directly on targets OEP. I don't know why this happens but if does, you press F9 until you land on OEP:
0042ADB4 PUSH EBP
0042ADB5 MOV EBP,ESP
0042ADB7 ADD ESP,-0C
0042ADBA PUSH EBX
0042ADBB CALL packed.004031A0
0042ADC0 CALL packed.0040469C
0042ADC5 CALL packed.00407208
0042ADCA CALL packed.0040DB20
0042ADCF CALL packed.0040DC04
0042ADD4 CALL packed.0040FB60
0042ADD9 CALL packed.004161F8
0042ADDE CALL packed.00422AB0
0042ADE3 CALL packed.00427AE0
0042ADE8 CALL packed.004281E0
0042ADED MOV EBX,packed.0042C628
0042ADF2 MOV EAX,DWORD PTR DS:[EBX]
0042ADF4 CALL packed.00422118
0042ADF9 MOV EDX,packed.0042AE60 ; ASCII "Base Calculator"
0042ADFE MOV EAX,DWORD PTR DS:[EBX]
0042AE00 CALL packed.00421E44
...
...
Now we need to dump target and reapair that dump. For decrypting target and finding OEP you can use this little script that I made:
msgyn "IGNORE ALL EXCEPTIONS and make sure that NO BREAKPOINT IS LEFT! Then (this is the most important) set OllyDbg to be just-in-time debugger (instead DrWatson) and set to 'Attach without confirmation'. You have done all this?"
cmp $RESULT,0
je exit
var tmp1
var tmp2
//--------- Base and Size of image -----------
var Image_Base
gmi eip,MODULEBASE
mov Image_Base,$RESULT
var Image_Size
gmi eip,MODULESIZE
mov Image_Size,$RESULT
//------------- Debugee PID ----------------
var process_PID
gpa "CreateProcessA","kernel32.dll"
bp $RESULT
esto
bc eip
mov process_PID,esp
add process_PID,28
mov process_PID,[process_PID]
add process_PID,8
rtr
sti
sti
sti
mov process_PID,[process_PID]
//------ Number of imports in packed target -------
var imports
mov imports,eip
add imports,1C3
mov tmp1,imports
bp imports
esto
bc eip
sti
sti
sti
sti
mov imports,edx
//------------ OEP of packed target ---------------
var OEP
mov OEP,tmp1
add OEP,0a
bp OEP
esto
bc eip
add OEP,2
mov OEP,[OEP]
mov OEP,[OEP]
//------------ Base of import section --------------
var IAT
mov IAT,eip
add IAT,CD9
bp IAT
esto
bc eip
sti
mov IAT,ecx
//---------- Decrypt all untill IAT section ------------
var rel_oep
mov rel_oep,OEP
and rel_oep,0FFF
var break
mov break,eip
sub break,0cdd
bp break
var jump
mov jump,break
add jump,12
mov tmp1,[jump]
mov [jump],9090eceb
esto
add break,2
mov break,[break]
mov [break],401000
Decrypt: //Decrypt untill the end of file.
esto
add [break],1000
mov tmp2,[break]
cmp tmp2,IAT
jne Decrypt
bc eip
//------------ Detach processes -------------
mov eax,process_PID
asm eip,"PUSH EAX"
sti
asm eip,"CALL DebugActiveProcessStop"
msg "Done! Check log window for details and instructions."
log " "
log "- - - - - - - - - - - - - - - - - - - -"
log "BERIA 0.07 - UNPACKING SCRIPT by haggar"
log "- - - - - - - - - - - - - - - - - - - -"
log " "
log "Target is unpacked and processes (almost) detached."
log "If you have done all like I told you, another Olly"
log "will popup after you press F8 with unpacked target"
log "loaded in it, right on OEP."
log " "
log "Some information about unpacked target:"
log " "
log Image_Base
log Image_Size
log process_PID
log OEP
log IAT
log imports
log " "
log "Press F8 now to detach processes."
exit:
ret
- >
-
4.2. Dumping and repairing
--------------------------------------------------------------------------------
I have noticed that detached file in memory has only Read atribute. After dumping to hard drive and fixing imports with ImpREC, dumped file just didn't work. So I load it in olly and sow that ImpREC didn't fix import jumps. Then I have in olly select full access (read,write, execute) to image, I dumped and used ImpREC and this time dump was properly repaired. So before you use LordPE for dumping, be sure that you have give in Olly full access.
File in memory has only one section, PE header, but it's size is size of all sections. Minimize this Olly, you will need it later. Dump has lot of wrong values that needs to be changed. Open dump in LordPE's PE editor. First important values are:
EntryPoint = 00001660 --> Change it to 0002ADB4
SizeOfImage = 0004B000 --> This is good, remember it.
BaseOfData = 00003000 --> Set it to 00001000, same as BaseOfCode.
NumberOfSections = 0006 --> Importat one, set it to 1.
Now click "save" button, then "sections" and you will see only one section there. Right click on that section and "edit section header...". There change next values:
VirtualSize = 2000 --> Set it to 4A000 (that is SizeOfImage - PEheader size)
RawSize = 2000 --> Change it to 4A000.
Close window and click save button to save changes. Click on "directories" button and there set ImportTable RVA and Size to 0. Again save changes. Now dump has correct format and it can also be loaded in Olly. What we have done is, that we have placed all sections in one. That is because we doesn't know what original format of file was. Ok, I know because I packed this file, but it is even easier to reduce it to one section than try to rebuild original ones.
Now we need to fix imports.
-
4.3. Decrypting imports
--------------------------------------------------------------------------------
Open new instance of Olly and open target in it.
Protected target holds information of all dll's and api's in one tab. That tab is not encryped in any way, also it is very convenient that DLL and API names are sorted exactly like thunks in original IAT. My idea is to make inline patch that will load DLL's in memory, find address of all api's and store those api's in thunks format. Then I will just binary copy them and paste to unpacked file.
You will find tab easily. It starts at 4261ea:
004261EA 08 00 00 00 17 01 00 00 6B 65 72 6E 65 6C 33 32 ........kernel32
004261FA 2E 64 6C 6C 00 00 72 00 79 00 5C 00 4D 00 61 00 .dll..r.y.\.M.a.
0042620A 63 00 68 00 00 00 00 00 00 00 00 00 1B 00 00 00 c.h.............
0042621A 75 73 65 72 33 32 2E 64 6C 6C 00 00 5C 00 43 00 user32.dll..\.C.
0042622A 6C 00 61 00 73 00 73 00 65 00 73 00 00 00 00 00 l.a.s.s.e.s.....
...
...
0042645A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042646A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042647A 00 00 00 00 01 00 00 00 23 00 00 00 00 00 00 00 ........#.......
0042648A C0 D0 02 00 00 00 00 00 56 69 72 74 75 61 6C 46 ........VirtualF
0042649A 72 65 65 00 00 00 00 00 00 00 00 00 00 00 00 00 ree.............
004264AA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
004264BA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
004264CA 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ................
004264DA 23 00 00 00 00 00 00 00 C4 D0 02 00 00 00 00 00 #...............
004264EA 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 00 00 00 VirtualAlloc....
004264FA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
...
...
Table begins with dword value 00000008. That is number of dll's in table. Next dword is 00000171, that is number of all API's. Then we have 28h(40dec) byte arrays. First 24 bytes are reserved for dll name, and last 4 bytes hold number of API's per that dll. From that we can see which dll's program needs and how many API's must be in thunks:
Name NumberOfApi
kernel32.dll 1b
user32.dll 1
oleaut32.dll 5
advapi32.dll 6
kernel32.dll 23
gdi32.dll 38
user32.dll 89
comctl32.dll 0c
Second part of table consist of 58h(88dec) bytes arrays which holds API names. With this information I can inject some code that will load all these dll's, then get all API's, and format some kind of temporary thunk. I have injected code litle above this tab in our packed target:
0042615A PUSHAD <------------------------- This is not important, but habbit :)
0042615B PUSHFD
0042615C PUSH 004261F2 <------------------ This value points first dll name in table, kernel32.dll.
00426161 CALL kernel32.LoadLibraryA <----- I'm calling LoadLibraryA to load that dll in memory.
00426166 CMP EAX,0 <---------------------- If dll is already loaded, EAX=0, if not then EAX=handle of dll.
00426169 JNZ SHORT packed.00426176 <------ If EAX=0, I need second way to obtain handle of dll.
0042616B PUSH DWORD PTR DS:[42615D] <----- Push dll name again. This is second way using GetModuleHandle.
00426171 CALL kernel32.GetModuleHandleA <- If EAX=0, I'm using this api to retrieve handle.
00426176 MOV DWORD PTR DS:[426181],EAX <-- I'm giving EAX to GetProcAddress parameter.
0042617B PUSH 00426332 <------------------ Pushing API name. Points to first one -DeleteCriticalSection
00426180 PUSH 1000000 <------------------- This is 1000000 is just temporary. Here EAX=handle will be written.
00426185 CALL kernel32.GetProcAddress <--- This one gives me API.
0042618A MOV DWORD PTR DS:[426332],EAX <-- And I'm storing API. I'm gona overwrite api names, doesn't mathers.
0042618F DEC DWORD PTR DS:[426216] <------ Below lines are just to set pointers to new dll, api or place for thunk.
00426195 ADD DWORD PTR DS:[42617C],58
0042619C ADD DWORD PTR DS:[42618B],4
004261A3 CMP DWORD PTR DS:[426216],0
004261AA JNZ SHORT packed.0042617B
004261AC ADD DWORD PTR DS:[42615D],28
004261B3 DEC DWORD PTR DS:[4261EA]
004261B9 ADD DWORD PTR DS:[4261A5],28
004261C0 ADD DWORD PTR DS:[426191],28
004261C7 ADD DWORD PTR DS:[42618B],4
004261CE CMP DWORD PTR DS:[4261EA],0
004261D5 JNZ SHORT packed.0042615C
004261D7 NOP <---------------------------- Place bp here.
Probably this code looks confusing because it is self-modifiyng, but I wanted to make the smallest possible patch. This code will just try to load DLL using LoadLibraryA and by that retrieving to EAX handle of that dll. If dll is already loaded before, like kernel32.dll for example, the return value to EAX will be 0 so in that case I have included GetModuleHandleA api to obtaing handle from already loaded dll. After that, GetProcAddress will retrieve API from that dll on a base of handle and name of api, and place it in table.
If you are lazy to code all that, you can just binary paste next bytes:
60 9C 68 F2 61 42 00 E8 4E 77 A5 77 83 F8 00 75 0B FF 35 5D 61 42 00 E8 63 4B A5 77 A3 81 61 42
00 68 32 63 42 00 68 00 00 00 01 E8 FB 50 A5 77 A3 32 63 42 00 FF 0D 16 62 42 00 83 05 7C 61 42
00 58 83 05 8B 61 42 00 04 83 3D 16 62 42 00 00 75 CF 83 05 5D 61 42 00 28 FF 0D EA 61 42 00 83
05 A5 61 42 00 28 83 05 91 61 42 00 28 83 05 8B 61 42 00 04 83 3D EA 61 42 00 00 75 85 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
But remember that this will only work for this file and you need to change some things because your kernel address may differ.
After injecting, you should have next picture in CPU window:
And next one in dump window:
There is couple things to do before creating thunks. Check memory map window and you'll see that image has read only access (R):
Memory map
Address Size Owner Section Contains Type Access Initial Mapped as
00400000 00001000 packed PE header Imag R RWE
00401000 00002000 packed code Imag R RWE
00403000 00001000 packed data,imports Imag R RWE
00404000 00001000 packed Imag R RWE
00405000 00001000 packed Imag R RWE
00406000 0003C000 packed Imag R RWE
00442000 00009000 packed resources Imag R RWE
What we need is full access so right click and set full access:
Memory map
Address Size Owner Section Contains Type Access Initial Mapped as
00400000 00001000 packed PE header Imag RWE Copy RWE
00401000 00002000 packed code Imag RWE Copy RWE
00403000 00001000 packed data,imports Imag RWE Copy RWE
00404000 00001000 packed Imag RWE Copy RWE
00405000 00001000 packed Imag RWE Copy RWE
00406000 0003C000 packed Imag RWE Copy RWE
00442000 00009000 packed resources Imag RWE Copy RWE
Now we need to set start point to begining of our patch. Right click on first opcode, and from menu select "New origin here", just like on picture below:
Now just run, and if you have done it all right, in dump window you should see thunks (red collor):
0042615A 60 9C 68 32 63 42 00 E8 4E 77 A5 77 83 F8 00 75 `.h2cB..Nw.w...u
0042616A 0B FF 35 5D 61 42 00 E8 63 4B A5 77 A3 81 61 42 ..5]aB..cK.w..aB
0042617A 00 68 1A C3 42 00 68 00 00 34 77 E8 FB 50 A5 77 .h..B.h..4w..P.w
0042618A A3 AE 67 42 00 FF 0D 56 63 42 00 83 05 7C 61 42 .®gB...VcB...|aB
0042619A 00 58 83 05 8B 61 42 00 04 83 3D 56 63 42 00 00 .X...aB...=VcB..
004261AA 75 CF 83 05 5D 61 42 00 28 FF 0D EA 61 42 00 83 u...]aB.(...aB..
004261BA 05 A5 61 42 00 28 83 05 91 61 42 00 28 83 05 8B ..aB.(...aB.(...
004261CA 61 42 00 04 83 3D EA 61 42 00 00 75 85 90 90 90 aB...=.aB..u....
004261DA 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
004261EA 08 00 00 00 17 01 00 00 6B 65 72 6E 65 6C 33 32 ........kernel32
004261FA 2E 64 6C 6C 00 00 72 00 79 00 5C 00 4D 00 61 00 .dll..r.y.\.M.a.
0042620A 63 00 68 00 00 00 00 00 00 00 00 00 00 00 00 00 c.h.............
0042621A 75 73 65 72 33 32 2E 64 6C 6C 00 00 5C 00 43 00 user32.dll..\.C.
0042622A 6C 00 61 00 73 00 73 00 65 00 73 00 00 00 00 00 l.a.s.s.e.s.....
0042623A 1B 00 00 00 00 00 00 00 6F 6C 65 61 75 74 33 32 ........oleaut32
0042624A 2E 64 6C 6C 00 00 73 00 6F 00 63 00 69 00 61 00 .dll..s.o.c.i.a.
0042625A 74 00 69 00 00 00 00 00 1C 00 00 00 00 00 00 00 t.i.............
0042626A 61 64 76 61 70 69 33 32 2E 64 6C 6C 00 00 5C 00 advapi32.dll..\.
0042627A 43 00 4C 00 53 00 49 00 44 00 5C 00 00 00 00 00 C.L.S.I.D.\.....
0042628A 21 00 00 00 00 00 00 00 6B 65 72 6E 65 6C 33 32 !.......kernel32
0042629A 2E 64 6C 6C 00 00 37 00 2D 00 31 00 31 00 44 00 .dll..7.-.1.1.D.
004262AA 30 00 2D 00 00 00 00 00 27 00 00 00 00 00 00 00 0.-.....'.......
004262BA 67 64 69 33 32 2E 64 6C 6C 00 44 00 37 00 44 00 gdi32.dll.D.7.D.
004262CA 30 00 36 00 32 00 7D 00 5C 00 49 00 00 00 00 00 0.6.2.}.\.I.....
004262DA 4A 00 00 00 00 00 00 00 75 73 65 72 33 32 2E 64 J.......user32.d
004262EA 6C 6C 00 00 32 00 00 00 36 00 00 00 54 00 00 00 ll..2...6...T...
004262FA 80 80 80 D3 00 00 00 00 82 00 00 00 00 00 00 00 ................
0042630A 63 6F 6D 63 74 6C 33 32 2E 64 6C 6C 00 ED 69 DB comctl32.dll..i.
0042631A DB 78 D6 D6 35 EC EC 67 DC DC 7A D5 00 00 00 00 .x..5..g..z.....
0042632A 0B 01 00 00 00 00 00 00 CA 25 F5 77 90 56 F7 77 .........%.w.V.w
0042633A DE 55 F7 77 98 A6 E7 77 1E 15 E8 77 C5 AB E7 77 .U.w...w...w...w
0042634A CB 60 E7 77 D5 A5 E7 77 9C A8 E7 77 A2 A9 E7 77 .`.w...w...w.©.w
0042635A 44 AB E7 77 4F A7 E7 77 D9 AC E7 77 02 15 F5 77 D..wO..w...w...w
0042636A AB E2 E7 77 8D F0 E7 77 81 EF E7 77 90 C6 E6 77 ...w...w...w...w
0042637A 44 0C F6 77 A1 AA E7 77 62 38 E7 77 E7 E3 E7 77 D..w...wb8.w...w
0042638A B7 15 E8 77 4E E3 E7 77 63 98 E7 77 C9 B3 E7 77 ...wN..wc..w...w
0042639A 43 A6 E7 77 00 00 00 00 64 B0 D6 77 00 00 00 00 C..w....d..w....
004263AA E2 19 12 77 B8 AB 12 77 EC 14 12 77 8F 3D 12 77 ...w...w...w.=.w
004263BA 74 16 12 77 00 00 00 00 B1 63 DE 77 10 24 DD 77 t..w.....c.w.$.w
004263CA 9A 22 DD 77 6D 69 DE 77 D6 27 DD 77 D8 17 DD 77 .".wmi.w.'.w...w
004263DA B8 D0 02 00 8D F0 E7 77 C5 AB E7 77 99 98 E7 77 .......w...w...w
004263EA FA D2 E6 77 81 EF E7 77 9F EE E7 77 A1 AA E7 77 ...w...w...w...w
004263FA CC 39 E7 77 A4 E2 E7 77 B6 63 E7 77 B4 D8 E7 77 .9.w...w.c.w...w
0042640A 47 39 E7 77 92 F7 E6 77 1E 3A E7 77 4F 04 E7 77 G9.w...w.:.wO..w
0042641A 04 58 E7 77 EE FA E6 77 C9 56 E7 77 8E DF E6 77 .X.w...w.V.w...w
0042642A 02 DD E7 77 95 D0 E7 77 41 CA E6 77 85 B2 E7 77 ...w...wA..w...w
0042643A FC AC E7 77 8D 73 E7 77 32 A7 E7 77 14 69 E7 77 ...w.s.w2..w.i.w
0042644A 0C E6 E7 77 CD D5 E6 77 DF E5 E7 77 CB FF E6 77 ...w...w...w...w
0042645A A6 BD E7 77 C9 B3 E7 77 23 5D E7 77 43 A6 E7 77 ...w...w#].wC..w
0042646A 00 00 00 00 FC C0 00 7F 98 52 00 7F 83 65 00 7F .........R...e..
0042647A A9 64 00 7F 73 CD 02 7F 57 34 00 7F D7 1C 00 7F ©d..s...W4......
0042648A EF 3E 00 7F 26 D0 00 7F 42 56 03 7F 53 1E 00 7F .>..&...BV..S...
0042649A 82 1D 00 7F FB 4D 00 7F 00 1B 00 7F D7 53 00 7F .....M.......S..
004264AA 62 54 00 7F C7 C2 00 7F 94 BB 03 7F 84 C1 00 7F bT..............
004264BA B2 C5 00 7F 8E 9B 01 7F 5B 63 00 7F 0A 50 00 7F ........[c...P..
004264CA AD 28 00 7F 2B D1 00 7F 16 19 02 7F EE BF 00 7F .(..+...........
004264DA 5B BF 00 7F 9F 72 00 7F F6 20 00 7F AE 5A 00 7F [....r... ..®Z..
004264EA AA 50 00 7F 95 56 03 7F 66 91 01 7F 38 18 02 7F .P...V..f...8...
004264FA DE 4A 00 7F 31 5D 00 7F 7C CF 00 7F 1D BF 03 7F .J..1]..|.......
0042650A 6D 41 00 7F 04 7E 01 7F CC 39 00 7F 35 77 01 7F mA...~...9..5w..
0042651A 74 35 00 7F E4 20 00 7F D7 3C 00 7F B5 F2 00 7F t5... ...<......
0042652A D9 5A 00 7F C5 C4 00 7F 87 5B 00 7F 48 20 00 7F .Z.......[..H ..
0042653A 3E 36 00 7F 70 CB 00 7F E0 22 00 7F D0 58 03 7F >6..p...."...X..
0042654A DB 3B 00 7F 00 00 00 00 53 46 D4 77 6E B6 D6 77 .;......SF.wn..w
0042655A 47 3C D4 77 21 F4 D6 77 84 5B D4 77 6E B6 D4 77 G<.w!..w.[.wn..w
0042656A F0 9C D4 77 E2 3D D4 77 6F EA D5 77 60 2B D9 77 ...w.=.wo..w`+.w
0042657A 2C DA D6 77 0F 79 D4 77 E5 B8 D6 77 C9 CC D5 77 ,..w.y.w...w...w
0042658A EB AA D4 77 12 50 D5 77 E6 7E D4 77 00 79 D4 77 ...w.P.w.~.w.y.w
0042659A A2 BF D4 77 4E 7A D4 77 7B 41 D4 77 5D 68 D6 77 ...wNz.w{A.w]h.w
004265AA DB 61 D4 77 DD 56 D4 77 5F 6F D6 77 40 D4 D5 77 .a.w.V.w_o.w@..w
004265BA 22 8E D4 77 9B 79 D4 77 F8 6A D4 77 63 CD D6 77 "..w.y.w.j.wc..w
004265CA DD 6D D6 77 8B 9D D4 77 1D 5F D4 77 B8 71 D6 77 .m.w...w._.w.q.w
004265DA F4 45 D4 77 AF 6F D6 77 E7 4B D5 77 38 53 D4 77 .E.w.o.w.K.w8S.w
004265EA E3 7D D4 77 BF 8E D4 77 BF 8E D4 77 51 BF D4 77 .}.w...w...wQ..w
004265FA 11 46 D4 77 E4 B9 D4 77 48 44 D4 77 A3 64 D4 77 .F.w...wHD.w.d.w
0042660A D9 6C D6 77 39 45 D4 77 F8 DD D6 77 64 B0 D6 77 .l.w9E.w...wd..w
0042661A FB E2 D6 77 3D CF D5 77 FB 6D D4 77 1F 97 D4 77 ...w=..w.m.w...w
0042662A 7C 9C D4 77 8A 41 D4 77 73 79 D4 77 BB 5A D4 77 |..w.A.wsy.w.Z.w
0042663A 42 9C D4 77 A7 52 D4 77 AF 6A D4 77 DE 6A D4 77 B..w.R.w.j.w.j.w
0042664A 0A 59 D6 77 5D CF D5 77 00 53 D4 77 53 55 D4 77 .Y.w]..w.S.wSU.w
0042665A D8 86 D7 77 CE 58 D6 77 8A 6C D4 77 DC 59 D4 77 ...w.X.w.l.w.Y.w
0042666A FB 7F D4 77 0C 31 D5 77 94 56 D4 77 7E CC D5 77 ...w.1.w.V.w~..w
0042667A D6 3F D4 77 12 60 D4 77 64 61 D4 77 B6 41 D4 77 .?.w.`.wda.w.A.w
0042668A C9 48 D5 77 DD 68 D6 77 9C 66 D6 77 C8 54 D4 77 .H.w.h.w.f.w.T.w
0042669A B4 67 D4 77 59 70 D6 77 47 49 D5 77 3C 61 D4 77 .g.wYp.wGI.w<a.w
004266AA 50 D1 D5 77 83 D2 D5 77 29 6B D4 77 AB 74 D7 77 P..w...w)k.w.t.w
004266BA 74 96 D4 77 6A 68 D4 77 07 9C D4 77 D2 A0 D4 77 t..wjh.w...w...w
004266CA F8 85 D4 77 29 53 D4 77 A8 41 D4 77 1E CC D5 77 ...w)S.w.A.w...w
004266DA A9 CB D6 77 A7 45 D4 77 61 94 D4 77 3E 46 D4 77 ©..w.E.wa..w>F.w
004266EA AA 79 D4 77 79 CF D5 77 0E 6C D4 77 77 68 D4 77 .y.wy..w.l.wwh.w
004266FA 6E 6A D4 77 AE 69 D6 77 1E 48 D6 77 F1 52 D4 77 nj.w®i.w.H.w.R.w
0042670A D7 79 D4 77 2C 50 D5 77 CF CC D6 77 BF 57 D6 77 .y.w,P.w...w.W.w
0042671A 66 D2 D5 77 AA 5B D6 77 69 43 D4 77 80 A1 D4 77 f..w.[.wiC.w...w
0042672A 5A A2 D4 77 1B A2 D4 77 1B A2 D4 77 55 61 D4 77 Z..w...w...wUa.w
0042673A 50 5C D4 77 D2 E8 D5 77 B3 E7 D5 77 21 8B D4 77 P\.w...w...w!..w
0042674A 69 A2 D4 77 48 6A D6 77 B0 F7 D6 77 CC 6C D6 77 i..wHj.w...w.l.w
0042675A 76 8D D4 77 E7 D1 D5 77 69 5F D4 77 2E 7E D4 77 v..w...wi_.w.~.w
0042676A E2 52 D4 77 46 C2 D4 77 CC 92 D4 77 00 00 00 00 .R.wF..w...w....
0042677A 94 90 38 77 9E 91 38 77 47 90 38 77 5E 91 38 77 ..8w..8wG.8w^.8w
0042678A 80 91 38 77 38 91 38 77 C0 90 38 77 F7 90 38 77 ..8w8.8w..8w..8w
0042679A 54 50 34 77 25 74 35 77 3D 51 34 77 E3 AD 34 77 TP4w%t5w=Q4w..4w
004267AA 47 65 74 4C 61 73 74 45 72 72 6F 72 00 00 00 00 GetLastError....
004267BA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
004267CA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
004267DA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
004267EA 00 00 00 00 01 00 00 00 23 00 00 00 00 00 00 00 ........#.......
004267FA E8 D0 02 00 00 00 00 00 47 65 74 43 6F 6D 6D 61 ........GetComma
0042680A 6E 64 4C 69 6E 65 41 00 00 00 00 00 00 00 00 00 ndLineA.........
0042681A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042682A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042683A 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ................
Imports are now decrypted but we need to rebuild them on unpacked file.
-
4.4. Rebuilding imports
--------------------------------------------------------------------------------
We have just decrypted imports and created thunks, but we need to do that on unpacked target. Simpy binary copy all thunks and bynary paste them in unpacked file in second Olly (load another olly and use my script for decrypting and deataching, then paste thunks). IAT section is at 0042D000 as we sow before, but first thunk start at 42D0B0 as you can see from below code. You see that at 42D0B0 is first pointer to INT3 00003A00<->003A0000:
0042D000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D0A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0042D0B0 00 00 00 00 00 00 3A 00 01 00 3A 00 02 00 3A 00 ......:...:...:.
0042D0C0 03 00 3A 00 04 00 3A 00 05 00 3A 00 06 00 3A 00 ..:...:...:...:.
0042D0D0 07 00 3A 00 08 00 3A 00 09 00 3A 00 0A 00 3A 00 ..:...:...:...:.
0042D0E0 0B 00 3A 00 0C 00 3A 00 0D 00 3A 00 0E 00 3A 00 ..:...:...:...:.
0042D0F0 0F 00 3A 00 10 00 3A 00 11 00 3A 00 12 00 3A 00 ..:...:...:...:.
0042D100 13 00 3A 00 14 00 3A 00 15 00 3A 00 16 00 3A 00 ..:...:...:...:.
0042D110 17 00 3A 00 18 00 3A 00 19 00 3A 00 1A 00 3A 00 ..:...:...:...:.
0042D120 00 00 00 00 1B 00 3A 00 00 00 00 00 1C 00 3A 00 ......:.......:.
0042D130 1D 00 3A 00 1E 00 3A 00 1F 00 3A 00 20 00 3A 00 ..:...:...:. .:.
0042D140 00 00 00 00 21 00 3A 00 22 00 3A 00 23 00 3A 00 ....!.:.".:.#.:.
0042D150 24 00 3A 00 25 00 3A 00 26 00 3A 00 00 00 00 00 $.:.%.:.&.:.....
0042D160 27 00 3A 00 28 00 3A 00 29 00 3A 00 2A 00 3A 00 '.:.(.:.).:.*.:.
So paste all thunks from there:
0042D0B0 00 00 00 00 CA 25 F5 77 90 56 F7 77 DE 55 F7 77 .....%.w.V.w.U.w
0042D0C0 98 A6 E7 77 1E 15 E8 77 C5 AB E7 77 CB 60 E7 77 ...w...w...w.`.w
0042D0D0 D5 A5 E7 77 9C A8 E7 77 A2 A9 E7 77 44 AB E7 77 ...w...w.©.wD..w
0042D0E0 4F A7 E7 77 D9 AC E7 77 02 15 F5 77 AB E2 E7 77 O..w...w...w...w
0042D0F0 8D F0 E7 77 81 EF E7 77 90 C6 E6 77 44 0C F6 77 ...w...w...wD..w
0042D100 A1 AA E7 77 62 38 E7 77 E7 E3 E7 77 B7 15 E8 77 ...wb8.w...w...w
0042D110 4E E3 E7 77 63 98 E7 77 C9 B3 E7 77 43 A6 E7 77 N..wc..w...wC..w
0042D120 00 00 00 00 64 B0 D6 77 00 00 00 00 E2 19 12 77 ....d..w.......w
0042D130 B8 AB 12 77 EC 14 12 77 8F 3D 12 77 74 16 12 77 ...w...w.=.wt..w
0042D140 00 00 00 00 B1 63 DE 77 10 24 DD 77 9A 22 DD 77 .....c.w.$.w.".w
0042D150 6D 69 DE 77 D6 27 DD 77 D8 17 DD 77 B8 D0 02 00 mi.w.'.w...w....
0042D160 8D F0 E7 77 C5 AB E7 77 99 98 E7 77 FA D2 E6 77 ...w...w...w...w
0042D170 81 EF E7 77 9F EE E7 77 A1 AA E7 77 CC 39 E7 77 ...w...w...w.9.w
0042D180 A4 E2 E7 77 B6 63 E7 77 B4 D8 E7 77 47 39 E7 77 ...w.c.w...wG9.w
0042D190 92 F7 E6 77 1E 3A E7 77 4F 04 E7 77 04 58 E7 77 ...w.:.wO..w.X.w
0042D1A0 EE FA E6 77 C9 56 E7 77 8E DF E6 77 02 DD E7 77 ...w.V.w...w...w
0042D1B0 95 D0 E7 77 41 CA E6 77 85 B2 E7 77 FC AC E7 77 ...wA..w...w...w
0042D1C0 8D 73 E7 77 32 A7 E7 77 14 69 E7 77 0C E6 E7 77 .s.w2..w.i.w...w
0042D1D0 CD D5 E6 77 DF E5 E7 77 CB FF E6 77 A6 BD E7 77 ...w...w...w...w
0042D1E0 C9 B3 E7 77 23 5D E7 77 43 A6 E7 77 00 00 00 00 ...w#].wC..w....
0042D1F0 FC C0 00 7F 98 52 00 7F 83 65 00 7F A9 64 00 7F .....R...e..©d..
0042D200 73 CD 02 7F 57 34 00 7F D7 1C 00 7F EF 3E 00 7F s...W4.......>..
0042D210 26 D0 00 7F 42 56 03 7F 53 1E 00 7F 82 1D 00 7F &...BV..S.......
0042D220 FB 4D 00 7F 00 1B 00 7F D7 53 00 7F 62 54 00 7F .M.......S..bT..
0042D230 C7 C2 00 7F 94 BB 03 7F 84 C1 00 7F B2 C5 00 7F ................
0042D240 8E 9B 01 7F 5B 63 00 7F 0A 50 00 7F AD 28 00 7F ....[c...P...(..
0042D250 2B D1 00 7F 16 19 02 7F EE BF 00 7F 5B BF 00 7F +...........[...
0042D260 9F 72 00 7F F6 20 00 7F AE 5A 00 7F AA 50 00 7F .r... ..®Z...P..
0042D270 95 56 03 7F 66 91 01 7F 38 18 02 7F DE 4A 00 7F .V..f...8....J..
0042D280 31 5D 00 7F 7C CF 00 7F 1D BF 03 7F 6D 41 00 7F 1]..|.......mA..
0042D290 04 7E 01 7F CC 39 00 7F 35 77 01 7F 74 35 00 7F .~...9..5w..t5..
0042D2A0 E4 20 00 7F D7 3C 00 7F B5 F2 00 7F D9 5A 00 7F . ...<.......Z..
0042D2B0 C5 C4 00 7F 87 5B 00 7F 48 20 00 7F 3E 36 00 7F .....[..H ..>6..
0042D2C0 70 CB 00 7F E0 22 00 7F D0 58 03 7F DB 3B 00 7F p...."...X...;..
0042D2D0 00 00 00 00 53 46 D4 77 6E B6 D6 77 47 3C D4 77 ....SF.wn..wG<.w
0042D2E0 21 F4 D6 77 84 5B D4 77 6E B6 D4 77 F0 9C D4 77 !..w.[.wn..w...w
0042D2F0 E2 3D D4 77 6F EA D5 77 60 2B D9 77 2C DA D6 77 .=.wo..w`+.w,..w
0042D300 0F 79 D4 77 E5 B8 D6 77 C9 CC D5 77 EB AA D4 77 .y.w...w...w...w
0042D310 12 50 D5 77 E6 7E D4 77 00 79 D4 77 A2 BF D4 77 .P.w.~.w.y.w...w
0042D320 4E 7A D4 77 7B 41 D4 77 5D 68 D6 77 DB 61 D4 77 Nz.w{A.w]h.w.a.w
0042D330 DD 56 D4 77 5F 6F D6 77 40 D4 D5 77 22 8E D4 77 .V.w_o.w@..w"..w
0042D340 9B 79 D4 77 F8 6A D4 77 63 CD D6 77 DD 6D D6 77 .y.w.j.wc..w.m.w
0042D350 8B 9D D4 77 1D 5F D4 77 B8 71 D6 77 F4 45 D4 77 ...w._.w.q.w.E.w
0042D360 AF 6F D6 77 E7 4B D5 77 38 53 D4 77 E3 7D D4 77 .o.w.K.w8S.w.}.w
0042D370 BF 8E D4 77 BF 8E D4 77 51 BF D4 77 11 46 D4 77 ...w...wQ..w.F.w
0042D380 E4 B9 D4 77 48 44 D4 77 A3 64 D4 77 D9 6C D6 77 ...wHD.w.d.w.l.w
0042D390 39 45 D4 77 F8 DD D6 77 64 B0 D6 77 FB E2 D6 77 9E.w...wd..w...w
0042D3A0 3D CF D5 77 FB 6D D4 77 1F 97 D4 77 7C 9C D4 77 =..w.m.w...w|..w
0042D3B0 8A 41 D4 77 73 79 D4 77 BB 5A D4 77 42 9C D4 77 .A.wsy.w.Z.wB..w
0042D3C0 A7 52 D4 77 AF 6A D4 77 DE 6A D4 77 0A 59 D6 77 .R.w.j.w.j.w.Y.w
0042D3D0 5D CF D5 77 00 53 D4 77 53 55 D4 77 D8 86 D7 77 ]..w.S.wSU.w...w
0042D3E0 CE 58 D6 77 8A 6C D4 77 DC 59 D4 77 FB 7F D4 77 .X.w.l.w.Y.w...w
0042D3F0 0C 31 D5 77 94 56 D4 77 7E CC D5 77 D6 3F D4 77 .1.w.V.w~..w.?.w
0042D400 12 60 D4 77 64 61 D4 77 B6 41 D4 77 C9 48 D5 77 .`.wda.w.A.w.H.w
0042D410 DD 68 D6 77 9C 66 D6 77 C8 54 D4 77 B4 67 D4 77 .h.w.f.w.T.w.g.w
0042D420 59 70 D6 77 47 49 D5 77 3C 61 D4 77 50 D1 D5 77 Yp.wGI.w<a.wP..w
0042D430 83 D2 D5 77 29 6B D4 77 AB 74 D7 77 74 96 D4 77 ...w)k.w.t.wt..w
0042D440 6A 68 D4 77 07 9C D4 77 D2 A0 D4 77 F8 85 D4 77 jh.w...w...w...w
0042D450 29 53 D4 77 A8 41 D4 77 1E CC D5 77 A9 CB D6 77 )S.w.A.w...w©..w
0042D460 A7 45 D4 77 61 94 D4 77 3E 46 D4 77 AA 79 D4 77 .E.wa..w>F.w.y.w
0042D470 79 CF D5 77 0E 6C D4 77 77 68 D4 77 6E 6A D4 77 y..w.l.wwh.wnj.w
0042D480 AE 69 D6 77 1E 48 D6 77 F1 52 D4 77 D7 79 D4 77 ®i.w.H.w.R.w.y.w
0042D490 2C 50 D5 77 CF CC D6 77 BF 57 D6 77 66 D2 D5 77 ,P.w...w.W.wf..w
0042D4A0 AA 5B D6 77 69 43 D4 77 80 A1 D4 77 5A A2 D4 77 .[.wiC.w...wZ..w
0042D4B0 1B A2 D4 77 1B A2 D4 77 55 61 D4 77 50 5C D4 77 ...w...wUa.wP\.w
0042D4C0 D2 E8 D5 77 B3 E7 D5 77 21 8B D4 77 69 A2 D4 77 ...w...w!..wi..w
0042D4D0 48 6A D6 77 B0 F7 D6 77 CC 6C D6 77 76 8D D4 77 Hj.w...w.l.wv..w
0042D4E0 E7 D1 D5 77 69 5F D4 77 2E 7E D4 77 E2 52 D4 77 ...wi_.w.~.w.R.w
0042D4F0 46 C2 D4 77 CC 92 D4 77 00 00 00 00 94 90 38 77 F..w...w......8w
0042D500 9E 91 38 77 47 90 38 77 5E 91 38 77 80 91 38 77 ..8wG.8w^.8w..8w
0042D510 38 91 38 77 C0 90 38 77 F7 90 38 77 54 50 34 77 8.8w..8w..8wTP4w
0042D520 25 74 35 77 3D 51 34 77 E3 AD 34 77 00 00 00 00 %t5w=Q4w..4w....
Now open ImpREC , attach to this process, enter OEP=0002ADB4 and click "IAT Auto search". For IAT size enter 1000 and click "Get imports". There will be two invalid thunks. First one is good but that dll is not loaded in memory so ImpREC doesn't know to what dll those import belongs. Second thunk has one invalid import and that is truly invalid because there should bezero DWORD instead that thunk. It's just some junk that stayed from my inline rebuilder.
Now save that import tree to hard disk and open it in Notepad, we gona fix that invalid module. In tree you can see invalid thunk (red one below):
; Syntax for each function in a thunk (the separator is a TAB)
; ------------------------------------------------------------
; Flag RVA ModuleName Ordinal Name
;
; Details for <Valid> parameter:
; ------------------------------
; Flag: 0 = valid: no -> - Name contains the address of the redirected API (you can set
; it to zero if you edit it).
; - Ordinal is not considered but you should let '0000' as value.
; - ModuleName is not considered but you should let '?' as value.
;
; 1 = valid: yes -> All next parameters on the line will be considered.
; Function imported by ordinal must have no name (the 4th TAB must
; be there though).
;
; 2 = Equivalent to 0 but it is for the loader.
;
; 3 = Equivalent to 1 but it is for the loader.
;
; 4 = Equivalent to 0 with (R) tag.
;
; 5 = Equivalent to 1 with (R) tag.
;
; And finally, edit this file as your own risk! :-)
Target: x:\xxxxxxxxxxxxx\beria\packed.exe
OEP: 0002ADB4 IATRVA: 0002D0B0 IATSize: 00001000
FThunk: 0002D0B4 NbFunc: 0000001B
1 0002D0B4 kernel32.dll 007C DeleteCriticalSection
1 0002D0B8 kernel32.dll 023B LeaveCriticalSection
1 0002D0BC kernel32.dll 0091 EnterCriticalSection
1 0002D0C0 kernel32.dll 0210 InitializeCriticalSection
1 0002D0C4 kernel32.dll 0368 VirtualFree
1 0002D0C8 kernel32.dll 0365 VirtualAlloc
1 0002D0CC kernel32.dll 0246 LocalFree
1 0002D0D0 kernel32.dll 0242 LocalAlloc
1 0002D0D4 kernel32.dll 0379 WideCharToMultiByte
1 0002D0D8 kernel32.dll 0349 TlsSetValue
1 0002D0DC kernel32.dll 0348 TlsGetValue
1 0002D0E0 kernel32.dll 025F MultiByteToWideChar
1 0002D0E4 kernel32.dll 0170 GetModuleHandleA
1 0002D0E8 kernel32.dll 0163 GetLastError
1 0002D0EC kernel32.dll 0104 GetCommandLineA
1 0002D0F0 kernel32.dll 0386 WriteFile
1 0002D0F4 kernel32.dll 0301 SetFilePointer
1 0002D0F8 kernel32.dll 02F8 SetEndOfFile
1 0002D0FC kernel32.dll 02BF RtlUnwind
1 0002D100 kernel32.dll 029E ReadFile
1 0002D104 kernel32.dll 0291 RaiseException
1 0002D108 kernel32.dll 01A9 GetStdHandle
1 0002D10C kernel32.dll 0156 GetFileSize
1 0002D110 kernel32.dll 0159 GetFileType
1 0002D114 kernel32.dll 00B1 ExitProcess
1 0002D118 kernel32.dll 004F CreateFileA
1 0002D11C kernel32.dll 0031 CloseHandle
FThunk: 0002D124 NbFunc: 00000001
1 0002D124 user32.dll 01DD MessageBoxA
FThunk: 0002D12C NbFunc: 00000005
0 0002D12C ? 0000 771219E2
0 0002D130 ? 0000 7712ABB8
0 0002D134 ? 0000 771214EC
0 0002D138 ? 0000 77123D8F
0 0002D13C ? 0000 77121674
FThunk: 0002D144 NbFunc: 00000006
1 0002D144 advapi32.dll 01F9 RegSetValueExA
1 0002D148 advapi32.dll 01EC RegQueryValueExA
1 0002D14C advapi32.dll 01E2 RegOpenKeyExA
1 0002D150 advapi32.dll 01DB RegFlushKey
1 0002D154 advapi32.dll 01CD RegCreateKeyExA
1 0002D158 advapi32.dll 01C9 RegCloseKey
FThunk: 0002D160 NbFunc: 00000023
1 0002D160 kernel32.dll 0386 WriteFile
1 0002D164 kernel32.dll 0365 VirtualAlloc
1 0002D168 kernel32.dll 0342 TerminateThread
1 0002D16C kernel32.dll 0338 SizeofResource
1 0002D170 kernel32.dll 0301 SetFilePointer
1 0002D174 kernel32.dll 02FB SetErrorMode
1 0002D178 kernel32.dll 029E ReadFile
1 0002D17C kernel32.dll 025E MulDiv
1 0002D180 kernel32.dll 024F LockResource
1 0002D184 kernel32.dll 0241 LoadResource
1 0002D188 kernel32.dll 023C LoadLibraryA
1 0002D18C kernel32.dll 01F7 GlobalUnlock
1 0002D190 kernel32.dll 01F3 GlobalReAlloc
1 0002D194 kernel32.dll 01EF GlobalHandle
1 0002D198 kernel32.dll 01F0 GlobalLock
1 0002D19C kernel32.dll 01EC GlobalFree
1 0002D1A0 kernel32.dll 01E7 GlobalDeleteAtom
1 0002D1A4 kernel32.dll 01E5 GlobalAlloc
1 0002D1A8 kernel32.dll 01E3 GlobalAddAtomA
1 0002D1AC kernel32.dll 01D6 GetVersionExA
1 0002D1B0 kernel32.dll 01D5 GetVersion
1 0002D1B4 kernel32.dll 01AE GetSystemDefaultLCID
1 0002D1B8 kernel32.dll 0192 GetProcAddress
1 0002D1BC kernel32.dll 016E GetModuleFileNameA
1 0002D1C0 kernel32.dll 0166 GetLocaleInfoA
1 0002D1C4 kernel32.dll 0139 GetCurrentThreadId
1 0002D1C8 kernel32.dll 0137 GetCurrentProcessId
1 0002D1CC kernel32.dll 0136 GetCurrentProcess
1 0002D1D0 kernel32.dll 00ED FreeResource
1 0002D1D4 kernel32.dll 00EB FreeLibrary
1 0002D1D8 kernel32.dll 00DA FindResourceA
1 0002D1DC kernel32.dll 006B CreateThread
1 0002D1E0 kernel32.dll 004F CreateFileA
1 0002D1E4 kernel32.dll 0037 CompareStringA
1 0002D1E8 kernel32.dll 0031 CloseHandle
FThunk: 0002D1F0 NbFunc: 00000038
1 0002D1F0 gdi32.dll 0253 UnrealizeObject
1 0002D1F4 gdi32.dll 024B StretchDIBits
1 0002D1F8 gdi32.dll 024A StretchBlt
1 0002D1FC gdi32.dll 0244 SetWindowOrgEx
1 0002D200 gdi32.dll 0242 SetWinMetaFileBits
1 0002D204 gdi32.dll 0240 SetViewportOrgEx
1 0002D208 gdi32.dll 023D SetTextColor
1 0002D20C gdi32.dll 0239 SetStretchBltMode
1 0002D210 gdi32.dll 0236 SetROP2
1 0002D214 gdi32.dll 0223 SetEnhMetaFileBits
1 0002D218 gdi32.dll 0217 SetBkMode
1 0002D21C gdi32.dll 0216 SetBkColor
1 0002D220 gdi32.dll 0210 SelectPalette
1 0002D224 gdi32.dll 020F SelectObject
1 0002D228 gdi32.dll 0208 SaveDC
1 0002D22C gdi32.dll 0201 RestoreDC
1 0002D230 gdi32.dll 01F7 Rectangle
1 0002D234 gdi32.dll 01F6 RectVisible
1 0002D238 gdi32.dll 01F4 RealizePalette
1 0002D23C gdi32.dll 01EF Polyline
1 0002D240 gdi32.dll 01E1 PlayEnhMetaFile
1 0002D244 gdi32.dll 01DE PatBlt
1 0002D248 gdi32.dll 01D2 MoveToEx
1 0002D24C gdi32.dll 01C8 IntersectClipRect
1 0002D250 gdi32.dll 01C4 GetWindowOrgEx
1 0002D254 gdi32.dll 01C2 GetWinMetaFileBits
1 0002D258 gdi32.dll 01BD GetTextMetricsA
1 0002D25C gdi32.dll 01B7 GetTextExtentPointA
1 0002D260 gdi32.dll 01AA GetSystemPaletteEntries
1 0002D264 gdi32.dll 01A6 GetStockObject
1 0002D268 gdi32.dll 019B GetPaletteEntries
1 0002D26C gdi32.dll 0196 GetObjectA
1 0002D270 gdi32.dll 0176 GetEnhMetaFilePaletteEntries
1 0002D274 gdi32.dll 0175 GetEnhMetaFileHeader
1 0002D278 gdi32.dll 0172 GetEnhMetaFileBits
1 0002D27C gdi32.dll 016C GetDeviceCaps
1 0002D280 gdi32.dll 016B GetDIBits
1 0002D284 gdi32.dll 0166 GetCurrentPositionEx
1 0002D288 gdi32.dll 014B GetBitmapBits
1 0002D28C gdi32.dll 00D8 ExcludeClipRect
1 0002D290 gdi32.dll 00CE EnumFontsA
1 0002D294 gdi32.dll 0090 DeleteObject
1 0002D298 gdi32.dll 008E DeleteEnhMetaFile
1 0002D29C gdi32.dll 008D DeleteDC
1 0002D2A0 gdi32.dll 0051 CreateSolidBrush
1 0002D2A4 gdi32.dll 004C CreateRectRgn
1 0002D2A8 gdi32.dll 0049 CreatePenIndirect
1 0002D2AC gdi32.dll 0046 CreatePalette
1 0002D2B0 gdi32.dll 003B CreateFontIndirectA
1 0002D2B4 gdi32.dll 0034 CreateDIBitmap
1 0002D2B8 gdi32.dll 002E CreateCompatibleDC
1 0002D2BC gdi32.dll 002D CreateCompatibleBitmap
1 0002D2C0 gdi32.dll 002A CreateBrushIndirect
1 0002D2C4 gdi32.dll 0028 CreateBitmap
1 0002D2C8 gdi32.dll 0024 CopyEnhMetaFileA
1 0002D2CC gdi32.dll 0013 BitBlt
FThunk: 0002D2D4 NbFunc: 00000089
1 0002D2D4 user32.dll 02D6 WindowFromPoint
1 0002D2D8 user32.dll 02D3 WinHelpA
1 0002D2DC user32.dll 02D1 WaitMessage
1 0002D2E0 user32.dll 02D0 WaitForInputIdle
1 0002D2E4 user32.dll 02BC UpdateWindow
1 0002D2E8 user32.dll 02B4 UnregisterClassA
1 0002D2EC user32.dll 02AF UnhookWindowsHookEx
1 0002D2F0 user32.dll 02AB TranslateMessage
1 0002D2F4 user32.dll 02AA TranslateMDISysAccel
1 0002D2F8 user32.dll 02A5 TrackPopupMenu
1 0002D2FC user32.dll 029A SystemParametersInfoA
1 0002D300 user32.dll 0293 ShowWindow
1 0002D304 user32.dll 0290 ShowOwnedPopups
1 0002D308 user32.dll 028F ShowCursor
1 0002D30C user32.dll 0285 SetWindowRgn
1 0002D310 user32.dll 028B SetWindowsHookExA
1 0002D314 user32.dll 0287 SetWindowTextA
1 0002D318 user32.dll 0284 SetWindowPos
1 0002D31C user32.dll 0283 SetWindowPlacement
1 0002D320 user32.dll 0281 SetWindowLongA
1 0002D324 user32.dll 027B SetTimer
1 0002D328 user32.dll 0270 SetScrollPos
1 0002D32C user32.dll 026F SetScrollInfo
1 0002D330 user32.dll 026D SetRect
1 0002D334 user32.dll 026B SetPropA
1 0002D338 user32.dll 025E SetMenu
1 0002D33C user32.dll 0258 SetForegroundWindow
1 0002D340 user32.dll 0257 SetFocus
1 0002D344 user32.dll 024E SetCursor
1 0002D348 user32.dll 024B SetClipboardData
1 0002D34C user32.dll 0245 SetCapture
1 0002D350 user32.dll 0244 SetActiveWindow
1 0002D354 user32.dll 023C SendMessageA
1 0002D358 user32.dll 0235 ScrollWindow
1 0002D35C user32.dll 0232 ScreenToClient
1 0002D360 user32.dll 022D RemovePropA
1 0002D364 user32.dll 022C RemoveMenu
1 0002D368 user32.dll 022B ReleaseDC
1 0002D36C user32.dll 022A ReleaseCapture
1 0002D370 user32.dll 021B RegisterClipboardFormatA
1 0002D374 user32.dll 021B RegisterClipboardFormatA
1 0002D378 user32.dll 0217 RegisterClassA
1 0002D37C user32.dll 020C PtInRect
1 0002D380 user32.dll 0202 PostQuitMessage
1 0002D384 user32.dll 0200 PostMessageA
1 0002D388 user32.dll 01FE PeekMessageA
1 0002D38C user32.dll 01F4 OpenClipboard
1 0002D390 user32.dll 01F3 OffsetRect
1 0002D394 user32.dll 01EF OemToCharA
1 0002D398 user32.dll 01DD MessageBoxA
1 0002D39C user32.dll 01DC MessageBeep
1 0002D3A0 user32.dll 01D4 MapVirtualKeyA
1 0002D3A4 user32.dll 01C9 LoadStringA
1 0002D3A8 user32.dll 01BC LoadIconA
1 0002D3AC user32.dll 01B8 LoadCursorA
1 0002D3B0 user32.dll 01B3 KillTimer
1 0002D3B4 user32.dll 01B1 IsZoomed
1 0002D3B8 user32.dll 01B0 IsWindowVisible
1 0002D3BC user32.dll 01AD IsWindowEnabled
1 0002D3C0 user32.dll 01AC IsWindow
1 0002D3C4 user32.dll 01A9 IsRectEmpty
1 0002D3C8 user32.dll 01A7 IsIconic
1 0002D3CC user32.dll 01A1 IsDialogMessage
1 0002D3D0 user32.dll 01A0 IsClipboardFormatAvailable
1 0002D3D4 user32.dll 0194 InvalidateRect
1 0002D3D8 user32.dll 0193 IntersectRect
1 0002D3DC user32.dll 018F InsertMenuItemA
1 0002D3E0 user32.dll 018E InsertMenuA
1 0002D3E4 user32.dll 018B InflateRect
1 0002D3E8 user32.dll 017C GetWindowThreadProcessId
1 0002D3EC user32.dll 0178 GetWindowTextA
1 0002D3F0 user32.dll 0176 GetWindowRgn
1 0002D3F4 user32.dll 0175 GetWindowRect
1 0002D3F8 user32.dll 0174 GetWindowPlacement
1 0002D3FC user32.dll 016F GetWindowLongA
1 0002D400 user32.dll 015E GetSystemMetrics
1 0002D404 user32.dll 015D GetSystemMenu
1 0002D408 user32.dll 015B GetSysColor
1 0002D40C user32.dll 015A GetSubMenu
1 0002D410 user32.dll 0157 GetScrollPos
1 0002D414 user32.dll 014B GetPropA
1 0002D418 user32.dll 0146 GetParent
1 0002D41C user32.dll 016B GetWindow
1 0002D420 user32.dll 0139 GetMenuStringA
1 0002D424 user32.dll 0138 GetMenuState
1 0002D428 user32.dll 0133 GetMenuItemCount
1 0002D42C user32.dll 012D GetMenu
1 0002D430 user32.dll 0129 GetLastActivePopup
1 0002D434 user32.dll 0122 GetKeyState
1 0002D438 user32.dll 0120 GetKeyNameTextA
1 0002D43C user32.dll 011B GetIconInfo
1 0002D440 user32.dll 0118 GetForegroundWindow
1 0002D444 user32.dll 0117 GetFocus
1 0002D448 user32.dll 010F GetDesktopWindow
1 0002D44C user32.dll 010E GetDCEx
1 0002D450 user32.dll 010D GetDC
1 0002D454 user32.dll 010C GetCursorPos
1 0002D458 user32.dll 0109 GetCursor
1 0002D45C user32.dll 0102 GetClipboardData
1 0002D460 user32.dll 0100 GetClientRect
1 0002D464 user32.dll 00F7 GetClassInfoA
1 0002D468 user32.dll 00F4 GetCapture
1 0002D46C user32.dll 00EC GetActiveWindow
1 0002D470 user32.dll 00EA FrameRect
1 0002D474 user32.dll 00E3 FillRect
1 0002D478 user32.dll 00E0 EqualRect
1 0002D47C user32.dll 00DF EnumWindows
1 0002D480 user32.dll 00DC EnumThreadWindows
1 0002D484 user32.dll 00CD EnumClipboardFormats
1 0002D488 user32.dll 00C9 EndPaint
1 0002D48C user32.dll 00C5 EnableWindow
1 0002D490 user32.dll 00C3 EnableMenuItem
1 0002D494 user32.dll 00C2 EmptyClipboard
1 0002D498 user32.dll 00BD DrawTextA
1 0002D49C user32.dll 00B9 DrawMenuBar
1 0002D4A0 user32.dll 00B7 DrawIcon
1 0002D4A4 user32.dll 00A2 DispatchMessageA
1 0002D4A8 user32.dll 009A DestroyWindow
1 0002D4AC user32.dll 0098 DestroyMenu
1 0002D4B0 user32.dll 0096 DestroyCursor
1 0002D4B4 user32.dll 0096 DestroyCursor
1 0002D4B8 user32.dll 0092 DeleteMenu
1 0002D4BC user32.dll 008F DefWindowProcA
1 0002D4C0 user32.dll 008C DefMDIChildProcA
1 0002D4C4 user32.dll 008A DefFrameProcA
1 0002D4C8 user32.dll 0061 CreateWindowExA
1 0002D4CC user32.dll 005F CreatePopupMenu
1 0002D4D0 user32.dll 005E CreateMenu
1 0002D4D4 user32.dll 0058 CreateIcon
1 0002D4D8 user32.dll 0043 CloseClipboard
1 0002D4DC user32.dll 0041 ClientToScreen
1 0002D4E0 user32.dll 003A CheckMenuItem
1 0002D4E4 user32.dll 001C CallWindowProcA
1 0002D4E8 user32.dll 001B CallNextHookEx
1 0002D4EC user32.dll 000E BeginPaint
1 0002D4F0 user32.dll 0027 CharLowerA
1 0002D4F4 user32.dll 0003 AdjustWindowRectEx
FThunk: 0002D4FC NbFunc: 0000000C
1 0002D4FC comctl32.dll 0038 ImageList_GetDragImage
1 0002D500 comctl32.dll 0031 ImageList_DragShowNolock
1 0002D504 comctl32.dll 004C ImageList_SetDragCursorImage
1 0002D508 comctl32.dll 0030 ImageList_DragMove
1 0002D50C comctl32.dll 002F ImageList_DragLeave
1 0002D510 comctl32.dll 002E ImageList_DragEnter
1 0002D514 comctl32.dll 0036 ImageList_EndDrag
1 0002D518 comctl32.dll 002A ImageList_BeginDrag
1 0002D51C comctl32.dll 004B ImageList_SetBkColor
1 0002D520 comctl32.dll 0046 ImageList_ReplaceIcon
1 0002D524 comctl32.dll 002D ImageList_Destroy
1 0002D528 comctl32.dll 002C ImageList_Create
There is one invalid thunk with 5 unknown imports. Instead API names, there are API addresses there. But which dll is that and what API's should be there? Answer is simple, just look in IAT table of packed.exe:
0042623A 1B 00 00 00 01 00 00 00 6F 6C 65 61 75 74 33 32 ........oleaut32
0042624A 2E 64 6C 6C 00 00 73 00 6F 00 63 00 69 00 61 00 .dll..s.o.c.i.a.
0042625A 74 00 69 00 00 00 00 00 1C 00 00 00 05 00 00 00 t.i.............
0042626A 61 64 76 61 70 69 33 32 2E 64 6C 6C 00 00 5C 00 advapi32.dll..\.
...
...
00426C8A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426C9A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426CAA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426CBA 00 00 00 00 01 00 00 00 23 00 00 00 00 00 00 00 ........#.......
00426CCA 24 D1 02 00 00 00 00 00 56 61 72 69 61 6E 74 43 $.......VariantC
00426CDA 68 61 6E 67 65 54 79 70 65 45 78 00 00 00 00 00 hangeTypeEx.....
00426CEA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426CFA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426D0A 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ................
00426D1A 23 00 00 00 00 00 00 00 2C D1 02 00 00 00 00 00 #.......,.......
00426D2A 56 61 72 69 61 6E 74 43 6F 70 79 49 6E 64 00 00 VariantCopyInd..
00426D3A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426D4A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426D5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426D6A 00 00 00 00 01 00 00 00 23 00 00 00 00 00 00 00 ........#.......
00426D7A 30 D1 02 00 00 00 00 00 56 61 72 69 61 6E 74 43 0.......VariantC
00426D8A 6C 65 61 72 00 00 00 00 00 00 00 00 00 00 00 00 lear............
00426D9A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426DAA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426DBA 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ................
00426DCA 23 00 00 00 00 00 00 00 34 D1 02 00 00 00 00 00 #.......4.......
00426DDA 53 79 73 53 74 72 69 6E 67 4C 65 6E 00 00 00 00 SysStringLen....
00426DEA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426DFA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426E0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426E1A 00 00 00 00 01 00 00 00 23 00 00 00 00 00 00 00 ........#.......
00426E2A 38 D1 02 00 00 00 00 00 53 79 73 41 6C 6C 6F 63 8.......SysAlloc
00426E3A 53 74 72 69 6E 67 4C 65 6E 00 00 00 00 00 00 00 StringLen.......
00426E4A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426E5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00426E6A 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ................
00426E7A 23 00 00 00 00 00 00 00 3C D1 02 00 00 00 00 00 #.......<.......
As you can see, dll is oleaut32.dll and API's are
VariantChangeTypeEx
VariantCopyInd
VariantClear
SysStringLen
SysAllocStringLen
We now can edit missing part in import tree:
FThunk: 0002D12C NbFunc: 00000005
1 0002D12C oleaut32.dll 0000 VariantChangeTypeEx
1 0002D130 oleaut32.dll 0000 VariantCopyInd
1 0002D134 oleaut32.dll 0000 VariantClear
1 0002D138 oleaut32.dll 0000 SysStringLen
1 0002D13C oleaut32.dll 0000 SysAllocStringLen
Save changes to import tree, load it in ImpREC and fix dump. Run dump and it should work ;-) !
That's it , beria is unpacked.
-->
-
=-=-=-=-=-=-=-=
در آخر اسکریپت مربوط به آموزش فوق :
msgyn "IGNORE ALL EXCEPTIONS and make sure that NO BREAKPOINT IS LEFT! Then (this is the most important) set OllyDbg to be just-in-time debugger (instead DrWatson) and set to 'Attach without confirmation'. You have done all this?"
cmp $RESULT,0
je exit
var tmp1
var tmp2
//--------- Base and Size of image -----------
var Image_Base
gmi eip,MODULEBASE
mov Image_Base,$RESULT
var Image_Size
gmi eip,MODULESIZE
mov Image_Size,$RESULT
//------------- Debugee PID ----------------
var process_PID
gpa "CreateProcessA","kernel32.dll"
bp $RESULT
esto
bc eip
mov process_PID,esp
add process_PID,28
mov process_PID,[process_PID]
add process_PID,8
rtr
sti
sti
sti
mov process_PID,[process_PID]
//------ Number of imports in packed target -------
var imports
mov imports,eip
add imports,1C3
mov tmp1,imports
bp imports
esto
bc eip
sti
sti
sti
sti
mov imports,edx
//------------ OEP of packed target ---------------
var OEP
mov OEP,tmp1
add OEP,0a
bp OEP
esto
bc eip
add OEP,2
mov OEP,[OEP]
mov OEP,[OEP]
//------------ Base of import section --------------
var IAT
mov IAT,eip
add IAT,CD9
bp IAT
esto
bc eip
sti
mov IAT,ecx
//---------- Decrypt all untill IAT section ------------
var rel_oep
mov rel_oep,OEP
and rel_oep,0FFF
var break
mov break,eip
sub break,0cdd
bp break
var jump
mov jump,break
add jump,12
mov tmp1,[jump]
mov [jump],9090eceb
esto
add break,2
mov break,[break]
mov [break],401000
Decrypt: //Decrypt untill the end of file.
esto
add [break],1000
mov tmp2,[break]
cmp tmp2,IAT
jne Decrypt
bc eip
//------------ Detach processes -------------
mov eax,process_PID
asm eip,"PUSH EAX"
sti
asm eip,"CALL DebugActiveProcessStop"
msg "Done! Check log window for details and instructions."
log " "
log "- - - - - - - - - - - - - - - - - - - -"
log "BERIA 0.07 - UNPACKING SCRIPT by haggar"
log "- - - - - - - - - - - - - - - - - - - -"
log " "
log "Target is unpacked and processes (almost) detached."
log "If you have done all like I told you, another Olly"
log "will popup after you press F8 with unpacked target"
log "loaded in it, right on OEP."
log " "
log "Some information about unpacked target:"
log " "
log Image_Base
log Image_Size
log process_PID
log OEP
log IAT
log imports
log " "
log "Press F8 now to detach processes."
exit:
ret
-
==============================
Alex Protector v1.0 beta2 - manually unpacking
==============================
Alex Protector is simple freeware protector for PE files. It has IAT redirection very simular to Armadillo's Import Eliminator feature and a very interesting way of stealing bytes from OEP.
You will need usual tools for this:
- Windows XP
- OllyDbg 1.10
- LordPE
- ImpREC
- Hex editor
1. Quick analising
It is always intersting to trace trough code and see what exactly protector does, but that kind of approach is very hard and time consuming. I was going to write that kind of tutorial, but I put aside this project to examne some others protectors and lost will for continuing. So I decide that I will wrote tutorial that will "just" explain how to quick unpack some target.
Protector doesn't have some fancy anti-debug tricks and we can just run protected file trough debugger without problem. Debug tricks in this protector are based on exceptions and RDTSC opcodes. I already told you that the most interesting part is OEP stealing and IAT redirection.
Protector will redirect imports to some allocated block of memory and obfuscate it there. Also it gona steal couple first bytes from OEP and mix them with junk in another separate allocaded memory block.
Let see what we have there. Open target in Olly. You will get "Bad or unknown format..." message. This is minor anoyance because we cannot see sections properly in memory map window. Now, place breakpoint on the last opcode in the VirtualAlloc API , click "go to" -> "expression" and enter VirtualAlloc, then place bp on first RETN opcode (in my case it is RETN 10):
77E7ABC5 PUSH EBP
77E7ABC6 MOV EBP,ESP
77E7ABC8 PUSH DWORD PTR SS:[EBP+14]
77E7ABCB PUSH DWORD PTR SS:[EBP+10]
77E7ABCE PUSH DWORD PTR SS:[EBP+C]
77E7ABD1 PUSH DWORD PTR SS:[EBP+8]
77E7ABD4 PUSH -1
77E7ABD6 CALL kernel32.VirtualAllocEx
77E7ABDB POP EBP
77E7ABDC RETN 10 <--------------------- Here is mine!!!
Now run olly with Shift+F9 and you will break on that bp. EAX register will hold now some value, that value is base address of some allocated memory block. Write down that value, keep pressing and do that every time when you stop untill crackme opens. Then in memory map check every block that has been allocated. There are couple interesting (select disassemble view on each dump window):
Block with stolen OEP's code:
This block holds stolen OEP code mixed with junk. You will easy recognized it because it has only on jump in whole block and that jump is at the end and leads in code section to place after stolen bytes:
003B0000 MOV EDI,DFB4AF72
003B0006 LEA EDI,DWORD PTR DS:[1A58BA5F]
003B000C DEC EDI
003B000E SHRD EDI,ESI,0F2
003B0012 BSR EDI,ESI
...
...
lot of similar code here
...
...
003B0C5C TEST EDI,ESI
003B0C5E TEST EDI,874CDC1C
003B0C64 AND EDI,9378C643
003B0C6A JMP packed.004079DE <---------------- Jump to code section!!!
003B0C6F ADD BYTE PTR DS:[EAX],AL
003B0C71 ADD BYTE PTR DS:[EAX],AL
003B0C73 ADD BYTE PTR DS:[EAX],AL
003B0C75 ADD BYTE PTR DS:[EAX],AL
003B0C77 ADD BYTE PTR DS:[EAX],AL
We will not try to find original bytes here, we going just to append this code to our main dump. Most of files will work properly even if you don't add this code. Stolen code are usually 2-3 bytes, never more.
Block with obfuscated imports:
This block looks like this: It has lot of jumps and you will notice RDTSC opcodes which checks are program is debugged. You will also notice some API values. This block you can easy find just by following some import in unpacked crackme:
003A0000 ADD AL,0
003A0002 CMP AL,BYTE PTR DS:[EAX]
003A0004 JMP SHORT 003A0007
003A0006 LEAVE
003A0007 PUSHAD
003A0008 RDTSC
003A000A JMP SHORT 003A000D
003A000C LEAVE
003A000D MOV EBX,EAX
003A000F JMP SHORT 003A0012
003A0011 LEAVE
003A0012 MOV ECX,EDX
003A0014 RDTSC
003A0016 SUB EAX,EBX
003A0018 SBB EDX,ECX
003A001A JMP SHORT 003A001D
003A001C ???
003A001D RDTSC
003A001F ADD EAX,EBX
003A0021 ADC EDX,ECX
003A0023 RDTSC
003A0025 JMP SHORT 003A0028
003A0027 ???
003A0028 SUB EAX,EBX
003A002A JMP SHORT 003A002D
003A002C ???
003A002D SBB EDX,ECX
003A002F TEST EDX,EDX
003A0031 JNZ SHORT 003A0040
003A0033 POPAD
003A0034 JMP SHORT 003A0037
003A0036 ???
003A0037 PUSH ntdll.RtlDeleteCriticalSection <--- Here is API value pushed!
003A003C JMP SHORT 003A003F
003A003E JMP E93BEC06
There is one more block that holds API names, but it is not important for us. Ofcourse, above addresses will probably be different on your computer.
To fix all that we need some section where we will place our import thunks because ImpREC cannot read those which are not in main image. Problem is that we don't know which one section to use because we cannot see them in Olly. But good thing is that protector doesn't check PE header and file size, so we can add couple sections with LordPE. Close olly and open our target in hex editor (make backup before) and add to the end of file 4000h bytes. Open then file in LordPE's pe editor and add one section that you will name NewOEP. Set it's VirtualSize=2000 ans RawSize=1500. Then create one more section, call it NewIAT and enter sizes same as NewOEP. Run target and it will work normall :) Good! Now we gona unpack that modified target.
2. OEP and stolen code
Ok, do you remember that block that has stolen code? Common sense tell us that block will be executed last, before jumping to code section. So we need to break there somehow. That is really easy, you need to use memory and hardware breakpoints and you will catch it easy. You can do it in this way: Place bp on the end of VirtualAlloc and keep pressing Shift+F9 untill you see in EAX value that is address of your stolen OEP block. At my computer that is b30000, for you it can be different so you just follow way how did I do it and not exactly values. But keep pressing untill that value changes to another and then stop. Now go to that 3b0000 (or whatever) in the CPU window:
003B0000 0000 ADD BYTE PTR DS:[EAX],AL <---- Place mem and hw bp here!
003B0002 0000 ADD BYTE PTR DS:[EAX],AL
003B0004 0000 ADD BYTE PTR DS:[EAX],AL
003B0006 0000 ADD BYTE PTR DS:[EAX],AL
003B0008 0000 ADD BYTE PTR DS:[EAX],AL
003B000A 0000 ADD BYTE PTR DS:[EAX],AL
003B000C 0000 ADD BYTE PTR DS:[EAX],AL
003B000E 0000 ADD BYTE PTR DS:[EAX],AL
003B0010 0000 ADD BYTE PTR DS:[EAX],AL
003B0012 0000 ADD BYTE PTR DS:[EAX],AL
003B0014 0000 ADD BYTE PTR DS:[EAX],AL
003B0016 0000 ADD BYTE PTR DS:[EAX],AL
...
...
As you can see there is nothing there. Normally because nothing is written there yet. Place on first line breakpoint memory on write and and the same spot, hardware bp on execution. That is so we will stop when protector writes here and when this code is being executed. Remove bp from VirtualAlloc and presShift+F9. First you will break two times here in this unpacking procedure:
00411316 MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] <--- First time here.
00411317 MOV BL,2
00411319 CALL packed.0041138B
...
... <-------------------------------------------------- One more time somewhere here.
...
0041139D ADC ECX,ECX
0041139F CALL packed.0041138B
004113A4 JB SHORT packed.00411398
004113A6 RETN
004113A7 SUB EDI,DWORD PTR SS:[ESP+28]
004113AB MOV DWORD PTR SS:[ESP+1C],EDI
004113AF POPAD
004113B0 RETN
Press Shift+F9 once more and you will break on hardware bp on execution in our block:
003B0000 MOV EDI,DFB4AF72 <---------------------- Hre you are! Binary copy from here...
003B0006 LEA EDI,DWORD PTR DS:[1A58BA5F]
003B000C DEC EDI
...
...
003B0C5E TEST EDI,874CDC1C
003B0C64 AND EDI,9378C643 <---------------------- ...to here!
003B0C6A JMP packed.004079DE <------------------- This jump you will assemble.
003B0C6F ADD BYTE PTR DS:[EAX],AL
You can remove all breakpoints now. You are at the place before jumping to "false" OEP and execution of packed target. We will first deal with this stolen code. What we gona do is just binary copy-paste all that code to our NewOEP section, so select all from 3b0000 to 3b0c64 and binary copy it. Last jump we will change manually. Dou you remember where starts our NewOEP section? If not check file with LordPE, it satarts from 14000+400000=414000 so go there in olly:
00414000 ADD BYTE PTR DS:[EAX],AL
00414002 ADD BYTE PTR DS:[EAX],AL
00414004 ADD BYTE PTR DS:[EAX],AL
00414006 ADD BYTE PTR DS:[EAX],AL
00414008 ADD BYTE PTR DS:[EAX],AL
...
...
and binary paste previous copied code:
00414000 MOV EDI,DFB4AF72
00414006 LEA EDI,DWORD PTR DS:[1A58BA5F]
0041400C DEC EDI
...
...
00414C64 AND EDI,9378C643
00414C6A ADD BYTE PTR DS:[EAX],AL <------ And just here you need to place jump to false OEP.
00414C6C ADD BYTE PTR DS:[EAX],AL
00414C6E ADD BYTE PTR DS:[EAX],AL
And just assemble at the end that jump to false OEP. We couldn't binary copy it because value would be different, you have now:
00414000 MOV EDI,DFB4AF72
00414006 LEA EDI,DWORD PTR DS:[1A58BA5F]
0041400C DEC EDI
...
...
00414C64 AND EDI,9378C643
00414C6A JMP packed.004079DE
00414C6F NOP
00414C70 ADD BYTE PTR DS:[EAX],AL
00414C72 ADD BYTE PTR DS:[EAX],AL
Stolen code is resolved and now we must fix IAT.
3. Building new IAT
This is little harder part but it's not problem. First you must see how obfuscated import looks. Follow this address to see one example:
00401084 JMP DWORD PTR DS:[3A0784]
That is one import jump. So jump reads value that is stored at 3a0784 and jumps to that value. But interesting is, that value is just 4 bytes below first one DS:[003A0784]=003A0788. if we follow that in dump we will see this:
003A0784 88 07 3A 00 EB 01 C9 60 0F 31 EB 01 C9 8B D8 EB ..:....`.1......
003A0794 01 C9 8B CA 0F 31 2B C3 1B D1 EB 01 C7 0F 31 03 .....1+.......1.
003A07A4 C3 13 D1 0F 31 EB 01 C7 2B C3 EB 01 C7 1B D1 85 ....1...+.......
003A07B4 D2 75 0D 61 EB 01 C7 68 A1 AA E7 77 EB 01 E9 C3 .u.a...h...w....
003A07C4 EB 01 E9 F0 0F C7 C8 EB 01 E9 D2 07 3A 00 EB 01 ............:...
Select disassemble view to get clear picture
003A0784 8807 MOV BYTE PTR DS:[EDI],AL <--- Jump reads these 4 bytes and jumps there!
003A0786 3A00 CMP AL,BYTE PTR DS:[EAX] <--/
003A0788 EB 01 JMP SHORT 003A078B <--------- But that leads here!
003A078A C9 LEAVE
003A078B 60 PUSHAD
003A078C 0F31 RDTSC
003A078E EB 01 JMP SHORT 003A0791
003A0790 C9 LEAVE
003A0791 8BD8 MOV EBX,EAX
003A0793 EB 01 JMP SHORT 003A0796
003A0795 C9 LEAVE
003A0796 8BCA MOV ECX,EDX
003A0798 0F31 RDTSC
003A079A 2BC3 SUB EAX,EBX
003A079C 1BD1 SBB EDX,ECX
003A079E EB 01 JMP SHORT 003A07A1
003A07A0 C7 ???
003A07A1 0F31 RDTSC
003A07A3 03C3 ADD EAX,EBX
003A07A5 13D1 ADC EDX,ECX
003A07A7 0F31 RDTSC
003A07A9 EB 01 JMP SHORT 003A07AC
003A07AB C7 ???
003A07AC 2BC3 SUB EAX,EBX
003A07AE EB 01 JMP SHORT 003A07B1
003A07B0 C7 ???
003A07B1 1BD1 SBB EDX,ECX
003A07B3 85D2 TEST EDX,EDX
003A07B5 75 0D JNZ SHORT 003A07C4
003A07B7 61 POPAD
003A07B8 EB 01 JMP SHORT 003A07BB
003A07BA C7 ???
003A07BB 68 A1AAE777 PUSH kernel32.ReadFile
003A07C0 EB 01 JMP SHORT 003A07C3
003A07C2 -E9 C3EB01E9 JMP E93BF38A
Ha, you see trick? It just continues from same place. This code has some junk and when I removed it, we can see this:
003A0784 8807 MOV BYTE PTR DS:[EDI],AL <--- Our first 4 bytes.
003A0786 3A00 CMP AL,BYTE PTR DS:[EAX] <--/
003A0788 90 NOP
003A0789 90 NOP
003A078A 90 NOP
003A078B 60 PUSHAD
003A078C 0F31 RDTSC <-------------------- Hmm, check.
003A078E 90 NOP
003A078F 90 NOP
003A0790 90 NOP
003A0791 8BD8 MOV EBX,EAX
003A0793 90 NOP
003A0794 90 NOP
003A0795 90 NOP
003A0796 8BCA MOV ECX,EDX
003A0798 0F31 RDTSC
003A079A 2BC3 SUB EAX,EBX
003A079C 1BD1 SBB EDX,ECX
003A079E 90 NOP
003A079F 90 NOP
003A07A0 90 NOP
003A07A1 0F31 RDTSC
003A07A3 03C3 ADD EAX,EBX
003A07A5 13D1 ADC EDX,ECX
003A07A7 0F31 RDTSC
003A07A9 90 NOP
003A07AA 90 NOP
003A07AB 90 NOP
003A07AC 2BC3 SUB EAX,EBX
003A07AE 90 NOP
003A07AF 90 NOP
003A07B0 90 NOP
003A07B1 1BD1 SBB EDX,ECX
003A07B3 85D2 TEST EDX,EDX
003A07B5 75 0D JNZ SHORT 003A07C4 <------- You see? If this code is traced, then we jump below!
003A07B7 61 POPAD
003A07B8 90 NOP
003A07B9 90 NOP
003A07BA 90 NOP
003A07BB 68 A1AAE777 PUSH kernel32.ReadFile <---- Push API value!
003A07C0 90 NOP
003A07C1 90 NOP
003A07C2 90 NOP
003A07C3 C3 RETN <---------------------- Then jump to API!
003A07C4 90 NOP
003A07C5 90 NOP
003A07C6 90 NOP
003A07C7 F0:0FC7C8 LOCK CMPXCHG8B EAX <------- If traced we jump here where ilegal operation is!
We will fix this: we just take API value from push opcode 003A07BB 68 A1AAE777 PUSH kernel32.ReadFile and that value A1AAE777 we place instead our first 4 bytes of this obfuscated API call. But we will not do that manually, we will just use ollyscript for that. Lusky for us, all impoct jumps use this same pattern. After using script, we have:
00401084 JMP DWORD PTR DS:[3A0784] ; kernel32.ReadFile
But that is not done since ImpREc still cannot recognize such API jump. We will now use other script for making new IAT in our main image. First remember that we made NewIAT section at 16000+400000=416000 and we will redirect jumps there. Script will ask you where OEP is, that is 401000 section and where is newIAt section, that is 416000, and then it will rebuild new thunks. Your API jump will have new value:
00401084 JMP DWORD PTR DS:[416000] ; kernel32.ReadFile
Check that section in dump and you will see thunks:
00416000 A1 AA E7 77 90 C6 E6 77 81 EF E7 77 8D F0 E7 77 ...w...w...w...w
00416010 63 98 E7 77 DF E5 E7 77 AB E2 E7 77 8D 73 E7 77 c..w...w...w.s.w
00416020 FC AC E7 77 7E 17 E6 77 94 D9 E7 77 D3 6F ED 77 ...w~..w...w.o.w
00416030 35 4E E7 77 0C 61 E7 77 4F A7 E7 77 9C A8 E7 77 5N.w.a.wO..w...w
00416040 AA 7E E7 77 D5 A5 E7 77 CB 60 E7 77 C5 AB E7 77 .~.w...w.`.w...w
00416050 1E 15 E8 77 98 A6 E7 77 FC AC E7 77 D9 AC E7 77 ...w...w...w...w
00416060 D5 A5 E7 77 44 AB E7 77 A2 A9 E7 77 B1 E2 E7 77 ...wD..w.©.w...w
00416070 8D 73 E7 77 FC AC E7 77 94 D9 E7 77 02 DD E7 77 .s.w...w...w...w
00416080 AA 7E E7 77 0C 61 E7 77 00 00 00 00 44 0C F6 77 .~.w.a.w....D..w
00416090 02 15 F5 77 DE 55 F7 77 90 56 F7 77 CA 25 F5 77 ...w.U.w.V.w.%.w
004160A0 00 00 00 00 64 B0 D6 77 FB 6D D4 77 39 D6 D6 77 ....d..w.m.w9..w
004160B0 21 8B D4 77 50 5C D4 77 69 43 D4 77 77 43 D4 77 !..wP.wiC.wwC.w
004160C0 12 60 D4 77 FB 7F D4 77 7C 9C D4 77 FB 6D D4 77 .`.w...w|..w.m.w
004160D0 64 B0 D6 77 51 BF D4 77 1D 5F D4 77 9B 79 D4 77 d..wQ..w._.w.y.w
004160E0 E2 3D D4 77 84 5B D4 77 00 00 00 00 D8 17 DD 77 .=.w.[.w.......w
004160F0 9A 22 DD 77 10 24 DD 77 00 00 00 00 74 16 12 77 .".w.$.w....t..w
00416100 4B 17 12 77 8F 3D 12 77 EC 14 12 77 B8 AB 12 77 K..w.=.w...w...w
00416110 E2 19 12 77 00 00 00 00 CE 7C 01 7F 00 00 00 00 ...w.....|......
00416120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Good, IAT is fixed! Now you need dump and repair file.
3. Dumping and correcting dump
Just return now to that original block with stolen OEP code and place bp on last jump:
003B0C6A JMP packed.004079DE <------- Place bp here!
003B0C6F ADD BYTE PTR DS:[EAX],AL
003B0C71 ADD BYTE PTR DS:[EAX],AL
003B0C73 ADD BYTE PTR DS:[EAX],AL
Run, remove bp and pres F7 to get in target code section:
004079DE CALL packed.004045B4
004079E3 MOV ESI,packed.004095CC
004079E8 MOV EDI,packed.004095E4
004079ED MOV EBX,packed.004095A0
004079F2 XOR EAX,EAX
004079F4 PUSH EBP
004079F5 PUSH packed.00407C84
004079FA PUSH DWORD PTR FS:[EAX]
004079FD MOV DWORD PTR FS:[EAX],ESP
00407A00 MOV EAX,DWORD PTR DS:[408280]
00407A05 MOV EAX,DWORD PTR DS:[EAX]
...
...
Dump it from there. Use ImpREC, as OEP enter 79de and find imports. You will have all imports in 6 modules without any invalid. Fix dump and close ImpREC. If you start dumped file, it will probably run normaly because protector has stole just couple bytes, but I was testing some files that have important first few bytes and file would crush. So what we need is to change Original Entry Point to that NewOEP block where we have pasted stolen code. Open dump in LordPE and for EntryPoint enter 14000, save changes and run. File works ok :) That is all, I have included my dump and you can examne it so you can see what and how did I do it.
4. Couple more words
I have included in archive next files: packed.exe - original packed target; packed+2.exe - packed file which I added two new sections before unpacking; dumped.exe - unpacked and dumped target; "AlexProtector1.0 - tutorial.txt" - this tutorial.
I have included two scripts for fixing IAT. First Script "AlexProt I.txt" will fix obfuscation from IAT block. You need just enter base address of that block. Second script "AlexProt II.txt" is one that will make new IAT in some section that you chose. You need enter base address of code section so script can find jumps/calls and base of new section where you want to make new IAT. Scrip also needs to be manually changed in some parts for every new file. Actually, this script is one from my Armadillo tutorial.
Btw, for unpacking AlexProtextor 1.0 you have loveboom's script that can unpack and fix IAT on the fly. You can find that script on the forum in topic where I posted OllyScript plugin. But that script will fail in this example.
In this example we have unpacked delphi program where import jumps where JMP DWORD[xxxxxxxx]. In some other apps like ASM compiled, or C++, you can find CALL DWORD[xxxxxxxx].
-
Level : intermediate
====================================
Armadillo 4.30a with Debug Blocker - manually unpacking
====================================
Welcome to new, 5. tutorial in Armadillo serial! Today we will dealing Armadillo 4.30a with standard protection plus Debug Blocker feature, for those who are not familiar with terms - the infamous double process protection.
1. Tools and requirements
- Windows XP , MUST HAVE FOR THIS TUTORIAL;
- OllyDbg 1.10 (hide olly plugin or similar);
- LordPE;
- ImpREC;
- Hex editor;
For following this tutorial you must know how to use above tools, you must have some knowledge about PE file structure and you must know how to unpack single process Armadillo.
2. Killing Debug Blocker - taking control of unpacking process
Acctually, defeating Debug Blocker is very easy, you just must be careful that you do not make some mistake because then you will have to it all again. First, ignore all exceptions in olly and add custom ones if stop on some during unpacking. Load target in Olly, then use plugin to hide Olly and place breakpoint on OutputDebugStringA API. Here is Entry Point of armadillo:
00456000 PUSHAD
00456001 CALL Armadill.00456006
00456006 POP EBP
00456007 PUSH EAX
00456008 PUSH ECX
00456009 BSWAP EDX
0045600B NOT EDX
0045600D PUSHFD
0045600E NOT EDX
00456010 BSWAP EDX
00456012 JMP SHORT Armadill.00456023
00456014 MOV ECX,EBB80FEB
00456019 POP ES
...
...
...
Now you need to place bp on WriteProcessMemory in kernel but armadillo is checking couple first opcodes for brakpoints so I will place bp on end of that API. Hardware breakpoints didn't worked for me neither. So click "go to" and enter WriteProcessMemory to land in kernel:
77E61A94 PUSH EBP <---------------------- Begining of API, you are here!
77E61A95 MOV EBP,ESP
77E61A97 PUSH ECX
77E61A98 PUSH ECX
77E61A99 MOV EAX,DWORD PTR SS:[EBP+C]
77E61A9C PUSH EBX
77E61A9D MOV EBX,DWORD PTR SS:[EBP+14]
77E61AA0 PUSH ESI
...
...
...
77E61B23 LEAVE
77E61B24 RETN 14 <---------------------- Place bp here!!!
Place bp where I told you and run target. You will break on your bp. Remove it and with F7 return to main module and then press Ctrl+A to analyse code. Scroll up and you will see:
00437CD3 PUSH EAX ; /pBytesWritten = 00000001
00437CD4 PUSH 2 ; |BytesToWrite = 2
00437CD6 LEA ECX,DWORD PTR SS:[EBP-8] ; |
00437CD9 PUSH ECX ; |Buffer = 0012D83C
00437CDA MOV EDX,DWORD PTR SS:[EBP+10] ; |Armadill.<ModuleEntryPoint>
00437CDD PUSH EDX ; |Address = 7FFE0304
00437CDE MOV EAX,DWORD PTR SS:[EBP+8] ; |
00437CE1 MOV ECX,DWORD PTR DS:[EAX] ; |
00437CE3 PUSH ECX ; |hProcess = 0012D83C
00437CE4 CALL DWORD PTR DS:[<&KERNEL32.WriteProce>; WriteProcessMemory
00437CEA JO SHORT Armadill.00437CF3 <------------------------------------ You are here!!!!
00437CEC JL SHORT Armadill.00437CF1
00437CEE JMP SHORT Armadill.00437CF5
00437CF0 DB E8
00437CF1 JE SHORT Armadill.00437CEE
00437CF3 JMP SHORT Armadill.00437CEE
00437CF5 JMP SHORT Armadill.00437D56
00437CF7 LEA EDX,DWORD PTR SS:[EBP-4]
00437CFA PUSH EDX ; /pBytesWritten = 7FFE0304
00437CFB PUSH 2 ; |BytesToWrite = 2
00437CFD PUSH Armadill.0046E4A4 ; |Buffer = Armadill.0046E4A4
00437D02 MOV EAX,DWORD PTR SS:[EBP+10] ; |Armadill.<ModuleEntryPoint>
00437D05 PUSH EAX ; |Address = 1
00437D06 MOV ECX,DWORD PTR SS:[EBP+8] ; |
00437D09 MOV EDX,DWORD PTR DS:[ECX] ; |ntdll.77F75BD1
00437D0B PUSH EDX ; |hProcess = 7FFE0304
00437D0C CALL DWORD PTR DS:[<&KERNEL32.WriteProce>; WriteProcessMemory <------ Place bp here and run!!!
You see two calls to WriteProcessMemory and you have just returned from first one. What did this first one done, I don't know, but for us is important second call. Place bp it and run. A new process will will start, now you have two processes in task manager. When you break, remove bp and take a look closer what we have here:
/pBytesWritten = 0000004C
|BytesToWrite = 2 <-------------- Two bytes are written.
|Buffer = Armadill.0046E4A4 <---- This is buffer where bytes are. Follow this in dump!!!
|Armadill.<ModuleEntryPoint>
|Address = 456000 <-------------- This is where bytes will be written!
|
|
|hProcess = 0000004C
WriteProcessMemory
You see that arm will write two bytes from buffer to 456000 address. That address is entry point of armadillo itself. Folow that buffer in dump window (immediate constant):
0046E4A4 60 E8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 `...............
0046E4B4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0046E4C4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Now change those bytes to EB FE which is hex value for infinite jump. This will make armadillo second process to loop forever. Remember original bytes or write them down because later you will need to restore them. Changes are:
0046E4A4 EB FE 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0046E4B4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0046E4C4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Now press F9 to start target. Your CPU usage will grow because infinite jump. Dont mind for that. In a command bar type "bp WaitForDebugEvent" and place bp. You will break in kernel on that API:
77EB5B98 >PUSH EBP
77EB5B99 MOV EBP,ESP
77EB5B9B SUB ESP,68
77EB5B9E PUSH ESI
77EB5B9F PUSH DWORD PTR SS:[EBP+C]
77EB5BA2 LEA EAX,DWORD PTR SS:[EBP-8]
...
...
Remove that bp and return to armadillo code. You shoud be here (EAX should be=0):
0043328D TEST EAX,EAX
0043328F JE Armadill.00435CA5
00433295 MOV EAX,DWORD PTR SS:[EBP-204]
0043329B AND EAX,0FF
004332A0 TEST EAX,EAX
004332A2 JE SHORT Armadill.004332B7
004332A4 MOV ECX,DWORD PTR DS:[46E5B4]
004332AA CMP DWORD PTR DS:[ECX+20],0
004332AE JE SHORT Armadill.004332B7
004332B0 MOV BYTE PTR SS:[EBP-204],0
004332B7 PUSH Armadill.0046E4A8 ; /pCriticalSection = Armadill.0046E4A8
004332BC CALL DWORD PTR DS:[<&KERNEL32.EnterCriti>; EnterCriticalSection
004332C2 PUSHAD
004332C3 XOR EAX,EAX
...
...
Now we need to deatach processes. First you must know what proces is armadillo debugger process and what process is being debugged. That is very easy; process that is created later is debugger. But we must know it's PID. It is also not hard; open window for attaching to active process in olly and you will see two indentical processes. One that is RED, is our first proces. Second process is one that is created later and we need his PID. For my example that PID is 510. It will be different for you (it is different every time you start program). Remember that PID. Now we will make patch that will kill debug blocker. On our line of code assemble next opcodes:
0043328D PUSH 510 <----------------------------- 510=my PID, your will be different!
00433292 CALL kernel32.DebugActiveProcessStop <- To stop debugging. Only WinXP has this API!!!
00433297 NOP <---------------------------------- Then place bp here and run!!!
00433298 NOP
00433299 NOP
0043329A NOP
0043329B AND EAX,0FF
004332A0 TEST EAX,EAX
004332A2 JE SHORT Armadill.004332B7
004332A4 MOV ECX,DWORD PTR DS:[46E5B4]
004332AA CMP DWORD PTR DS:[ECX+20],0
004332AE JE SHORT Armadill.004332B7
004332B0 MOV BYTE PTR SS:[EBP-204],0
004332B7 PUSH Armadill.0046E4A8 ; /pCriticalSection = Armadill.0046E4A8
004332BC CALL DWORD PTR DS:[<&KERNEL32.EnterCriti>; EnterCriticalSection
004332C2 PUSHAD
004332C3 XOR EAX,EAX
...
...
PUSH opcode will have value of your PID. Then add CALL DebugActiveProcessStop, place bp on NOP below it and run. When olly break on your bp, Debug Blocker is defeated, two armadillo processes are separated now! Congratulations ;) DebugActiveProcessStop is reason why you must have Windows XP to kill Debug Blocker, only XP has this API that we need to deatach processes. Do you know what you can do now? You can close your Olly, that will kill just first proces. Armadillo second proces is looping forever in memory, you can see that in task manager. Read next chapter to see what's next.
3. Attaching and unpacking Armadillo
You have killed Debug Blocker, but now you need to unpack target. Without debug blocker, we have buisness with common armadillo and I have already explained how to unpack armadillo with single process tricks. But we must do one thing more. Our two processes are still there and we need only one. While your first olly is still working, open another one and attach to one of our two processes. You need attach to one that has PID that we have pushed, ie. second process. In my example it was 510 one.
When you attach, you will break in ntdll.dll on system breakpoint. Press F9 to run it and then press F12 to pause program. You will break here:
00456000 >JMP SHORT Armadill.<ModuleEntryPoint> <------- Here!!!
00456002 ADD BYTE PTR DS:[EAX],AL
00456004 ADD BYTE PTR DS:[EAX],AL
00456006 POP EBP
00456007 PUSH EAX
00456008 PUSH ECX
00456009 BSWAP EDX
0045600B NOT EDX
0045600D PUSHFD
0045600E NOT EDX
00456010 BSWAP EDX
00456012 JMP SHORT Armadill.00456023
00456014 MOV ECX,EBB80FEB
00456019 POP ES
0045601A MOV ECX,EB900FEB
0045601F OR CH,BH
00456021 JMP SHORT Armadill.0045602E
00456023 PREFIX REPNE:
00456024 JMP SHORT Armadill.0045601B
00456026 JMP SHORT Armadill.0045601E
...
...
...
Very good. Naw you can close first olly. Do you see infinite jump at Entry Point? You need restore original bytes there. Those where 60e8, restore them and you'll see usuall armadiillo entry point:
00456000 >PUSHAD
00456001 CALL Armadill.00456006
00456006 POP EBP
00456007 PUSH EAX
00456008 PUSH ECX
00456009 BSWAP EDX
0045600B NOT EDX
0045600D PUSHFD
0045600E NOT EDX
00456010 BSWAP EDX
00456012 JMP SHORT Armadill.00456023
00456014 MOV ECX,EBB80FEB
00456019 POP ES
0045601A MOV ECX,EB900FEB
0045601F OR CH,BH
00456021 JMP SHORT Armadill.0045602E
00456023 PREFIX REPNE:
00456024 JMP SHORT Armadill.0045601B
00456026 JMP SHORT Armadill.0045601E
...
...
...
And now you have armadillo with standard protection, just usual IAT problem. You can unpack it normal as any other single process armadillo. Use script that I give you in archive to unpack it if you are lazy, but it would be better that you practice a little. Dump and fix IAT with ImpREC. You can also reduce file size with LordPE.
-
Level : intermediate
=====================================
Armadillo 3.70 with Import Elimination - manually unpacking
=====================================
This is 4. tutorial in Armadillo serial and today we will talk about another specific Armadillo feature - Import Elimination.
1. Intro
Tools
- OllyDbg 1.10
- LordPE
- ImpREC
- Hex editor
Hi and welcome to new Armadillo tutorial!
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
Our target has a weird OEP:
00404000 WAIT <-------------------------- OEP!
00404001 FINIT
00404003 WAIT
00404004 FCLEX
00404006 FLDCW WORD PTR DS:[406000]
0040400C PUSH EBP
0040400D MOV EBP,ESP
0040400F CALL IAT_elim.00404415
00404014 PUSH 0
00404019 CALL DWORD PTR DS:[A99018] <------- IAT elimination!
0040401F MOV DWORD PTR DS:[40F007],EAX
00404024 PUSHAD
00404025 MOV DWORD PTR DS:[40F00B],ESP
0040402B JMP IAT_elim.00404060
00404030 MOV ESP,DWORD PTR DS:[40F00B]
00404036 POPAD
00404037 CALL IAT_elim.00404955
0040403C CALL IAT_elim.004044AE
00404041 MOV ESP,EBP
00404043 POP EBP
00404044 PUSH DWORD PTR DS:[40F1D4]
0040404A CALL DWORD PTR DS:[A99168] <------- IAT elimination!
00404050 WAIT
00404051 FCLEX
00404053 FLDCW WORD PTR DS:[406000]
00404059 RETN
Check where call at 00404019 leads you:
003BD687 PUSH EBP
003BD688 MOV EBP,ESP
003BD68A PUSH ECX
003BD68B PUSH EBX
003BD68C PUSH ESI
003BD68D PUSH EDI
003BD68E PUSHAD
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
003BD6B7 POPAD
003BD6B8 MOV EAX,DWORD PTR SS:[EBP-4]
003BD6BB POP EDI
003BD6BC POP ESI
003BD6BD POP EBX
003BD6BE LEAVE
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:
EAX 00000001
ECX 003E0AA4 ASCII "ArmAccess"
EDX F03B0000
EBX 376BA5C1
ESP 0012BAD4
EBP 0012BAE8
ESI 77C422A2 msvcrt._stricmp
EDI 00000004
EIP 003BA80E
Keep pressing untill you see there next:
EAX FFFFFFFF
ECX 0012CEB0 ASCII "MessageBoxA"
EDX 0012CEB0 ASCII "MessageBoxA"
EBX 1BDA0012
ESP 0012BAE8
EBP 0012ED3C
ESI 00002710
EDI 0012D1E0
EIP 77C4230A msvcrt.77C4230A
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:
00404000 WAIT
00404001 FINIT
00404003 WAIT
00404004 FCLEX
00404006 FLDCW WORD PTR DS:[406000]
0040400C PUSH EBP
0040400D MOV EBP,ESP
0040400F CALL IAT_elim.00404415
00404014 PUSH 0
00404019 CALL DWORD PTR DS:[A99020] ; kernel32.GetModuleHandleA
0040401F MOV DWORD PTR DS:[40F007],EAX
00404024 PUSHAD
00404025 MOV DWORD PTR DS:[40F00B],ESP
0040402B JMP IAT_elim.00404060
00404030 MOV ESP,DWORD PTR DS:[40F00B]
00404036 POPAD
00404037 CALL IAT_elim.00404955
0040403C CALL IAT_elim.004044AE
00404041 MOV ESP,EBP
00404043 POP EBP
00404044 PUSH DWORD PTR DS:[40F1D4]
0040404A CALL DWORD PTR DS:[A99170] ; kernel32.ExitProcess
00404050 WAIT
00404051 FCLEX
00404053 FLDCW WORD PTR DS:[406000]
00404059 RETN
0040405A ADD BYTE PTR DS:[EAX],AL
...
...
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:
00404019 FF15 2090A900 CALL DWORD PTR DS:[A99020] ; kernel32.GetModuleHandleA
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:
00404019 FF15 2090A900 CALL DWORD PTR DS:[A99020] ; kernel32.GetModuleHandleA
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:
findop x,#FF15????A900#
where x is variable for address. I sugest you to read readme.txt from OllyScrypt plugin because this plugin is very helpfull for unpacking.
After using script, my pointers look like this:
00404019 FF15 00104000 CALL DWORD PTR DS:[401000] ; kernel32.GetModuleHandleA
Check .idata section now:
00401000 D9 AC E7 77 00 00 00 00 63 98 E7 77 00 00 00 00 ...w....c..w....
00401010 91 4B E7 77 00 00 00 00 25 E2 E7 77 00 00 00 00 .K.w....%..w....
00401020 7C 88 E7 77 00 00 00 00 A1 16 F5 77 00 00 00 00 |..w.......w....
00401030 CC 95 E6 77 00 00 00 00 A1 16 F5 77 00 00 00 00 ...w.......w....
00401040 6B 15 F5 77 00 00 00 00 2C DA D6 77 00 00 00 00 k..w....,..w....
00401050 D2 A0 D4 77 00 00 00 00 94 56 D4 77 00 00 00 00 ...w.....V.w....
00401060 2E 7E D4 77 00 00 00 00 32 A7 E7 77 00 00 00 00 .~.w....2..w....
00401070 12 50 D5 77 00 00 00 00 64 B0 D6 77 00 00 00 00 .P.w....d..w....
00401080 F0 9C D4 77 00 00 00 00 04 58 E7 77 00 00 00 00 ...w.....X.w....
00401090 C9 56 E7 77 00 00 00 00 00 00 00 00 00 00 00 00 .V.w............
004010A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
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.