Contribute  :  Web Resources  :  Past Polls  :  Site Statistics  :  Downloads  :  Forum  
    BiW ReversingThe challenge is yours    
 Welcome to BiW Reversing
 Monday, August 21 2017 @ 01:07 AM CEST

ExeCryptor 2.2.50 - Unpacking MSVC++ target

   

TutorialsLevel : intermediate

ExeCryptor 2.2.50 - unpacking MSVC+ target - by haggar


Hi and welcome to new tutorial. This one shall be very quick and brief since I already wrote two tutorials. Target for this tutorial is UnPackMe_ExeCryptor2.2.50.j.exe provided by Teddy Rogers. It can be found on SnD site http://www.tuts4you.com/. It is MSVC++ target protected with all options.






ExeCryptor targets differ from one to second, but differences are minor. Once you understand one version, you will have open door for other ones. Most of differences are Olly detections which are changed from version to version so patching Olly is useless. Every new version will find easy Olly in memory. ExeCryptor checks all processes and reads couple bytes from specific adddresses. Example, it checks some exports, or ODBG strings in every process to recognize Olly. If it finds some process, it terminate it. Processes are enumerated with GetWindowThreadProcessId.



- Killing debugger checks -

Ok, enough of talking. Open Olly and in debugging options, under events, set Olly to break on System Breakpoint. This is to avoid target autorun in Olly. Olly will set breakpoint on EP of target and that breakpoint is detected by ExeCryptor (EC). Open bp window and delete that bp.

EC has several debugger checks:
BeingDebugged
NtGlobalFlag
HeapFlag
IsDebuggerPresent
CheckRemoteDebuggerPresent

I already explained these checks in one my tutorial so look there for explanation. If you don't want to waste time to manually disable checks, use some plugin like HideOlly or OllyAdvanced. But warning! Plugins can be detected by EC. Plugins sometimes (depending on type of plugin and hide method) hooks APIs and EC checks for such redirections. So select only features for these checks.



- Killing threads -

EC uses a lot of threads to perform active monitoring and protection. These threads checks for debuggers, breakpoints, hostile windows, etc... To disable these checks , we can patch CreateThread API so threads are never started. Go to CreateThread and NOP whole API till the last RETN xxxx opcode. I sad already that EC versions have minor changes. In my previous tutorials, it was enough to patch CreateThread API. But this version uses CloseHandle to close handle of thread after it is created. If threads are not created, CloseHandle will couse exception and target will crush. So we must patch CloseHandle API in the same way as CreateThread.



- OllyDbg targeted tricks -

EC really hate Olly and because of that it tries to detect and kill Olly by any means. One trick that is used to crush Olly is OutputDebugStringA exploit. This is probably nothing new for reader of this small tutorial because this trick is used in lot of protectors, but in case that you didn't know for it:
There is some bug in Olly that will couse Olly to crush if debugged executable file name is "%s%s", or if OutputDebugStringA send this string to Olly. To prevent crushing we can patch that API just like we patched CreateThread and CloseHandle. Instead of NOPing whole API, you can just place RETN 4 opcode at the API start.

EC can use FindWindowA, ReadProcessMemory tricks too for detecting Olly, but in this version those checks are performed just with threads. And we killed threads so this not we can run target under Olly.



- Finding OEP and restoring OEP code -

After we patched all checks, we need to break on OEP. We will use memory breakpoints for this. Place mem bp on first section and run. First time we will stop at unpacking procedure:

00519E01 AA STOS BYTE PTR ES:[EDI]
00519E02 ^EB E9 JMP SHORT UnPackMe.00519DED
00519E04 E8 FC000000 CALL UnPackMe.00519F05
00519E09 0F82 97000000 JB UnPackMe.00519EA6
00519E0F E8 F1000000 CALL UnPackMe.00519F05
00519E14 73 5B JNB SHORT UnPackMe.00519E71
00519E16 B9 04000000 MOV ECX,4
00519E1B E8 FD000000 CALL UnPackMe.00519F1D
00519E20 48 DEC EAX
...
...
00519F33 E8 CDFFFFFF CALL UnPackMe.00519F05
00519F38 ^72 F2 JB SHORT UnPackMe.00519F2C
00519F3A C3 RETN
00519F3B 8BE5 MOV ESP,EBP
00519F3D 5D POP EBP
00519F3E C3 RETN
00519F3F 90 NOP

