Jump to content
Tuts 4 You

[unpackme] ExeCryptor 2.4.1 UnpackMe 2009


Recommended Posts

Well, I know that execryptor 2.4.1 is actually quite old.

But just click on protect is not enough, this itime i used some sdk, and also put a 5 uses trial, after 5 uses some strings are lost.

And also i put some custom things that will make the target more hard.

Difficulty: 3/10

Goal: unpack it and make it working forever.

Good luck :)


Edited by EvOlUtIoN
  • Like 1
Link to comment
Share on other sites

Interesting. This reminds me of an old target I had to inline once (RSI had some issues as well). What puzzles me still is the fact that you've used god damn high memory (BaseOfCode, SizeOfImage) so that the "unpacked" file eats up to ~700MB of memory. This is one thing I gotta solve first, then I'll post my version. Maybe an inline? :-)

Edited by SunBeam
Link to comment
Share on other sites

Well the big memory used is one of thing i have implemented manually, this was for avoid do use automatic unpacker. Maybe it will work anyway, but the operation take more than a while. :) It should be easy to solve though, not needed much knowledge, and using correct plugins and pe editors you can dump with a more reasonable size.

I prefer unpacked instead of inline or loader.

Link to comment
Share on other sites

@thisistest: OEP is at 401900.

And Evo set a SEH at OEP, just to make sure nothing wrong happens in between :-)

2944EE01 64:FF35 00000000 PUSH DWORD PTR FS:[0]

2944EE08 - E9 092BFBD6 JMP execrypt.00401916


00401916 64:8925 00000000 MOV DWORD PTR FS:[0],ESP

0040191D 83EC 50 SUB ESP,50

00401920 53 PUSH EBX

00401921 56 PUSH ESI

00401922 57 PUSH EDI

Working on unpacking it :-P

Link to comment
Share on other sites

I never said it's ASM :-P Just traced till obfu_OEP, then out of wrapper and into stolen bytes. Then landed at that SEH (generated probably with _try _except etc..)..

Link to comment
Share on other sites

Since we're doing a little contest here.. Let's join the fun. :)

Unpacking Ftw.

Btw if sunbeam can't do this in 10 mins it's at least 5/10. ;)


And yeah that 700mb resource section is rather annoying. :)

Edited by quosego
Link to comment
Share on other sites

I know it is annoying, and i can tell that the protection can be done also better indeed, i will put it in another target...i don't think this will take so much to be solved. Simply it is better to dump with a method different from other times :).

Link to comment
Share on other sites

Good work, LCF-AT.

And despite quosego's remark, it still puzzles me how to solve this unpackme. It's not EXECryptor that bugs me, but the god damn resources section.

LCF-AT, will you shed some light into this? As in, how you unpacked it - just the "how to cut the freaking 700 MB out of the dumped file" part :-) Or you may share it all..

Link to comment
Share on other sites

Yeah it can be done by dumping partially etc and reconstructing.. But I was just being stubborn and simply wanted to do it like I always do execryptor.

Which didn't work in my slow VM which takes ages to process this.. More like a time thing than impossible.

Wanted to just move everything low mem and insert a big virtual size in the PE header like the original. :)

Link to comment
Share on other sites

Nothing is impossible of course, but how to distribute a 700MB unpacked file? :)

My aim was to produce an unpackme harder than a simple execryptor old unpackme, and seems that i done it.

Congratulations for both solvers.

Link to comment
Share on other sites

Idea was this -- when you buff up the resources section up to 700 MB, addresses around it get that amount added to them. As in:

sec1 - 400000

sec2 - 400000 + 700MB -> 254xxxxx

And guess what happens when you put on EXECryptor. Of course, the calculated VM will do this:

push 290932009

add eax, 273289371

pop ebx

add eax,ebx


So result will be an address like 254xxxxx <- and how would you go through that VM?

