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);
            }
Beispiel #3
0
        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);
        }