Level : intermediate
Anticrack Software Protector Pro v1.35 - manually unpacking
Hi and wellcome to my new tutorial ;) Today we gona talk about ACProtect 1.35 also known as Anticrack Protector or UltraProtect.
Some features of this protector:
- Anti debugging tricks like IsDebuggerPresent and CreateToolhep32Snapshot,
- Imports redirection,
- Stolen and obfuscated OEP,
- Code replacing,
- Embedded protection,
- Runtime encryption and decryption,
- Compression of executable,
- Some more minor things.
In this tutorial we will see how to unpack target, repair IAT, fix stolen OEP and we gona say couple words about code replacing. Our target will be AVIpreview.exe. AVIpreview is some freeware abandoned application which I packed with trial version of ACProtect so you don't think that I spreed cracks or warez trough mine tutorials. I chose this app because it's not so big but it has lot of imports which is better for practice than some small crackme. Tools that you'll need:
- OllyDbg 1.10
- Hex Editor
- Target and stuff is here http://www.reversing.be/binaries/articles/200509131247.rar
1. QUICK ANALYSIS
ACProtector code is full of encrypted layers so it can be very annoying to trace trough. When you open target in olly, you are at the entry point here:
00421001 CALL AVIPrevi.00421007
00421006 JNZ SHORT AVIPrevi.00420F8B
00421008 LES EAX,FWORD PTR DS:[EBX+EAX*2]
0042100B INC EDI
Trace little with F7 and you'll see where is end of first decryptor loop:
00421128 JNZ AVIPrevi.0042109E <------------ Jump that throw you back!
0042112E JMP SHORT AVIPrevi.00421131 <------- Place bp here to avoid it.
00421130 JNS SHORT AVIPrevi.00421198
That is example how ALL decryptor loops in this protector looks. Always is some JNZ that throws you back. Below it is usually some JMP or PUSH EAX or some CALL. Never mind for that, you just place bp below our JNZ and press F9 to decrypt. But there is a loot of such decryptor loops and manually is very hard to precede in this way. Because that I wrote small script that will find such jumps and place bp below it, the execute it to the that bp, remove bp and ask you do you want to continue. But we will get to this later.
1.2 Interesting weakness
Altough protector encrypts it's own code, it doesn't encrypt packed file. That is big, BIG, weakness, because if you pack app without compressing and using CRC check, file can be cracked without unpacking. This is very bad from ACProtector side.
1.2 Antidebug stuff
Now, let me show you how does ACProtect hides imports. But first, we must avoid anti-stuff. First, ignore ALL exceptions in Olly, then use some plugin to hide olly from IsDebuggerPresent check, then place in command line (or command bar) "bp CreateToolhelp32Snapshot+1". You will place bp on second instruction of this API because protector checks first instruction for software bp, and it also chechs for hardware breakpoints. Run it and you should break in kernel32 on that API:
77E999A6 PUSH EBP <--------------------- First API instruction.
77E999A7 MOV EBP,ESP <------------------ You are here!!!
77E999A9 SUB ESP,0C
77E999AC PUSH ESI
77E999AD MOV ESI,DWORD PTR SS:[EBP+C]
77E99A15 POP ESI
77E99A17 RETN 8 <---------------------- Return to protector code.
Little explanation: this API create snapshot of all processes, threads and heaps and it's purpose is to determ what program started our packed target. Our target needs to be started by EXPLORER.EXE. If target is started via olly or some other debugger, protector will terminate it and packed target. There is simple trick how to avoid this. I sow this trick in KaGra's tutorial: We will fool protector that there are no processes and rest by paching this API. Do not wory, all changes are temporary in memory so you will not screw your kernel32.dll. Watch this:
77E999A6 PUSH EBP
77E999A7 POP EBP <---------------------- Restoring pushed value from stack.
77E999A8 XOR EAX,EAX <------------------ EAX=0, so pretector think there are nothing to see.
77E999AA RETN 8 <----------------------- Return to protector code.
77E999AD MOV ESI,DWORD PTR SS:[EBP+C]
77E999B0 TEST ESI,ESI
77E999B2 JE kernel32.77EA800A
77E99A15 POP ESI
77E99A17 RETN 8
Now place memory breakpoint on code section
00401000 00014000 AVIPrevi .text code
and run target. You will first stop here because stolen bytes:
00412D16 JMP DWORD PTR DS: ; MSVCRT._except_handler3
00412D1C JMP DWORD PTR DS:[41556C] ; MSVCRT._controlfp
Press F9 once more time and you'll get that ACProtect reminder nag. Click OK on it and you will now land on false OEP:
00412AEB CMP DWORD PTR DS:[41B020],EBX
00412AF1 JNZ SHORT AVIPrevi.00412AFF
00412AF3 PUSH AVIPrevi.00412D12
00412AF8 CALL DWORD PTR DS:
00412AFE POP ECX
00412AFF CALL AVIPrevi.00412D00
Above is some junk code to confuse you. Protector has done some import redirection to it's own section (perplex one). Let me show you, go to memory window and double click on last section - perplex. In dump window select disassemble view and check this:
00421044 PUSH 7F62A025
00421049 XOR DWORD PTR SS:[ESP],8850BE0
00421051 PUSH 476408A8
00421056 XOR DWORD PTR SS:[ESP],3083BFF8
004212F5 PUSH 7757B958
004212FA XOR DWORD PTR SS:[ESP],83EA58
00421302 PUSH 77521539
00421307 XOR DWORD PTR SS:[ESP],84C3D8
These are hidden imports. Value after push will be XOR-ed with second one and than RETN will throw us at that address whic is acctually some API address. This is not hard to fix but there is smarter way to do this. Now we gona unpack our target.
2. FIXING IMPORTS AND DUMPING
ACProtector has some more lacks; it doesn't encrypt import section and it doesn't change it's name. Take a look in the memory map window, .rdata is section which should hold imports. Place memory bp on access on it, hide olly from IsDebuggerPresent check and place CreateToolhelp32Snapshot bp like first time. Run target and you will break exactly at the procedure where protector redirects imports, from 435856 to 435AD7. I will not paste here whole code bacuse is't big, I will show you only the most important parts.
First it uses GetProcAddress to get API. Then it first ckecking is that API MessageBox or RegisterHotKey. Those two API's are important for protector and they are always redirected. I don't know why they are important, but we will prevent that redirecting:
00435986 CMP EAX,DWORD PTR SS:[EBP+41E2D8] ; USER32.MessageBoxA
0043598C JE SHORT AVIPrevi.004359AE <-------------------------------- NOP this jump!!!
00435992 CMP EAX,DWORD PTR SS:[EBP+4101AC] ; USER32.RegisterHotKey
00435998 JE SHORT AVIPrevi.004359A3 <-------------------------------- NOP this jump!!!
Simply NOP that two jumps. Next, protector checks which API needs to be redirected. Read comments:
004359C2 JE SHORT AVIPrevi.004359D9
004359C8 CMP DWORD PTR SS:[EBP+4023FE],ESI
004359CE JE SHORT AVIPrevi.004359D9
004359D4 JMP SHORT AVIPrevi.00435A39 <------ Good jump!!!
004359D9 CMP BYTE PTR SS:[EBP+4159EB],0
004359E0 JE SHORT AVIPrevi.00435A39 <-------- Good jump!!!
004359E6 JMP SHORT AVIPrevi.004359EF <------- Bad jump!!!
004359EB ADD DWORD PTR DS:[EAX],EAX
004359ED ADD BYTE PTR DS:[EAX],AL
004359EF MOV ESI,DWORD PTR SS:[EBP+40FCF3]
004359F5 ADD ESI,0D
004359F8 SUB ESI,AVIPrevi.00401BEA
004359FE SUB ESI,EBP
00435A00 CMP ESI,0
00435A03 JG SHORT AVIPrevi.00435A39 <-------- Good jump!!!
This part redirect (or not) imports:
00435A16 MOV EBX,EAX
00435A18 POP EAX
00435A19 XOR EAX,EBX
00435A1B MOV BYTE PTR DS:[ESI],68
00435A1E MOV DWORD PTR DS:[ESI+1],EAX
00435A21 MOV DWORD PTR DS:[ESI+5],243481
00435A28 MOV DWORD PTR DS:[ESI+8],EBX
00435A2B MOV BYTE PTR DS:[ESI+C],0C3
00435A2F POP EBX
00435A30 MOV EAX,ESI
00435A32 ADD DWORD PTR SS:[EBP+40FCF3],0D
00435A39 POP ESI <-------------------------- Good place to jump, import OK!!!
00435A3B MOV EDX,EAX
00435A3D SUB EDI,DWORD PTR SS:[EBP+40FC2E]
00435A43 MOV EAX,EDI
00435A45 MOV ECX,101
00435A4A LEA EDI,DWORD PTR SS:[EBP+40F0D3]
00435A50 REPNE SCAS DWORD PTR ES:[EDI]
00435A52 OR ECX,ECX
00435A54 JE SHORT AVIPrevi.00435A69
That jump which I called "Bad jump" will trhow you at the place where import will be redirected. To fix that and prevent redirection, you need change that jump to jump where good jumps leads. So change:
004359E6 JMP SHORT AVIPrevi.004359EF
004359E6 JMP SHORT AVIPrevi.00435A39
Now scroll down and to the end of procedure and place bp there:
00435AB1 CMP ECX,0 <------------------------- Place bp here!!!
00435AB4 JL SHORT AVIPrevi.00435AD0
00435AB6 MOV EAX,DWORD PTR DS:[ESI+ECX*4]
00435AB9 MOV EBX,DWORD PTR DS:[ESI+ECX*4+4]
00435ABD SUB EAX,EBX
00435ABF ROR EAX,1B
00435AC2 XOR EAX,EDX
00435AC4 ADD EDX,668C0E89
00435ACA MOV DWORD PTR DS:[ESI+ECX*4],EAX
00435ACD DEC ECX
00435ACE JMP SHORT AVIPrevi.00435AB1
00435AD2 CALL AVIPrevi.004334BC
This procedure at the end will just destroy import redirection procedure when is done. Run our target to decrypt all imports and you'll stop on the abowe bp. You have just fixed imports! Bravo ;) Now you need break on the code section where false OEP is and dump file. I eaxplained how you will avoid anti-debug stuff already, after that use lordPE for dumping file. Fix imports with ImpREC where OEP is 00412AEB=00012AEB, our false OEP. There will not be neither one invalid import :) If you have just one or two invalid, then you have done something wrong.
Run dumped_.exe and file will just close or crush. That is expected since we have stolen OEP issue. We gona fix that now.
3. STOLEN OEP AND FIXNG DUMP
ACProtect has stole lot of instructiones from OEP and mix them with some junk. It is hard to clear false code and restore stolen bytes exactly, but we can fix this little different and easier. We gona just copy-paste all that code to our dumped file , not taking worry what is junk and what is not. First we need to prepare dumped file.
Open your favorite hex editor and add 1000(hex) bytes to the end of dumped_.exe (file that is fixed with ImpREC) and save changes. It could be less than 1000 but who cares. Then load that file in LordPE's PE editor, click on sections, select last one (.mackt) and click to edit section header. There change VirtualSize from 1000 to 2000 and RawSize from 1000 to 2000 too. Save changes. We have done that because there we will paste our code so wee need bigger last section. One more thing, use LordPE's rebuilder to rebuild dumped file so you can open it in olly. Bu be sure that in Rebuilder options is checked only Validate PE.
Now open packed file and get to the CreateToolhelp32Snapshot check. Fix it, and return to protector code where you'll see some api calls. Ignore that and scroll down to end of this procedure, place bp there:
0043200F JMP SHORT AVIPrevi.00431FF2
00432013 RETN <--------------------------- Place bp here!!!
Run and you'll break on it, remove bp, trace untill you see next one:
004334A1 JMP SHORT AVIPrevi.00433484
Do the same and execute last RETN with F7 and you should be here:
00437005 JMP AVIPrevi.0043700D
0043700A ADC EBX,ECX
0043700C INC EBP
0043700D MOV EAX,3D
00437012 CALL AVIPrevi.00437018
00437017 JGE SHORT AVIPrevi.00436F9C
00437019 ADD AL,24
That is just beggining of decryptor layers. You need to decrypt them and find stolen bytes. As I sad on the begining, there are large number of decryption layers and it's hard to trace manualy. Now is time to use my small scrip that will make this easier. Run "ACProtector - pass layers.txt" script and that script will ask you do you want to decrypt next layer. Keep clicking "Yes" untill you get here:
00438652 PUSH EAX
00438653 CALL AVIPrevi.00438659
00438658 JS SHORT AVIPrevi.004385DD
0043865A LES EAX,FWORD PTR DS:[EAX+EBX*2]
0043865D CALL AVIPrevi.004325D9
00438662 JS AVIPrevi.0043866A
00438668 TEST EBP,ESI
0043866B PUSH EAX
0043866C MOV EAX,AVIPrevi.00421E15
00438671 MOV DWORD PTR DS:[EAX],ESI
00438673 POP EAX
00438674 PUSH DWORD PTR DS:[421E15]
0043867A PUSH EAX
0043867B MOV DWORD PTR SS:[ESP],EDX
0043867E PUSH EDI
0043867F MOV EDI,AVIPrevi.00421C8D
00438684 MOV EDX,EDI
00438686 POP EDI
00438687 PUSH ECX
00438688 MOV ECX,EDX
0043868A MOV ESI,ECX
0043868C POP ECX
0043868D POP DWORD PTR DS:[421D01]
00438693 MOV EDX,DWORD PTR DS:[421D01]
00438699 MOV DWORD PTR DS:[ESI],EBP
0043869B POP DWORD PTR DS:[421DB9]
004386A1 PUSH EBX
004386A2 MOV EBX,AVIPrevi.00421DB9
004386A7 MOV ESI,DWORD PTR DS:[EBX]
004386A9 POP EBX
004386AA PUSH DWORD PTR DS:[421C8D]
004386B0 MOV DWORD PTR DS:[421D7D],ESP
This code between POPAD and PUSHAD is stolen OEP's code with some obfuscated code. Trace to 0043866B PUSH EAX, then select all that code from 0043866B 4386B8 and binary copy it. Open another instance of olly and open in it our dumped file and go to 441000 where you can see that there are lot of empty space. That is part of our last section which we expanded. Now, binary paste there all code that you have copied from first file. You will do that for all code that we found. Now use again our script untill you get at the next part and the binary copy-paste that code too right after first pasted part. Pasted code must continue on each other. You will find next stolen code at these addresses:
After this last one, you will get ACProtect nag window. Click OK on it and script will normally stop on next decrypted place and ask you do you want to continue. Click "No" because you should be at the very end. There should be some CALL's and this part below:
0043DEB0 LOOPD SHORT AVIPrevi.0043DEAA
0043DEB2 POPAD <---------------------------- Place bp here!
0043DEB3 JMP SHORT AVIPrevi.0043DEB6
Place bp, run and execute that jump and you will find yourself on jump that throws you at the false OEP:
0043DEB6 JMP DWORD PTR DS:[43DEF8] ; AVIPrevi.00412AEB
This is not much important for us, but you can also binary copy that jump too and paste it to dumped file. Then save all that changes to dumped file by selecting all that code and selecting "Copy to executable -> selection". Shit! I got message "Unable to locate date in the executable file.". Damn! That means that we need more space in our dumped file, I didn't added enough bytes or I started to paste bytes to far. But don't panic folks, we can fast fix this without doing all this job again. Just copy dumped_.exe in the came folder so you have now "Copy of dumped_.exe" there. Don't close your two olly so you do not lose all your job. Open copy of dumped in hex editor and add 2000 bytes more. Then in LordPE set VS and RS to 4000. Use PE rebuilder again. Then all code that you have pasted to dumped_.exe from 441000 to 44130A, binary copy it and paste it to "Copy of dumped_.exe" from the same address (altough addres isn't important). Now save changes, yes it works, and close that olly. Stolen code is retrived, we just need to set new OEP. Open dumped file in LordPE's PE editor again and for EntryPoint enter 41000, then save changes. Now, the moment of truth! Run file.... YES!!! It works! Open some avi file and program will work OK :) Congratulation, you have just unpacked ACProtector Pro 1.35.
4. CODE REPLACING
I will just sad couple words about code replacing. ACProtect substitute some simple instructions like MOV DWORD [xxxx],yyyy to some CALL zzzz which calls protector code. There that stolen instruction will be executed after lot of junk code. The best way to repair this would be to not touch nothing, just leave it there. Our AVIpreview had lot of this instructions which I didn't touch and our unpacked file works fine. This kind of code replacing needs more studing.
5. FINAL WORDS
That was all folks. There is some more things that needs to be discussed about ACPtotect , but maybe in next tutorial. ACProtect is not bad protector and it's not for begginers.
As usuall, greets goes to BIW crew and all users. See you in next tutorial :)
[ haggar ]