I've solved a loader once for WinOLS which used same tactics. So I had dumped the VM sections manually. Then loaded a dummy app. Used Cheat Engine to load up the sections in memory at their designated addresses, after which I ran he deVM script to acquire the crypt_constants used to clean the code. Once I got them all (cuz if I ran it through the 700MB VM, at some point Olly got stuck and would run very slow - like 1 instruction every 1 minute) I could see where I'm going :-)

So, once more, would be very interested in a "how to do this ****" tutorial ;) Now that the crackme's been solved..

Link to comment
Share on other sites


so I never would make a dump with a hugh size like 700 MB.

Here a short tutorial for SunBeam :) and also the others of course.


1. Get OEP / use HeapCreate or GetModuleHandleA to come close on this place.

2. Break on the first OEP command which will used.

3. Make a copy of the UnpackMe

4. Load the copy in LordPE and fix all manually

--- Just remove all 29xxxxxx / ALL / Imports, Tls etc...

5. Load the fixed size copy in a second Olly / EP 0054C985 RVA now

6. Dump all sections exept the last one of the first loaded UnpackMe in Olly 1

--- Use Dump Region and enter the address & size manually / look in Olly 2 there you can see the sections correctly now

401000 | 2000

403000 | 1000


7. Open a hex editor like winhex.Load on section like 401000-2000 into and select all and copy it with hex value

8. Go to Olly 2 and go to section 401000...select all and paste now you got one sections fixed.

9. Do the same with the rest too.

10. Fix IAT in your first Olly so for this you can use the script by PE_Kill to make it fast.

11. Select fixed IAT and copy it in Olly 2.

12. Set Olly 2 on the right OEP and fix the few stolen bytes.

13. Create a dump in Olly 2 with Olly Dump plugin,disable rebuild imports & enable fix raw size.

14. Load the new dump in Olly 2

15. Load / loadlib "COMCTL32.dll" / 00404458 773116C9 <----

16. Run

17. Bad message AV at address 294B0E68 so this address does not exist in our dump file.

18. Go to Olly 1 to address 294B0E68

19. Scroll up to find the start / or enter 2941B000 <-- start of code. till $+132FFE <-- End

20. Go again to LordPE and dump 2941B000 | 133000

21. Add section to our dump / make valid rebuild

22. Load dump in Olly /load COMCTL32.dll / insert IAT binary.

23. Open ImpRec enter data etc..

24. Fix our [section]-dump

25. Make valid rebuild-

26. Load fixed dump in Olly and run.Dump starts now-

27. Check the new added section to see whether this section is really needed or not.

28. Set MemBP on access on it and run.From codesection to new section to codesection / switching memBPs.

29. 3 times breaks on it....Look a bit back to find start of routine or other decision.

00401120  PUSH EBP  // RET
00401121 MOV EBP,ESP
00401123 SUB ESP,4
00401126 PUSH EBX
00401127 PUSH ESI
0040112B JMP 2944CC88004010D0 PUSH EBP // RET
004010D1 MOV EBP,ESP
004010D3 SUB ESP,1C
004010D6 JMP 294B0E68004012D5 CMP EAX,1
004012D8 JNZ SHORT 00401304
004012DA CALL 29448AA7 // NOP
004012DF CALL 2949250C // NOP

So make this patches and save and now you have a fast working file.So the code is not really needed so we can just make this patches in this case.Now you can also make some cosmetic changes like removing some sections and the TLS...CallBack [004BB12C] 2954C991 <-- 0 it-


Link to comment
Share on other sites

Yes, that's the right way...thank you LCF-AT


I solved the same winols loader, but i preferred an inline that time instead of unpacking.

Anyway that is where i taken the idea.

Link to comment
Share on other sites

  • 3 months later...


