Help - Search - Members - Calendar
Full Version: Reverse Engineering #2
Darkside_RG > Technical Discussions > Guides/How To > Coding Guides
Mazuki
Ok i'm back with another crackmes.de solution, i finally got around to doing some reversing again since i've been rather busy lately, but i had fun with this one, this is a .net crackme, so you are going to need these tools:

IDA
Hex Editor
Reflector (free .net disassembler, it's not required, but to follow a long it makes it far easier)

download the crackme from here: http://www.crackmes.de/users/raham2755/sep..._not_protected/

First open it in reflector and check .ctor() to see what functions are first loaded, initializecomponent is this function, go there

now aside from the fact that button 5 is never given an event handler, i will get to that later, but the author should have fixed this before posting.

double click .ctor() and go near the bottom and you will see base.Load += new EventHandler(this.Form1_Load);

this means that function Form1_Load is going to execute when the program does, so go there now

here you will see mostly things that do not concern us because we are not keygenning

find this:

bool flag = false;
flag = Scanner.ScanFile(Environment.CommandLine.Substring(1, Environment.CommandLine.Length - 3));
Crypt crypt = new Crypt();
crypt.STR1 = "True";
crypt.STR2 = flag.ToString();
long diff = crypt.GetDiff();
try
{
long num3 = 0x43L / diff;
}
catch
{
this.regPanel.Visible = true;
this.panel1.Visible = false;
}
}

this line of code is important

flag = Scanner.ScanFile(Environment.CommandLine.Substring(1, Environment.CommandLine.Length - 3));

this calls the PEScan.dll file to get a sha-512 hash of the file and compare it to a locally stored string that the designer put in, now we could go in and hash shit and see if it works, but that's a waste of time, go below that

now we see crypt.STR1 and STR2 are set to compare them using GetDiff()

STR1 it set to "TRUE" and STR2 is set to the string equivalent of the boolean flag, so we want true as well, remember that for when we modify the file, we need it to load the regpanel and not panel1 with the badboy message.

back in initialize component you see that button 5 is set as this.button5.Text = "Register";

so the function button5_Click is what we want to check out, go there now in reflector

again, skip the top stuff, it doesn't matter, check near the bottom

crypt.STR1 = txtToCode;
crypt.STR2 = str4;
long diff = crypt.GetDiff();
int num2 = 0;
try
{
num2 = Convert.ToInt32(Math.Log(Convert.ToDouble(diff)));
}
catch
{
num2 = 1;
}
bool flag = Convert.ToBoolean(diff);
bool flag2 = false;
try
{
long num3 = 60L / diff;
}
catch (DivideByZeroException)
{
flag2 = true;
}
this.tmrDisable.Enabled = flag;
this.tmrRegister.Enabled = flag2;
}


there are 2 ways to crack this, we can change the STR1 and STR2 to equal the same strings like in the Form1_Load function, or we can do it the way i did (the easy way)

down below you see:
this.tmrDisable.Enabled = flag;
this.tmrRegister.Enabled = flag2;

well if you check the tmrDisable object's event handler, you will see this gives us the badboy message on startup saying "No.its diffrent to last time :-P"

and the tmrRegister event handler says "The Game is overed again. :((" (this is the good boy message as it's in green, even though there is a frown)

flag2 is set to false meaning that it is not registered, and it will only register if the 'diff' variable (return from crypt.getDiff() above) is a 0 (meaning they are the same strings)

very simple, change flag2 to true and flag to false like this

bool flag2 = true;
try
{
flag = false;
}
catch (DivideByZeroException)
{
flag2 = true;
}
this.tmrDisable.Enabled = flag;
this.tmrRegister.Enabled = flag2;
}

now as far as i know, you can't actually change anything using reflector, so you have to load it into IDA and check the functions window (default top right) for the same function names, then look for the right locations that compare to the source code above.

for the button5_click function it can be difficult as there aren't many strings indicating anything, but have a look for strings you can find like "myReg" and "hey" first right click in the background of IDA View-A and select Text View

scroll down a little bit and you should see those strings along with "NoneBuddy" (you see that in reflector too) now IDA is nice in that it will show the try{} and catch{} statements for us, so look for the try with a catch that has the DivideByZeroException with it

you should see it just below this:

stloc.s 8
ldc.i4.0
stloc.s 9

now we want the 0 (which means false) to be a true, so we need it to be a 1, now unless you have knowledge of .NET assembly instructions and their bytes that match, how do we know that to change the 0x16 to at offset 0xBA0 ?

well we know that ldc.i4 0 = false right? so look for something that is true, should be ldc.i4 1 :) once you find that you will know that 16 makes it a 0 and 17 makes it a 1

