-
Level : intermediate
=======================================
Armadillo with Code Splicing (anti dump) - manually unpacking
=======================================
This is the third tutorial in Armadillo serial and it will discuss about one specific feature - code splicing. I will show two ways how to deal with this protection.
1. Requirements and tools
Basic info needed:
- Basic knowledge about PE structure;
- some experience with unpacking protectors;
- read my two previous tutorials about Armadillo.
Tools:
- OllyDbg 1.10
- LordPE
- ImpREC
- Hex editor
Few words:
Code splicing is feature that "steals" blocks of original program code and redirects it to some allocated memory block. If we
dump such file, dump will be crippled and this is known also as anti-dump method. Interesting is that allocated blocks vary
from execution to execution of packed program, always on little different address. There is two ways to fix this; first way
is to prevent and redirect splicing, second is to dump that spliced block(s) from memory and attach it to our dump.
Also note that this target finds our ollydbg.exe and refuse to start if process with that name is pressent so you must rename
olly to something else. Also, this Armadillo version detects breakpoints on dll's so we will place our bp's always on second
or even better, on last API opcodes. That is not problem at all.
2. Searching OEP, fixing IAT
This version of Armadillo doesn't use Olly exploit so just place bp on last opcode in CreateThread API (you know, go to ->
expression -> type CreateThread and place bp on last RETN) and run. Return to code and find that CALL EDI that throws you on
OEP:
003D6E73 CALL EDI <------ Jump to OEP!!
003D6E75 MOV EBX,EAX
003D6E77 POP EDI
003D6E78 MOV EAX,EBX
003D6E7A POP ESI
003D6E7B POP EBX
003D6E7C RETN
This is probably some 3.xx armadillo version because there are no CALL ECX but EDI. Execute it and you will land on OEP:
004061D0 PUSH EBP <------------------------- OEP!!!
004061D1 MOV EBP,ESP
004061D3 PUSH -1
004061D5 PUSH Armadill.0040A0D0
004061DA PUSH Armadill.00406F5C
004061DF MOV EAX,DWORD PTR FS:[0]
004061E5 PUSH EAX
004061E6 MOV DWORD PTR FS:[0],ESP
004061ED SUB ESP,58
004061F0 PUSH EBX
004061F1 PUSH ESI
004061F2 PUSH EDI
004061F3 MOV DWORD PTR SS:[EBP-18],ESP
004061F6 CALL DWORD PTR DS:[40A02C] <------- Missing import!!!
004061FC XOR EDX,EDX
004061FE MOV DL,AH
00406200 MOV DWORD PTR DS:[40C57C],EDX
You will not dump file now. Dumping will be the last thing to do in this tutorial. First we will prevent IAT redirecting and
save ImpREC tree for further use. Follow that DS:[40A02C] in dump:
0040A02C F7 DC 3B 00 1A AF 3B 00 B7 AF 3B 00 0C E6 E7 77 ..;...;...;....w
0040A03C A1 16 F5 77 6B 15 F5 77 95 9B E9 77 FC AC E7 77 ...wk..w...w...w
0040A04C 2F E0 E9 77 E8 E4 E7 77 9C A8 E7 77 54 AB 3B 00 /..w...w...wT.;.
Do you remember what you need to do from previous tutorials? Remember it's address in dump 0040A02C and restart target in
olly. Place bp on end of CreateThread API and follow in dump 0040A02C address which is place where API redirection value will
be placed:
0040A02C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Place hardware bp on write there, on first 4 bytes and run olly.
Breaking first time is not important:
77C42F43 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
77C42F45 JMP DWORD PTR DS:[EDX*4+77C43058]
77C42F4C MOV EAX,EDI
77C42F4E MOV EDX,3
77C42F53 SUB ECX,4
77C42F56 JB SHORT msvcrt.77C42F64
77C42F58 AND EAX,3
77C42F5B ADD ECX,EAX
77C42F5D JMP DWORD PTR DS:[EAX*4+77C42F70]
77C42F64 JMP DWORD PTR DS:[ECX*4+77C43068]
...
...
Second time is what we want (then delete hw bp):
003D4045 CMP DWORD PTR DS:[EAX+8],0
003D4049 JE SHORT 003D4093
003D404B PUSH 100
003D4050 LEA EAX,DWORD PTR SS:[EBP-1E84]
003D4056 PUSH EAX
003D4057 MOV EAX,DWORD PTR SS:[EBP-1D84]
003D405D PUSH DWORD PTR DS:[EAX]
003D405F CALL 003B7816
003D4064 ADD ESP,0C
003D4067 LEA EAX,DWORD PTR SS:[EBP-1E84]
003D406D PUSH EAX
003D406E PUSH DWORD PTR SS:[EBP-1D7C]
003D4074 CALL DWORD PTR DS:[3DB32C] ; msvcrt._stricmp
003D407A POP ECX
003D407B POP ECX
003D407C TEST EAX,EAX
003D407E JNZ SHORT 003D4091 <---------------------- Most important place, magic jump!!!
...
...
...
003D419A MOV DWORD PTR DS:[EAX],ECX
003D419C MOV EAX,DWORD PTR SS:[EBP-17DC] <--------- You landed here!!!
Remember address of "magic jump" 003D407E. Of course, on your system it can have different value. Now, remember what we have
done in second tutorial. This file has those CRC-decryption-encryption loops and file will crush when we change something.
Restart target, place bp on VirtualAlloc+1 in command bar and press Shift+F9 two times. Then in CPU window go to our jump
location 003D407E:
003D407E ADD BYTE PTR DS:[EAX],AL <---- You're here!
003D4080 ADD BYTE PTR DS:[EAX],AL
003D4082 ADD BYTE PTR DS:[EAX],AL
003D4084 ADD BYTE PTR DS:[EAX],AL
003D4086 ADD BYTE PTR DS:[EAX],AL
...
...
You will see nothing there because armadillo dll still isn't unpacked there. Never mind, you place hardware bp on execution
on 003D407E address, remove bp from VirtualAlloc and run olly. You will break on unpacked-decrypted code:
003D407E JNZ SHORT 003D4091 <---------------- Our magic jump!!!
003D4080 MOV EAX,DWORD PTR SS:[EBP-1D84]
003D4086 MOV EAX,DWORD PTR DS:[EAX+8]
003D4089 MOV DWORD PTR SS:[EBP-1D78],EAX
003D408F JMP SHORT 003D4093
003D4091 JMP SHORT 003D4030
003D4093 CMP DWORD PTR SS:[EBP-1D78],0
003D409A JNZ SHORT 003D40DB
003D409C MOVZX EAX,WORD PTR SS:[EBP-1D74]
...
...
Remove hardware bp, change JNZ to JMP and run olly. It will crush, but we have expected that. Still our import section will
have what we want. Like in the second tutorial, open another olly instance (hidden one too) and find OEP in new instance of
target. Import section is .rdata , binary copy whole that section from crushed target and paste it to new one where you found
OEP. Close olly that holds crushed target, open ImpREC and find imports. You will have 3 invalid thunks, cut it, and save
import tree to hard drive (remember, dumping is last thing).
First part of job is done and now it's time to meet Code Splacing.
3. Code Splicing - anti dumps
Trace in olly with F8 to first call:
0040622A CALL Armadill.00406E27
and enter in it:
00406E27 XOR EAX,EAX
00406E29 PUSH 0
00406E2B CMP DWORD PTR SS:[ESP+8],EAX
00406E2F JMP 03B542CA <------------------------------- Look this jump!!!
00406E34 SETE AL
00406E37 PUSH EAX
00406E38 CALL DWORD PTR DS:[40A06C] ; kernel32.HeapCreate
00406E3E TEST EAX,EAX
00406E40 JMP 03B542DC <------------------------------- Look this jump!!!
00406E45 JE SHORT Armadill.00406E5C
00406E47 CALL Armadill.004074B3
00406E4C TEST EAX,EAX
00406E4E JNZ SHORT Armadill.00406E5F
00406E50 JMP 03B542EF <------------------------------- Look this jump!!!
00406E55 NOP
00406E56 CALL DWORD PTR DS:[40A068] ; kernel32.HeapDestroy
00406E5C XOR EAX,EAX
00406E5E RETN
00406E5F PUSH 1
00406E61 POP EAX
00406E62 RETN
00406E63 INT3
00406E64 JMP 03B54300 <------------------------------- Look this jump!!!
There you will see lot of such jumps. Values of that jumps will be different at you. That is code splicing. Program flow
jumps to some allocated place of memory which cannot be dumped with main exe. There are two ways to fix this.
3.1 First way (lame one :) - dump exe, dump spliced block and attach it to main dump
- Ok, first repair PE header of our target, you know how, open another olly and copy-paste PE header from packed instance of
target to our first - unpacked. Then dump file with LordPE or olly dump (OEP is 61D0). Now use ImpREC and saved tree and fix
IAT. Now we need to add spliced block to dumped file in order to get working dump.
At my computer spliced block is here (and it's size is that big):
03B50000 00016000 Priv RWE RWE
- I will add to my dumped file 4000000 bytes (zeros) with hex editor to the end of the file. That is more than 60 MB, quite a
big. Don't wory for that, we gona fix size of exe later.
- Then I open LordPE's PE editor and there I will change VirtualSize and RawSize of last section (.mackt) for that amount of
bytes, so now my VS is 04001000 and RW is 04001000 too.
- Now I will open that dump in another olly and I will go at the 3B50000 address in it:
03B50000 0000 ADD BYTE PTR DS:[EAX],AL
03B50002 0000 ADD BYTE PTR DS:[EAX],AL
03B50004 0000 ADD BYTE PTR DS:[EAX],AL
03B50006 0000 ADD BYTE PTR DS:[EAX],AL
03B50008 0000 ADD BYTE PTR DS:[EAX],AL
03B5000A 0000 ADD BYTE PTR DS:[EAX],AL
03B5000C 0000 ADD BYTE PTR DS:[EAX],AL
03B5000E 0000 ADD BYTE PTR DS:[EAX],AL
...
...
That is where spliced code block should be. Now I will just binary copy all bytes from spliced block and paste it to my
dumped file starting from 3b5000 address and save changes. Since dump is big it can take some time.
- Now, after I have save all changes, I runned dumped file and guess what? Dump works great! Yeah! Do it like I did and your
file fill also work. If it's not working, check where did you make mistake. It's wery simple actually.
Ok, file works, but file on my drive is 64 MB in size! That's a big waste of space. Do not wory, you can reduce size of it
with LordPE or just pack it with some packer (WinUpack can pack it to ~250 kb). Rared file is less than 300 kb. But still,
this file waste lot of memory space for nothing. Second way of solwing splicing problem is much better.
Dumped file that I got with this way of unpacking I didn't put in archive to keep it smaller.
3.2 Redirecting spliced block
If you find OEP couple times in the same packed file, you will see that jumps to spliced block change thir values. This block
is loaded every time under some other address. And there is idea, maybe we can redirect that block to some closer place in
memory or even in our dump. Since base address of spliced block is some random value, you can conclude that armadillo uses
some function like GetTickCount to get/generate some random values. Indeed, I found that armadillo uses "time" API from
msvcrt.dll. You going to find it in this way, place bp on VirtualAlloc and press Shift+F9 3 times. At this time most of dll's
needed for operation are loaded. Then place bp on time API and pree Shift+F9 (remove bp from VirtualAlloc before). You will
break in msvcrt.dll, remove breakpoint and return tu code:
003D1EAF CALL DWORD PTR DS:[3DB2A8] ; msvcrt.time
003D1EB5 POP ECX <-------------------------------------- You are here!!!
003D1EB6 MOV DWORD PTR SS:[EBP-3110],EAX <-------------- EAX holds random value.
003D1EBC MOV EAX,DWORD PTR SS:[EBP-3110]
003D1EC2 MOV DWORD PTR SS:[EBP-1998],EAX
003D1EC8 AND DWORD PTR SS:[EBP-1980],0
003D1ECF CMP DWORD PTR SS:[EBP-1980],0
003D1ED6 JNZ 003D1FA3
003D1EDC MOV EAX,DWORD PTR SS:[EBP-1984]
003D1EE2 DEC EAX
003D1EE3 MOV DWORD PTR SS:[EBP-1984],EAX
003D1EE9 CMP DWORD PTR SS:[EBP-1984],0
003D1EF0 JNB SHORT 003D1F13
003D1EF2 MOV EAX,DWORD PTR SS:[EBP+8]
003D1EF5 MOV EAX,DWORD PTR DS:[EAX]
003D1EF7 AND DWORD PTR DS:[EAX],0
003D1EFA PUSH 3E1A9C ; ASCII "Location CS1"
003D1EFF MOV EAX,DWORD PTR SS:[EBP+8]
003D1F02 PUSH DWORD PTR DS:[EAX+4]
003D1F05 CALL 003DA258 ; JMP to msvcrt.strcpy
003D1F0A POP ECX
003D1F0B POP ECX
003D1F0C XOR EAX,EAX
003D1F0E JMP 003D512A
003D1F13 CMP DWORD PTR SS:[EBP-1984],0
003D1F1A JBE SHORT 003D1F33
003D1F1C LEA ECX,DWORD PTR SS:[EBP-1998]
003D1F22 CALL 003B511B
003D1F27 AND EAX,3FF0000 <---------------- The most important place vhere value gets final shape.
003D1F2C MOV DWORD PTR DS:[3E91D8],EAX <-- Save that value.
003D1F31 JMP SHORT 003D1F43
003D1F33 CMP DWORD PTR SS:[EBP-1984],0
003D1F3A JNZ SHORT 003D1F43
003D1F3C AND DWORD PTR DS:[3E91D8],0
003D1F43 PUSH 40
003D1F45 PUSH 2000
003D1F4A PUSH DWORD PTR SS:[EBP-1988]
003D1F50 PUSH DWORD PTR DS:[3E91D8]
003D1F56 CALL DWORD PTR DS:[3DB1B0] ; kernel32.VirtualAlloc <--- Allocating that memory.
003D1F5C MOV DWORD PTR SS:[EBP-1980],EAX <----------------------- We will change this EAX value!!!
003D1F62 CMP DWORD PTR SS:[EBP-1980],0
003D1F69 JE SHORT 003D1F9E <--------------- Check! This jump must not be taken!!
003D1F6B PUSH 40
003D1F6D PUSH 1000
003D1F72 PUSH DWORD PTR SS:[EBP-1988]
003D1F78 PUSH DWORD PTR DS:[3E91D8]
003D1F7E CALL DWORD PTR DS:[3DB1B0] ; kernel32.VirtualAlloc
003D1F84 MOV DWORD PTR SS:[EBP-1980],EAX <----------------------- We will change this EAX value!!!
003D1F8A CMP DWORD PTR SS:[EBP-1980],0
003D1F91 JE SHORT 003D1F9E <--------------- Check! This jump must not be taken!!
003D1F93 MOV EAX,DWORD PTR SS:[EBP-1980]
003D1F99 MOV DWORD PTR DS:[3E91D8],EAX
003D1F9E JMP 003D1ECF
003D1FA3 PUSH 1
You have just came from time function and EAX holds some random value. Most important place is that at 003D1F27 address.
There that random value will get final shape, something like 1C70000 and that is address where block will start. Than that
value is saved. Here we can force armadillo to extract that code where we like. Notice in memory dump what sections armadillo
has:
00400000 00001000 Armadill PE header Imag R RWE
00401000 00009000 Armadill .text Imag R RWE
0040A000 00001000 Armadill .rdata Imag R RWE
0040B000 00003000 Armadill .data Imag R RWE
0040E000 00030000 Armadill .text1 code Imag R RWE
0043E000 00010000 Armadill .adata code Imag R RWE
0044E000 00020000 Armadill .data1 data,imports Imag R RWE
0046E000 00030000 Armadill .pdata Imag R RWE
0049E000 00001000 Armadill .rsrc resources Imag R RWE
.text1, .adata, .data1 and .pdata are armadillo's sections. We can use some of that section as place for redirection. I will
force my redirection to .pdata section.
We will let armadillo to reserve block where he likes, but we gonna change address where it will extract code. Simply, when
you came to this two lines, change EAX to 46E000:
003D1F5C MOV DWORD PTR SS:[EBP-1980],EAX
003D1F84 MOV DWORD PTR SS:[EBP-1980],EAX
And that's it ;)! Armadillo will extract spliced plock in our dump. Now just place bp on CreateThread API and find OEP. When
you find OEP don't forget to fix PE header first. Than dump and then use that imports tree for ImpREC that you created and
saved in 2. chapter of this tutorial. With it , fix IAT of dumped file. Run it... It works!!! And our file size is now 650 kb
and not gigabytes like in first example. Maybe you can reduce size even more, but who cares. Armadillo with splicing code is
defeated.
4. Final words
I hope that my next tutorial will be about armadillo's import destruction or Debug Blocker features, but I will see can I do
that. With this knolwedge from this three tutorials, you can already unpack bunch of armadillo targets. Lot of targets don't
even use splicing code, just minimum protection.
-
Level : intermediate
=======================================
Armadillo 4.30a - unpacking armadillo with standard protection
=======================================
Welcome to next Armadillo tutorial! This tutorial is just second part of first one and heavily relies on it.
1. Requirements
- Windows XP
- Target
- OllyDbg 1.10
- ImpREC
- LordPE
Ofcourse, you must know how to use those tools. I will not explain how to set memory breakpoint on access,or hardware, or what window you need to open to find that what I'm talking about. It's pretty exousting to write in that way and if you wan't to deal with protectors you must already know all that.
Few words about our target :
- It uses same tricks as minimal protection;
- Encrypts loader code so it's harder to find redirection place;
- Decrypt/encrypt depends on CRC calculation, our changes affect target.
2. Reach OEP
You know how to reach OEP from first tutorial: use bp on OutputDebugStringA to kill Olly exploit, place bp on CreateThread to find CAL ECX that will throw you at OEP. Fix PE header by copy-paste bytes from another instance of target and dump file. You found OEP to be here:
004013FB PUSH EBP <--------------------- OEP!!!
004013FC MOV EBP,ESP
004013FE PUSH -1
00401400 PUSH Armadill.004040B8
00401405 PUSH Armadill.00401F30
0040140A MOV EAX,DWORD PTR FS:[0]
00401410 PUSH EAX
00401411 MOV DWORD PTR FS:[0],ESP
00401418 SUB ESP,58
0040141B PUSH EBX
0040141C PUSH ESI
0040141D PUSH EDI
0040141E MOV DWORD PTR SS:[EBP-18],ESP
00401421 CALL DWORD PTR DS:[40402C] <---- Missing import!!!
00401427 XOR EDX,EDX
00401429 MOV DL,AH
0040142B MOV DWORD PTR DS:[405544],EDX
3. Fixing imports
We will fix imports in the same way as we did in first tutorial, we will change magic jump from JNZ to JMP so it will never redirect imports. But there is two small problems - encryption and CRC. I hope that you didn't close olly after dumping. If you have, then again find OEP. Check that missing import:
00401421 CALL DWORD PTR DS:[40402C] <---- Missing import!!!
Follow it in dump:
0040402C 38ADAB00 567CAB00 197DAB00 0CE6E777 8...V|...}.....w
0040403C 959BE977 FCACE777 2FE0E977 E8E4E777 ...w...w/..w...w
Remember address of that redirected import -> 004042C. Now restart target in olly and get to OutputDebugStringA check. After you have fixed that check go to dump window and find this address. It will be empty but you place hardware bp on write on DWORD there (on first 4 bytes - zeroes) and press F9. You will stop first here (after nag window):
77C42F43 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
77C42F45 JMP DWORD PTR DS:[EDX*4+77C43058]
77C42F4C MOV EAX,EDI
77C42F4E MOV EDX,3
77C42F53 SUB ECX,4
77C42F56 JB SHORT msvcrt.77C42F64
77C42F58 AND EAX,3
...
...
Pres one more time F9 and you will stop where armadillo has wrote 4 bytes:
00ACCA31 CMP DWORD PTR DS:[EAX+8],0
00ACCA35 JE SHORT 00ACCA80
00ACCA37 PUSH 100
00ACCA3C LEA EAX,DWORD PTR SS:[EBP-3EA8]
00ACCA42 PUSH EAX
00ACCA43 MOV EAX,DWORD PTR SS:[EBP-3DA8]
00ACCA49 PUSH DWORD PTR DS:[EAX]
00ACCA4B CALL 00AA1FEC
00ACCA50 ADD ESP,0C
00ACCA53 LEA EAX,DWORD PTR SS:[EBP-3EA8]
00ACCA59 PUSH EAX
00ACCA5A LEA EAX,DWORD PTR SS:[EBP-3D98]
00ACCA60 PUSH EAX
00ACCA61 CALL DWORD PTR DS:[AD6388] ; msvcrt._stricmp <--- Remember this comparation from first tut!?!
00ACCA67 POP ECX
00ACCA68 POP ECX
00ACCA69 TEST EAX,EAX
00ACCA6B JNZ SHORT 00ACCA7E <------------------- Our magic jump! Remeber its address!!!
00ACCA6D MOV EAX,DWORD PTR SS:[EBP-3DA8]
00ACCA73 MOV EAX,DWORD PTR DS:[EAX+8]
00ACCA76 MOV DWORD PTR SS:[EBP-3598],EAX
00ACCA7C JMP SHORT 00ACCA80
00ACCA7E JMP SHORT 00ACCA1C
...
...
...
00ACCC1C MOV DWORD PTR DS:[EAX],ECX
00ACCC1E MOV EAX,DWORD PTR SS:[EBP-26F0] <------ You are here!!! Scroll up!!!
This code should be familiar to you from first tutorial. The most important part is our jump at 00ACCA6B. That address could be different on your computer, write it down. Now restart target in olly again and again get to the OutputDebugStringA. Fix it and then in CPU window go to 00ACCA6B expression (our jump):
00ACCA6B SAHF
00ACCA6C DAA
00ACCA6D JE SHORT 00ACC9F6
00ACCA6F IMUL EBX,EDX,-11
00ACCA72 AND BL,BYTE PTR DS:[ECX]
00ACCA74 ADC AH,BYTE PTR DS:[EDX-36]
00ACCA77 JMP FAR 7F51:23BB3B3D
00ACCA7E INT 0B6
00ACCA80 XCHG EAX,ECX
00ACCA81 MOV AH,2F
00ACCA83 INC EBX
00ACCA84 ADC BYTE PTR DS:[EBX+E602C4CA],BH
00ACCA8A SBB BYTE PTR DS:[ESI+ESI*8-57],91
00ACCA8F INT3
...
...
Instead of our jump, you will see some junk code as above. That is because in standard protection Armadillo dll is encrypted and decrypted on the fly. But we can easily solve this problem; on address 00ACCA6B where our jump should be, place hardware breakpoint on execution and just run olly. After nag window, code will decrypt and olly will stop on your breakpoint:
00ACCA6B JNZ SHORT 00ACCA7E
00ACCA6D MOV EAX,DWORD PTR SS:[EBP-3DA8]
00ACCA73 MOV EAX,DWORD PTR DS:[EAX+8]
00ACCA76 MOV DWORD PTR SS:[EBP-3598],EAX
00ACCA7C JMP SHORT 00ACCA80
00ACCA7E JMP SHORT 00ACCA1C
00ACCA80 MOV EAX,DWORD PTR SS:[EBP-2B58]
00ACCA86 INC EAX
...
...
...
Remove breakpoint and change JNZ to JMP and just run our target (F9). Soon target will just crush on some exception. Problem is that encrypt/decrypt process depends on some integrity check and since we have changed some bytes, file has become useless. But don't panic, this is not problem at all. Our file is crushed, but import section .rdata contains valid thunks. So binary copy whole .rdata section and open another instance of olly. Open target in that olly and find OEP without messing with imports problem. When you reach OEP there, just binary paste data from clipboard to .rdata section. You can close first olly now. Open ImpREC now and attach to our target, find imports, cut all invalid ones and repair dumped file. That's it! Run it and it will work fine ;)
-
Level : intermediate
=======================================
Armadillo 4.30a - unpacking armadillo with minimum protection
=======================================
1. Preparation
You will need next tools to follow this tutorial:
- Windows XP
- OllyDbg 1.10;
- ImpREC;
- LordPE;
- PEiD 0.93 (optional).
Unpacking armadillo can be very simple if protected target is using only minimum protection and this kind of apps you can find all over the net. I really don't know why developers doesn't use all options, maybe double process slows down protected program what can be issue if program is some maintaince utility like reg cleaner, defrag tool or similar. Anyway, in this case we have to deal with next problems:
- Olly OutputDebugStringA exploit;
- PE header changes that locks file;
- Import redirection and emulation.
2. Reaching OEP
First ignore all exceptions in olly options. Then open target in olly, click "Go to"->"Expression", enter VirtualAlloc and click OK. You will land in kernel on that API:
77E7ABC5 PUSH EBP <--------------------- Start of VirtualAlloc API.
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 <---------------------- Place bp here so Amadillo don't find it!!!
What acctually I wan't here? Armadillo will unpack and load it's own dll in memory so we must find where. When you break on this bp, AEX register will hold base address of allocated memory block where that dll will be unpacked. Press F9 once and when you stop on bp EAX will be =0. Press once more and EAX will now hold some value. On my machine EAX=00AA0000, for you it can differ. Now erase that bp and place bp in command bar on OutputDebugStringA API. Press F9 and you will land on it:
77E9B493 PUSH 22C <------------------------ You are here!!!
77E9B498 PUSH kernel32.77E9BE60
77E9B49D CALL kernel32.77E7A22B
...
...
...
77E9B4CB CALL kernel32.RaiseException
77E9B4D0 OR DWORD PTR SS:[EBP-4],FFFFFFFF
77E9B4D4 CALL kernel32.77E7A2F2
77E9B4D9 RETN 4
This is place where armadillo will try to crush olly. Olly cannot stand %s%s... string and that will just crush it. So we need to kill this check. It's not hard, just change first opcode of API to last one. So, remove bp and place instead PUSH 22C RETN 4:
77E9B493 RETN 4 <-------------------------- Changed!
77E9B496 NOP
77E9B497 NOP
77E9B498 PUSH kernel32.77E9BE60
...
...
...
77E9B4CB CALL kernel32.RaiseException
77E9B4D0 OR DWORD PTR SS:[EBP-4],FFFFFFFF
77E9B4D4 CALL kernel32.77E7A2F2
77E9B4D9 RETN 4
Now place bp on CreateThread API and run olly. You will break in kernel on CreateThread API (after nag window), remove bp from there, return to code with Alt+F9:
00AB94C4 POP EDI <----- You are now here!
00AB94C5 POP ESI
00AB94C6 LEAVE
00AB94C7 RETN <-------- Just trace and execute this RET with F7!
Do what I tell you and after exiting RET, you will see this:
00AC972D POP ECX
00AC972E MOV EDI,0AD8910
00AC9733 MOV ECX,EDI
...
...
...
00AC97ED CALL ECX
00AC97EF JMP SHORT 00AC9814
00AC97F1 CMP EDX,1
00AC97F4 JNZ SHORT 00AC9817
00AC97F6 PUSH DWORD PTR DS:[ESI+4]
00AC97F9 MOV EDX,DWORD PTR DS:[EAX+88]
00AC97FF XOR EDX,DWORD PTR DS:[EAX+84]
00AC9805 PUSH DWORD PTR DS:[ESI+8]
00AC9808 XOR EDX,DWORD PTR DS:[EAX+40]
00AC980B PUSH 0
00AC980D PUSH DWORD PTR DS:[ESI+C]
00AC9810 SUB ECX,EDX
00AC9812 CALL ECX <----------------------- Jump to OEP!!!
00AC9814 MOV DWORD PTR SS:[EBP-4],EAX
00AC9817 MOV EAX,DWORD PTR SS:[EBP-4]
00AC981A POP EDI
00AC981B POP ESI
00AC981C LEAVE
00AC981D RETN
You see that last CALL ECX? That is your jump to OEP. In previous versions 3.xx there was CALL EDI opcode instead CALL ECX, but armadillo developer has changed. He changes small deatails like that to prevent making of generic unpackers and olly scripts. I didn't get to that idea, others told me so I don't know is it truth but it could be. That call is your jump to OEP so execute it and you'll land on OEP at:
004013FB PUSH EBP <--------------------- OEP!!!
004013FC MOV EBP,ESP
004013FE PUSH -1
00401400 PUSH Armadill.004040B8
00401405 PUSH Armadill.00401F30
0040140A MOV EAX,DWORD PTR FS:[0]
00401410 PUSH EAX
00401411 MOV DWORD PTR FS:[0],ESP
00401418 SUB ESP,58
0040141B PUSH EBX
0040141C PUSH ESI
0040141D PUSH EDI
0040141E MOV DWORD PTR SS:[EBP-18],ESP
00401421 CALL DWORD PTR DS:[40402C] <----- Here it should b some import!!!
00401427 XOR EDX,EDX
00401429 MOV DL,AH
...
...
...
And you have found OEP. But if you dump file now it will be damage and locked because armadillo has changed three values in PE header. Also there is much bigger problem with stolen imports.
3. PE header issue
If you open memory map window you'll see that PE header is damaged and olly doesn't recognize it:
00400000 00001000 Armadill Imag R RWE <--- PE header!!!
00401000 00003000 Armadill .text Imag R RWE
00404000 00001000 Armadill .rdata Imag R RWE
00405000 00001000 Armadill .data Imag R RWE
00406000 00050000 Armadill .text1 code Imag R RWE
00456000 00010000 Armadill .adata Imag R RWE
00466000 00020000 Armadill .data1 data,imports Imag R RWE
00486000 00030000 Armadill .pdata Imag R RWE
004B6000 00002000 Armadill .rsrc resources Imag R RWE
Three values that armadillo has deleted are, PE header offset in DOS header, number of sections in PE header and EnryPoint of exe. To fix that just open another olly, open packed target in it, binary copy whole PE header and binary paste it insted this one. Now you can dump file with LordPE but there will be some number of unresolved thunks in ImpREC, in my case 16. Trace level 1 will gave false imports so do not relay on it.
4. IAT problem
.rdata section is one that holds import thunks. Take a look there (after you have reached OEP) and you will see that some values are not good:
00404020 FF 7E AB 00 7E 17 E6 77 AF 81 AB 00 A3 81 AB 00 .~..~..w........
00404030 D6 69 AB 00 99 6A AB 00 0C E6 E7 77 95 9B E9 77 .i...j.....w...w
00404040 FC AC E7 77 2F E0 E9 77 E8 E4 E7 77 9C A8 E7 77 ...w/..w...w...w
For example, first value on the abowe snippet is FF7EAB00 which is not value of some import. Second is good 7E17E677. As you can see, first value points to ArmDll in memory. We need to find where IAT is being redirected and prevent that redirection. Restart target in Olly, fix OutputDebugStringA problem and place hardware breakpoint on write in dump on 00404020. HW bp is on DWORD. Now just press F9 (that is after you have stop in kernel on debug string exploit) and you will stop here:
77C42F43 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
77C42F45 JMP DWORD PTR DS:[EDX*4+77C43058] ; MSVCRT.77C43068
77C42F4C MOV EAX,EDI ; Armadill.00404024
77C42F4E MOV EDX,3
77C42F53 SUB ECX,4
77C42F56 JB SHORT MSVCRT.77C42F64
77C42F58 AND EAX,3
77C42F5B ADD ECX,EAX
77C42F5D JMP DWORD PTR DS:[EAX*4+77C42F70]
77C42F64 JMP DWORD PTR DS:[ECX*4+77C43068]
77C42F6B NOP
77C42F6C JMP DWORD PTR DS:[ECX*4+77C42FEC]
...
...
This is first stop and it is not important. Press F9 once again and you will land on good spot:
00AC6979 CMP DWORD PTR DS:[EAX+8],0 <-------------- [5] It just compares does all APIs from list are checked!!!
00AC697D JE SHORT 00AC69C8
00AC697F PUSH 100
00AC6984 LEA EAX,DWORD PTR SS:[EBP-3BF4]
00AC698A PUSH EAX
00AC698B MOV EAX,DWORD PTR SS:[EBP-3AF4]
00AC6991 PUSH DWORD PTR DS:[EAX]
00AC6993 CALL 00ACCF05
00AC6998 ADD ESP,0C
00AC699B LEA EAX,DWORD PTR SS:[EBP-3BF4]
00AC69A1 PUSH EAX
00AC69A2 LEA EAX,DWORD PTR SS:[EBP-3AE4]
00AC69A8 PUSH EAX
00AC69A9 CALL DWORD PTR DS:[ACE384] ; MSVCRT._stricmp <--- [3] Compares API names !!!
00AC69AF POP ECX
00AC69B0 POP ECX
00AC69B1 TEST EAX,EAX
00AC69B3 JNZ SHORT 00AC69C6 <--------------- [4] If API is on the list, it will not jump!!!
00AC69B5 MOV EAX,DWORD PTR SS:[EBP-3AF4]
00AC69BB MOV EAX,DWORD PTR DS:[EAX+8]
00AC69BE MOV DWORD PTR SS:[EBP-32E4],EAX
00AC69C4 JMP SHORT 00AC69C8
00AC69C6 JMP SHORT 00AC6964
00AC69C8 MOV EAX,DWORD PTR SS:[EBP-28A4]
...
...
...
00AC6B64 MOV DWORD PTR DS:[EAX],ECX <--------- [2] But this is the place where value is written!!!
00AC6B66 MOV EAX,DWORD PTR SS:[EBP-24EC] <---- [1] You stopped here!!!
You have landed on place where redirected value has been written, but that is not so interesting and I just removed big chunk of code. Main part is at [5] where armadillo compare names of all API with some that it has on it's own list. If some API is on the list, jump [4] will not be executed and that API will be emulated. This is one of few part which we can change in order to prevent API redirection. Jump at [5] just compares does all API names from iner list are processed. So we need to change jump [4] from JNZ to JMP. But it is too late now because most of imports are already redirected. But remember where that jump is, on my computer it is at 00AC69B3. Write down your value and we gonna try again.
Restart target again in olly and fix Olly exploit. In CPU window select "Go to"->"Expression" and enter address of that jump, for me it is 00AC69B3. Follow it:
00AC69B3 JNZ SHORT 00AC69C6
...
...
As you can see, jump is there. Good! Now change it to JMP. And that's it, place bp on CreateThread and find OEP. Fire up ImpREC and get imports. Click show invalid and cut all invalid thunks. Fix dump, run it and it will work great! That's it ;)
6. Cosmetic surgery
Armadillo code that is added to packed exe is quite big. Packed file itself has 520 kb and my unpacked is now 740 kb. We can use LordPE to reduce size of exe. Open unpacked file in LordPE's PE editor. First change BaseOfCode from 6000 to 1000 and BaseOfData from 66000 to 5000. Then click on sections button. There you will see sections that Armadillo added; .text1, .adata, .data1 and .pdata. Right click on each section and select "wipe section header". Close section table. Click save button to save changes. Now open options in LordPE and for rebuilder, check Dumpfix,Realign file...->hardcore, and validate PE. Now rebuild unpacked file and it size will reduce up to 2% --> 22kb! Not bad ha :)
-
Level : newbie
Brief walkthrough of generic EXE32Pack v1.43 unpacking.
-=Soul12's Unpacking EXE32pack=- v0.1
Target: EXE32Pack v1.43
Generic: yes!
This Packer is a sligthy differnt packer compared to UPX is has a Limited amouny of protection
It Scrambles Imports(poorly) and attemts to hide OEP(again poorly) and tries to detect olly with IsDebuggerPresent ..
(why write about this packer, well knowledge is power..)
tools needed:
1. Olly+Ollydumb(imprec cant locate the imports)
Okay lets start load the file into olly and you see this:
0041500C > $ 3BC0 CMP EAX,EAX
0041500E 74 DB 74 ; CHAR 't'
0041500F 02 DB 02
00415010 81 DB 81
00415011 83 DB 83
00415012 . 55 PUSH EBP
00415013 . 3BC0 CMP EAX,EAX
00415015 . 74 02 JE SHORT exe32pac.00415019
00415017 . 8183 533BC974 >ADD DWORD PTR DS:[EBX+74C93B53],3B56BC01
Press f7 until you pass the push ebp and land on CMP EAX,EAX. if you look the Registers Window
youl notice that ESP has changed, right click on it and choose Follow in dump, Select the first 4 bytes and right click ->breakpoint ->hardware on access -> dword and press f9 you will break here:
00420156 3BE4 CMP ESP,ESP
00420158 74 01 JE SHORT exe32pac.0042015B
0042015A BF FFE0B801 MOV EDI,1B8E0FF
0042015F 0000 ADD BYTE PTR DS:[EAX],AL
00420161 003B ADD BYTE PTR DS:[EBX],BH
00420163 C9 LEAVE
now all you gotta do is press 3x f7 and your at OEP :) you will have to press ctrl+a in order to see it, now dump with ollydumb and youl have a fully working .exe .. the imports are still bit *censored*ed(maby somebody will borther fixing) but program runs and you can disassemble now :)
-
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
- LordPE
- ImpREC
- Hex Editor
1. QUICK ANALYSIS
1.1 Layers
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:
00421000 PUSHAD
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
77E99A16 LEAVE
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
77E99A16 LEAVE
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:
00412D15 RETN
00412D16 JMP DWORD PTR DS:[415570] ; 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:[415584]
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
00421050 RETN
00421051 PUSH 476408A8
00421056 XOR DWORD PTR SS:[ESP],3083BFF8
0042105D RETN
...
...
004212F5 PUSH 7757B958
004212FA XOR DWORD PTR SS:[ESP],83EA58
00421301 RETN
00421302 PUSH 77521539
00421307 XOR DWORD PTR SS:[ESP],84C3D8
0042130E RETN
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!!!
0043598E NOP
0043598F NOP
00435990 NOP
00435991 NOP
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
004359C4 NOP
004359C5 NOP
004359C6 NOP
004359C7 NOP
004359C8 CMP DWORD PTR SS:[EBP+4023FE],ESI
004359CE JE SHORT AVIPrevi.004359D9
004359D0 NOP
004359D1 NOP
004359D2 NOP
004359D3 NOP
004359D4 JMP SHORT AVIPrevi.00435A39 <------ Good jump!!!
004359D6 NOP
004359D7 NOP
004359D8 NOP
004359D9 CMP BYTE PTR SS:[EBP+4159EB],0
004359E0 JE SHORT AVIPrevi.00435A39 <-------- Good jump!!!
004359E2 NOP
004359E3 NOP
004359E4 NOP
004359E5 NOP
004359E6 JMP SHORT AVIPrevi.004359EF <------- Bad jump!!!
004359E8 NOP
004359E9 NOP
004359EA NOP
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!!!
00435A3A PUSHAD
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
to this:
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
00435AD0 POPAD
00435AD1 POPAD
00435AD2 CALL AVIPrevi.004334BC
00435AD7 RETN
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
00432011 POPAD
00432012 POPAD
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
004334A3 POPAD
004334A4 POPAD
004334A5 RETN
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
0043866A POPAD
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
004386B6 NOP
004386B7 NOP
004386B8 PUSHAD
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:
00438F8A POPAD
004398BA POPAD
0043A1DA POPAD
0043AB30 POPAD
0043B4BE POPAD
0043BE70 POPAD
0043C7A7 POPAD
0043D090 POPAD
0043D9EB POPAD
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.
-
Level : beginner
Using gdb to retrieve a deadlisting of a linux binary, comment the algoritm, and writing a keygen in C++
First I fired up gdb on the program, set the disassembly type to intel instead of the default att and turned on asm-demangle. I then set a breakpoint on main and disassembled the program and got the following output.
PS - I did not do any stepping through of the code through gdb's debugger, I only used it to disassemble the code and then manually analyzed it.
--------------------------------------------------------------------------------
linux2[1]% gdb small
GNU gdb Red Hat Linux (6.1post-1.20040607.52rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) set disassembly-flavor intel
(gdb) set print asm-demangle on
(gdb) break *main
Breakpoint 1 at 0x80487bc
(gdb) run
Starting program: /afs/bla/bla/home/small
Breakpoint 1, 0x080487bc in main ()
(gdb) disassemble
Dump of assembler code for function main:
0x080487bc : push ebp
0x080487bd : mov ebp,esp
0x080487bf : sub esp,0xe8
0x080487c5 : and esp,0xfffffff0
0x080487c8 : mov eax,0x0
0x080487cd : sub esp,eax
0x080487cf : sub esp,0x8
0x080487d2 : push 0x80486d8
0x080487d7 : sub esp,0xc
0x080487da : push 0x8048ae0
0x080487df : push 0x8049db8
0x080487e4 : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
0x080487e9 : add esp,0x14
0x080487ec : push eax
0x080487ed : call 0x8048658
0x080487f2 : add esp,0x10
0x080487f5 : sub esp,0x8
0x080487f8 : push 0x8048b20
0x080487fd : push 0x8049db8
0x08048802 : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
0x08048807 : add esp,0x10
0x0804880a : sub esp,0x8
0x0804880d : lea eax,[ebp-72]
0x08048810 : push eax
0x08048811 : push 0x8049e48
0x08048816 : call 0x80486c8 >& std::operator>> >(std::basic_istream >&, char*)>
0x0804881b : add esp,0x10
0x0804881e : sub esp,0x8
0x08048821 : push 0x8048b60
0x08048826 : push 0x8049db8
0x0804882b : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
0x08048830 : add esp,0x10
0x08048833 : sub esp,0x8
0x08048836 : lea eax,[ebp-136]
0x0804883c : push eax
0x0804883d : push 0x8049e48
0x08048842 : call 0x80486c8 >& std::operator>> >(std::basic_istream >&, char*)>
0x08048847 : add esp,0x10
0x0804884a : mov DWORD PTR [ebp-204],0x0
0x08048854 : lea eax,[ebp-72]
0x08048857 : add eax,DWORD PTR [ebp-204]
0x0804885d : cmp BYTE PTR [eax],0x0
0x08048860 : jne 0x8048864
0x08048862 : jmp 0x80488a6
0x08048864 : lea eax,[ebp-200]
0x0804886a : mov ecx,eax
0x0804886c : add ecx,DWORD PTR [ebp-204]
0x08048872 : lea eax,[ebp-72]
0x08048875 : add eax,DWORD PTR [ebp-204]
0x0804887b : mov al,BYTE PTR [eax]
0x0804887d : movsx dx,al
0x08048881 : mov DWORD PTR [ebp-218],0xa
0x0804888a : mov eax,edx
0x0804888c : cwd
0x0804888e : data16
---Type to continue, or q to quit---
0x0804888f : idiv DWORD PTR [ebp-218]
0x08048895 : mov al,dl
0x08048897 : add eax,0x30
0x0804889a : mov BYTE PTR [ecx],al
0x0804889c : lea eax,[ebp-204]
0x080488a2 : inc DWORD PTR [eax]
0x080488a4 : jmp 0x8048854
0x080488a6 : lea eax,[ebp-200]
0x080488ac : add eax,DWORD PTR [ebp-204]
0x080488b2 : mov BYTE PTR [eax],0x0
0x080488b5 : lea eax,[ebp-136]
0x080488bb : lea edx,[ebp-200]
0x080488c1 : sub esp,0x8
0x080488c4 : push eax
0x080488c5 : push edx
0x080488c6 : call 0x8048668
0x080488cb : add esp,0x10
0x080488ce : test eax,eax
0x080488d0 : jne 0x80488fa
0x080488d2 : sub esp,0x8
0x080488d5 : push 0x80486d8
0x080488da : sub esp,0xc
0x080488dd : push 0x8048b84
0x080488e2 : push 0x8049db8
0x080488e7 : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
0x080488ec : add esp,0x14
0x080488ef : push eax
0x080488f0 : call 0x8048658
0x080488f5 : add esp,0x10
0x080488f8 : jmp 0x8048920
0x080488fa : sub esp,0x8
0x080488fd : push 0x80486d8
0x08048902 : sub esp,0xc
0x08048905 : push 0x8048b90
0x0804890a : push 0x8049db8
0x0804890f : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
0x08048914 : add esp,0x14
0x08048917 : push eax
0x08048918 : call 0x8048658
0x0804891d : add esp,0x10
0x08048920 : mov eax,0x0
0x08048925 : leave
0x08048926 : ret
0x08048927 : nop
End of assembler dump.
(gdb) quit
The program is running. Exit anyway? (y or n) y
linux2[2]%
After this I began going through the code manually and adding my own C Style comments as seen below.
Dump of assembler code for function main:
// function prolog
0x080487bc : push ebp
0x080487bd : mov ebp,esp
// allocate some memory on the stack (232 bits or 29 bytes)
0x080487bf : sub esp,0xe8
// rounds the last digit in esp to 0..... purpose being?
0x080487c5 : and esp,0xfffffff0
// set eax to 0
0x080487c8 : mov eax,0x0
// esp -= eax (huh, we just set eax to 0)
0x080487cd : sub esp,eax
// esp -= 8 //allocate another byte)
0x080487cf : sub esp,0x8
0x080487d2 : push 0x80486d8
0x080487d7 : sub esp,0xc
// print out..... "-> Small crackme for Stingduk : push 0x8048ae0
0x080487df : push 0x8049db8
0x080487e4 : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
// adjust stack pointer from making the c call....
0x080487e9 : add esp,0x14
// print out..... "Give me your name (max 50 chars):"
0x080487ec : push eax
0x080487ed : call 0x8048658
0x080487f2 : add esp,0x10
0x080487f5 : sub esp,0x8
0x080487f8 : push 0x8048b20
0x080487fd : push 0x8049db8
0x08048802 : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
// adjust stackframe
0x08048807 : add esp,0x10
0x0804880a : sub esp,0x8
// accepts the name from cin ebp-72 (72 to 22)
// load the address of the local mem storage we created
0x0804880d : lea eax,[ebp-72]
0x08048810 : push eax
0x08048811 : push 0x8049e48
0x08048816 : call 0x80486c8 >& std::operator>> >(std::basic_istream >&, char*)>
0x0804881b : add esp,0x10
0x0804881e : sub esp,0x8
// print out.......... Pass me the serial (max 50 chars):
0x08048821 : push 0x8048b60
0x08048826 : push 0x8049db8
0x0804882b : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
0x08048830 : add esp,0x10
0x08048833 : sub esp,0x8
// accepts the userSerial from cin ebp-136 (136 to 86)
// load the address of the local mem storage we created
0x08048836 : lea eax,[ebp-136]
// push the local address on stack
0x0804883c : push eax
0x0804883d : push 0x8049e48
0x08048842 : call 0x80486c8 >& std::operator>> >(std::basic_istream >&, char*)>
// adjust stackframe
0x08048847 : add esp,0x10
// fill a dword (4 bytes) 204 to 200
// counter = 0;
0x0804884a : mov DWORD PTR [ebp-204],0x0
ebp-72 to -22 holds Name
ebp-136 to -86 holds userSerial
//------Begin Loop--------/
// load the address of Name from local memory
0x08048854 : lea eax,[ebp-72]
// add whats in ebp-204 to eax... initially 0, incremented at the end of each loop.
0x08048857 : add eax,DWORD PTR [ebp-204]
// compare 1 byte at a time, contents of eax and 0
// check for null char termination
0x0804885d : cmp BYTE PTR [eax],0x0
// if (!null char)
// continue;
// else
// break;
0x08048860 : jne 0x8048864
0x08048862 : jmp 0x80488a6
// load address of ebp-200 to eax (calculatedSerial)
0x08048864 : lea eax,[ebp-200]
// using ecx as a temp var/reg
// ecx = eax
// ecx = calculatedSerial;
0x0804886a : mov ecx,eax
// ecx += contents of ebp-204 (counter/offset variable)
// ecx = &calculatedSerial[counter];
0x0804886c : add ecx,DWORD PTR [ebp-204]
// get first char of name
// eax = address of [ebp-72]
// eax = name;
0x08048872 : lea eax,[ebp-72]
// 204 to 200
// eax += contents of 4 bytes from ebp-204 (counter/offset variable)
// eax = &name[counter];
0x08048875 : add eax,DWORD PTR [ebp-204]
// al = name[counter];
// al = contents of eax
0x0804887b : mov al,BYTE PTR [eax]
// dx = al, converting a single byte al to double byte dx
0x0804887d : movsx dx,al
// move 0xa or 10 into contents of ebp-218 TO -214
// divideBy = 10;
0x08048881 : mov DWORD PTR [ebp-218],0xa
// move edx into eax..... what about high bits of edx?
0x0804888a : mov eax,edx
// sign extend ax to dx:ax
// word to dword, bit 15 of ax will be copied into all of dx (all 1's or 0's)
0x0804888c : cwd
0x0804888e : data16 // this ensures its a 16 bit operation even tho dword i think..
// DX = just the sign, AX = *name[counter];
// divide DX:AX by 10 and store result in AX and remainder in DX
0x0804888f : idiv DWORD PTR [ebp-218] // signed dividing by 10
// DX = ASCII value of currChar % 10
// AX = ASCII value of currChar / 10
// take low byte from remainder and store in al.... previously division
// al = dl
0x08048895 : mov al,dl
// add 30h to eax... makes sense 48 is 0 in ascii., mod 10 system will return us in 0 to 9
// range of possible ints for eax is 48 to 57, they will all be ASCII 0's to 1's
0x08048897 : add eax,0x30
// *calculatedSerial[counter] = al;
// *ecx = al (low byte is going into mem contents of ecx, remainder of previous division % 10...)
0x0804889a : mov BYTE PTR [ecx],al
// eax = address of ebp-204 or counter
0x0804889c : lea eax,[ebp-204]
// (*eax)++ or counter++ contained at ebp-204 to 200
0x080488a2 : inc DWORD PTR [eax]
0x080488a4 : jmp 0x8048854
//-------END LOOP------/
// eax = address of ebp-200 (calculatedSerial)
0x080488a6 : lea eax,[ebp-200]
// (add the counter to calculatedSerial store in eax)
// eax += contents of 4 bytes of ebp-204 to 200
0x080488ac : add eax,DWORD PTR [ebp-204]
// null delimit the calculatedSerial
// contents of eax = 0
0x080488b2 : mov BYTE PTR [eax],0x0
// load address of ebp-136 (User supplied serial) into eax
0x080488b5 : lea eax,[ebp-136]
// load address of ebp-200 (calculatedSerial)
0x080488bb : lea edx,[ebp-200]
// adjust stack pointer
0x080488c1 : sub esp,0x8
// push &userSerial and &calculatedSerial onto stack and compare the two with strcmp
0x080488c4 : push eax
0x080488c5 : push edx
0x080488c6 : call 0x8048668
// adjust stack frame
0x080488cb : add esp,0x10
// test to see what strcmp returns
0x080488ce : test eax,eax
// jump to main+318 if not equal (failed check)
0x080488d0 : jne 0x80488fa
// adjust stack frame
0x080488d2 : sub esp,0x8
// print out cracked message.... "Great work!"
0x080488d5 : push 0x80486d8
0x080488da : sub esp,0xc
0x080488dd : push 0x8048b84
0x080488e2 : push 0x8049db8
0x080488e7 : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
0x080488ec : add esp,0x14
0x080488ef : push eax
0x080488f0 : call 0x8048658
0x080488f5 : add esp,0x10
// must jump to very end of program regardless to end the program.
0x080488f8 : jmp 0x8048920
// adjust stack frame
0x080488fa : sub esp,0x8
// print out error message..... "No luck here mate :("
0x080488fd : push 0x80486d8
0x08048902 : sub esp,0xc
0x08048905 : push 0x8048b90
0x0804890a : push 0x8049db8
0x0804890f : call 0x8048698 >& std::operator >(std::basic_ostream >&, char const*)>
0x08048914 : add esp,0x14
0x08048917 : push eax
0x08048918 : call 0x8048658
0x0804891d : add esp,0x10
// put 0 in eax to exit the program
0x08048920 : mov eax,0x0
// destroy stack frame and buhbye
0x08048925 : leave
0x08048926 : ret
0x08048927 : nop
End of assembler dump.
--------------------------------------------------------------------------------
So basically the program loops through each char of the name, mods the ASCII's decimal value by 10 and then adds 48 to that remainder.
A mod system of 10 will always bring you back to the numbers 0 to 9 and then adding 48 will always bring you to the ASCII values 0 to 9.
My first test was to check my handle to see if I could get 'aa' to work.
a = 97 in ASCII decimal 97 % 10 = 7 7 + 48 = 55 55 in ASCII decimal = 7 so the key should be 77
--------------------------------------------------------------------------------
linux2[28]% ./small
-> Small crackme for Stingduk <-
Give me your name (max 50 chars): aa
Pass me the serial (max 50 chars): 77
Great work!
And as we can see it works.
Now to write a Keygen.....
//------------------------
// keygen.cpp
// tested with g++ 3.2.3
//------------------------
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
cout << "Please enter a name: ";
cin >> name;
cout << "Your key is: ";
for (int i = 0; i < name.size(); i++)
cout << (int) name[i] % 10;
cout << endl;
return 0;
}
linux2[32]% g++ keygen.cpp -o keygen
linux2[33]% ./keygen
Please enter a name: Koffee
Your key is: 512211
linux2[34]% ./keygen
Please enter a name: BiWReversing
Your key is: 657218145503
linux2[35]% ./keygen
Please enter a name: somenamehere
Your key is: 519107914141
linux2[36]% ./small
-> Small crackme for Stingduk <-
Give me your name (max 50 chars): Koffee
Pass me the serial (max 50 chars): 512211
Great work!
linux2[37]% ./small
-> Small crackme for Stingduk <-
Give me your name (max 50 chars): BiWReversing
Pass me the serial (max 50 chars): 657218145503
Great work!
linux2[38]% ./small
-> Small crackme for Stingduk <-
Give me your name (max 50 chars): intentionalFail
Pass me the serial (max 50 chars): 1421532523532
No luck here mate :(
linux2[39]%
-
Krypton 0.5 - (half)manually unpacking
--------------------------------------------------------------------------------
This tutorial discuss about Krypton 0.5 protection features and their improvements from 0.3 version. Krypton 0.5 is not bad protector but it has one big lack, it is very unstable and lot of packed files will just crash. Let's go ride into new adventure ;)
1. Indruduction
--------------------------------------------------------------------------------
Hi and welcome to new tutorial! We will walk trough Krypton 0.5 protection features to see what is new and what is old comparing to previous 0.3 version (don't know where is 0.4). Like in the first tutorial, approach will be the same. We will try to fix dumped file after reaching OEP and OllyScript plugin will help me alot in that. This tutorial relies on last one so it is good thing to read that tutorial first.
You will need some tools and stuff for work:
- Target and utilities , here [bin]
- OllyDbg 1.10 (OllyScript & OllyDump plugins)
- ImpREC
- LordPE
- some hex editor
So what Krypton 0.5 have and what do not have? I found next:
- two possible jumps to OEP;
- obfuscation which is simmilar as in 0.3 version;
- breakpoint checks on API functions;
- API obfuscation , same as in the 0.3 version;
- API code execution , same as in the 0.3 version;
- code encryption I , same as in the 0.3 version;
- code substitution II, III, IV , new feature;
- code on-the-fly encryption/decryption , new feature;
- threads that doing all this (not too sure about this);
- it doesn't have CRC checks;
- it doesn't have anti-debug checks.
Target is Crud's CRACKME3.EXE which I packed with all options in Krypton (actually, one is missing but I will say few words about that at the end of tutorial).
---->
-
2. How to find OEP
--------------------------------------------------------------------------------
I was experimenting with memory and hardware breakpoints and I found that like in 0.3 version, here we also have two possible jumps to OEP. Which one will be used depends of packing options. Krypton allocates one memory block in which it unpacks its own loader. Loader unpacks packed file and then it jump to OEP. So you need to stop somewhere in loader code and you can done this like we did in 0.3 version, using VirtualAlloc API and memory breakpoint on one byte in allocated block (check first tutorial for details). Then you need to find possible OEP jumps. As I sad, there are two possible jumps to OEP. One is via JMP EDX where EDX=OEP, second is via PUSH-RETN combination. Since code is obfuscated you won't see those opcodes so I will give you bynary signature of them:
a) First one is executed if file is packed with minimal options. Search for this binary string in loader code:
8B9513784400
and you will find this code:
003BEAE6 MOV EDX,DWORD PTR SS:[EBP+447813] <--- DWORD is OEP address (when you break here)!
003BEAEC JMP SHORT 003BEB2F
003BEAEE FILD QWORD PTR DS:[ECX+4E]
003BEAF1 POP EAX
003BEAF2 FISTP WORD PTR DS:[ECX+71]
003BEAF5 LOCK JMP SHORT 003BEAF9
003BEAF8 FBSTP TBYTE PTR DS:[EAX-15]
003BEAFB FIST WORD PTR DS:[ECX-15]
003BEAFE HLT
003BEAFF POP ESI
003BEB00 XCHG EAX,EBX
003BEB01 RETF 4B91
003BEB04 MOV BL,0EB
003BEB07 HLT
003BEB08 BOUND EAX,QWORD PTR DS:[EAX-3B]
003BEB0B SUB EBX,EDI
003BEB0D STC
003BEB0E SBB AL,0D3
003BEB10 INC ECX
003BEB11 TEST AL,6A
003BEB13 JMP EDX <----------------------------- And here it jumps to OEP!
So just place bp on this last JMP EDX. But you don't know will this jump will be used, so you need to place bp on second possible jump
b) For second jump, search this binary string:
C3EB1EDF694E58DF5972F5EB01DF73F0DF599C83C1E79DFFE1 EB0D51E8F0FFFFFFE801000000
and you will land here:
003C3958 RETN <---------------------- Second possible jump to OEP! Place bp here.
003C3959 JMP SHORT 003C3979
003C395B FILD QWORD PTR DS:[ECX+4E]
003C395E POP EAX
003C395F FISTP WORD PTR DS:[ECX+72]
003C3962 CMC
003C3963 JMP SHORT 003C3966
003C3965 FBSTP TBYTE PTR DS:[EBX-10]
003C3968 FISTP WORD PTR DS:[ECX-64]
003C396B ADD ECX,-19
003C396E POPFD
003C396F JMP ECX
003C3971 JMP SHORT 003C3980
003C3973 PUSH ECX
003C3974 CALL 003C3969
003C3979 CALL 003C397F
003C397E JMP CA29BAE0
Note that Olly doesn't display correctly code because obfuscation so you will at first see this as a first line:
003C3957 E9 C3EB1EDF JMP DF5B251F
You see, C3=RETN is second byte so you just hit Ctrl+G and in "expression to follow" enter addres that point to C3 byte (3c3958 in my case).
When you had finish with bp's, hit F9 and you will break on one of these two bp's and that's it ;) OEP found. Now when you reached OEP we will see how Krypton interfear with packed file. Btw, for fast finding OEP you can use script in 9. chapter of this tutorial.
-
3. IAT redirection and obfuscation
--------------------------------------------------------------------------------
There is nothing new with IAT comparing to 0.3 version. We have exactly the same obfuscation:
0037wwww ADD DWORD[0037uuuu],CONSTANT
0037wwww MOV EAX,DWORD[00370000]
0037wwww SUB DWORD[0037uuuu],CONSTANT
0037wwww JMP EAX
0037uuuu SOME_4_BYTES
0037wwww XOR DWORD[0037uuuu],CONSTANT
0037wwww MOV EAX,DWORD[00370000]
0037wwww XOR DWORD[0037uuuu],CONSTANT
0037wwww JMP EAX
0037uuuu SOME_4_BYTES
And we have indentical API execution but just with different parameters and obfuscation is different. Check tutorial about 0.3 version because there is no need to write all over again the same thing. Two scripts for repairing imports, you can find in 9. chapter.
-
4. Code decryption/encryption I
--------------------------------------------------------------------------------
This is also same feature as in the 0.3 version where MOV XXX,DWORD[yyyyyyyy] or PUSH XXX,DWORD[yyyyyyyy] is substituded with CALL DWORD[zzzzzzzz]. Again, no need to repeating so read first tutorial and use script in 9. chapter. You need to edit it ofcourse.