protected bool CheckSameMethods(IMethod method, MethodDef methodToInline, int ignoreLastMethodToInlineArgs) { var methodToInlineArgs = methodToInline.Parameters; var methodArgs = DotNetUtils.GetArgs(method); bool hasImplicitThis = method.MethodSig.ImplicitThis; if (methodToInlineArgs.Count - ignoreLastMethodToInlineArgs != methodArgs.Count) { return(false); } for (int i = 0; i < methodArgs.Count; i++) { var methodArg = methodArgs[i]; var methodToInlineArg = GetArgType(methodToInline, methodToInlineArgs[i].Type); if (!IsCompatibleType(i, methodArg, methodToInlineArg)) { if (i != 0 || !hasImplicitThis) { return(false); } if (!IsCompatibleValueThisPtr(methodArg, methodToInlineArg)) { return(false); } } } return(true); }
bool FindArgs(CallResult callResult) { var block = callResult.block; var method = callResult.GetMethodRef(); var methodArgs = DotNetUtils.GetArgs(method); int numArgs = methodArgs.Count; var args = new object[numArgs]; int instrIndex = callResult.callEndIndex - 1; for (int i = numArgs - 1; i >= 0; i--) { object arg = null; if (!GetArg(method, block, ref arg, ref instrIndex)) { return(false); } if (arg is int) { arg = FixIntArg(methodArgs[i], (int)arg); } else if (arg is long) { arg = FixIntArg(methodArgs[i], (long)arg); } args[i] = arg; } callResult.args = args; callResult.callStartIndex = instrIndex + 1; return(true); }
protected InstructionPatcher TryInlineOtherMethod(int patchIndex, MethodDef methodToInline, Instruction instr, int instrIndex, int popLastArgs) { int loadIndex = 0; int methodArgsCount = DotNetUtils.GetArgsCount(methodToInline); bool foundLdarga = false; while (instr != null && loadIndex < methodArgsCount) { bool isLdarg = true; switch (instr.OpCode.Code) { case Code.Ldarg: case Code.Ldarg_S: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: break; case Code.Ldarga: case Code.Ldarga_S: foundLdarga = true; break; default: isLdarg = false; break; } if (!isLdarg) { break; } if (instr.GetParameterIndex() != loadIndex) { return(null); } loadIndex++; instr = DotNetUtils.GetInstruction(methodToInline.Body.Instructions, ref instrIndex); instr = OnAfterLoadArg(methodToInline, instr, ref instrIndex); } if (instr == null || loadIndex != methodArgsCount - popLastArgs) { return(null); } switch (instr.OpCode.Code) { case Code.Call: case Code.Callvirt: if (foundLdarga) { return(null); } var callInstr = instr; var calledMethod = callInstr.Operand as IMethod; if (calledMethod == null) { return(null); } if (!IsCompatibleType(-1, calledMethod.MethodSig.RetType, methodToInline.MethodSig.RetType)) { return(null); } if (!CheckSameMethods(calledMethod, methodToInline, popLastArgs)) { return(null); } if (!HasAccessTo(instr.Operand)) { return(null); } return(new InstructionPatcher(patchIndex, instrIndex, callInstr)); case Code.Newobj: if (foundLdarga) { return(null); } var newobjInstr = instr; var ctor = newobjInstr.Operand as IMethod; if (ctor == null) { return(null); } if (!IsCompatibleType(-1, ctor.DeclaringType, methodToInline.MethodSig.RetType)) { return(null); } var methodArgs = methodToInline.Parameters; var calledMethodArgs = DotNetUtils.GetArgs(ctor); if (methodArgs.Count + 1 - popLastArgs != calledMethodArgs.Count) { return(null); } for (int i = 1; i < calledMethodArgs.Count; i++) { if (!IsCompatibleType(i, calledMethodArgs[i], methodArgs[i - 1].Type)) { return(null); } } if (!HasAccessTo(instr.Operand)) { return(null); } return(new InstructionPatcher(patchIndex, instrIndex, newobjInstr)); case Code.Ldfld: case Code.Ldflda: case Code.Ldftn: case Code.Ldvirtftn: case Code.Ldlen: case Code.Initobj: case Code.Isinst: case Code.Castclass: case Code.Newarr: case Code.Ldtoken: case Code.Unbox_Any: var ldInstr = instr; if (methodArgsCount != 1) { return(null); } if (instr.OpCode.OperandType != OperandType.InlineNone && !HasAccessTo(instr.Operand)) { return(null); } return(new InstructionPatcher(patchIndex, instrIndex, ldInstr)); default: return(null); } }
bool DeobfuscateFields() { foreach (var info in fieldWrites.Values) { info.Clear(); } foreach (var method in allMethods) { if (method.Body == null) { continue; } var instructions = method.Body.Instructions; for (int i = 0; i < instructions.Count; i++) { var instr = instructions[i]; TypeSig fieldType = null; TypeInfo <FieldDef> info = null; IField field; switch (instr.OpCode.Code) { case Code.Stfld: case Code.Stsfld: field = instr.Operand as IField; if (field == null) { continue; } if (!fieldWrites.TryGetValue(field, out info)) { continue; } bool wasNewobj; fieldType = GetLoadedType(info.arg.DeclaringType, method, instructions, i, out wasNewobj); if (fieldType == null) { continue; } info.Add(fieldType, wasNewobj); break; case Code.Call: case Code.Calli: case Code.Callvirt: case Code.Newobj: var pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i); var calledMethod = instr.Operand as IMethod; if (calledMethod == null) { continue; } var calledMethodDefOrRef = calledMethod as IMethodDefOrRef; var calledMethodSpec = calledMethod as MethodSpec; if (calledMethodSpec != null) { calledMethodDefOrRef = calledMethodSpec.Method; } if (calledMethodDefOrRef == null) { continue; } IList <TypeSig> calledMethodArgs = DotNetUtils.GetArgs(calledMethodDefOrRef); calledMethodArgs = DotNetUtils.ReplaceGenericParameters(calledMethodDefOrRef.DeclaringType.TryGetGenericInstSig(), calledMethodSpec, calledMethodArgs); for (int j = 0; j < pushedArgs.NumValidArgs; j++) { var pushInstr = pushedArgs.GetEnd(j); if (pushInstr.OpCode.Code != Code.Ldfld && pushInstr.OpCode.Code != Code.Ldsfld) { continue; } field = pushInstr.Operand as IField; if (field == null) { continue; } if (!fieldWrites.TryGetValue(field, out info)) { continue; } fieldType = calledMethodArgs[calledMethodArgs.Count - 1 - j]; if (!IsValidType(info.arg.DeclaringType, fieldType)) { continue; } info.Add(fieldType); } break; default: continue; } } } bool modified = false; var removeThese = new List <FieldDef>(); foreach (var info in fieldWrites.Values) { if (info.UpdateNewType(module)) { removeThese.Add(info.arg); GetUpdatedField(info.arg).newFieldType = info.newType; info.arg.FieldSig.Type = info.newType; modified = true; } } foreach (var field in removeThese) { fieldWrites.Remove(field); } return(modified); }
void DeobfuscateMethod(MethodDef method) { if (!method.IsStatic || method.Body == null) { return; } bool fixReturnType = IsUnknownType(method.MethodSig.GetRetType()); argInfos.Clear(); foreach (var arg in method.Parameters) { if (arg.IsHiddenThisParameter) { continue; } if (!IsUnknownType(arg)) { continue; } argInfos[arg] = new TypeInfo <Parameter>(arg); } if (argInfos.Count == 0 && !fixReturnType) { return; } var methodParams = method.Parameters; PushedArgs pushedArgs; var instructions = method.Body.Instructions; for (int i = 0; i < instructions.Count; i++) { var instr = instructions[i]; switch (instr.OpCode.Code) { case Code.Ret: if (!fixReturnType) { break; } bool wasNewobj; var type = GetLoadedType(method, method, instructions, i, out wasNewobj); if (type == null) { break; } methodReturnInfo.Add(type); break; case Code.Call: case Code.Calli: case Code.Callvirt: case Code.Newobj: pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i); var calledMethod = instr.Operand as IMethod; if (calledMethod == null) { break; } var calledMethodParams = DotNetUtils.GetArgs(calledMethod); for (int j = 0; j < pushedArgs.NumValidArgs; j++) { int calledMethodParamIndex = calledMethodParams.Count - j - 1; var ldInstr = pushedArgs.GetEnd(j); switch (ldInstr.OpCode.Code) { case Code.Ldarg: case Code.Ldarg_S: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: AddMethodArgType(method, GetParameter(methodParams, ldInstr), DotNetUtils.GetArg(calledMethodParams, calledMethodParamIndex)); break; default: break; } } break; case Code.Castclass: pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) { break; } AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), instr.Operand as ITypeDefOrRef); break; case Code.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) { break; } AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), instr.GetLocal(method.Body.Variables)); break; case Code.Stsfld: pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) { break; } AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), instr.Operand as IField); break; case Code.Stfld: pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs >= 1) { var field = instr.Operand as IField; AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), field); if (pushedArgs.NumValidArgs >= 2 && field != null) { AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(1)), field.DeclaringType); } } break; case Code.Ldfld: case Code.Ldflda: pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) { break; } AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), instr.Operand as IField); break; //TODO: For better results, these should be checked: case Code.Starg: case Code.Starg_S: case Code.Ldelema: case Code.Ldelem: case Code.Ldelem_I: case Code.Ldelem_I1: case Code.Ldelem_I2: case Code.Ldelem_I4: case Code.Ldelem_I8: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_Ref: case Code.Ldelem_U1: case Code.Ldelem_U2: case Code.Ldelem_U4: case Code.Ldind_I: case Code.Ldind_I1: case Code.Ldind_I2: case Code.Ldind_I4: case Code.Ldind_I8: case Code.Ldind_R4: case Code.Ldind_R8: case Code.Ldind_Ref: case Code.Ldind_U1: case Code.Ldind_U2: case Code.Ldind_U4: case Code.Ldobj: case Code.Stelem: case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Ref: case Code.Stind_I: case Code.Stind_I1: case Code.Stind_I2: case Code.Stind_I4: case Code.Stind_I8: case Code.Stind_R4: case Code.Stind_R8: case Code.Stind_Ref: case Code.Stobj: default: break; } } }