Jump to content
Tuts 4 You

[CrackMe/KeygenMe] Naked naughty .net doggy


Ufo-Pu55y

Recommended Posts

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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