This still doesn't solve my initial problem. As I said, when EXECryptor unwraps itself, the VM works in such a fashion that the calculated addresses are in high memory. My goal wasn't to unpack the file, but rather make it so VM is moved to low memory, in order for me to clean it up (since Olly stucks at high memory). I followed your tutorial up to the point where you say "check if sections are used with memory breakpoints on access". Then it hit me - I don't want to remove sections from the file, I just want the unpacked code to land in low memory.

See this:

0054C985 > E8 3BFFFFFF CALL copy.0054C8C5

0054C98A 05 690A0000 ADD EAX,0A69



0054C8C5 E8 00000000 CALL copy.0054C8CA

0054C8CA 58 POP EAX

0054C8CB 56 PUSH ESI

0054C8CC 57 PUSH EDI

0054C8CD 51 PUSH ECX

0054C8CE 53 PUSH EBX

0054C8CF 50 PUSH EAX


0054C8D3 81EB CAC85429 SUB EBX,2954C8CA // ------------------- [1]

0054C8D9 B8 EE690000 MOV EAX,69EE

0054C8DE 50 PUSH EAX

0054C8DF 6A 04 PUSH 4

0054C8E1 68 00100000 PUSH 1000

0054C8E6 50 PUSH EAX

0054C8E7 6A 00 PUSH 0

0054C8E9 B8 C4B04B29 MOV EAX,294BB0C4 // ------------------- [2]



What I showed above is only the easy part. There are portions in EC that use calculus:


{ calculus here } // $RESULT is something like 29xxxxxx


So yeah, any ideas? :-)

Link to comment
Share on other sites

I found the solution, yet I gotta fix VolX's script a bit for deVM-ing. Basically, follow your tutorial, remove all 29xxxxxx from everything (SizeOfImage, BaseOfCode, sections, IAT location and APIs, TLS wiped). Save file and rebuild PE. Load file and use this as a script:

__in_opt LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flAllocationType,
__in DWORD flProtect // ptr
pauseexec pushad push 40
push 3000
push 133000
push 2941B000
call VirtualAlloc
mov ecx, 133000
mov esi, 41B000
mov edi, 2941B000
rep movs byte ptr [edi], byte ptr [esi]
popadendemov eip, 2954C991ret

It allocates the high-memory of the original file, without .rsrc being that BIG. Then copies the code starting from first EC section till end of file to what we earlier allocated. Sets EIP, so we can trace from there :-) Unpacking of code works perfectly, as EC fills the sections correctly. The only thing deVM script fails at is getting correct SizeOfImage. I'll fix it in VolX's script.

EDIT: Now that I changed my PC (to a Core2Duo one) Olly doesn't freeze anymore when script traces through high-memory for those 0x40 crypt constants T_T. This is stupid.. Makes me wanna kill myself. Well, it was good to try as proof of concept. Maybe some of you still have old rigs on which Olly will basically run a line of code every 2-3 minutes in a 700MB memory-mapped file :-)

Edited by SunBeam
Link to comment
Share on other sites

Here you go, unpacked, VM-included and cleaned. Don't expect it to run, I'll explain :-)




00401900 - E9 19530929 JMP 29496C1E

29496C1E 50 PUSH EAX // save state of EAX ..

29496C27 68 2DA077AA PUSH AA77A02D // from here [1]


29496C34 58 POP EAX


29496C3D 81E8 B8572167 SUB EAX,672157B8

29496C43 ^ E9 DC71FBFF JMP 2944DE24


2944DE24 81C0 C1E5ECE5 ADD EAX,E5ECE5C1 // to here [2]


2944DE31 870424 XCHG DWORD PTR SS:[ESP],EAX // we get [ESP] == 29432E36


2944DE3A E9 31F30300 JMP 2948D170


2948D170 C3 RETN

So exit point is 29432E36. Moving on:

29432E36 56 PUSH ESI // save state of ESI register


29432E3F 68 042F35EB PUSH EB352F04 // from here [3]


29432E4C 5E POP ESI


29432E55 81CE 9AE49A60 OR ESI,609AE49A