now that flag2 is changed (which gives us the good boy message) we need to fix the other flag variable to be false or our change to true won't matter.

below the try we have basically a confusing IF statement in a try/catch, try to divide a number by the 'diff' variable and if 'diff' is a zero it will throw the exception and set the flag2 as true, well we already did that, so lets change all the code in the try{} statement to modify the flag variable to be false

now in .net, unlike almost all other languages, a 0x00 byte = NOP (no operation point) so we want to NOP out everything inside the try{} statement EXCEPT the leave.s LOC xxx this is because the leave.s LOC points to the location it should jump to, if the previous instruction does not throw the divide by zero exception

it should be offsets 0xBA4 to 0xBAC, now we just need to insert the 0 for the flag variable, but how do we know what instruction to put for modifying the different variable? well that's easy

above, we changed the value for flag2 to be 1 instead of zero, well just above that is the modification of the flag variable, and you will see that it uses stloc.s 8 instead of flag2 that uses stloc.s 9

so now we know what opcodes we need :)

use these: ldc.i4.0 stloc.s 8 and in hex these are as follows 0x16 0x13 0x08

change the following offsets/bytes in a hex editor

-offset- | -bytes-
0xBA0 16->17
0xBA4 1F->00
0xBA5 3C->16
0xBA6 6A->13
0xBA7 11->08

0xBA8-0xBAC make all 0x00

now we have to go back to the form1_load function and fix the two strings to always be true, otherwise on the load, it will use the PEScan.dll file to check if any modifications have been made, and give us an even worse badboy message.

in IDA go to form1_load and use the same method we used before to try and find the right location, we know that STR1 = "True"; is there, so look for that string and we will be right by our location

now it gets tricky, you should see this in IDA View-A when you find the "True" string:

stloc.s 9
ldloc.s 9
ldstr "True"
stfld class System.String Sepanta_Security_Lock.Crypt::STR1
ldloc.s 9
ldloca.s 8
call class System.String [mscorlib]System.Boolean::ToString()
stfld class System.String Sepanta_Security_Lock.Crypt::STR2
ldloc.s 9

here can be difficult to figure out, i had a few crashed .exe files and improper functions before i got it right, the problem is that the auther typecasts a boolean to a string and then sets that as STR2

a good way to look at this is calling a function inside a function, in the source code you see this:

crypt.STR2 = flag.ToString();

but a computer can't assign a variable like that directly, because it's in a different class, so it calls the system.string function with the parameter we say (pushed on the cpu stack)

so first it has to push the location of the string we want to end on (STR2) to the stack, then it has to push the location of the variable we are acting on to convert to a string (flag) onto the stack using ldloca.s 8

if we compare it to the function above for STR1, the only pieces we should need are the stfld instruction and the ldloc.s 9 instruction, these are the only 2 that are common between them, so they are the only 2 we should have to use (if not, we always have backups right? wink.gif )

so NOP out the ldloc.s 9 and change the ldloca.s 8 to ldloc.s 9, then we have to change the call to ToString() to use the "True" string

check the hex bytes of the above ldstr "True" by clicking on it, and selecting Hex View-A and it will highlight the bytes you need, there should be 5 in total

now do the same for the call to ToString() and it should use the same amount of bytes (lucky us)

change the call from what it is, to the EXACT same bytes as above, and it should load STR2 with "True" so this way the call to GetDiff() will return a 0 and will think that the file has not been modified on startup

offset changes:

go to 0x76E

change from:
0000076eh: 11 09 12 08 28 2F 00 00 0A
to:
0000076eh: 00 00 11 09 72 DD 00 00 70

now because the author didn't put an event handler on the button5 (register) you have to fix that as well, just change the bytes below and it will work ok, if there is a demand for it, i will explain how i figured this little tidbit out as well :)

at offset 0x111C

from:
0000111ch: 7B 0D 00 00 04 02 FE 06 13
to:
0000111ch: 7B 11 00 00 04 02 FE 06 10

enjoy

-mazuki
Ferretboy
Now, this is something I've been looking forward to! As soon as I get a chance to work through it I'll post back... Thanks! drinks.gif
Flatline
Excellent guide. Thanks mazuki a013.gif
wolf_40
this is great i think i will try it
Pierre23q
uhh seems like a nice tut. But when i click on the link to download that crackme it comes up with a user and password? i dont get it. anyone care to explain this to a foolish kid?
M15T3R-3
This is great. Thank you for sharing your knowledge yet again Maz!!!!!! drinks.gif
Pierre23q
mister-3 how did you download the file ? where did you get a user name as pass for crackmes.de how am i meant to register ? if i cant even access the site?
Mazuki
crackmes was taken offline everyone sorry, i'll see if i can't post a mirror for the files
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2012 Invision Power Services, Inc.