diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 6518312c..a2950b05 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -75,6 +75,7 @@ + diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs b/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs index a61cac7f..29621135 100644 --- a/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs @@ -81,6 +81,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor { StringDecrypter stringDecrypter; BooleanDecrypter booleanDecrypter; BoolValueInliner boolValueInliner; + MetadataTokenObfuscator metadataTokenObfuscator; bool canRemoveDecrypterType = true; bool startedDeobfuscating = false; @@ -313,6 +314,8 @@ namespace de4dot.deobfuscators.dotNET_Reactor { } DeobfuscatedFile.stringDecryptersAdded(); + metadataTokenObfuscator = new MetadataTokenObfuscator(module); + if (Operations.DecryptStrings != OpDecryptString.None) addResourceToBeRemoved(stringDecrypter.StringsResource, "Encrypted strings"); if (options.DecryptMethods) { @@ -341,6 +344,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor { } public override void deobfuscateMethodEnd(Blocks blocks) { + metadataTokenObfuscator.deobfuscate(blocks); base.deobfuscateMethodEnd(blocks); } @@ -348,8 +352,10 @@ namespace de4dot.deobfuscators.dotNET_Reactor { removeInlinedMethods(); if (options.RestoreTypes) new TypesRestorer(module).deobfuscate(); - if (canRemoveDecrypterType && methodsDecrypter.MethodsDecrypterMethod != null) + if (canRemoveDecrypterType && methodsDecrypter.MethodsDecrypterMethod != null) { addTypeToBeRemoved(methodsDecrypter.MethodsDecrypterMethod.DeclaringType, "Decrypter type"); + addTypeToBeRemoved(metadataTokenObfuscator.Type, "Metadata token obfuscator"); + } base.deobfuscateEnd(); } diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/MetadataTokenObfuscator.cs b/de4dot.code/deobfuscators/dotNET_Reactor/MetadataTokenObfuscator.cs new file mode 100644 index 00000000..24bb7c98 --- /dev/null +++ b/de4dot.code/deobfuscators/dotNET_Reactor/MetadataTokenObfuscator.cs @@ -0,0 +1,99 @@ +/* + Copyright (C) 2011 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 Mono.Cecil; +using Mono.Cecil.Cil; +using de4dot.blocks; + +namespace de4dot.deobfuscators.dotNET_Reactor { + // Find the class that returns a RuntimeTypeHandle/RuntimeFieldHandle. The value passed to + // its methods is the original metadata token, which will be different when we save the file. + class MetadataTokenObfuscator { + ModuleDefinition module; + TypeDefinition type; + MethodDefinition typeMethod; + MethodDefinition fieldMethod; + + public TypeDefinition Type { + get { return type; } + } + + public MetadataTokenObfuscator(ModuleDefinition module) { + this.module = module; + find(); + } + + void find() { + foreach (var type in module.Types) { + var fields = type.Fields; + if (fields.Count != 1) + continue; + if (fields[0].FieldType.FullName != "System.ModuleHandle") + continue; + if (type.HasProperties || type.HasEvents) + continue; + + MethodDefinition fieldMethod = null, typeMethod = null; + foreach (var method in type.Methods) { + if (DotNetUtils.isMethod(method, "System.RuntimeTypeHandle", "(System.Int32)")) + typeMethod = method; + else if (DotNetUtils.isMethod(method, "System.RuntimeFieldHandle", "(System.Int32)")) + fieldMethod = method; + } + + if (typeMethod == null || fieldMethod == null) + continue; + + this.type = type; + this.typeMethod = typeMethod; + this.fieldMethod = fieldMethod; + return; + } + } + + public void deobfuscate(Blocks blocks) { + if (type == null) + return; + + foreach (var block in blocks.MethodBlocks.getAllBlocks()) { + var instrs = block.Instructions; + for (int i = 0; i < instrs.Count - 1; i++) { + var instr = instrs[i]; + if (instr.OpCode.Code != Code.Ldc_I4) + continue; + var call = instrs[i + 1]; + if (call.OpCode.Code != Code.Call) + continue; + var method = call.Operand as MethodReference; + if (!MemberReferenceHelper.compareTypes(type, method.DeclaringType)) + continue; + var methodDef = DotNetUtils.getMethod(module, method); + if (methodDef == null) + continue; + if (methodDef != typeMethod && methodDef != fieldMethod) + continue; + + int token = (int)instrs[i].Operand; + instrs[i] = new Instr(Instruction.Create(OpCodes.Nop)); + instrs[i + 1] = new Instr(new Instruction(OpCodes.Ldtoken, module.LookupToken(token) as MemberReference)); + } + } + } + } +}