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]; TypeReference fieldType = null; TypeInfo <FieldDefinition> info = null; FieldReference field; switch (instr.OpCode.Code) { case Code.Stfld: case Code.Stsfld: field = instr.Operand as FieldReference; if (field == null) { continue; } if (!fieldWrites.TryGetValue(new FieldReferenceAndDeclaringTypeKey(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 MethodReference; if (calledMethod == null) { continue; } IList <TypeReference> calledMethodArgs = DotNetUtils.getArgs(calledMethod); calledMethodArgs = DotNetUtils.replaceGenericParameters(calledMethod.DeclaringType as GenericInstanceType, calledMethod as GenericInstanceMethod, 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 FieldReference; if (field == null) { continue; } if (!fieldWrites.TryGetValue(new FieldReferenceAndDeclaringTypeKey(field), out info)) { continue; } fieldType = calledMethodArgs[calledMethodArgs.Count - 1 - j]; if (!isValidType(info.arg.DeclaringType, fieldType)) { continue; } info.add(fieldType); } break; default: continue; } } } bool changed = false; var removeThese = new List <FieldDefinition>(); foreach (var info in fieldWrites.Values) { if (info.updateNewType(module)) { removeThese.Add(info.arg); getUpdatedField(info.arg).newFieldType = info.newType; info.arg.FieldType = info.newType; changed = true; } } foreach (var field in removeThese) { fieldWrites.Remove(new FieldReferenceAndDeclaringTypeKey(field)); } return(changed); }
public static TypeReference getLoadedType(MethodDefinition method, IList <Instruction> instructions, int instrIndex, int argIndexFromEnd, out bool wasNewobj) { wasNewobj = false; var pushedArgs = MethodStack.getPushedArgInstructions(instructions, instrIndex); var pushInstr = pushedArgs.getEnd(argIndexFromEnd); if (pushInstr == null) { return(null); } TypeReference type; VariableDefinition local; switch (pushInstr.OpCode.Code) { case Code.Ldstr: type = method.Module.TypeSystem.String; break; case Code.Conv_I: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I_Un: type = method.Module.TypeSystem.IntPtr; break; case Code.Conv_U: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U_Un: type = method.Module.TypeSystem.UIntPtr; break; case Code.Conv_I8: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: type = method.Module.TypeSystem.Int64; break; case Code.Conv_U8: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: type = method.Module.TypeSystem.UInt64; break; case Code.Conv_R8: case Code.Ldc_R8: case Code.Ldelem_R8: case Code.Ldind_R8: type = method.Module.TypeSystem.Double; break; case Code.Call: case Code.Calli: case Code.Callvirt: var calledMethod = pushInstr.Operand as MethodReference; if (calledMethod == null) { return(null); } type = calledMethod.MethodReturnType.ReturnType; break; case Code.Newarr: type = pushInstr.Operand as TypeReference; if (type == null) { return(null); } type = new ArrayType(type); wasNewobj = true; break; case Code.Newobj: var ctor = pushInstr.Operand as MethodReference; if (ctor == null) { return(null); } type = ctor.DeclaringType; wasNewobj = true; break; case Code.Castclass: case Code.Isinst: case Code.Unbox_Any: case Code.Ldelem_Any: case Code.Ldobj: type = pushInstr.Operand as TypeReference; break; case Code.Ldarg: case Code.Ldarg_S: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: type = DotNetUtils.getArgType(method, pushInstr); break; case Code.Ldloc: case Code.Ldloc_S: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: local = DotNetUtils.getLocalVar(method.Body.Variables, pushInstr); if (local == null) { return(null); } type = local.VariableType; break; case Code.Ldloca: case Code.Ldloca_S: local = pushInstr.Operand as VariableDefinition; if (local == null) { return(null); } type = createByReferenceType(local.VariableType); break; case Code.Ldarga: case Code.Ldarga_S: type = createByReferenceType(DotNetUtils.getArgType(method, pushInstr)); break; case Code.Ldfld: case Code.Ldsfld: var field = pushInstr.Operand as FieldReference; if (field == null) { return(null); } type = field.FieldType; break; case Code.Ldflda: case Code.Ldsflda: var field2 = pushInstr.Operand as FieldReference; if (field2 == null) { return(null); } type = createByReferenceType(field2.FieldType); break; case Code.Ldelema: case Code.Unbox: type = createByReferenceType(pushInstr.Operand as TypeReference); break; default: return(null); } return(type); }
void deobfuscateMethod(MethodDefinition method) { if (!method.IsStatic || method.Body == null) { return; } bool fixReturnType = isUnknownType(method.MethodReturnType); argInfos.Clear(); foreach (var arg in method.Parameters) { if (!isUnknownType(arg)) { continue; } argInfos[arg] = new TypeInfo <ParameterDefinition>(arg); } if (argInfos.Count == 0 && !fixReturnType) { return; } var methodParams = DotNetUtils.getParameters(method); 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 MethodReference; if (calledMethod == null) { break; } var calledMethodParams = DotNetUtils.getParameters(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.getParameter(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 TypeReference); 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)), DotNetUtils.getLocalVar(method.Body.Variables, instr)); break; case Code.Stsfld: pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs < 1) { break; } addMethodArgType(method, getParameter(methodParams, pushedArgs.getEnd(0)), instr.Operand as FieldReference); break; case Code.Stfld: pushedArgs = MethodStack.getPushedArgInstructions(instructions, i); if (pushedArgs.NumValidArgs >= 1) { var field = instr.Operand as FieldReference; 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 FieldReference); break; //TODO: For better results, these should be checked: case Code.Starg: case Code.Starg_S: case Code.Ldelema: case Code.Ldelem_Any: 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_Any: 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; } } }
public static TypeSig getLoadedType(MethodDef method, IList <Instruction> instructions, int instrIndex, int argIndexFromEnd, out bool wasNewobj) { wasNewobj = false; var pushedArgs = MethodStack.getPushedArgInstructions(instructions, instrIndex); var pushInstr = pushedArgs.getEnd(argIndexFromEnd); if (pushInstr == null) { return(null); } TypeSig type; Local local; var corLibTypes = method.DeclaringType.Module.CorLibTypes; switch (pushInstr.OpCode.Code) { case Code.Ldstr: type = corLibTypes.String; break; case Code.Conv_I: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I_Un: type = corLibTypes.IntPtr; break; case Code.Conv_U: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U_Un: type = corLibTypes.UIntPtr; break; case Code.Conv_I8: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: type = corLibTypes.Int64; break; case Code.Conv_U8: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: type = corLibTypes.UInt64; break; case Code.Conv_R8: case Code.Ldc_R8: case Code.Ldelem_R8: case Code.Ldind_R8: type = corLibTypes.Double; break; case Code.Call: case Code.Calli: case Code.Callvirt: var calledMethod = pushInstr.Operand as IMethod; if (calledMethod == null) { return(null); } type = calledMethod.MethodSig.GetRetType(); break; case Code.Newarr: var type2 = pushInstr.Operand as ITypeDefOrRef; if (type2 == null) { return(null); } type = new SZArraySig(type2.ToTypeSig()); wasNewobj = true; break; case Code.Newobj: var ctor = pushInstr.Operand as IMethod; if (ctor == null) { return(null); } type = ctor.DeclaringType.ToTypeSig(); wasNewobj = true; break; case Code.Castclass: case Code.Isinst: case Code.Unbox_Any: case Code.Ldelem: case Code.Ldobj: type = (pushInstr.Operand as ITypeDefOrRef).ToTypeSig(); break; case Code.Ldarg: case Code.Ldarg_S: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: type = pushInstr.GetArgumentType(method.MethodSig, method.DeclaringType); break; case Code.Ldloc: case Code.Ldloc_S: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: local = pushInstr.GetLocal(method.Body.Variables); if (local == null) { return(null); } type = local.Type.RemovePinned(); break; case Code.Ldloca: case Code.Ldloca_S: local = pushInstr.Operand as Local; if (local == null) { return(null); } type = createByRefType(local.Type.RemovePinned()); break; case Code.Ldarga: case Code.Ldarga_S: type = createByRefType(pushInstr.GetArgumentType(method.MethodSig, method.DeclaringType)); break; case Code.Ldfld: case Code.Ldsfld: var field = pushInstr.Operand as IField; if (field == null || field.FieldSig == null) { return(null); } type = field.FieldSig.GetFieldType(); break; case Code.Ldflda: case Code.Ldsflda: var field2 = pushInstr.Operand as IField; if (field2 == null || field2.FieldSig == null) { return(null); } type = createByRefType(field2.FieldSig.GetFieldType()); break; case Code.Ldelema: case Code.Unbox: type = createByRefType(pushInstr.Operand as ITypeDefOrRef); break; default: return(null); } return(type); }