/* Copyright (C) 2011-2015 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.IO; using dnlib.DotNet; using de4dot.blocks; namespace de4dot.code.deobfuscators.Agile_NET { class CliSecureRtType { ModuleDefMD module; TypeDef cliSecureRtType; MethodDef postInitializeMethod; MethodDef initializeMethod; Dictionary stringDecrypterInfos = new Dictionary(); MethodDef loadMethod; bool foundSig; public bool Detected { get { return foundSig || cliSecureRtType != null; } } public TypeDef Type { get { return cliSecureRtType; } } public IEnumerable StringDecrypterInfos { get { return stringDecrypterInfos.Keys; } } public MethodDef PostInitializeMethod { get { return postInitializeMethod; } } public MethodDef InitializeMethod { get { return initializeMethod; } } public MethodDef LoadMethod { get { return loadMethod; } } public CliSecureRtType(ModuleDefMD module) { this.module = module; } public CliSecureRtType(ModuleDefMD module, CliSecureRtType oldOne) { this.module = module; cliSecureRtType = Lookup(oldOne.cliSecureRtType, "Could not find CliSecureRt type"); postInitializeMethod = Lookup(oldOne.postInitializeMethod, "Could not find postInitializeMethod method"); initializeMethod = Lookup(oldOne.initializeMethod, "Could not find initializeMethod method"); foreach (var info in oldOne.stringDecrypterInfos.Keys) { var m = Lookup(info.Method, "Could not find string decrypter method"); var f = Lookup(info.Field, "Could not find string decrypter field"); stringDecrypterInfos[new StringDecrypterInfo(m, f)] = true; } loadMethod = Lookup(oldOne.loadMethod, "Could not find loadMethod method"); foundSig = oldOne.foundSig; } T Lookup(T def, string errorMessage) where T : class, ICodedToken { return DeobUtils.Lookup(module, def, errorMessage); } public void Find(byte[] moduleBytes) { if (cliSecureRtType != null) return; if (Find2()) return; if (Find3()) return; FindNativeCode(moduleBytes); } static readonly string[] requiredFields1 = new string[] { "System.Boolean", }; bool Find2() { foreach (var cctor in DeobUtils.GetInitCctors(module, 3)) { foreach (var calledMethod in DotNetUtils.GetCalledMethods(module, cctor)) { var type = calledMethod.DeclaringType; if (type.IsPublic) continue; var fieldTypes = new FieldTypes(type); if (!fieldTypes.All(requiredFields1)) continue; if (!HasInitializeMethod(type, "_Initialize") && !HasInitializeMethod(type, "_Initialize64")) continue; initializeMethod = calledMethod; postInitializeMethod = FindMethod(type, "System.Void", "PostInitialize", "()"); loadMethod = FindMethod(type, "System.IntPtr", "Load", "()"); cliSecureRtType = type; FindStringDecrypters(); return true; } } return false; } void FindStringDecrypters() { AddStringDecrypterMethod(FindStringDecrypterMethod(cliSecureRtType)); } void AddStringDecrypterMethod(MethodDef method) { if (method != null) stringDecrypterInfos[new StringDecrypterInfo(method)] = true; } static string[] requiredFields6 = new string[] { "System.Byte[]", }; static string[] requiredFields7 = new string[] { "System.Byte[]", "System.Collections.Hashtable", }; bool Find3() { foreach (var type in module.Types) { if (type.Fields.Count < 1 || type.Fields.Count > 2) continue; var fieldTypes = new FieldTypes(type); if (!fieldTypes.Exactly(requiredFields6) && !fieldTypes.Exactly(requiredFields7)) continue; if (type.Methods.Count != 2) continue; if (type.FindStaticConstructor() == null) continue; var cs = type.FindMethod("cs"); if (cs == null) continue; AddStringDecrypterMethod(cs); cliSecureRtType = type; return true; } return false; } static MethodDef FindStringDecrypterMethod(TypeDef type) { foreach (var method in type.Methods) { if (method.Body == null || !method.IsStatic) continue; if (!DotNetUtils.IsMethod(method, "System.String", "(System.String)")) continue; return method; } return null; } static MethodDef FindMethod(TypeDef type, string returnType, string name, string parameters) { var methodName = returnType + " " + type.FullName + "::" + name + parameters; foreach (var method in type.Methods) { if (method.Body == null || !method.IsStatic) continue; if (method.FullName != methodName) continue; return method; } return null; } static bool HasInitializeMethod(TypeDef type, string name) { var method = DotNetUtils.GetPInvokeMethod(type, name); if (method == null) return false; var sig = method.MethodSig; if (sig.Params.Count != 1) return false; if (sig.Params[0].GetElementType() != ElementType.I) return false; var retType = sig.RetType.GetElementType(); if (retType != ElementType.Void && retType != ElementType.I4) return false; return true; } bool FindNativeCode(byte[] moduleBytes) { var bytes = moduleBytes != null ? moduleBytes : DeobUtils.ReadModule(module); using (var peImage = new MyPEImage(bytes)) return foundSig = MethodsDecrypter.Detect(peImage); } public bool IsAtLeastVersion50() { return DotNetUtils.HasPinvokeMethod(cliSecureRtType, "LoadLibraryA"); } public void FindStringDecrypterMethod() { if (cliSecureRtType != null) return; foreach (var type in module.Types) { if (type.Fields.Count != 0) continue; if (type.Methods.Count != 1) continue; var cs = type.Methods[0]; if (!IsOldStringDecrypterMethod(cs)) continue; cliSecureRtType = type; AddStringDecrypterMethod(cs); return; } } static bool IsOldStringDecrypterMethod(MethodDef method) { if (method == null || method.Body == null || !method.IsStatic) return false; if (!DotNetUtils.IsMethod(method, "System.String", "(System.String)")) return false; if (!DeobUtils.HasInteger(method, 0xFF)) return false; return true; } } }