Alex Protector v1.0 beta2 - manually unpacking

Tuesday, October 04 2005 @ 10:15 PM CEST

Contributed by: haggar

Level : beginner

==============================
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
- Target is here http://www.reversing.be/binaries/articles/20051004221300702.rar




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].


Greets goes to all BIW crew, especialy to detten for publishing my tutorials on biw site. See you in the next tutorial :)




[ haggar ]

8 comments



http://www.reversing.be/article.php?story=20051004221547626