/// <summary> /// Print out information about whether or not a devirtualization attempt was /// successful, and if not why not. /// </summary> /// <param name="options">MonoOptions set from passed command-line arguments</param> /// <param name="module">EazModule</param> /// <param name="attempt">Data about the devirtualization attempt</param> static void PrintAttemptSuccess(MonoOptions options, EazModule module, DevirtualizeAttempt attempt) { var reader = attempt.Reader; if (attempt.Successful) { Console.WriteLine("--> Devirtualizable"); } else if (attempt.WasInstructionUnknown) { var matches = module.VirtualInstructions .Where((instr) => { return(instr.VirtualCode == reader.LastVirtualOpCode); }) .ToArray(); if (matches.Length > 0) { VirtualOpCode v = matches[0]; Console.WriteLine("--> Not yet devirtualizable (contains unknown virtual instruction)"); Console.WriteLine("-----> Virtual OpCode = {0} @ [{1}] (0x{2:X8})", reader.LastVirtualOpCode, reader.CurrentInstructionOffset, reader.CurrentVirtualOffset); Console.WriteLine("-----> Delegate method: {0} (MDToken = 0x{1:X8})", v.DelegateMethod.FullName, v.DelegateMethod.MDToken.Raw); } else { Console.WriteLine("--> Not yet devirtualizable (contains unexpected virtual instruction @ [{0}] (0x{1:X8}))", reader.CurrentInstructionOffset, reader.CurrentVirtualOffset); } } else { Console.WriteLine("--> Not yet devirtualizable (threw exception)"); } }
/// <summary> /// Print out information about whether or not a devirtualization attempt was /// successful, and if not why not. /// </summary> /// <param name="options">MonoOptions set from passed command-line arguments</param> /// <param name="module">EazModule</param> /// <param name="attempt">Data about the devirtualization attempt</param> static void PrintAttemptSuccess(MonoOptions options, EazModule module, DevirtualizeAttempt attempt) { var reader = attempt.Reader; if (attempt.Successful) Console.WriteLine("--> Devirtualizable"); else if (attempt.WasInstructionUnknown) { var matches = module.VirtualInstructions .Where((instr) => { return instr.VirtualCode == reader.LastVirtualOpCode; }) .ToArray(); if (matches.Length > 0) { VirtualOpCode v = matches[0]; Console.WriteLine("--> Not yet devirtualizable (contains unknown virtual instruction)"); Console.WriteLine("-----> Virtual OpCode = {0} @ [{1}] (0x{2:X8})", reader.LastVirtualOpCode, reader.CurrentInstructionOffset, reader.CurrentVirtualOffset); Console.WriteLine("-----> Delegate method: {0} (MDToken = 0x{1:X8})", v.DelegateMethod.FullName, v.DelegateMethod.MDToken.Raw); } else { Console.WriteLine("--> Not yet devirtualizable (contains unexpected virtual instruction @ [{0}] (0x{1:X8}))", reader.CurrentInstructionOffset, reader.CurrentVirtualOffset); } } else Console.WriteLine("--> Not yet devirtualizable (threw exception)"); }
public Devirtualizer(EazModule module, DevirtualizeOptions options, IList <Type> fixers, ILogger logger) { this.Parent = module; this.Options = options; this.Injector = new AttributeInjector(module); this.Fixers = (fixers != null ? fixers : new List <Type>()); this.Logger = (logger != null ? logger : DummyLogger.NoThrowInstance); }
public Devirtualizer(EazModule module, DevirtualizeOptions options, IList<Type> fixers, ILogger logger) { this.Parent = module; this.Options = options; this.Injector = new AttributeInjector(module); this.Fixers = (fixers != null ? fixers : new List<Type>()); this.Logger = (logger != null ? logger : DummyLogger.NoThrowInstance); }
public VirtualMachineType(EazModule module, ILogger logger) { if (module == null) throw new ArgumentNullException(); this.Parent = module; this.Logger = (logger != null ? logger : DummyLogger.NoThrowInstance); this.Initialize(); }
public VirtualMachineType(EazModule module, ILogger logger) { if (module == null) { throw new ArgumentNullException(); } this.Parent = module; this.Logger = (logger != null ? logger : DummyLogger.NoThrowInstance); this.Initialize(); }
static Boolean TryLoadModule(String path, ILogger logger, out EazModule module) { try { ModuleDefMD moduleDef = ModuleDefMD.Load(path); AssemblyResolver asmResolver = new AssemblyResolver(); ModuleContext modCtx = new ModuleContext(asmResolver); // All resolved assemblies will also get this same modCtx asmResolver.DefaultModuleContext = modCtx; moduleDef.Context = modCtx; foreach (TypeDef typeDef in moduleDef.Types) { if (!typeDef.HasMethods) { continue; } foreach (MethodDef method in typeDef.Methods) { if (!method.HasBody || !method.Body.HasInstructions) { continue; } BlockDeobfuscator(method); } } module = new EazModule(moduleDef, logger); } catch (IOException e) { // Console.WriteLine(e.Message); Console.Write(e); module = null; return(false); } return(true); }
static Boolean TryLoadModule(String path, ILogger logger, out EazModule module) { try { ModuleDefMD moduleDef = ModuleDefMD.Load(path); AssemblyResolver asmResolver = new AssemblyResolver(); ModuleContext modCtx = new ModuleContext(asmResolver); // All resolved assemblies will also get this same modCtx asmResolver.DefaultModuleContext = modCtx; moduleDef.Context = modCtx; module = new EazModule(moduleDef, logger); } catch (IOException e) { // Console.WriteLine(e.Message); Console.Write(e); module = null; return(false); } return(true); }
public Devirtualizer(EazModule module) : this(module, DevirtualizeOptions.Nothing) { }
static Boolean TryLoadModule(String path, out EazModule module) { return(TryLoadModule(path, null, out module)); }
public VirtualMachineType(EazModule module) : this(module, null) { }
/// <summary> /// Find all virtual instructions given the main virtualization type. /// </summary> /// <param name="module">Module</param> /// <param name="virtualizationType">Main virtualization type (class)</param> /// <returns>All found virtualization instructions</returns> public static IList<VirtualOpCode> FindAllInstructions(EazModule module, TypeDef virtualizationType) { if (module == null || virtualizationType == null) throw new ArgumentNullException(); // Find dictionary method MethodDef dictMethod = null; var methods = virtualizationType.Methods; foreach(var method in methods) { if(method.IsPrivate && !method.IsStatic && method.Parameters.Count == 1 && method.HasReturnType && method.ReturnType.FullName.StartsWith("System.Collections.Generic.Dictionary")) { dictMethod = method; break; } } if (dictMethod == null) throw new Exception("Unable to find dictionary method"); // Each dictionary addition looks like this: //IL_000b: ldloc.0 // [0] //IL_000c: ldarg.0 // [0] //IL_000d: ldfld class Class33 Class805::class33_0 // 0x0400092c // TypeDef of this class (Class33) is important //IL_0012: ldfld class Class487 Class33::class487_162 // 0x040000da // FieldDef of this field (class487_162) is important //IL_0017: callvirt instance int32 Class487::method_1() // 0x06000ac3 //IL_001c: ldarg.0 // [0] //IL_001d: ldfld class Class33 Class805::class33_0 // 0x0400092c //IL_0022: ldfld class Class487 Class33::class487_162 // 0x040000da //IL_0027: ldarg.0 // [0] //IL_0028: ldftn instance void Class805::method_281(class Class1) // 0x060015ca //IL_002e: newobj instance void Class805/Delegate9::.ctor(object, native int) // 0x060015dc //IL_0033: newobj instance void Class805/Class808::.ctor(class Class487, class Class805/Delegate9) // 0x060015e5 //IL_0038: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32, class Class805/Class808>::Add(!0, !1) // 0x0a000b63 if (!dictMethod.HasBody || !dictMethod.Body.HasInstructions) throw new Exception("Dictionary method has no instructions"); IList<Instruction[]> subsequences = Helpers.FindOpCodePatterns(dictMethod.Body.Instructions, DictionaryAddPattern); // Remove this check later..? if (subsequences.Count != 203) throw new Exception("Number of found subsequences (DictionaryAddPattern) != 203 (expected value)"); List<VirtualOpCode> vInstructions = new List<VirtualOpCode>(); TypeDef containerType = null; // Each series of instructions represents a virtualized instruction foreach(var instrs in subsequences) { VirtualOpCode vInstruction = new VirtualOpCode(); containerType = ((FieldDef)instrs[2].Operand).FieldType.TryGetTypeDef(); // ldfld FieldDef instructionField = ((FieldDef)instrs[3].Operand); // ldfld MethodDef delegateMethod = ((MethodDef)instrs[9].Operand); // ldftn vInstruction.Parent = module; vInstruction.DictionaryMethod = dictMethod; vInstruction.ContainerType = containerType; vInstruction.InstructionField = instructionField; vInstruction.DelegateMethod = delegateMethod; vInstructions.Add(vInstruction); } if (containerType == null) throw new Exception("Container type cannot be null"); // Get the container .ctor method MethodDef containerCtor = null; foreach(var m in containerType.FindMethods(".ctor")) { containerCtor = m; break; } if (containerCtor == null) throw new Exception("Container .ctor method cannot be found"); // Each field construction looks like this: //IL_0000: ldarg.0 // [0] //IL_0001: ldc.i4 1550052828 //IL_0006: ldc.i4.5 //IL_0007: newobj instance void Class487::.ctor(int32, valuetype Enum2) // 0x06000ac1 //IL_000c: stfld class Class487 Class33::class487_47 // 0x04000067 if (!containerCtor.HasBody || !containerCtor.Body.HasInstructions) throw new Exception("Container .ctor method has no instructions"); if (containerCtor.Body.Instructions.Count < (vInstructions.Count * 5)) throw new Exception("Container .ctor not large enough for all virtual instructions"); // 5 instructions per sequence, with 3 trailing instructions int subsequenceCount = (containerCtor.Body.Instructions.Count - 3) / 5; // This makes a bit of an assumption.. for(int i = 0; i < subsequenceCount; i++) { // Grab the subsequence List<Instruction> subsequence = new List<Instruction>(); for (int j = 0; j < 5; j++) subsequence.Add(containerCtor.Body.Instructions[(i * 5) + j]); if (subsequence[0].OpCode.Code != Code.Ldarg_0) throw new Exception("Unexpected opcode in container .ctor subsequence"); Int32 virtualOpCode = Helpers.GetLdcOperand(subsequence[1]); Int32 operandType = Helpers.GetLdcOperand(subsequence[2]); FieldDef instructionField = (FieldDef)subsequence[4].Operand; // Find virtual instruction with matching instruction field MD token to set foreach(var vInstr in vInstructions) { if(vInstr.InstructionField.MDToken == instructionField.MDToken) { vInstr.HasVirtualCode = true; vInstr.VirtualCode = virtualOpCode; vInstr.VirtualOperandType = operandType; vInstr.TrySetIdentify(); // Try to identify and set original opcode break; } } } return vInstructions.ToArray(); }
public Devirtualizer(EazModule module, DevirtualizeOptions options, ILogger logger) : this(module, options, null, logger) { }
/// <summary> /// Print out information about a devirtualization attempt. /// </summary> /// <param name="options">MonoOptions set from passed command-line arguments</param> /// <param name="module">EazModule</param> /// <param name="attempt">Data about the devirtualization attempt</param> static void PrintAttempt(MonoOptions options, EazModule module, DevirtualizeAttempt attempt) { var reader = attempt.Reader; var method = attempt.Method; var stub = attempt.VirtualizedMethod; var body = attempt.MethodBody; IList <Local> locals = attempt.Successful ? body.Variables : reader.Locals; IList <ExceptionHandler> handlers = attempt.Successful ? body.ExceptionHandlers : reader.ExceptionHandlers; IList <Instruction> instructions = attempt.Successful ? body.Instructions : reader.Instructions; // Message prefix String prefix; switch (options.Action) { case ProgramAction.Devirtualize: prefix = "Devirtualized"; break; case ProgramAction.Methods: default: prefix = "Found"; break; } Console.WriteLine("{0} {1} (MDToken = 0x{2:X8})", prefix, method.FullName, method.MDToken.Raw); if (options.Action == ProgramAction.Methods || options.Verbose) { Console.WriteLine("--> Position string: {0}", stub.PositionString); Console.WriteLine("--> Position: {0} (0x{0:X8})", stub.Position); Console.WriteLine("--> Resource: {0}", stub.ResourceStringId); Console.WriteLine("--> Crypto key: {0}", stub.ResourceCryptoKey); Console.WriteLine("--> Actual method size: {0} (0x{0:X8})", reader.CodeSize); if (options.Action == ProgramAction.Methods) { PrintAttemptSuccess(options, module, attempt); } } if (options.Action == ProgramAction.Methods || options.Verbose) { Console.WriteLine(); // Print locals if (locals.Count > 0) { Int32 index = 0; Console.WriteLine("Locals:"); Console.WriteLine("-------"); foreach (var local in locals) { Console.WriteLine("local[{0}]: {1}", index++, local.Type.FullName); } Console.WriteLine(); } // Print exception handlers if (handlers.Count > 0) { Int32 index = 0; Console.WriteLine("Exception Handlers:"); Console.WriteLine("-------------------"); foreach (var handler in handlers) { if (handler.CatchType != null) { Console.WriteLine("handler[{0}]: HandlerType = {1}, CatchType = {2}", index++, handler.HandlerType, handler.CatchType); } else { Console.WriteLine("handler[{0}]: HandlerType = {1}", index++, handler.HandlerType); } Console.WriteLine("--> Try: [{0}, {1}]", handler.TryStart, handler.TryEnd); Console.WriteLine("--> Handler: [{0}, {1}]", handler.HandlerStart, handler.HandlerEnd); Console.WriteLine("--> Filter: {0}", handler.FilterStart); } Console.WriteLine(); } // Print instructions if (instructions != null && instructions.Count > 0) { Console.WriteLine("Instructions:"); Console.WriteLine("-------------"); foreach (var instr in instructions) { Console.WriteLine(instr); } Console.WriteLine(); } // Print out exception, if any if (!attempt.Successful && !attempt.WasInstructionUnknown) { Console.Write(attempt.Exception); Console.WriteLine(); Console.WriteLine(); } } if (!(options.Action == ProgramAction.Devirtualize && !options.Verbose)) { Console.WriteLine(); } }
/// <summary> /// Print out information about a devirtualization attempt. /// </summary> /// <param name="options">MonoOptions set from passed command-line arguments</param> /// <param name="module">EazModule</param> /// <param name="attempt">Data about the devirtualization attempt</param> static void PrintAttempt(MonoOptions options, EazModule module, DevirtualizeAttempt attempt) { var reader = attempt.Reader; var method = attempt.Method; var stub = attempt.VirtualizedMethod; var body = attempt.MethodBody; IList<Local> locals = attempt.Successful ? body.Variables : reader.Locals; IList<ExceptionHandler> handlers = attempt.Successful ? body.ExceptionHandlers : reader.ExceptionHandlers; IList<Instruction> instructions = attempt.Successful ? body.Instructions : reader.Instructions; // Message prefix String prefix; switch(options.Action) { case ProgramAction.Devirtualize: prefix = "Devirtualized"; break; case ProgramAction.Methods: default: prefix = "Found"; break; } Console.WriteLine("{0} {1} (MDToken = 0x{2:X8})", prefix, method.FullName, method.MDToken.Raw); if (options.Action == ProgramAction.Methods || options.Verbose) { Console.WriteLine("--> Position string: {0}", stub.PositionString); Console.WriteLine("--> Position: {0} (0x{0:X8})", stub.Position); Console.WriteLine("--> Resource: {0}", stub.ResourceStringId); Console.WriteLine("--> Crypto key: {0}", stub.ResourceCryptoKey); Console.WriteLine("--> Actual method size: {0} (0x{0:X8})", reader.CodeSize); if (options.Action == ProgramAction.Methods) PrintAttemptSuccess(options, module, attempt); } if (options.Action == ProgramAction.Methods || options.Verbose) { Console.WriteLine(); // Print locals if (locals.Count > 0) { Int32 index = 0; Console.WriteLine("Locals:"); Console.WriteLine("-------"); foreach (var local in locals) Console.WriteLine("local[{0}]: {1}", index++, local.Type.FullName); Console.WriteLine(); } // Print exception handlers if (handlers.Count > 0) { Int32 index = 0; Console.WriteLine("Exception Handlers:"); Console.WriteLine("-------------------"); foreach (var handler in handlers) { if (handler.CatchType != null) Console.WriteLine("handler[{0}]: HandlerType = {1}, CatchType = {2}", index++, handler.HandlerType, handler.CatchType); else Console.WriteLine("handler[{0}]: HandlerType = {1}", index++, handler.HandlerType); Console.WriteLine("--> Try: [{0}, {1}]", handler.TryStart, handler.TryEnd); Console.WriteLine("--> Handler: [{0}, {1}]", handler.HandlerStart, handler.HandlerEnd); Console.WriteLine("--> Filter: {0}", handler.FilterStart); } Console.WriteLine(); } // Print instructions if (instructions != null && instructions.Count > 0) { Console.WriteLine("Instructions:"); Console.WriteLine("-------------"); foreach (var instr in instructions) Console.WriteLine(instr); Console.WriteLine(); } // Print out exception, if any if (!attempt.Successful && !attempt.WasInstructionUnknown) { Console.Write(attempt.Exception); Console.WriteLine(); Console.WriteLine(); } } if (!(options.Action == ProgramAction.Devirtualize && !options.Verbose)) Console.WriteLine(); }
/// <summary> /// Construct an AttributeInjector for a specific module. /// </summary> /// <param name="module">Target module</param> public AttributeInjector(EazModule module) { this.EazModule = module; }
/// <summary> /// Construct a MethodStub from an existing method. /// </summary> /// <param name="module">Parent module</param> /// <param name="method">Stub method</param> public MethodStub(EazModule module, MethodDef method) { this.Parent = module; this.Method = method; this.Initialize(); }
static Boolean TryLoadModule(String path, ILogger logger, out EazModule module) { try { ModuleDefMD moduleDef = ModuleDefMD.Load(path); AssemblyResolver asmResolver = new AssemblyResolver(); ModuleContext modCtx = new ModuleContext(asmResolver); // All resolved assemblies will also get this same modCtx asmResolver.DefaultModuleContext = modCtx; moduleDef.Context = modCtx; module = new EazModule(moduleDef, logger); } catch (IOException e) { // Console.WriteLine(e.Message); Console.Write(e); module = null; return false; } return true; }
static Boolean TryLoadModule(String path, out EazModule module) { return TryLoadModule(path, null, out module); }
public Devirtualizer(EazModule module, DevirtualizeOptions options) : this(module, options, null) { }
public Devirtualizer(EazModule module, ILogger logger) : this(module, DevirtualizeOptions.Nothing, logger) { }
public Devirtualizer(EazModule module, IList<Type> fixers, ILogger logger) : this(module, DevirtualizeOptions.Nothing, fixers, logger) { }
public Devirtualizer(EazModule module, IList <Type> fixers, ILogger logger) : this(module, DevirtualizeOptions.Nothing, fixers, logger) { }
/// <summary> /// Find all virtual instructions given the main virtualization type. /// </summary> /// <param name="module">Module</param> /// <param name="virtualizationType">Main virtualization type (class)</param> /// <returns>All found virtualization instructions</returns> public static IList <VirtualOpCode> FindAllInstructions(EazModule module, TypeDef virtualizationType) { if (module == null || virtualizationType == null) { throw new ArgumentNullException(); } // Find dictionary method MethodDef dictMethod = null; var methods = virtualizationType.Methods; foreach (var method in methods) { if (method.IsPrivate && !method.IsStatic && method.Parameters.Count == 1 && method.HasReturnType && method.ReturnType.FullName.StartsWith("System.Collections.Generic.Dictionary")) { dictMethod = method; break; } } if (dictMethod == null) { throw new Exception("Unable to find dictionary method"); } // Each dictionary addition looks like this: //IL_000b: ldloc.0 // [0] //IL_000c: ldarg.0 // [0] //IL_000d: ldfld class Class33 Class805::class33_0 // 0x0400092c // TypeDef of this class (Class33) is important //IL_0012: ldfld class Class487 Class33::class487_162 // 0x040000da // FieldDef of this field (class487_162) is important //IL_0017: callvirt instance int32 Class487::method_1() // 0x06000ac3 //IL_001c: ldarg.0 // [0] //IL_001d: ldfld class Class33 Class805::class33_0 // 0x0400092c //IL_0022: ldfld class Class487 Class33::class487_162 // 0x040000da //IL_0027: ldarg.0 // [0] //IL_0028: ldftn instance void Class805::method_281(class Class1) // 0x060015ca //IL_002e: newobj instance void Class805/Delegate9::.ctor(object, native int) // 0x060015dc //IL_0033: newobj instance void Class805/Class808::.ctor(class Class487, class Class805/Delegate9) // 0x060015e5 //IL_0038: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32, class Class805/Class808>::Add(!0, !1) // 0x0a000b63 if (!dictMethod.HasBody || !dictMethod.Body.HasInstructions) { throw new Exception("Dictionary method has no instructions"); } IList <Instruction[]> subsequences = Helpers.FindOpCodePatterns(dictMethod.Body.Instructions, DictionaryAddPattern); // Remove this check later..? if (subsequences.Count != 203) { throw new Exception(String.Format( "Number of found subsequences (DictionaryAddPattern) {0} != 203 (expected value)", subsequences.Count)); } List <VirtualOpCode> vInstructions = new List <VirtualOpCode>(); TypeDef containerType = null; // Each series of instructions represents a virtualized instruction foreach (var instrs in subsequences) { VirtualOpCode vInstruction = new VirtualOpCode(); containerType = ((FieldDef)instrs[2].Operand).FieldType.TryGetTypeDef(); // ldfld FieldDef instructionField = ((FieldDef)instrs[3].Operand); // ldfld MethodDef delegateMethod = ((MethodDef)instrs[9].Operand); // ldftn vInstruction.Parent = module; vInstruction.DictionaryMethod = dictMethod; vInstruction.ContainerType = containerType; vInstruction.InstructionField = instructionField; vInstruction.DelegateMethod = delegateMethod; vInstructions.Add(vInstruction); } if (containerType == null) { throw new Exception("Container type cannot be null"); } // Get the container .ctor method MethodDef containerCtor = null; foreach (var m in containerType.FindMethods(".ctor")) { containerCtor = m; break; } if (containerCtor == null) { throw new Exception("Container .ctor method cannot be found"); } // Each field construction looks like this: //IL_0000: ldarg.0 // [0] //IL_0001: ldc.i4 1550052828 //IL_0006: ldc.i4.5 //IL_0007: newobj instance void Class487::.ctor(int32, valuetype Enum2) // 0x06000ac1 //IL_000c: stfld class Class487 Class33::class487_47 // 0x04000067 if (!containerCtor.HasBody || !containerCtor.Body.HasInstructions) { throw new Exception("Container .ctor method has no instructions"); } if (containerCtor.Body.Instructions.Count < (vInstructions.Count * 5)) { throw new Exception("Container .ctor not large enough for all virtual instructions"); } // 5 instructions per sequence, with 3 trailing instructions int subsequenceCount = (containerCtor.Body.Instructions.Count - 3) / 5; // This makes a bit of an assumption.. for (int i = 0; i < subsequenceCount; i++) { // Grab the subsequence List <Instruction> subsequence = new List <Instruction>(); for (int j = 0; j < 5; j++) { subsequence.Add(containerCtor.Body.Instructions[(i * 5) + j]); } if (subsequence[0].OpCode.Code != Code.Ldarg_0) { throw new Exception("Unexpected opcode in container .ctor subsequence"); } Int32 virtualOpCode = Helpers.GetLdcOperand(subsequence[1]); Int32 operandType = Helpers.GetLdcOperand(subsequence[2]); FieldDef instructionField = (FieldDef)subsequence[4].Operand; // Find virtual instruction with matching instruction field MD token to set foreach (var vInstr in vInstructions) { if (vInstr.InstructionField.MDToken == instructionField.MDToken) { vInstr.HasVirtualCode = true; vInstr.VirtualCode = virtualOpCode; vInstr.VirtualOperandType = operandType; vInstr.TrySetIdentify(); // Try to identify and set original opcode break; } } } return(vInstructions.ToArray()); }