Jump to content
Tuts 4 You

[CrackMe/KeygenMe] Naked naughty .net doggy


Recommended Posts

Posted (edited)

Here we go, friends of .NET & other sh!t ! :biggrin:

This was a fast one today evening, but I'm sure it's not easy to solve.

It's clean and small, but might turn out as a hard nut :dry:

Level : Bitch

Good luck !

CrackMe.zip

PS: Yes, it IS keygenable.. but just bring me that goodboy and u're actually done.

Edited by Ufo-Pu55y
Posted

What 0.0 When Loaded In OllyDBG Program Runs = /

Posted (edited)

I don't get it.

private void Check1(int i, string s)
{
byte[] check = Resources.check;
int index = 0x0;
while (i < (check.Length / 0x4))
{
check[index] = (byte) (check[index] ^ ((byte) (i >> 0x18)));
check[index + 0x1] = (byte) (check[index + 0x1] ^ ((byte) (i >> 0x10)));
check[index + 0x2] = (byte) (check[index + 0x2] ^ ((byte) (i >> 0x8)));
check[index + 0x3] = (byte) (check[index + 0x3] ^ ((byte) i));
i += 0x4;
}
BinaryWriter writer = new BinaryWriter(File.Open(Application.StartupPath + @"\check.dll", FileMode.Create));
writer.Write(check);
writer.Flush();
writer.Close();
this.Check2(s);
}

"i" will never be large enough to change the first bytes to "MZ"?

I don't think you can get the goodboy without cracking it.

unless .net doesn't care if the first 2 bytes aren't MZ, olly did though...

Your reflection method gave me an idea for protection :D .

Edited by high6
Posted

My bad :X

I made a mistake ! I reattached the crackme like it was supposed to be.

The 1st (deleted) one also fully works, but I didn't intend to encrypt the first 4 bytes only :crazy:

Wow, I will never post **** again when I'm ****ing tired already :\

So please could everybody download the harder one again ? :biggrin:

ps: damn

Posted (edited)

Getting this answered quickly, is there a problem with reflector or do you want an overflow exception?

		check[num++] = (byte) (check[num++] ^ ((byte) (i >> 0x18)));
check[num++] = (byte) (check[num++] ^ ((byte) (i >> 0x10)));
check[num++] = (byte) (check[num++] ^ ((byte) (i >> 0x8)));
check[num++] = (byte) (check[num++] ^ ((byte) i));

The decryption doesn't seem to fit the encryption. Should num be increased twice on 1 line?

What you currently have shouldn't have aligned bytes but it does. (what I mean is you have a bunch of 0xDD6F2464 instead of 0x00000000) instead of anything being 0x00000000

Edited by high6
Posted (edited)

Not sure about C# but in C++ you cant use ++ on a var appearing twice in an assignment , thats basically undefined :o

Meh.X = Meh[i++].Y might be

Meh[i+1].X = Meh[i+1].Y or even Meh.X = Meh[i+1].Y

Didnt I tell you not to code crackmes when you're ****ed :>

Edited by Killboy
Posted
Not sure about C# but in C++ you cant use ++ on a var appearing twice in an assignment , thats basically undefined :o

Meh.X = Meh[i++].Y might be

Meh[i+1].X = Meh[i+1].Y or even Meh.X = Meh[i+1].Y

Didnt I tell you not to code crackmes when you're ****ed :>

var++ means that right after the variable is used it is increased just like ++var means its increased before use.

Posted
Getting this answered quickly, is there a problem with reflector or do you want an overflow exception?
You better stop trusting reflector from now on,

since it's fingered by redgate :biggrin:

Ok, but to calm down:

				bCF[j++] ^= (byte)(i >> 24);
bCF[j++] ^= (byte)(i >> 16);
bCF[j++] ^= (byte)(i >> 8);
bCF[j++] ^= (byte)(i);
Didnt I tell you not to code crackmes when you're ****ed :>
smilie_tra_184.gif
Posted
Getting this answered quickly, is there a problem with reflector or do you want an overflow exception?
You better stop trusting reflector from now on,

since it's fingered by redgate :biggrin:

Ok, but to calm down:

				bCF[j++] ^= (byte)(i >> 24);
bCF[j++] ^= (byte)(i >> 16);
bCF[j++] ^= (byte)(i >> 8);
bCF[j++] ^= (byte)(i);
Didnt I tell you not to code crackmes when you're ****ed :>
smilie_tra_184.gif

