Yoda's Protector v1.03.2 – manually unpacking tutorial

Tuesday, August 23 2005 @ 10:41 PM CEST

Contributed by: haggar

Level : beginner

1. Intro

Hi and welcome to my new small tutorial about unpacking latest yoda’s protector. This tutorial will not go in the depth of new yoda’s anti-debug tricks, we will work around that field simply because got lost in all that SetThreadPriority, Block input and all that s**t that Ashkbiz Danehkar has thrown inside.
Restarting computer every time when you forget to place bp on a right place is not funny.

Anyway, here is content:

You will need next tools:
- OllyDbg 1.10 (ollydump plugin too)
- ImpREC
- PEiD
- LordPE
- dUP2 - diablo2oo2's Universal Patcher
- target here

In this archive you’ll find next:

- yP1.03.2 - unpacking tutorial.doc , this tutorial
- yP PEiD signatures.txt , correct signatures for PEiD
- yodaOEP.exe , patch for unpacking first target
- keygenme1.exe , target.

2. Unpacking

As we said, yoda doesn’t steal OEP bytes, it does not interferes with the unpacked program in memory, even IAT redirection is very simple – it’s not changed from the early beginning. This all goes to our favor. We will not approach to unpacking in usual way, tracing to OEP and avoiding anti-debug tricks, but let’s not just talk.
Grab target “keygenme1.exe” that I packed with latest yoda. I used all options that yoda offers, except header erasing because target crushed with that option.
So run target and open OllyDbg.
In Olly menu chose “File” ->“Attach”, select path to our target and click attach button.
Target will freeze and Olly will stop at system bp:


77F767CE   C3                         RETN
77F767CF > CC                        INT3
77F767D0   C3                          RETN
77F767D1   8B4424 04             MOV EAX,DWORD PTR SS:[ESP+4]
77F767D5   CC                         INT3
77F767D6   C2 0400                 RETN 4
77F767D9 > 64:A1 18000000   MOV EAX,DWORD PTR FS:[18]
77F767DF   C3                          RETN
77F767E0 > 57                          PUSH EDI
77F767E1   8B7C24 0C            MOV EDI,DWORD PTR SS:[ESP+C]
Open executables window and double click on our target. Then press Ctrl+A to analyze module.

You should be here:

00401000  /$ 33C0             XOR EAX,EAX
00401002  |. 394424 08      CMP DWORD PTR SS:[ESP+8],EAX
00401006  |. 7E 14               JLE SHORT Crackme_.0040101C
00401008  |> 8B4C24 04      /MOV ECX,DWORD PTR SS:[ESP+4]
0040100C  |. 8B0C81           |MOV ECX,DWORD PTR DS:[ECX+EAX*4]
0040100F  |. 3B4C24 0C      |CMP ECX,DWORD PTR SS:[ESP+C]
00401013  |. 74 0A             |JE SHORT Crackme_.0040101F
00401015  |. 40                   |INC EAX
00401016  |. 3B4424 08      |CMP EAX,DWORD PTR SS:[ESP+8]
0040101A  |.^7C EC          JL SHORT Crackme_.00401008
0040101C  |> 32C0           XOR AL,AL
0040101E  |. C3                RETN
0040101F  |> B0 01          MOV AL,1
00401021  . C3                 RETN
00401022  /$ 55                PUSH EBP
00401023  |. 8BEC            MOV EBP,ESP
00401025  |. 51                  PUSH ECX
00401026  |. 51                   PUSH ECX
You are in the target code now. Press F9 and target will run normally, you could now do whatever you want with it. Our next step would be to find where is OEP of packed file.
This part that could be the hardest thing for us, but not necessary. There are couple ways to find where OEP should be. This is one approach. Open memory window:

Memory map
Address    Size       Owner      Section    Contains           Type   Access    Initial   

Mapped as
00400000   00001000   Crackme_              PE header      Imag   RW        RWE
00401000   00004000   Crackme_              code,data      Imag   RW        RWE
00405000   0000E000                                                       Imag   RW        RWE
00420000   00006000                                                       Map    R E       R E
004E0000   00002000                                                        Map    R E       R E
004F0000   00103000                                                         Map    R         R
Place memory bp on access to code section and then try to click on crackme. You will probably stop here:

0040129C  /. 55                          PUSH EBP
0040129D  |. 8BEC                    MOV EBP,ESP
0040129F  |. 8B45 0C                MOV EAX,DWORD PTR SS:[EBP+C]
004012A2  |. 83E8 10                SUB EAX,10 
004012A5  |. 0F84 A0000000   JE Crackme_.0040134B
004012AB  |. 2D 00010000       SUB EAX,100
004012B0  |. 74 50                     JE SHORT Crackme_.00401302
004012B2  |. 48                         DEC EAX
004012B3  |. 0F85 9D000000    JNZ Crackme_.00401356
004012B9  |. 0FB745 10             MOVZX EAX,WORD PTR SS:[EBP+10]
If you are not there – it doesn’t matters. Important is that crackme is suspended so we can dump now. So dump it with OllyDump plugin, but uncheck “Rebuild import” option.
Entry point of this dump also isn’t important for now (don’t close olly after dumping). Now scan dumped file with PEiD. It will show “Microsoft Visual C++ 6.0”. This is important because programs compiled with same version of compilers have similar OEP. Using PEiD, find on your drive some exe that is compiled with this version Visual C++. I found flashget.exe, a download manager.
Its OEP looks like this:

004A2F61 >/$ 55                       PUSH EBP
004A2F62  |. 8BEC                    MOV EBP,ESP
004A2F64  |. 6A FF                   PUSH -1
004A2F66  |. 68 000D4F00       PUSH flashget.004F0D00
004A2F6B  |. 68 5C7F4A00     PUSH flashget.004A7F5C   ;  SE handler installation
004A2F70  |. 64:A1 00000000  MOV EAX,DWORD PTR FS:[0]
004A2F76  |. 50                         PUSH EAX
004A2F77  |. 64:8925 000000> MOV DWORD PTR FS:[0],ESP
004A2F7E  |. 83EC 58               SUB ESP,58
004A2F81  |. 53                         PUSH EBX
004A2F82  |. 56                         PUSH ESI
004A2F83  |. 57                          PUSH EDI             ;  ntdll.77F5164E
004A2F84  |. 8965 E8                 MOV DWORD PTR SS:[EBP-18],ESP
004A2F87  |. FF15 0C234E00  CALL DWORD PTR DS:[<&KERNEL32.GetVersion
004A2F8D  |. 33D2                   XOR EDX,EDX
004A2F8F  |. 8AD4                   MOV DL,AH
004A2F91  |. 8915 186A5100   MOV DWORD PTR DS:[516A18],EDX
004A2F97  |. 8BC8                    MOV ECX,EAX
004A2F99  |. 81E1 FF000000   AND ECX,0FF
OEP in our packed crackme will be very similar to this one so we need to find these combinations of opcodes in it. Of course, scrolling down and trying to recognize something like this is impossible with bigger file, but we can speed that.
Binary copy all bytes from flasget.exe (or some app that you found on your hard drive starting from 4A2F70 to 4A2F84.

Close that olly and go to first one, in which is our target.
Scroll to the 401000 address, left click on the first line, then right-click and chose “Search for” -> “Binary String” and paste content of clipboard to “Hex + xx” field. Then check “Entire block” and click “OK” button.

First address where olly found same bytes is here:

004014B4  /. 55                       PUSH EBP
004014B5  |. 8BEC                 MOV EBP,ESP
004014B7  |. 6A FF                 PUSH -1
004014B9  |. 68 C0504000      PUSH 4050C0
004014BE  |. 68 9C224000     PUSH 40229C                ;  SE handler installation
004014C3  |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
004014C9  |. 50                        PUSH EAX
004014CA  |. 64:8925 000000>MOV DWORD PTR FS:[0],ESP
004014D1  |. 83EC 58               SUB ESP,58
004014D4  |. 53                         PUSH EBX
004014D5  |. 56                        PUSH ESI              ;  Crackme_.0040129C
004014D6  |. 57                        PUSH EDI
004014D7  |. 8965 E8               MOV DWORD PTR SS:[EBP-18],ESP
004014DA  |. FF15 30504000  CALL DWORD PTR DS:[405030]
004014E0  |. 33D2                    XOR EDX,EDX
004014E2  |. 8AD4                   MOV DL,AH
004014E4  |. 8915 80854000   MOV DWORD PTR DS:[408580],EDX
Bold opcodes are our match. But there are more locations with same bytes so we need to be more sure.
Click on 4014DA line and press ENTER to follow that address in CPU window.
You will land here:

0014B684  -E9 0C1AD377      JMP kernel32.GetVersion
0014B689  -E9 D5E1D277      JMP kernel32.ExitProcess
0014B68E  -E9 D85EE077      JMP ntdll.RtlFreeHeap
0014B693  -E9 0960E077        JMP ntdll.RtlAllocateHeap
0014B698  -E9 1B60D177       JMP kernel32.TerminateProcess
0014B69D  -E9 6A2FD377      JMP kernel32.GetCurrentProcess
….
….
You can see that it points to redirected API and not any API, but to GetVersion. That API is usually the first one used in this version of VC++ so we are at the right place, our OEP is:

004014B4  /. 55                       PUSH EBP
004014B5  |. 8BEC                 MOV EBP,ESP
004014B7  |. 6A FF                 PUSH -1
…
…
If you cannot find OEP, or you find more possible OEP’s, then experiment a little and open different files on your drive to learn how OEP’s looks. You can close all olly’s now.
You could now fix IAT with ImpREC and repair dump with this OEP, but with bigger files that dump will crush. I don’t know the actual reason, but we shouldn’t allow target to run and then dump it.
We need to STOP target at the OEP and THEN dump it and fix imports.
How we gonna stop file in memory without having target in debugger?
I get one idea there, we could make a loader that will find OEP and replace it with EBFE bytes. That is infinite loop jump, a jump that jumps to itself. It means that such file in memory will be fully unpacked , but it will not be executed. Then we can attach to target and make good working dump.

For making loader we will use dUP2 - diablo2oo2's Universal Patcher, a excellent pathing engine made by diablo2oo2 (well, you could use any loader engine that you like, I just lately often use this one which is very good). To learn how to use patcher read help files inside dUP2 packet. If you are lazy, mine loader “YodaOEP.exe” is included in this archive.

You need to substitute these bytes (address --> byte):

4014B4 --> 55
4014B5 --> 8B
with this ones:
4014B4 --> EB
4014B5 --> FE
Make that loader and run it in the same folder with target “keygenme1.exe”. Uuuuups, CPU usage goes to 100%, remember that’s because infinite jump. Good sign, our loader has done it’s job.

Now open Olly and attach to the target, double click to keygen1.exe process in the executables window, press Ctrl+A and in the memory window place memory bp on access to code section.
Press F9 and you are at the program OEP:

004014B4   >-EB FE                JMP SHORT Crackme1.004014B4
004014B6     EC                       DB EC
004014B7   . 6A FF                  PUSH -1
004014B9   . 68 C0504000       PUSH 4050C0
004014BE   . 68 9C224000       PUSH 40229C                              ;  SE handler 

installation
004014C3   . 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
004014C9   . 50                         PUSH EAX
004014CA   . 64:8925 000000>MOV DWORD PTR FS:[0],ESP
004014D1   . 83EC 58               SUB ESP,58
004014D4   . 53                         PUSH EBX
004014D5   . 56                         PUSH ESI
004014D6   . 57                         PUSH EDI
004014D7   . 8965 E8                MOV DWORD PTR SS:[EBP-18],ESP
004014DA   . FF15 30504000  CALL DWORD PTR DS:[405030]
004014E0   . 33D2                    XOR EDX,EDX
004014E2   . 8AD4                    MOV DL,AH
004014E4   . 8915 80854000    MOV DWORD PTR DS:[408580],EDX
Do you see first line? Our infinite jump is there. Before dumping we need to restore original bytes instead infinite jump EBEF. Replace it with 558B with binary editing:

004014B4     55                         PUSH EBP
004014B5     8BEC                   MOV EBP,ESP
004014B7   . 6A FF                  PUSH -1
004014B9   . 68 C0504000      PUSH 4050C0
004014BE   . 68 9C224000      PUSH 40229C                              ;  SE handler 

installation
004014C3   . 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
004014C9   . 50                        PUSH EAX
004014CA   . 64:8925 000000>MOV DWORD PTR FS:[0],ESP
004014D1   . 83EC 58              SUB ESP,58
004014D4   . 53                        PUSH EBX
004014D5   . 56                        PUSH ESI
004014D6   . 57                        PUSH EDI
004014D7   . 8965 E8                MOV DWORD PTR SS:[EBP-18],ESP
004014DA   . FF15 30504000  CALL DWORD PTR DS:[405030]
004014E0   . 33D2                     XOR EDX,EDX
004014E2   . 8AD4                    MOV DL,AH
That’s it! Now dump file with ollydump (uncheck import fixing) and run ImpREC. There attach to keygenme1.exe, input 14B4 as OEP and search for imports. I get two thunks and both are not valid. Newermind, trace with level 1 and you’ll find all imports.
If maybe couple bad thunk has left, just cut it.
Now fix dump and run it.
It works great! Yep, you have defeated yoda’s protector 1.03.2 :)

3. Final words

This approach to unpacking yoda protected targets seams to be very easy and yet, it works. For example, I packed Mozilla Firefox (~MB) and unpacked it in few minutes. Also, you could use this approach for any protector you like except those ones who debugs itself like armadillo, new PESpin, beria, etc.

The main problem would be to find OEP. In VC++, Borland C++ It’s not hard, VB is the easiest for that. Harder would be with Delphi programs, or ASM. But with some experience and practice it can be done.

Big greets goes to all folks on biw; detten, stingduk, thorpe, TDC ... just to name few.

6 comments



http://www.reversing.be/article.php?story=20050823224144160