rendari

(Part 2 of .NET native exe insights)Serial fishing and patching .NET exes with Ollydb

Rating: 5 votes, 3.00 average.
(Part 2 of .NET native exe insights)Serial fishing and patching .NET exes with Ollydbg.


Last blog post I pointed out how native exes, when used improperly, do nothing to deter reverse engineer of
completely decompiling your product, and doing with it as they please (cracking). Now, I would like to assume
that the developer bothered reading my blog post, and actually bothered wiping the IL from his native exe. While
I do admit that this is a "final" solution to decompilation, as I mentioned before it is faaaar from a "final"
solution to crackers. Hackers have been going at native code for years, so with a bit of brainpower and Olly, a
native .NET exe should pose no challenge to them.

In this post I will observe a simple keygenme, and I will show you how I was able to
a) patch it
b) fish a serial for it...

in less that 5 minutes with Olly.

Here is the link to the keygenme we will be dealing with(same as in last blog post):

http://www.filesend.net/download.php?f=644ee1dfd1b9246aee11d64b931bd0fb

Download it, extract it anywhere, and Ngen it

>ngen unpackme.exe.

Then, take unpackme.exe, and load it into Olly. Check all exceptions, and run the Unpackme. It will pop up with
a little dialogue asking for a name and serial. Click the "Check" button, and observe the error message:

"Invalid serial. Pls don't hack me :'("

Hardy harr.

Well, now lets think for a second. This is a string that is needed for the unpackme to run. Therefore, it can
probably be found the native image of the unpackme. We also know that all strings in a .NET exe are stored in
the metadata. As I pointed out in the last tutorial, the metadata of a .NET exe is in the .IL section of the
native exe. So, we know that somewhere in the .IL section of our native exe, we will find a string saying:
"Invalid serial. Pls don't hack me :'("

Furthermore, if you paid close attention to the .NET file format, you know that all strings in .NET are stored as
unicode. So, somewhere in the .IL section of our native .NET exe there will be a UNICODE string that says:
"Invalid serial. Pls don't hack me :'(".

Now, suppose that we locate this string. What do we do with it? Quite simple: We put a hardware breakpoint upon
it. Once it is accessed, we know that the routine it was accessed from is part of the serial checking routine.

Alright, now in Olly, with the unpackme running in the background, press ALT+M to open a list of all modules.
Scroll down a bit until you find the native image of unpackme.exe (Unpackme.ni.exe). You should see this:

Code:
30000000    00001000 (  Unpack_1 3             PE header     Imag   R         RWE
30002000    00004000 (  Unpack_1 3  .text      code          Imag   R E       RWE
30006000    00001000 (  Unpack_1 3  .extrel    code          Imag   R E       RWE
30008000    00005000 (  Unpack_1 3  .data      code,data     Imag   RW        RWE
3000E000    00001000 (  Unpack_1 3  .xdata                   Imag   RWE       RWE
30010000    00001000 (  Unpack_1 3  .dbgmap                  Imag   R         RWE
30012000    00004000 (  Unpack_1 3  .il                      Imag   R         RWE
30016000    00001000 (  Unpack_1 3  .rsrc      resources     Imag   R         RWE
30018000    00001000 (  Unpack_1 3  .reloc     relocations   Imag   R         RWE
Now, we are interested in the .IL section of this native exe, because that is where the string we are trying to
breakpoint is. In the dump window of Ollydbg, press CTRL+G, type 30012000, and press enter. This will move the
Ollydbg hex dump window to the beginning of the .IL section. Then, still in the dump window, press
CTRL+B (binary search), and under unicode type in:
"Invalid serial.". Then press enter to let Olly search. It should end up here:

Code:
300142FD   49 00 6E 00 76 00 61 00  I.n.v.a.
30014305   6C 00 69 00 64 00 20 00  l.i.d. .
3001430D   53 00 65 00 72 00 69 00  S.e.r.i.
30014315   61 00 6C 00 2E 00 20 00  a.l... .
3001431D   50 00 6C 00 73 00 20 00  P.l.s. .
30014325   64 00 6F 00 6E 00 27 00  d.o.n.'.
3001432D   74 00 20 00 68 00 61 00  t. .h.a.
30014335   63 00 6B 00 20 00 6D 00  c.k. .m.
3001433D   65 00 20 00 3A 00 27 00  e. .:.'.
30014345   28 00 01 81 7B 54 00 68  (.{T.h
3001434D   00 65 00 20 00 70 00 6F  .e. .p.o
30014355   00 69 00 6E 00 74 00 20  .i.n.t.
3001435D   00 6F 00 66 00 20 00 74  .o.f. .t
30014365   00 68 00 69 00 73 00 20  .h.i.s.
3001436D   00 55 00 6E 00 70 00 61  .U.n.p.a
30014375   00 63 00 6B 00 6D 00 65  .c.k.m.e
3001437D   00 20 00 69 00 73 00 20  . .i.s.
30014385   00 66 00 6F 00 72 00 20  .f.o.r.
Cool! This is the badboy string we are interested in. Write down the address, restart the target in Olly, and
press F9 to run Olly once again. Do not click on the check button yet. First, go to the address we wrote down
(300142FD) select the first 4 bytes,
Right click -> breakpoint -> hardware, on access -> byte

Now, go back to the unpackme, and click on the "Check" button. Olly should break with a hardware DWORD on access
at a place that looks like this:

Code:
7814507A    F3:A5              REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
7814507C    FF2495 94511478    JMP DWORD PTR DS:[EDX*4+78145194]
78145083    90                 NOP
Alright now, go to
Debug -> hardware breakpoints

in Olly, and delete your hardware breakpoint that you set upon this string.

Now, its time to trace a bit with F8 until we get to the .text section of Unpackme.exe. Just hold F8 until
you end up here:

Code:
300041D0    57                 PUSH EDI
300041D1    56                 PUSH ESI
300041D2    53                 PUSH EBX
300041D3    55                 PUSH EBP
300041D4    83EC 10            SUB ESP,10
300041D7    891424             MOV DWORD PTR SS:[ESP],EDX
300041DA    8BF1               MOV ESI,ECX
300041DC    8B05 0CE00030      MOV EAX,DWORD PTR DS:[3000E00C]                 ; Unpack_1.300081B4
300041E2    8338 00            CMP DWORD PTR DS:[EAX],0
300041E5    74 05              JE SHORT Unpack_1.300041EC
300041E7    E8 12E1084A        CALL mscorwks.7A0922FE
After you've debugged .NET exe's a bit in Olly you will recognize this as the beginning of a method, just like
PUSH EBP
MOV EBP, ESP

usually marks the beginning of a routine in VC++...

Anyways, since this routine has accessed the "Invalid serial" string, we can assume that this routine is the
serial check routine. Start tracing at it with F8. A messagebox telling you you entered the wrong serial will
pop up after you trace over this call:

Code:
300042A6    8B05 18BF0030      MOV EAX,DWORD PTR DS:[3000BF18]
300042AC    8B08               MOV ECX,DWORD PTR DS:[EAX]
300042AE    FF15 C0BF0030      CALL DWORD PTR DS:[3000BFC0]                    ; System_W.7B26EC88
300042B4    90                 NOP
Interesting... look around in Olly and try to get a feel for what is happening. Even a noob should be able to
understand what is happening here:

Code:
30004270    8BF8               MOV EDI,EAX
30004272    6A 00              PUSH 0
30004274    8BD3               MOV EDX,EBX
30004276    8BCF               MOV ECX,EDI
30004278    FF15 BCBF0030      CALL DWORD PTR DS:[3000BFBC]                    ; Compare strings (Microsoft.VisualBasic.dll)
3000427E    8BF8               MOV EDI,EAX
30004280    85FF               TEST EDI,EDI
30004282    0F94C0             SETE AL
30004285    0FB6C0             MOVZX EAX,AL
30004288    894424 04          MOV DWORD PTR SS:[ESP+4],EAX
3000428C    837C24 04 00       CMP DWORD PTR SS:[ESP+4],0			; were they the same?
30004291    74 12              JE SHORT Unpack_1.300042A5			; if not, JMP
30004293    8B05 14BF0030      MOV EAX,DWORD PTR DS:[3000BF14]
30004299    8B08               MOV ECX,DWORD PTR DS:[EAX]
3000429B    FF15 C0BF0030      CALL DWORD PTR DS:[3000BFC0]                    ; good boy message. 
300042A1    90                 NOP
300042A2    90                 NOP
300042A3    EB 10              JMP SHORT Unpack_1.300042B5
300042A5    90                 NOP
300042A6    8B05 18BF0030      MOV EAX,DWORD PTR DS:[3000BF18]
300042AC    8B08               MOV ECX,DWORD PTR DS:[EAX]
300042AE    FF15 C0BF0030      CALL DWORD PTR DS:[3000BFC0]                    ; bad boy message.
300042B4    90                 NOP
300042B5    90                 NOP
300042B6    90                 NOP
300042B7    90                 NOP
300042B8    83C4 10            ADD ESP,10
300042BB    5D                 POP EBP
300042BC    5B                 POP EBX
300042BD    5E                 POP ESI
300042BE    5F                 POP EDI
300042BF    C2 0400            RETN 4
Simple, eh? Just for kicks, nop the JE at 30004291 and press F9 to run the unpackme. Click on the "Check" button and watch
as this string pops up:

"Good work! Now go and post a solution or suggestions so I can improve the protector =)"

And that's it. You more or less cracked this simple unpackme. If you want the solution to become permanent, just use a hex
editor to change Unpackme.ni.exe accordingly. I'm sure you can figure out how to do that on your own

What it more interesting is actually fishing a valid serial with Olly. Look at this code right here:

Code:
30004270    8BF8               MOV EDI,EAX
30004272    6A 00              PUSH 0
30004274    8BD3               MOV EDX,EBX
30004276    8BCF               MOV ECX,EDI
30004278    FF15 BCBF0030      CALL DWORD PTR DS:[3000BFBC]                    ; Microsof.5E464AD0
It should be pretty obvious to an experienced reverser that a string compare is happening at 30004278. The only irregular
thing is that the parameters are put in EDX and ECX, and people familiar with .NET will attest that this is actually regular.
The compiler simply prefers using registers to pass parameters instead of the stack. Not very neat, but w/e, .NET wasn't
designed to be pretty (obviously).

Let's put a breakpoint upon 30004278 and examine the contents ot the EDX and ECX registers. Select 30004278, press F2 to
place a breakpoint in Olly, and press F9 to run the target. Click on the "Check" button in the unpackme, and watch Olly
break at 30004278. The contents of the EDX and ECX registers should be:

01323ED8
01323E74

(note: it's probably different on each machine. Don't worry about that).

Alright, these 2 values are both pointers. Lets see what they point to:

ECX:
Code:
01323ED8   E0 A3 0F 79 13 00 00 00  y...
01323EE0   11 00 00 00 45 00 6E 00  ...E.n.
01323EE8   74 00 65 00 72 00 20 00  t.e.r. .
01323EF0   53 00 65 00 72 00 69 00  S.e.r.i.
01323EF8   61 00 6C 00 20 00 48 00  a.l. .H.
01323F00   65 00 72 00 65 00 00 00  e.r.e...
EDX:
Code:
01323E74   E0 A3 0F 79 19 00 00 00  y...
01323E7C   18 00 00 00 68 00 79 00  ...h.y.
01323E84   37 00 31 00 71 00 38 00  7.1.q.8.
01323E8C   5A 00 6D 00 74 00 49 00  Z.m.t.I.
01323E94   4E 00 7A 00 7A 00 43 00  N.z.z.C.
01323E9C   35 00 45 00 45 00 4F 00  5.E.E.O.
01323EA4   75 00 55 00 59 00 77 00  u.U.Y.w.
01323EAC   3D 00 3D 00 00 00 00 00  =.=.....
So, ECX is the contents of the textbox where we entered the serial. Since I didn't touch that text box, the text it is
reading is: "Enter Serial Here".

In EDX is a jumbled unicode string. It doesn't take a genius to figure out that this is probably the correct serial, and it
is being compared against the invalid serial. The jumbled unicode string is:

hy71q8ZmtINzzC5EEOuUYw==

Cool. So that is theoretically the valid serial. Let's put theory to the test. Restart the unpackme to undo all changes we
have made to it so far, and then press F9 to run it again. In the dialog where is prompts us for name and serial, leave the
name as is, while for the serial type in: hy71q8ZmtINzzC5EEOuUYw==. Press "Check" to let the crackme check if the serial is
correct.

It is. You will get the goodboy message.

Now, incase you were wondering, the art of debugging .NET exes in Olly isn't just useful for native .NET exes. It also has
practical applications.

Take for example the .NET unpackme I posted on crackmes awhile ago. Noone expect bigmouse was able to unpack it, so I assume
a lot of people here don't have experience with JIT hooks, and are simply stumped when they see them in an unpackme.

So, screw the JIT hooks, lets fish a valid serial for the unpackme in Olly ^^.

Download the unpackme here:

http://www.filesend.net/download.php?f=67ccb0a87cc8f2f2f8d3776f9612f129

The procedure for cracking this is very similar to last time. First we find a string that we want to break
upon, and then from there we trace to the serial check routine. From there on... well figure out what its
doing and patch/fish accordingly

Start off by opening the file in Olly. If we analyze the file in ILDasm, we will see that it is invoking the
assembly through Assembly.Load. Therefore, some buffer in memory must contain the semi-decrypted exe. Just look
for that buffer in the Modules window. For me, it was 00C70000

Code:
00C70000  4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00  MZ.........
I know that this is the memory area I was looking for because of the MZ header... Now, in this memory area, the
string we are looking to break upon (Invalid serial. Pls don't hack me :'( ) Can be located. So, just do a
binary search for the Unicode "Invalid serial." You will end up here:

Code:
00C7426D  49 00 6E 00 76 00 61 00 6C 00 69 00 64 00 20 00  I.n.v.a.l.i.d. .
00C7427D  53 00 65 00 72 00 69 00 61 00 6C 00 2E 00 20 00  S.e.r.i.a.l... .
00C7428D  50 00 6C 00 73 00 20 00 64 00 6F 00 6E 00 27 00  P.l.s. .d.o.n.'.
00C7429D  74 00 20 00 68 00 61 00 63 00 6B 00 20 00 6D 00  t. .h.a.c.k. .m.
00C742AD  65 00 20 00 3A 00 27 00 28 00 01 81 7B 54 00 68  e. .:.'.(.{T.h
00C742BD  00 65 00 20 00 70 00 6F 00 69 00 6E 00 74 00 20  .e. .p.o.i.n.t.
00C742CD  00 6F 00 66 00 20 00 74 00 68 00 69 00 73 00 20  .o.f. .t.h.i.s.
00C742DD  00 55 00 6E 00 70 00 61 00 63 00 6B 00 6D 00 65  .U.n.p.a.c.k.m.e
00C742ED  00 20 00 69 00 73 00 20 00 66 00 6F 00 72 00 20  . .i.s. .f.o.r.
00C742FD  00 79 00 6F 00 75 00 20 00 74 00 6F 00 20 00 67  .y.o.u. .t.o. .g
00C7430D  00 65 00 74 00 20 00 61 00 20 00 67 00 72 00 61  .e.t. .a. .g.r.a
00C7431D  00 73 00 70 00 20 00 6F 00 66 00 20 00 62 00 61  .s.p. .o.f. .b.a
00C7432D  00 73 00 69 00 63 00 20 00 4A 00 49 00 54 00 20  .s.i.c. .J.I.T.
00C7433D  00 68 00 6F 00 6F 00 6B 00 69 00 6E 00 67 00 2E  .h.o.o.k.i.n.g..
...set a HW BP on access on the first 4 bytes of the string, just like I explained earlier in the post. Then
proceed to run the file, click on the "Check" button, and you should break here:

Code:
79E7EFCB    6BC0 21            |IMUL EAX,EAX,21
79E7EFCE    33C6               |XOR EAX,ESI
79E7EFD0    41                 |INC ECX
79E7EFD1    3BCA               |CMP ECX,EDX
79E7EFD3  ^ 72 F3              \JB SHORT mscorwks.79E7EFC8
79E7EFD5    5E                 POP ESI
79E7EFD6    C2 0800            RETN 8
Remove your hardware breakpoint, and proceed to trace with F8 until you come up to some code that looks like this:
(or you could just set a breakpoint at this place, as it is very important in .NET reversing. It is the exit point
of the .NET jitter. When .NET exits from the JIT dll and goes into the native code, it will always pass through
this point).

Code:
79E7BBA3   .  FF15 9411E779    CALL DWORD PTR DS:[<&KERNEL32.SetLastError>]    ; \SetLastError
79E7BBA9   .  8B45 D8          MOV EAX,DWORD PTR SS:[EBP-28]
79E7BBAC   .  E8 365CFFFF      CALL mscorwks.79E717E7
79E7BBB1   .  C2 0400          RETN 4
This is the JIT just checking if there were any errors during the jitting. Then it returns to a little memory
area where it restores all registers modified by the jitter:

Code:
00341F3E    897B 0C            MOV DWORD PTR DS:[EBX+C],EDI
00341F41    8B4E 08            MOV ECX,DWORD PTR DS:[ESI+8]
00341F44    8946 08            MOV DWORD PTR DS:[ESI+8],EAX
00341F47    8BC1               MOV EAX,ECX
00341F49    83C4 04            ADD ESP,4
00341F4C    5A                 POP EDX
00341F4D    59                 POP ECX
00341F4E    89EC               MOV ESP,EBP
00341F50    5D                 POP EBP
00341F51    83C4 04            ADD ESP,4
00341F54    5F                 POP EDI
00341F55    5E                 POP ESI
00341F56    5B                 POP EBX
00341F57    5D                 POP EBP
00341F58    83C4 08            ADD ESP,8
00341F5B    C3                 RETN
The above memory areas will always be returned to out of the jitter. Its just a little consistency that I noticed
that helps my eyes adjust as I trace with F8 through native .NET code. Anyways, once you trace over the ret at 00341F5B, you
will trace about 5 more lines and then be in the middle of the native code of the serial check routine:


Code:
00C81F28    57                 PUSH EDI
00C81F29    56                 PUSH ESI
00C81F2A    53                 PUSH EBX
00C81F2B    55                 PUSH EBP
00C81F2C    83EC 10            SUB ESP,10
00C81F2F    891424             MOV DWORD PTR SS:[ESP],EDX
00C81F32    8BF1               MOV ESI,ECX
00C81F34    833D 90339300 00   CMP DWORD PTR DS:[933390],0
00C81F3B    74 05              JE SHORT 00C81F42
00C81F3D    E8 BC034179        CALL mscorwks.7A0922FE
00C81F42    33D2               XOR EDX,EDX
00C81F44    895424 08          MOV DWORD PTR SS:[ESP+8],EDX
00C81F48    33ED               XOR EBP,EBP
00C81F4A    33DB               XOR EBX,EBX
00C81F4C    33D2               XOR EDX,EDX
00C81F4E    895424 0C          MOV DWORD PTR SS:[ESP+C],EDX
00C81F52    C74424 04 00000000 MOV DWORD PTR SS:[ESP+4],0
00C81F5A    90                 NOP
00C81F5B    8BCE               MOV ECX,ESI
00C81F5D    8B01               MOV EAX,DWORD PTR DS:[ECX]
00C81F5F    FF90 F8050000      CALL DWORD PTR DS:[EAX+5F8]
00C81F65    8BF8               MOV EDI,EAX
00C81F67    8BCF               MOV ECX,EDI
00C81F69    8B01               MOV EAX,DWORD PTR DS:[ECX]
00C81F6B    FF90 64010000      CALL DWORD PTR DS:[EAX+164]
00C81F71    8BF8               MOV EDI,EAX
00C81F73    8BEF               MOV EBP,EDI
00C81F75    8BCE               MOV ECX,ESI
00C81F77    8B01               MOV EAX,DWORD PTR DS:[ECX]
00C81F79    FF90 00060000      CALL DWORD PTR DS:[EAX+600]
00C81F7F    8BF8               MOV EDI,EAX
00C81F81    8BCF               MOV ECX,EDI
00C81F83    8B01               MOV EAX,DWORD PTR DS:[ECX]
00C81F85    FF90 64010000      CALL DWORD PTR DS:[EAX+164]
00C81F8B    8BF8               MOV EDI,EAX
00C81F8D    897C24 0C          MOV DWORD PTR SS:[ESP+C],EDI
00C81F91    8B05 78302902      MOV EAX,DWORD PTR DS:[2293078]
00C81F97    894424 08          MOV DWORD PTR SS:[ESP+8],EAX
00C81F9B    FF7424 08          PUSH DWORD PTR SS:[ESP+8]
00C81F9F    8BD5               MOV EDX,EBP
00C81FA1    8BCE               MOV ECX,ESI
00C81FA3    3909               CMP DWORD PTR DS:[ECX],ECX
00C81FA5    E8 4A67CBFF        CALL 009386F4
00C81FAA    8BF8               MOV EDI,EAX
00C81FAC    8BDF               MOV EBX,EDI
00C81FAE    8BCE               MOV ECX,ESI
00C81FB0    8B01               MOV EAX,DWORD PTR DS:[ECX]
00C81FB2    FF90 00060000      CALL DWORD PTR DS:[EAX+600]
00C81FB8    8BF8               MOV EDI,EAX
00C81FBA    8BCF               MOV ECX,EDI
00C81FBC    8B01               MOV EAX,DWORD PTR DS:[ECX]
00C81FBE    FF90 64010000      CALL DWORD PTR DS:[EAX+164]
00C81FC4    8BF8               MOV EDI,EAX
00C81FC6    6A 00              PUSH 0
00C81FC8    8BD3               MOV EDX,EBX
00C81FCA    8BCF               MOV ECX,EDI
00C81FCC    E8 FF2A7E5D        CALL Microsof.5E464AD0
00C81FD1    8BF8               MOV EDI,EAX
00C81FD3    85FF               TEST EDI,EDI
00C81FD5    0F94C0             SETE AL
00C81FD8    0FB6C0             MOVZX EAX,AL
00C81FDB    894424 04          MOV DWORD PTR SS:[ESP+4],EAX
00C81FDF    837C24 04 00       CMP DWORD PTR SS:[ESP+4],0
00C81FE4    74 0F              JE SHORT 00C81FF5
00C81FE6    8B0D 7C302902      MOV ECX,DWORD PTR DS:[229307C]
00C81FEC    E8 97CC5E7A        CALL System_W.7B26EC88
00C81FF1    90                 NOP
00C81FF2    90                 NOP
00C81FF3    EB 0D              JMP SHORT 00C82002
00C81FF5    90                 NOP
00C81FF6    8B0D 80302902      MOV ECX,DWORD PTR DS:[2293080]
00C81FFC    E8 87CC5E7A        CALL System_W.7B26EC88
00C82001    90                 NOP
00C82002    90                 NOP
00C82003    90                 NOP
00C82004    90                 NOP
00C82005    83C4 10            ADD ESP,10
00C82008    5D                 POP EBP
00C82009    5B                 POP EBX
00C8200A    5E                 POP ESI
00C8200B    5F                 POP EDI
00C8200C    C2 0400            RETN 4
Look familiar? Yep, its the exactly same stuff as I described previously in the post. Thus, if you were
reading closely, you should understand how to be able to fish the serial and patch it to work however you
might like.

Now, I was planning to show you how to write a loader to patch my .NET stuff right here, but that will have
to wait on another post, where I show you how to write loaders to patch the native code and thus completely
bypass relying on the IL Right now, once again, I am too tired to continue =(.

In conclusion:

I showed you the basics of native .NET code, and I showed you how to break into it so that you may debug it in Olly.
Thus, if the IL code of an exe is too well protected or simply not availible, you can fall back to reversing
this stuff.

I would also like to note that I have not yet found a way to resolve the native function names/exports of
VisualBasic.ni.dll. If I do find out a way, it will make reversing much similar because then we will be able
to break upon functions with interesting names such as strcmp. Its something I need to look into.

but for now, sleeeeeeeep

peace

-Rendari

Submit "(Part 2 of .NET native exe insights)Serial fishing and patching .NET exes with Ollydb" to Digg Submit "(Part 2 of .NET native exe insights)Serial fishing and patching .NET exes with Ollydb" to del.icio.us Submit "(Part 2 of .NET native exe insights)Serial fishing and patching .NET exes with Ollydb" to StumbleUpon Submit "(Part 2 of .NET native exe insights)Serial fishing and patching .NET exes with Ollydb" to Google

Updated March 24th, 2008 at 02:00 by rendari

Categories
Uncategorized

Comments