Reflector is still the same old System.Reflection gui imo...

Posted (edited)
Reflector is still the same old System.Reflection gui imo...

And I was only kiddin. The code shown by reflector is fully functional, but not as I coded it !

Coz it would increase the var twice each line.. that's all

EDIT/

Looks like a neat lill anti-ripping effect :o

Edited by Ufo-Pu55y
Posted (edited)

Well I am stuck getting 6 opcodes to turn 0x6f6a57b0 into 0xdd6f2464

I will try again when I am awake.

Edit: Gathered the strength to finish it.

cazaB!kA-caca :kA-Ghfg5

is mine

		string GetUserNameSpecial()
{
char[] ret = Environment.UserName.ToCharArray();
for (int i = 0; i < ret.Length; i++)
{
ret[i] = (char)(ret[i] - 1);
}
return new string(ret);
}
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = "cazaB!kA-caca :kA-" + GetUserNameSpecial();
}
Edited by high6
Posted

omg you're sooo good

did you just guess or did some maths???

Posted
		string GetUserNameSpecial()
{
char[] ret = Environment.UserName.ToCharArray();
for (int i = 0; i < ret.Length; i++)
{
ret[i] = (char)(ret[i] - 1);
}
return new string(ret);
}
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = "cazaB!kA-caca :kA-" + GetUserNameSpecial();
}

Okies, good job :) I know the function is silly, but I guess only the first part of the serial

was the interesting one..

Posted
omg you're sooo good

did you just guess or did some maths???

I brute forced it because I already knew that the number needed to decrypt was 0xdd6f2464.

knowing each function was 4 opcodes (without params) it limited what it could be. Also only 3 opcodes could do math because the 4th is the return.

So I figured

First it must push the argument. So I wrote down "ca" which when used is 0x2 (ldarg_0)

