/* 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.Collections.Generic; using dnlib.DotNet; using dnlib.DotNet.Emit; using de4dot.blocks; namespace de4dot.code.deobfuscators.CodeVeil { // Detects the type CV adds to the assembly that gets called from ::.cctor. class MainType { ModuleDefMD module; TypeDef theType; MethodDef initMethod; MethodDef tamperCheckMethod; ObfuscatorVersion obfuscatorVersion = ObfuscatorVersion.Unknown; List rvas = new List(); // _stub and _executive List otherInitMethods = new List(); public bool Detected { get { return theType != null; } } public ObfuscatorVersion Version { get { return obfuscatorVersion; } } public TypeDef Type { get { return theType; } } public MethodDef InitMethod { get { return initMethod; } } public List OtherInitMethods { get { return otherInitMethods; } } public MethodDef TamperCheckMethod { get { return tamperCheckMethod; } } public List Rvas { get { return rvas; } } public MainType(ModuleDefMD module) { this.module = module; } public MainType(ModuleDefMD module, MainType oldOne) { this.module = module; this.theType = Lookup(oldOne.theType, "Could not find main type"); this.initMethod = Lookup(oldOne.initMethod, "Could not find main type init method"); this.tamperCheckMethod = Lookup(oldOne.tamperCheckMethod, "Could not find tamper detection method"); this.obfuscatorVersion = oldOne.obfuscatorVersion; this.rvas = oldOne.rvas; foreach (var otherInitMethod in otherInitMethods) otherInitMethods.Add(Lookup(otherInitMethod, "Could not find otherInitMethod")); } T Lookup(T def, string errorMessage) where T : class, ICodedToken { return DeobUtils.Lookup(module, def, errorMessage); } public void Find() { var cctor = DotNetUtils.GetModuleTypeCctor(module); if (cctor == null) return; var instrs = cctor.Body.Instructions; for (int i = 0; i < instrs.Count - 2; i++) { var ldci4_1 = instrs[i]; if (!ldci4_1.IsLdcI4()) continue; var ldci4_2 = instrs[i + 1]; if (!ldci4_2.IsLdcI4()) continue; var call = instrs[i + 2]; if (call.OpCode.Code != Code.Call) continue; var initMethodTmp = call.Operand as MethodDef; ObfuscatorVersion obfuscatorVersionTmp; if (!CheckInitMethod(initMethodTmp, out obfuscatorVersionTmp)) continue; if (!CheckMethodsType(initMethodTmp.DeclaringType)) continue; obfuscatorVersion = obfuscatorVersionTmp; theType = initMethodTmp.DeclaringType; initMethod = initMethodTmp; break; } } static string[] fieldTypesV5 = new string[] { "System.Byte[]", "System.Collections.Generic.List`1", "System.Runtime.InteropServices.GCHandle", }; bool CheckInitMethod(MethodDef initMethod, out ObfuscatorVersion obfuscatorVersionTmp) { obfuscatorVersionTmp = ObfuscatorVersion.Unknown; if (initMethod == null) return false; if (initMethod.Body == null) return false; if (!initMethod.IsStatic) return false; if (!DotNetUtils.IsMethod(initMethod, "System.Void", "(System.Boolean,System.Boolean)")) return false; if (HasCodeString(initMethod, "E_FullTrust")) { if (DotNetUtils.GetPInvokeMethod(initMethod.DeclaringType, "user32", "CallWindowProcW") != null) obfuscatorVersionTmp = ObfuscatorVersion.V4_1; else obfuscatorVersionTmp = ObfuscatorVersion.V4_0; } else if (HasCodeString(initMethod, "Full Trust Required")) obfuscatorVersionTmp = ObfuscatorVersion.V3; else if (initMethod.DeclaringType.HasNestedTypes && new FieldTypes(initMethod.DeclaringType).All(fieldTypesV5)) obfuscatorVersionTmp = ObfuscatorVersion.V5_0; else return false; return true; } static bool HasCodeString(MethodDef method, string str) { foreach (var s in DotNetUtils.GetCodeStrings(method)) { if (s == str) return true; } return false; } bool CheckMethodsType(TypeDef type) { rvas = new List(); var fields = GetRvaFields(type); if (fields.Count < 2) // RVAs for executive and stub are always present if encrypted methods return true; foreach (var field in fields) rvas.Add((uint)field.RVA); return true; } static List GetRvaFields(TypeDef type) { var fields = new List(); foreach (var field in type.Fields) { var etype = field.FieldSig.GetFieldType().GetElementType(); if (etype != ElementType.U1 && etype != ElementType.U4) continue; if (field.RVA == 0) continue; fields.Add(field); } return fields; } public void Initialize() { if (theType == null) return; tamperCheckMethod = FindTamperCheckMethod(); otherInitMethods = FindOtherInitMethods(); } MethodDef FindTamperCheckMethod() { foreach (var method in theType.Methods) { if (!method.IsStatic || method.Body == null) continue; if (!DotNetUtils.IsMethod(method, "System.Void", "(System.Reflection.Assembly,System.UInt64)")) continue; return method; } return null; } List FindOtherInitMethods() { var list = new List(); foreach (var method in theType.Methods) { if (!method.IsStatic) continue; if (method.Name == ".cctor") continue; if (!DotNetUtils.IsMethod(method, "System.Void", "()")) continue; list.Add(method); } return list; } public MethodDef GetInitStringDecrypterMethod(MethodDef stringDecrypterInitMethod) { if (stringDecrypterInitMethod == null) return null; if (theType == null) return null; foreach (var method in theType.Methods) { if (!method.IsStatic || method.Body == null) continue; if (CallsMethod(method, stringDecrypterInitMethod)) return method; } return null; } bool CallsMethod(MethodDef methodToCheck, MethodDef calledMethod) { foreach (var method in DotNetUtils.GetCalledMethods(module, methodToCheck)) { if (method == calledMethod) return true; } return false; } public void RemoveInitCall(Blocks blocks) { if (initMethod == null || theType == null) return; if (blocks.Method.Name != ".cctor") return; if (blocks.Method.DeclaringType != DotNetUtils.GetModuleType(module)) return; foreach (var block in blocks.MethodBlocks.GetAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count - 2; i++) { if (!instrs[i].IsLdcI4()) continue; if (!instrs[i + 1].IsLdcI4()) continue; var call = instrs[i + 2]; if (call.OpCode.Code != Code.Call) continue; if (call.Operand != initMethod) continue; block.Remove(i, 3); return; } } } } }