Wednesday, April 13 2005 @ 04:57 PM CEST Contributed by: haggar Views: 24580
Level : newbie
This is my tutorial about ASProtect. Well, actually it is my attempt to understand what ASProtect doing to packed programs. I wrote this tut maybe couple days ago and yet today I would change some parts if I had a time.
There is an 'interactive' Ollydbg plugin tutorial in the attachment, or you can just read the regular tutorial below.
Enjoy and post questions, commmets, corrections, ideas ..... I need all of them ;-)
Find the Ollydbg plugin tutorial & Ollydbg asprotect plugins here : attachment
Lately I had some succses with unpacking ASProtect (half)manually so I have decided to share this experience with others (beginners).
Like many other noobs, I have read dozen of tutorials which describe unpacking ASProtect, but blindly following that tutorials I couldn't unpack anything by myself. Those "...just press Ctrl+F9 now and you will emediatley land on OEP..." or "...enter tc>900000 and hit run..." have take me usually to some exception that Olly couldn't pass. So I started to digging and pasing through ASPr code just to tray figure something myself. Well, I had some sucsess ;-)
1. We gonna need something for this tutor:
- target: Easy Video Capture v1.30 (~600kb in size) , video-capture.info
- OllyDbg 1.10 (try to have it's plugins, esp. CommandBar and Dump)
- LordPE
- ImportREC
2. IsDebuggerPresent check:
First stepp is of course, to install our app and then load it to Olly.
ASProtect have option to detect debugger through IsDebuggerPresent API function. Some protected programs use that option and some doesn't which depends of app autor. I usually just run first time app in Olly just to see will I get that message "Debugger detected...". This option is just pain in the ass because we must spend some time to click on IsDebuggerPresent plugin in Olly if program uses this check and that is quite boring since usually I must restart target couple times. Buah, our target is using that check. Ok, find someware that plugin for Olly which fools this check because that is fastest way to pass it, but I'm gonna also describe manually how to do it in next part. And next part is:
3. Finding OEP:
Finding OEP is not some hard thinking proces, it's acctually well know Shift+F9 + counting exceptions and then watching jumps and lots of tracing through code.
So, go to Olly Debugging Options and uncheck all that exceptions except those memory violations in KERNEL32.DLL.
Also we must fool debugger check. In CommandLine plugin type "bp IsDebuggerPresent" and press ENTER; or if you have not that plugin right click on CPU window in Olly, select "Search for" ... "Names in all modules", find Eport KERNEL32.IsDebuggerPresent, right click and "Toggle brakpoint". Now just press Shift+F9 and after 15 times you should land in kernel:
Maybe in your case this will look diferent, but first byte must be 01. That byte is confirmation that debuger is present and you need set it on zero. Rigt click on that 01 byte in dump and chose "Bynary - Fill with 00's". It should look like this now:
You have just fooled debugger check. Probably all this you know from before.
Now we must continue with Shift+F9. I press first until bp 15 times and after 16 and then program has started. So I have pressed it 31 times. Now we need again but this time press it only 30 times. Also, you culd not even to count untill you triger bp in kernel and then count only last 16-1. You should land now here:
00B339EC 3100 XOR DWORD PTR DS:[EAX],EAX <---- Your here on the exception!
00B339EE 64:8F05 00000000 POP DWORD PTR FS:[0]
00B339F5 58 POP EAX <---- Place bp here!
00B339F6 833D B07EB300 00 CMP DWORD PTR DS:[B37EB0],0
00B339FD 74 14 JE SHORT 00B33A13
00B339FF 6A 0C PUSH 0C
00B33A01 B9 B07EB300 MOV ECX,0B37EB0
00B33A06 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
00B33A09 BA 04000000 MOV EDX,4
00B33A0E E8 2DD1FFFF CALL 00B30B40
00B33A13 FF75 FC PUSH DWORD PTR SS:[EBP-4]
00B33A16 FF75 F8 PUSH DWORD PTR SS:[EBP-8]
00B33A19 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00B33A1C 8338 00 CMP DWORD PTR DS:[EAX],0
00B33A1F 74 02 JE SHORT 00B33A23
00B33A21 FF30 PUSH DWORD PTR DS:[EAX]
00B33A23 FF75 F0 PUSH DWORD PTR SS:[EBP-10]
00B33A26 FF75 EC PUSH DWORD PTR SS:[EBP-14]
00B33A29 C3 RETN <--- Or place bp here!
Now, I'm gonna tell you something from my experience. I have notice mostly two variations of ASProtect: first group have this last pice of code that you see above exactly the same while second have differnt with some calls and jumps. At this first group it is a very easy to find OEP, while for second one it needs to be more patient. Also, there are no anti-debug tricks after this period. To continue with our target, place bp on one of two places that I have marked on abowe code and run app. We have reall boring job now - we must trace with F7 to see what code is doing. It will circle around and around with conditional jumps. If you notice that behaviouring, place bp under couple such jumps and run program to save time, for example:
After you are on that last RETN, continue with F7. Look where jumps are throwing you and you'll see that loot of jumps has no purpose at all - they throw you at the same place where you going to pass when they don't execute. After some time you will find yourself here:
00B45ED4 81EA 314F0F4A SUB EDX,4A0F4F31
00B45EDA 0F81 1F000000 JNO 00B45EFF
00B45EE0 E8 08000000 CALL 00B45EED <------------------------ Place bp here!
00B45EE5 F0:69EE 8F1C25FA LOCK IMUL EBP,ESI,FA251C8F
00B45EEC AB STOS DWORD PTR ES:[EDI]
00B45EED E8 0B000000 CALL 00B45EFD
00B45EF2 87B4DD 522320D9 XCHG DWORD PTR SS:[EBP+EBX*8+D9202352],E>
00B45EF9 9E SAHF
00B45EFA 7F 4C JG SHORT 00B45F48
00B45EFC 95 XCHG EAX,EBP
00B45EFD 59 POP ECX
00B45EFE 5E POP ESI
00B45EFF 81C2 2D4F0F4A ADD EDX,4A0F4F2D
00B45F05 81EB 4D667D59 SUB EBX,597D664D
00B45F0B 81FA 54EBFFFF CMP EDX,-14AC
00B45F11 ^0F85 5BFFFFFF JNZ 00B45E72
00B45F17 E8 0E000000 CALL 00B45F2A <----------------------- Place bp here!
00B45F1C 4E DEC ESI
00B45F1D 6F OUTS DX,DWORD PTR ES:[EDI] 00B45F1E 7C 05 JL SHORT 00B45F25
You just keep on tracing with F7 and you'll see that these two jumps just spining you around. So place bp under them on those calls and run app. You will land on that second call and some code below will change. Continue with F7 and you'll find one more jump that is doing similar thing:
00B44E14 ^75 E9 JNZ SHORT 00B44DFF
00B44E16 5E POP ESI <--------------- Place bp here and run app!
00B44E17 5B POP EBX
00B44E18 5D POP EBP
00B44E19 C2 0800 RETN 8
00B44E1C 0102 ADD DWORD PTR DS:[EDX],EAX
00B44E1E C3 RETN
Place bp on marked place and run target. Continue with F7 and you'll land on POPAD opcode after which one there are lots of JMP's. This pice is standard in this version of ASProtect and this is place where ASProtect is stealing bytes (but later about that). Pass this junk of code with F7 to the last RETN at:
00B45000 68 C3F44000 PUSH 40F4C3
00B45005 68 DB4DB400 PUSH 0B44DDB
00B4500A C3 RETN <--------- Until this RETN
Then execute that RETN:
00B44DDB EB 01 JMP SHORT 00B44DDE
00B44DDD 9A 51579CFC BF1F CALL FAR 1FBF:FC9C5751
00B44DE4 4E DEC ESI
00B44DE5 B4 00 MOV AH,0
00B44DE7 B9 5E140000 MOV ECX,145E
00B44DEC F3:AA REP STOS BYTE PTR ES:[EDI]
00B44DEE 9D POPFD
00B44DEF 5F POP EDI
00B44DF0 59 POP ECX
00B44DF1 C3 RETN <-------------------- Put bp here!
Now you can trace further with F7 (if you want to see what is doing here - nothing special) or put bp on this new RETN and start target. You will see that lot of code has changed at the bottom of the Olly window, but notice where this last RETN is returning you! It returns you to VideoCap.0040F4C3. Execute that RETN with F7 and youl land here:
Press Ctrl+A to analize code and scroll a litle bit up. Those zeroes are stolen bytes/opcodes/instructions and real OEP starts at first zero byte at 0040F496!
0040F490 $-FF25 50174100 JMP DWORD PTR DS:[411750] ; msvcrt._ftol
0040F496 00 DB 00 <-------------------------This shuld be real OEP.
0040F497 00 DB 00
0040F498 00 DB 00
...
[cut]
...
...
0040F4C0 00 DB 00
0040F4C1 00 DB 00
0040F4C2 . 00FF ADD BH,BH
0040F4C4 . 15 30174100 ADC EAX,VideoCap.00411730
0040F4C9 . 59 POP ECX
0040F4CA . 830D F4AE4100 >OR DWORD PTR DS:[41AEF4],FFFFFFFF
0040F4D1 . 830D F8AE4100 >OR DWORD PTR DS:[41AEF8],FFFFFFFF
0040F4D8 . FF15 38174100 CALL DWORD PTR DS:[411738] ; msvcrt.__p__fmode
Now you have founded false and right OEP! False is at the 0040F4C3 and real is at the 0040F496 address! Remember that two addresses!!! What is false and what purpose of false OEP I will explain in next part:
4. False and right OEP, stolen bytes:
What is this thing with false-real OEP and stolen bytes? From where these bytes are stolen and why? This used to confusing me in the beining reading others tutorials.
The answer is very simple:
You know that every program has it's beginning, first line of code to process. That first line is OEP. You also know that packers unpacking program in memory and then execute it right from that OEP. ASProtect is doing that litle diferent. ASProtect copyes first couple instructiones from packed program to itself code and substitute those in program with zeros. After unpacking program in memory it executes those couple instructions (that should be in original program) within it self code and then continue to run original program from that address after that zeroes. Now we gonna find stolen bytes. These bytes can be little hard to determine because ASProtect mix them with some junk code just to confuse reverser. Only in one version of ASProtect I have fand those stolen bytes in original form.
Also you must know that usualy programs compiled with same compiler have same or similar first instructions. That can help you because if you open some other nonpacked program in Olly which is compiled with same compiler you can see how OEP shuld look like and you'll know when you see stolen bytes somewhere in ASProtect code.
Now we gonna find that bytes. At first look, this program look like it's compiled in some MS Visual C++. Open couple nonpacked programs in Olly and scan them with PEiD and you will easy notice diference between Delphy, Borlland's C++, MS Visual C++ ... In most cases your target will be compiled in some MSV C++.
So now restart target in Olly, pass that exceptions and debugger check again and stop at POPAD opcode after which you can notice lot of jumps:
This place contains our stolen bytes but also lot of junk code. Trace through with F7 and you will keep finding byte by byte. All that jumps and weird opcodes are just junk and I will show here just real stolen bytes:
00B451B7 55 PUSH EBP This is first stolen byte and it belongs on OEP.
00B451C0 8BEC MOV EBP,ESP This is the next stolen part.
00B451C2 6A FF PUSH -1
00B451C4 68 D8354100 PUSH 4135D8
00B451C9 68 1CF64000 PUSH 40F61C
00B451CE 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
00B463F9 50 PUSH EAX This one too.
00B45206 64:8925 00000000 MOV DWORD PTR FS:[0],ESP Next part.
00B4520D 83EC 68 SUB ESP,68
00B45239 53 PUSH EBX
00B4526B 56 PUSH ESI
00B4529D 57 PUSH EDI
00B452A6 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP This is last stolen pice.
00B452A9 33DB XOR EBX,EBX
00B452AB 895D FC MOV DWORD PTR SS:[EBP-4],EBX
00B452AE 6A 02 PUSH 2
Of course you will need some experience to recognize real bytes but that will come after few unpacked targets. This code above is all that is stolen. Trace further until you reach here:
Look at that PUSH 40F4C3 opcode. Do you remmber address of the false OEP? If not, than scroll up in this tutorial where I told you to remember OEP's addresses! Yep, that opcode pushes false OEP address! Change that address to 0040F496 which is address of the real OEP by pressing SPACE and changing opcode to PUSH 0040F496. It should look now:
00B45093 EB 01 JMP SHORT 00B45096
00B45095 9A 51579CFC BFD7 CALL FAR D7BF:FC9C5751 ; Far call
00B4509C 50 PUSH EAX
00B4509D B4 00 MOV AH,0
00B4509F B9 5E140000 MOV ECX,145E
00B450A4 F3:AA REP STOS BYTE PTR ES:[EDI]
00B450A6 9D POPFD
00B450A7 5F POP EDI
00B450A8 59 POP ECX
00B450A9 C3 RETN <------------- Put bp!
Place bp on this last RETN, run target, remove bp, execute RETN with F7 and you'll land on real OEP address right on that first zeros. Pres Ctrl+A and it suld look like this:
0040F496 00 DB 00
0040F497 00 DB 00
0040F498 00 DB 00
0040F499 00 DB 00
0040F49A 00 DB 00
0040F49B 00 DB 00
...
[cut]
...
0040F4BD 00 DB 00
0040F4BE 00 DB 00
0040F4BF 00 DB 00
0040F4C0 00 DB 00
0040F4C1 00 DB 00
0040F4C2 . 00FF ADD BH,BH
0040F4C4 . 15 30174100 ADC EAX,VideoCap.00411730
0040F4C9 . 59 POP ECX
0040F4CA . 830D F4AE4100 >OR DWORD PTR DS:[41AEF4],FFFFFFFF
0040F4D1 . 830D F8AE4100 >OR DWORD PTR DS:[41AEF8],FFFFFFFF
0040F4D8 . FF15 38174100 CALL DWORD PTR DS:[411738] ; msvcrt.__p__fmode
0040F4DE . 8B0D E8AE4100 MOV ECX,DWORD PTR DS:[41AEE8]
0040F4E4 . 8908 MOV DWORD PTR DS:[EAX],ECX
0040F4E6 . FF15 84174100 CALL DWORD PTR DS:[411784] ; msvcrt.__p__commode
Now you need to put in all that stolen bytes that we have founded before. Do it by asembly or by binary editing. At the end it should look like this (blue was stolen):
Now dump target with LordPE. If you scan it with PEiD you will found --> Microsoft Visual C++ 6.0. Our target is unpacked and stolen bytes are returned but we need to repir IAT.
5. Fixing IAT:
We will repair IAT using ImpREC but ASProtect is using one feature which make harder to do that job. I'm not pozitive sure if I'm right (somebody correct me if not) but ASProtect redirects some part of IAT jumps. I think that idea is to redirect jump in IAT table to some other location and there litle encrypt that jump, something like :
XOR EAX,76543210
jmp EAX
Above is just example of code that ImpREC cannot read. When you unpack target, that jump in IAT that leads to this example now leads to nothing and our target is crushing. Tankfuly, there are peoples who know about this more than me and they have made some plugins for ImpREC to fix this. To repair IAT use the plugins in the attachment.
Anyway,good try...