Then there where 2 more options left so I wrote this code to figure it out.

		private int S2I(string s)
{
int num = 0x1;
if (s == null)
{
return 0x0;
}
for (int i = 0x0; i < s.Length; i++)
{
num *= Convert.ToInt32(s[i]);
}
return num;
}
private OpCode GetOpcode(short s)
{
switch (s)
{
case 0x1:
return OpCodes.Break; case 0x2:
return OpCodes.Ldarg_0; case 0x3:
return OpCodes.Ldarg_1; case 0x4:
return OpCodes.Ldarg_2; case 0x5:
return OpCodes.Ldarg_3; case 0x6:
return OpCodes.Ldloc_0; case 0x7:
return OpCodes.Ldloc_1; case 0x8:
return OpCodes.Ldloc_2; case 0x9:
return OpCodes.Ldloc_3; case 0xa:
return OpCodes.Stloc_0; case 0xb:
return OpCodes.Stloc_1; case 0xc:
return OpCodes.Stloc_2; case 0xd:
return OpCodes.Stloc_3; case 0xe:
return OpCodes.Ldloc_3; case 0x16:
return OpCodes.Ldc_I4_0; case 0x17:
return OpCodes.Ldc_I4_1; case 0x18:
return OpCodes.Ldc_I4_2; case 0x19:
return OpCodes.Ldc_I4_3; case 0x1a:
return OpCodes.Ldc_I4_4; case 0x1b:
return OpCodes.Ldc_I4_5; case 0x1c:
return OpCodes.Ldc_I4_6; case 0x1d:
return OpCodes.Ldc_I4_7; case 0x1e:
return OpCodes.Ldc_I4_8; case 0x1f:
return OpCodes.Ldc_I4_S; case 0x20:
return OpCodes.Ldc_I4; case 0x21:
return OpCodes.Ldc_I8; case 0x22:
return OpCodes.Ldc_R4; case 0x23:
return OpCodes.Ldc_R8; case 0x25:
return OpCodes.Dup; case 0x26:
return OpCodes.Pop; case 0x27:
return OpCodes.Jmp; case 0x28:
return OpCodes.Call; case 0x29:
return OpCodes.Calli; case 0x2a:
return OpCodes.Ret; case 0x2b:
return OpCodes.Br_S; case 0x2c:
return OpCodes.Brfalse_S; case 0x2d:
return OpCodes.Brtrue_S; case 0x58:
return OpCodes.Add; case 0x59:
return OpCodes.Sub; case 0x5a:
return OpCodes.Mul; case 0x5b:
return OpCodes.Div; case 0x5c:
return OpCodes.Div_Un; case 0x5d:
return OpCodes.Rem; case 0x5e:
return OpCodes.Rem_Un; case 0x5f:
return OpCodes.And; case 0x60:
return OpCodes.Or; case 0x61:
return OpCodes.Xor; case 0x62:
return OpCodes.Shl; case 0x63:
return OpCodes.Shr; case 0x64:
return OpCodes.Shr_Un; case 0x65:
return OpCodes.Neg; case 0x66:
return OpCodes.Not; case 0x67:
return OpCodes.Conv_I1; case 0x68:
return OpCodes.Conv_I2; case 0x69:
return OpCodes.Conv_I4; case 0x6a:
return OpCodes.Conv_I8;
}
return OpCodes.Nop;
}
short[] Operators = {
0x58,
0x59,
0x5A,
0x5B,
0x5C,
0x5D,
0x5E,
0x5F,
0x60,
0x61,
0x62,
0x63,
0x64
};
short[] Vals = {
0x02,
0x17,
0x18,
0x19,
0x1A,
0x1B,
0x1C,
0x1D,
0x1E
};
private void bruteforce()
{
for (int i1 = 0; i1 < Operators.Length; i1++)
{
for (int i2 = 0; i2 < Vals.Length; i2++)
{
for (int i3 = 0; i3 < Operators.Length; i3++)
{
for (int i4 = 0; i4 < Vals.Length; i4++)
{
Type[] parameterTypes = new Type[] { typeof(int) };
DynamicMethod method = new DynamicMethod("", typeof(int), parameterTypes, typeof(Form1).Module);
DynamicMethod method2 = new DynamicMethod("", typeof(int), parameterTypes, typeof(Form1).Module);
ILGenerator iLGenerator = method.GetILGenerator();
ILGenerator generator2 = method2.GetILGenerator();
iLGenerator.Emit(OpCodes.Ldarg_0);
generator2.Emit(OpCodes.Ldarg_0);
iLGenerator.Emit(GetOpcode(Vals[i2]));
generator2.Emit(GetOpcode(Vals[i4]));
iLGenerator.Emit(GetOpcode(Operators[i1]));
generator2.Emit(GetOpcode(Operators[i3]));
iLGenerator.Emit(OpCodes.Ret);
generator2.Emit(OpCodes.Ret);
dShot1 shot = (dShot1)method.CreateDelegate(typeof(dShot1));
dShot2 shot2 = (dShot2)method2.CreateDelegate(typeof(dShot2));
int idx = shot(this.S2I("WTF:?"));
if (idx != 0) //Divide by zero, O ****!
idx = shot2(idx);
if ((uint)idx == 0xDD6F2464)
{
}
}
}
}
}
}
private delegate int dShot1(int input); private delegate int dShot2(int input);

As you can see I filled in the 2 static instructions.

Then I set a breakpoint on the bracket after "if ((uint)idx == 0xDD6F2464)"

And then let it run and checked the instructions it used.

I know its bruteforcing but really that is the only option without a key to start.

Posted
I know its bruteforcing but really that is the only option without a key to start.

I was expecting somebody to take the initial value (0x6f6a57b0) and the last one (0xdd6f2464.. simply getting

by looking at some must-have bytes in the encrypted dll) - and then starting to play for a while which 2

small calculations would be needed to get it.

But I really like the bruteforcing approach much more, coz that's what I had in my mind.. cheerio

Posted

i thought you really used some advanced maths technique :P

wish i still had my vs 2008, since my computer's now formatted, i just tried it in c

and only tried the few basic instructions with consts in my bruteforcer :(

next time i'll remember to convert the whole thing into c

Posted
I know its bruteforcing but really that is the only option without a key to start.

I was expecting somebody to take the initial value (0x6f6a57b0) and the last one (0xdd6f2464.. simply getting

by looking at some must-have bytes in the encrypted dll) - and then starting to play for a while which 2

small calculations would be needed to get it.

But I really like the bruteforcing approach much more, coz that's what I had in my mind.. cheerio

My calculator doesn't have right shift XD.

I actually had guessed it with divide it by 8 and square it but I forgot it (was tired) and got ****ed so I bruteforced it.

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...