Ufo-Pu55y Posted September 27, 2008 Posted September 27, 2008 (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 : BitchGood luck !CrackMe.zipPS: Yes, it IS keygenable.. but just bring me that goodboy and u're actually done. Edited September 30, 2008 by Ufo-Pu55y
r00t_H@ck3r Posted September 28, 2008 Posted September 28, 2008 What 0.0 When Loaded In OllyDBG Program Runs = /
high6 Posted September 29, 2008 Posted September 29, 2008 (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 . Edited September 29, 2008 by high6
Ufo-Pu55y Posted September 30, 2008 Author Posted September 30, 2008 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 Wow, I will never post **** again when I'm ****ing tired already :\ So please could everybody download the harder one again ? :biggrin: ps: damn
high6 Posted September 30, 2008 Posted September 30, 2008 (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 September 30, 2008 by high6
Killboy Posted September 30, 2008 Posted September 30, 2008 (edited) Not sure about C# but in C++ you cant use ++ on a var appearing twice in an assignment , thats basically undefined 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 September 30, 2008 by Killboy
high6 Posted September 30, 2008 Posted September 30, 2008 Not sure about C# but in C++ you cant use ++ on a var appearing twice in an assignment , thats basically undefined 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.
Ufo-Pu55y Posted September 30, 2008 Author Posted September 30, 2008 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 :>
high6 Posted September 30, 2008 Posted September 30, 2008 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 :> Reflector is still the same old System.Reflection gui imo...
Ufo-Pu55y Posted September 30, 2008 Author Posted September 30, 2008 (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 Edited September 30, 2008 by Ufo-Pu55y
high6 Posted September 30, 2008 Posted September 30, 2008 (edited) Well I am stuck getting 6 opcodes to turn 0x6f6a57b0 into 0xdd6f2464I will try again when I am awake.Edit: Gathered the strength to finish it.cazaB!kA-caca :kA-Ghfg5is 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 September 30, 2008 by high6
SMK Posted October 1, 2008 Posted October 1, 2008 omg you're sooo gooddid you just guess or did some maths???
Ufo-Pu55y Posted October 1, 2008 Author Posted October 1, 2008 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..
high6 Posted October 1, 2008 Posted October 1, 2008 omg you're sooo gooddid 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 figuredFirst 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.
Ufo-Pu55y Posted October 1, 2008 Author Posted October 1, 2008 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 gettingby looking at some must-have bytes in the encrypted dll) - and then starting to play for a while which 2small 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
SMK Posted October 2, 2008 Posted October 2, 2008 i thought you really used some advanced maths technique 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
high6 Posted October 2, 2008 Posted October 2, 2008 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 gettingby looking at some must-have bytes in the encrypted dll) - and then starting to play for a while which 2small 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.. cheerioMy 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.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now