public static int Execute(ModuleDef module, Module reflModule) { if (module is null) { throw new ArgumentNullException(nameof(module)); } if (reflModule is null) { throw new ArgumentNullException(nameof(reflModule)); } var decrypters = new HashSet <MethodDef>(); foreach (var method in module.GlobalType.Methods) { if (!method.HasBody) { continue; } if (!method.IsStatic || !method.HasGenericParameters) { continue; } if (method.ReturnType.ElementType != ElementType.MVar || method.Parameters.Count != 1 || method.Parameters[0].Type.ElementType != ElementType.U4) { continue; } decrypters.Add(method); } var oldAssemblyResolver = module.Context.AssemblyResolver; var oldResolver = module.Context.Resolver; module.Context.AssemblyResolver = NullResolver.Instance; module.Context.Resolver = new Resolver(NullResolver.Instance); int count = 0; foreach (var method in module.EnumerateAllMethods()) { if (!method.HasBody) { continue; } if (decrypters.Contains(method)) { continue; } for (int i = 1; i < method.Body.Instructions.Count; i++) { var instructions = method.Body.Instructions; var instruction = instructions[i]; if (instruction.OpCode.Code != Code.Call) { continue; } if (!(instruction.Operand is MethodSpec operandMethod)) { continue; } if (!(operandMethod.Method is MethodDef operandMethodDef)) { continue; } if (!decrypters.Contains(operandMethodDef)) { continue; } var ldKeyInstr = default(Instruction); int key = 0; for (int j = 1; j <= i; j++) { var instr = instructions[i - j]; if (instr.OpCode.Code == Code.Nop) { continue; } if (instr.OpCode.Code != Code.Ldc_I4) { break; } ldKeyInstr = instr; key = (int)instr.Operand; break; } if (ldKeyInstr is null) { Logger.LogError($"[0x{method.MDToken.Raw:X8}] 无法找到常量解密器参数"); continue; } var constantType = operandMethod.GenericInstMethodSig.GenericArguments[0].RemoveModifiers(); var elementType = constantType.ElementType; var arrayType = default(TypeSig); var arrayElementType = default(ElementType); var reflType = ToType(elementType); if (reflType is null) { if (elementType != ElementType.SZArray) { Logger.LogError($"[0x{method.MDToken.Raw:X8}] 无效常量解密器泛型参数"); continue; } var arraySig = (SZArraySig)operandMethod.GenericInstMethodSig.GenericArguments[0]; arrayType = arraySig.Next.RemoveModifiers(); arrayElementType = arrayType.ElementType; reflType = ToType(arrayElementType); if (reflType is null) { Logger.LogError($"[0x{method.MDToken.Raw:X8}] 无效常量解密器泛型参数"); continue; } } object value; try { var reflMethod = reflModule.ResolveMethod(operandMethod.MDToken.ToInt32()); value = reflMethod.Invoke(null, new object[] { (uint)key }); } catch (Exception ex) { Logger.LogError($"[0x{method.MDToken.Raw:X8}] 调用常量解密器失败"); Logger.LogException(ex); continue; } if (value is null) { Logger.LogError($"[0x{method.MDToken.Raw:X8}] 常量解密器返回值为空"); continue; } if (elementType != ElementType.SZArray) { switch (elementType) { case ElementType.Boolean: case ElementType.Char: case ElementType.I1: case ElementType.U1: case ElementType.I2: case ElementType.U2: case ElementType.I4: case ElementType.U4: instruction.OpCode = OpCodes.Ldc_I4; instruction.Operand = Convert.ToInt32(value); break; case ElementType.I8: case ElementType.U8: instruction.OpCode = OpCodes.Ldc_I8; instruction.Operand = Convert.ToInt64(value); break; case ElementType.R4: instruction.OpCode = OpCodes.Ldc_R4; instruction.Operand = value; break; case ElementType.R8: instruction.OpCode = OpCodes.Ldc_R8; instruction.Operand = value; break; case ElementType.String: instruction.OpCode = OpCodes.Ldstr; instruction.Operand = value; break; default: throw new InvalidOperationException(); } } else { int elementSize; switch (arrayElementType) { case ElementType.Boolean: case ElementType.I1: case ElementType.U1: elementSize = 1; break; case ElementType.Char: case ElementType.I2: case ElementType.U2: elementSize = 2; break; case ElementType.I4: case ElementType.U4: case ElementType.R4: elementSize = 4; break; case ElementType.I8: case ElementType.U8: case ElementType.R8: elementSize = 8; break; default: throw new InvalidOperationException(); } byte[] data = new byte[((Array)value).Length * elementSize]; Buffer.BlockCopy((Array)value, 0, data, 0, data.Length); var arrayInitializer = CreateArrayInitializer(module, arrayType.ToTypeDefOrRef(), ((Array)value).Length, data); instructions.InsertRange(i, arrayInitializer); instruction.OpCode = OpCodes.Nop; instruction.Operand = null; i += arrayInitializer.Count; } ldKeyInstr.OpCode = OpCodes.Nop; ldKeyInstr.Operand = null; count++; } } module.Context.AssemblyResolver = oldAssemblyResolver; module.Context.Resolver = oldResolver; foreach (var decrypter in decrypters) { decrypter.DeclaringType.Methods.Remove(decrypter); } return(count); }
/// <summary> /// Type conversation (arguments and return value are the same): /// refType -> no conv /// refType* -> conv_i /// valType -> ldarga /// valType* -> conv_i /// genType -> ldarga (we should dereference in runtime if it is reference type) /// genType* -> conv_i /// /// Calling conversation /// arguments = method arguments + method return buffer (if method has return value) /// </summary> /// <returns></returns> public int Link() { foreach (var method in _module.EnumerateAllMethods()) { var parameters = method.Parameters; if (parameters.Count > ushort.MaxValue) { throw new NotSupportedException(); } var methodInstantiation = method.GenericParameters; if (methodInstantiation.Count > byte.MaxValue) { throw new NotSupportedException(); } var type = method.DeclaringType; var typeInstantiation = type.GenericParameters; if (typeInstantiation.Count > byte.MaxValue) { throw new NotSupportedException(); } #if DEBUG for (int i = 0; i < typeInstantiation.Count; i++) { System.Diagnostics.Debug.Assert(typeInstantiation[i].Number == i); } for (int i = 0; i < methodInstantiation.Count; i++) { System.Diagnostics.Debug.Assert(methodInstantiation[i].Number == i); } #endif _instructions = new List <Instruction>(); _pinnedArguments = new List <Local>(); _returnBuffer = null; EmitPinArguments(parameters); // pin arguments EmitInitCall(method, parameters); // load moduleId, load methodToken EmitLoadArguments(parameters); // load arguments EmitLoadReturnBuffer(method); // load return buffer EmitLoadTypeArgument(type, typeInstantiation); // load typeInstantiation EmitLoadMethodArgument(method, methodInstantiation); // load methodInstantiation EmitInstruction(OpCodes.Call, _dispatch); // call InterpreterStub.Dispatch EmitUnpinArguments(); // unpin arguments EmitGetReturnValue(method); // get return value EmitInstruction(OpCodes.Ret); // ret var locals = new LocalList(_pinnedArguments); if (!(_returnBuffer is null)) { locals.Add(_returnBuffer); } var body = new CilBody(true, _instructions, EmptyExceptionHandlers, locals); if (!(method.Body is null)) { method.FreeMethodBody(); method.Body = body; } method.Attributes &= ~MethodAttributes.UnmanagedExport; if ((method.ImplAttributes & (MethodImplAttributes.Native | MethodImplAttributes.Unmanaged)) == (MethodImplAttributes.Native | MethodImplAttributes.Unmanaged)) { method.Body = body; method.ImplAttributes &= ~(MethodImplAttributes.Native | MethodImplAttributes.Unmanaged | MethodImplAttributes.PreserveSig); method.ImplAttributes |= MethodImplAttributes.IL; } } _module.Resources.Clear(); if ((_module.Cor20HeaderFlags & ComImageFlags.NativeEntryPoint) == ComImageFlags.NativeEntryPoint) { _module.NativeEntryPoint = 0; } _module.Cor20HeaderFlags &= ~(ComImageFlags.ILOnly | ComImageFlags.Bit32Preferred | ComImageFlags.Bit32Required | ComImageFlags.NativeEntryPoint); _module.Cor20HeaderFlags |= ComImageFlags.ILOnly; if (!(_module.VTableFixups is null)) { _module.VTableFixups.VTables.Clear(); } return(_moduleId); }
public static int Execute(ModuleDef module, bool ignoreAccess, bool removeProxyMethods) { if (module is null) { throw new ArgumentNullException(nameof(module)); } var proxyMethods = new Dictionary <MethodDef, Instruction>(); foreach (var method in module.EnumerateAllMethods()) { if (!method.HasBody) { continue; } if (!(ignoreAccess || method.IsPrivateScope)) { continue; } bool isProxy = true; var realInstruction = default(Instruction); foreach (var instruction in method.Body.Instructions) { switch (instruction.OpCode.Code) { case Code.Nop: case Code.Ldarg: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: case Code.Ldarg_S: case Code.Ldarga: case Code.Ldarga_S: case Code.Ret: continue; case Code.Call: case Code.Callvirt: case Code.Newobj: if (realInstruction is null) { realInstruction = instruction; continue; } break; } isProxy = false; break; } if (!isProxy) { Logger.LogWarning($"[0x{method.MDToken.Raw:X8}] {method} 不是代理方法(可能判断错误)"); continue; } proxyMethods.Add(method, realInstruction); } var oldAssemblyResolver = module.Context.AssemblyResolver; var oldResolver = module.Context.Resolver; module.Context.AssemblyResolver = NullResolver.Instance; module.Context.Resolver = new Resolver(NullResolver.Instance); foreach (var method in module.EnumerateAllMethods()) { if (!method.HasBody) { continue; } if (proxyMethods.ContainsKey(method)) { continue; } foreach (var instruction in method.Body.Instructions) { if (instruction.OpCode.Code != Code.Call) { continue; } var operandMethod = ((IMethod)instruction.Operand).ResolveMethodDef(); if (operandMethod is null) { continue; } if (!proxyMethods.TryGetValue(operandMethod, out var realCall)) { continue; } instruction.OpCode = realCall.OpCode; instruction.Operand = realCall.Operand; } } module.Context.AssemblyResolver = oldAssemblyResolver; module.Context.Resolver = oldResolver; if (removeProxyMethods) { foreach (var proxyMethod in proxyMethods.Keys) { proxyMethod.DeclaringType.Methods.Remove(proxyMethod); } } return(proxyMethods.Count); }