/* Copyright (C) 2011-2014 de4dot@gmail.com This file is part of de4dot. de4dot is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. de4dot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with de4dot. If not, see . */ using System; using System.Collections.Generic; using System.Text; using dnlib.DotNet; using dnlib.DotNet.Emit; using de4dot.blocks; namespace de4dot.code.deobfuscators.Eazfuscator_NET { class DecrypterType { ModuleDefMD module; ISimpleDeobfuscator simpleDeobfuscator; TypeDef type; MethodDef int64Method; bool initialized; ulong l1; int i1, i2, i3; int m1_i1, m2_i1, m2_i2, m3_i1; MethodDef[] efConstMethods; public MethodDef Int64Method { get { return int64Method; } } public TypeDef Type { get { return type; } set { if (type == null) type = value; else if (type != value) throw new ApplicationException("Found another one"); } } public bool Detected { get { return type != null; } } public DecrypterType(ModuleDefMD module, ISimpleDeobfuscator simpleDeobfuscator) { this.module = module; this.simpleDeobfuscator = simpleDeobfuscator; } public bool Initialize() { if (initialized) return true; int64Method = FindInt64Method(); if (int64Method == null) return false; if (!InitializeEfConstMethods()) return false; if (!FindInt1And2()) return false; if (!FindInt3()) return false; if (!FindMethodInts()) return false; initialized = true; return true; } bool InitializeEfConstMethods() { if (type == null) return false; efConstMethods = new MethodDef[6]; efConstMethods[0] = FindEfConstMethodCall(int64Method); efConstMethods[5] = FindEfConstMethodCall(efConstMethods[0]); efConstMethods[4] = FindEfConstMethodCall(efConstMethods[5]); var calls = FindEfConstMethodCalls(efConstMethods[4]); if (calls.Count != 2) return false; if (GetNumberOfTypeofs(calls[0]) == 3) { efConstMethods[2] = calls[0]; efConstMethods[1] = calls[1]; } else { efConstMethods[2] = calls[0]; efConstMethods[1] = calls[1]; } efConstMethods[3] = FindEfConstMethodCall(efConstMethods[1]); foreach (var m in efConstMethods) { if (m == null) return false; } return true; } static int GetNumberOfTypeofs(MethodDef method) { if (method == null) return 0; int count = 0; foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code == Code.Ldtoken) count++; } return count; } MethodDef FindEfConstMethodCall(MethodDef method) { var list = FindEfConstMethodCalls(method); if (list == null || list.Count != 1) return null; return list[0]; } List FindEfConstMethodCalls(MethodDef method) { if (method == null) return null; var list = new List(); foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code != Code.Call) continue; var calledMethod = instr.Operand as MethodDef; if (calledMethod == null || !calledMethod.IsStatic || calledMethod.Body == null) continue; if (!DotNetUtils.IsMethod(calledMethod, "System.Int32", "()")) continue; if (type.NestedTypes.IndexOf(calledMethod.DeclaringType) < 0) continue; list.Add(calledMethod); } return list; } MethodDef FindInt64Method() { if (type == null) return null; foreach (var method in type.Methods) { if (!method.IsStatic || method.Body == null || method.HasGenericParameters) continue; if (!DotNetUtils.IsMethod(method, "System.Int64", "()")) continue; if (!FindInt64(method)) continue; return method; } return null; } bool FindInt64(MethodDef method) { var instrs = method.Body.Instructions; for (int i = 0; i < instrs.Count - 1; i++) { var ldci8 = instrs[i]; if (ldci8.OpCode.Code != Code.Ldc_I8) continue; if (instrs[i + 1].OpCode.Code != Code.Xor) continue; l1 = (ulong)(long)ldci8.Operand; return true; } return false; } bool FindInt1And2() { var consts = GetConstants(efConstMethods[2]); if (consts.Count != 2) return false; i1 = consts[0]; i2 = consts[1]; return true; } bool FindInt3() { var consts = GetConstants(efConstMethods[5]); if (consts.Count != 1) return false; i3 = consts[0]; return true; } bool FindMethodInts() { foreach (var nestedType in type.NestedTypes) { var methods = GetBinaryIntMethods(nestedType); if (methods.Count < 3) continue; foreach (var m in methods) simpleDeobfuscator.Deobfuscate(m); if (!FindMethod1Int(methods)) continue; if (!FindMethod2Int(methods)) continue; if (!FindMethod3Int(methods)) continue; return true; } return false; } static List GetBinaryIntMethods(TypeDef type) { var list = new List(); foreach (var method in type.Methods) { if (!method.IsStatic || method.Body == null) continue; if (!DotNetUtils.IsMethod(method, "System.Int32", "(System.Int32,System.Int32)")) continue; list.Add(method); } return list; } bool FindMethod1Int(IEnumerable methods) { foreach (var method in methods) { if (CountInstructions(method, Code.Ldarg_0) != 1) continue; var constants = GetConstants(method); if (constants.Count != 1) continue; m1_i1 = constants[0]; return true; } return false; } bool FindMethod2Int(IEnumerable methods) { foreach (var method in methods) { var constants = GetConstants(method); if (constants.Count != 2) continue; m2_i1 = constants[0]; m2_i2 = constants[1]; return true; } return false; } bool FindMethod3Int(IEnumerable methods) { foreach (var method in methods) { if (CountInstructions(method, Code.Ldarg_0) != 2) continue; var constants = GetConstants(method); if (constants.Count != 1) continue; m3_i1 = constants[0]; return true; } return false; } static int CountInstructions(MethodDef method, Code code) { int count = 0; foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code == code) count++; } return count; } static List GetConstants(MethodDef method) { var list = new List(); if (method == null) return list; int index = 0; var instrs = method.Body.Instructions; var constantsReader = new EfConstantsReader(method); while (true) { int val; if (!constantsReader.GetNextInt32(ref index, out val)) break; if (index < instrs.Count && instrs[index].OpCode.Code != Code.Ret) list.Add(val); } return list; } int BinOp1(int a, int b) { return a ^ (b - m1_i1); } int BinOp2(int a, int b) { return (a - m2_i1) ^ (b + m2_i2); } int BinOp3(int a, int b) { return a ^ (b - m3_i1) ^ (a - b); } int ConstMethod1() { return BinOp3(BinOp2(efConstMethods[1].DeclaringType.MDToken.ToInt32(), BinOp3(efConstMethods[0].DeclaringType.MDToken.ToInt32(), efConstMethods[4].DeclaringType.MDToken.ToInt32())), ConstMethod6()); } int ConstMethod2() { return BinOp1(efConstMethods[2].DeclaringType.MDToken.ToInt32(), efConstMethods[3].DeclaringType.MDToken.ToInt32() ^ BinOp2(efConstMethods[1].DeclaringType.MDToken.ToInt32(), BinOp3(efConstMethods[5].DeclaringType.MDToken.ToInt32(), ConstMethod4()))); } int ConstMethod3() { return BinOp3(BinOp1(ConstMethod2() ^ i1, efConstMethods[3].DeclaringType.MDToken.ToInt32()), BinOp2(efConstMethods[0].DeclaringType.MDToken.ToInt32() ^ efConstMethods[5].DeclaringType.MDToken.ToInt32(), i2)); } int ConstMethod4() { return BinOp3(efConstMethods[3].DeclaringType.MDToken.ToInt32(), BinOp1(efConstMethods[0].DeclaringType.MDToken.ToInt32(), BinOp2(efConstMethods[1].DeclaringType.MDToken.ToInt32(), BinOp3(efConstMethods[2].DeclaringType.MDToken.ToInt32(), BinOp1(efConstMethods[4].DeclaringType.MDToken.ToInt32(), efConstMethods[5].DeclaringType.MDToken.ToInt32()))))); } int ConstMethod5() { return BinOp2(BinOp2(ConstMethod3(), BinOp1(efConstMethods[4].DeclaringType.MDToken.ToInt32(), ConstMethod2())), efConstMethods[5].DeclaringType.MDToken.ToInt32()); } int ConstMethod6() { return BinOp1(efConstMethods[5].DeclaringType.MDToken.ToInt32(), BinOp3(BinOp2(efConstMethods[4].DeclaringType.MDToken.ToInt32(), efConstMethods[0].DeclaringType.MDToken.ToInt32()), BinOp3(efConstMethods[2].DeclaringType.MDToken.ToInt32() ^ i3, ConstMethod5()))); } public ulong GetMagic() { if (type == null) throw new ApplicationException("Can't calculate magic since type isn't initialized"); var bytes = new List(); if (module.Assembly != null) { if (!PublicKeyBase.IsNullOrEmpty2(module.Assembly.PublicKey)) bytes.AddRange(module.Assembly.PublicKeyToken.Data); bytes.AddRange(Encoding.Unicode.GetBytes(module.Assembly.Name.String)); } int cm1 = ConstMethod1(); bytes.Add((byte)(type.MDToken.ToInt32() >> 24)); bytes.Add((byte)(cm1 >> 16)); bytes.Add((byte)(type.MDToken.ToInt32() >> 8)); bytes.Add((byte)cm1); bytes.Add((byte)(type.MDToken.ToInt32() >> 16)); bytes.Add((byte)(cm1 >> 8)); bytes.Add((byte)type.MDToken.ToInt32()); bytes.Add((byte)(cm1 >> 24)); ulong magic = 0; foreach (var b in bytes) { magic += b; magic += magic << 20; magic ^= magic >> 12; } magic += magic << 6; magic ^= magic >> 22; magic += magic << 30; return magic ^ l1; } } }