When you break, remove mem bp, place bp at the last RETN. Last RETN is last opcode of this unpacking procedure and when you break there, code is unpacked. Remove that bp and place new mem bp. Run and you will break in procedure that writes destination of CALLs:

004B613E AC LODS BYTE PTR DS:[ESI]
004B613F D0E8 SHR AL,1
004B6141 80F8 74 CMP AL,74
004B6144 75 0E JNZ SHORT UnPackMe.004B6154
004B6146 8B06 MOV EAX,DWORD PTR DS:[ESI]
004B6148 0FC8 BSWAP EAX
004B614A 01C8 ADD EAX,ECX
004B614C 8906 MOV DWORD PTR DS:[ESI],EAX
004B614E 83C6 04 ADD ESI,4
004B6151 83E9 04 SUB ECX,4
004B6154 49 DEC ECX
004B6155 ^7F E7 JG SHORT UnPackMe.004B613E
004B6157 59 POP ECX
004B6158 5E POP ESI
004B6159 C3 RETN

Again, remove mem bp, place bp at the RETN, run and remove that bp. If you place next memory breakpoint on first section, you will break at OEP or first code that is executed in code section:

004271C5 50 PUSH EAX
004271C6 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
004271CD 83C4 A8 ADD ESP,-58
004271D0 53 PUSH EBX
004271D1 56 PUSH ESI
004271D2 57 PUSH EDI ; UnPackMe.00400000
004271D3 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
004271D6 FF15 DC0A4600 CALL DWORD PTR DS:[460ADC]
004271DC 33D2 XOR EDX,EDX
004271DE 8AD4 MOV DL,AH
004271E0 8915 34E64500 MOV DWORD PTR DS:[45E634],EDX
004271E6 8BC8 MOV ECX,EAX

But this is not OEP. OEP is stolen and code that was at OEP is already executed within EC code. Scroll up and you will see that OEP should be at the 004271B0:

004271B0 -E9 6CD10500 JMP UnPackMe.00484321
004271B5 58 POP EAX ; UnPackMe.004DC082
004271B6 C1C0 18 ROL EAX,18
004271B9 -E9 424E0400 JMP UnPackMe.0046C000
004271BE 70 12 JO SHORT UnPackMe.004271D2
004271C0 6C INS BYTE PTR ES:[EDI],DX ; I/O command
004271C1 90 NOP
004271C2 321F XOR BL,BYTE PTR DS:[EDI]
004271C4 ED IN EAX,DX ; I/O command

At that adres is not some jump. That jump leads to obfuscated reall OEP code that is placed inside EC section:

00484321 E8 FDA60000 CALL UnPackMe.0048EA23
00484326 F0:26:05 DCA804E>LOCK ADD EAX,E004A8DC
0048432D A5 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
0048432E E8 33E40100 CALL UnPackMe.004A2766
...

Proof that this place is OEP is also fact that EC checks this exact address for breakpoint:

0052286C 8A00 MOV AL,BYTE PTR DS:[EAX]
0052286E 2C 99 SUB AL,99
...
00525EBE F62A IMUL BYTE PTR DS:[EDX]
00525EC0 3C A4 CMP AL,0A4
00525EC2 0F85 C1040000 JNZ UnPackMe.00526389 <---- NO BP.
00525EC8 ^E9 D74FFFFF JMP UnPackMe.0051AEA4 <---- BP detected!


EC has strong obfuscation that makes impossible to reconstruct OEP code. But in this example number of stolen opcodes is small and most opcodes can be recovered by experience. Open some MSVC++ 6.0 file in second Olly and binary copy first 0x15 bytes. Paste them to our target at OEP. I have used Mozilla Firefox OEP bytes:

004271B0 55 PUSH EBP
004271B1 8BEC MOV EBP,ESP
004271B3 6A FF PUSH -1
004271B5 68 60ED9C00 PUSH 9CED60
004271BA 68 CE688A00 PUSH 8A68CE
004271BF 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
004271C5 50 PUSH EAX

Two PUSH values are wrong but they can be found in stack:

0012FFB4 004292C8 UnPackMe.004292C8
0012FFB8 00450E60 UnPackMe.00450E60
0012FFBC FFFFFFFF
0012FFC0 0012FFF0
...

Now OEP has correct opcodes:

004271B0 55 PUSH EBP
004271B1 8BEC MOV EBP,ESP
004271B3 6A FF PUSH -1
004271B5 68 600E4500 PUSH UnPackMe.00450E60
004271BA 68 C8924200 PUSH UnPackMe.004292C8
004271BF 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]




- Decrypting imports -

IAT section is 00460000. Most of imports are redirected in EC code where they are decrypted. In my past two tutorials I have explained how IAT is protected and how to recover it. But that was case when for imports are used jumps. VC++ use calls so I had to write new script. This script doesn't search for JMP/CALL, instead it just walks trough thunks in IAT section and decrypts protected ones. Script is below, paste it to some text file and use by some script plugin. My comments exapain most of things altough you don't need to understand it or change for this target:

// ----------- ExeCryptor 2.2.50 - for VC++ IAT ------------------
var oep
var thunk
var pointer
var ref_esp
var temp

mov oep,eip
mov thunk,00460000

LABEL_01: //Examne thunks label.
cmp thunk,00461000 //Is it end of IAT? Then finish.
je END_01
cmp [thunk],0 //Is thunk empty? Then go to next.
add thunk,4
je LABEL_01
sub thunk,4
cmp [thunk],10000000 //Does thunk holds API? Go to next again.
add thunk,4
ja LABEL_01
sub thunk,4 //Thunk holds redirected import.
mov pointer,[thunk]

mov eip,pointer
mov ref_esp,esp //Stack reference (start ESP value).
mov temp,0
LABEL_02: //Trace untill return ESP value is decrypted.
sti
add temp,1
cmp temp,30 //Trace first 30 opcodes.
jne LABEL_02

mov temp,esp
LABEL_03: //Find referenced stack value.
add temp,4
cmp temp,ref_esp
jne LABEL_03
sub temp,4

mov temp,[temp] //Get "Magic return address".
bp temp
esto
bc eip

cmp eax,10000000 //Is EAX<10000000 (EAX<IMPORT) ?
add thunk,4
jb LABEL_01 //Then it is self-fixed import.

sub thunk,4 //If not self-fix, fix it!
mov [thunk],eax
add thunk,4

jmp LABEL_01

END_01:
mov eip,oep //Restore OEP.
ret
//------------------------ End of script ------------------------------


When script is finished, dump image with LordPE (note that you'll had to correct ImageSize before you dump), load ImpREC and set OEP to 271B0, then rebuild IAT on dumped file.




- Fixing dump -

As a last touch, you need to erase TLS information from PE header. Use LordPE or CFF Explorer, set TLS offset and size to 0. You can also delete EC 3 sections to ge smaller dump. If you want to make perfect dump, you can place IAT in original IAT section at 00460000. Check my dump how I did it.

Dump is here http://www.reversing.be/binaries/articles/20061206202534115.rar





- The end -

Greets goes to Teddy for his great site, ARTEAM, CRACKMES.DE, BIW reversing, and to you.


haggar,2006






What's Related

Story Options

ExeCryptor 2.2.50 - Unpacking MSVC++ target | 0 comments | Create New Account
The following comments are owned by whomever posted them. This site is not responsible for what they say.
 Copyright © 2017 BiW Reversing
 All trademarks and copyrights on this page are owned by their respective owners.
Powered By Geeklog 
Created this page in 0.05 seconds