29432E5B ^\E9 06D5FEFF JMP 29420366


29420366 81C6 EB13823D ADD ESI,3D8213EB // till here [4]


29420373 873424 XCHG DWORD PTR SS:[ESP],ESI // we get [ESP] == 29420389; used later as RET point for function 2949BEE5


2942037C E9 64BB0700 JMP 2949BEE5

Now we are inside an EXECryptor_API, which starts here:

2949BEE5 55 PUSH EBP

2949BEE6 8BEC MOV EBP,ESP <-- we step over this line with F7

So, follow ESP (or EBP, since they are equal), follow in dump and set a hardware breakpoint on access (DWORD). Shift+F9 and we're here:

00401046 8BE5 MOV ESP,EBP

00401048 5D POP EBP

00401049 C3 RETN <-- you are here

Exit RET with F7 and we are where I said earlier:

29420389 50 PUSH EAX

This is another masked API:

29420389 50 PUSH EAX


29420392 892C24 MOV DWORD PTR SS:[ESP],EBP

Those two basically mean PUSH EBP :-) Then:

294B3405 89E5 MOV EBP,ESP <-- F7 to step over this line

If we repeat the same idea, with following ESP (or EBP) in stack, setting a HWBP on access, DWORD, we observe that API never exits. Application dies. Let's investigate why..

2944EE01 64:FF35 00000000 PUSH DWORD PTR FS:[0] // part of the stolen bytes from 401900

2944EE08 - E9 092BFBD6 JMP unpacked.00401916




Well, if you trace down the code, you will end up to here:

004019AC 52 PUSH EDX

004019AD 50 PUSH EAX

004019AE 6A 00 PUSH 0

004019B0 53 PUSH EBX

004019B1 E8 3AF8FFFF CALL unpacked.004011F0

That is WinMain(). Inside it, tracing a bit, we get up to here:

00401260 6A 00 PUSH 0

00401262 68 80124000 PUSH unpacked.00401280

00401267 6A 00 PUSH 0

00401269 68 E9030000 PUSH 3E9

0040126E 53 PUSH EBX

0040126F FF15 48444000 CALL DWORD PTR DS:[<&user32.DialogBoxParamA>] ; user32.DialogBoxParamA

The function at 401280 is the one that crashes us. Let's see why:

00401280 53 PUSH EBX <-- set breakpoint here with F2

Shift+F9 once. Shift+F9 once more, and trace a bit up to here:

004012B2 E8 19FEFFFF CALL unpacked.004010D0

This is a call to VM (well, it's clean now so you can see where you're going). So let's trace a bit:

29486B87 FF15 C4434000 CALL DWORD PTR DS:[<&kernel32.VirtualQuery>] ; kernel32.VirtualQuery

Stack is:

$ ==> > 2941B000 |Address = 2941B000

4 > 0012FB18 |Buffer = 0012FB18

8 > 0000001C \BufSize = 1C (28.)

So it interrogates the current section's characteristics. Moving on:

29426381 817D E8 00004000 CMP DWORD PTR SS:[EBP-18],400000 // [EBP-18] would be 29410000

29426388 0F84 CE680200 JE 2944CC5C

Since this check fails, cuz 29410000 used to be a section inside the original executable, which I've relocated, its base won't be the same as the file's (400000). Check fails, we crash :-) So let's fix it:

29426388 /E9 CF680200 JMP 2944CC5C

2942638D |90 NOP

Now you'll see it runs :-P Chunk is copied from 41B000, so let's find those bytes in there and change them in the file, so when copy ocurrs, JMP is fixed by itself:

00426381 817D E8 00004000 CMP DWORD PTR SS:[EBP-18],unpacked.00400000

00426388 E9 CF680200 JMP unpacked.0044CC5C

0042638D 90 NOP

Save changes to the file and see it work now :-)

I'll post more about used APIs later on ;-)




Edited by SunBeam
  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...