de4dot-cex/de4dot.code/deobfuscators/TypesRestorer.cs

674 lines
19 KiB
C#
Raw Permalink Normal View History

/*
2015-10-30 05:45:26 +08:00
Copyright (C) 2011-2015 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
2012-04-06 02:45:16 +08:00
using System;
using System.Collections.Generic;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators {
// Restore the type of all fields / parameters that have had their type turned into object.
// This thing requires a lot more code than I have time to do now (similar to symbol renaming)
// so it will be a basic implementation only.
public abstract class TypesRestorerBase {
2012-11-01 21:39:39 +08:00
ModuleDef module;
List<MethodDef> allMethods;
Dictionary<Parameter, TypeInfo<Parameter>> argInfos = new Dictionary<Parameter, TypeInfo<Parameter>>();
TypeInfo<Parameter> methodReturnInfo;
2012-11-03 05:53:24 +08:00
Dictionary<IField, TypeInfo<FieldDef>> fieldWrites = new Dictionary<IField, TypeInfo<FieldDef>>(FieldEqualityComparer.CompareDeclaringTypes);
Dictionary<int, UpdatedMethod> updatedMethods = new Dictionary<int, UpdatedMethod>();
Dictionary<int, UpdatedField> updatedFields = new Dictionary<int, UpdatedField>();
class UpdatedMethod {
public int token;
2012-11-01 21:39:39 +08:00
public TypeSig[] newArgTypes;
public TypeSig newReturnType;
2012-11-01 21:39:39 +08:00
public UpdatedMethod(MethodDef method) {
token = method.MDToken.ToInt32();
2013-01-19 20:03:57 +08:00
newArgTypes = new TypeSig[DotNetUtils.GetArgsCount(method)];
}
}
class UpdatedField {
public int token;
2012-11-01 21:39:39 +08:00
public TypeSig newFieldType;
2012-11-01 21:39:39 +08:00
public UpdatedField(FieldDef field) {
token = field.MDToken.ToInt32();
}
}
2011-11-01 09:22:05 +08:00
class TypeInfo<T> {
2012-11-02 04:09:09 +08:00
Dictionary<TypeSig, bool> types = new Dictionary<TypeSig, bool>(TypeEqualityComparer.Instance);
public TypeSig newType = null;
2011-11-01 09:22:05 +08:00
public T arg;
bool newobjTypes;
2012-11-02 04:09:09 +08:00
public Dictionary<TypeSig, bool> Types {
get { return types; }
}
2011-11-01 06:58:19 +08:00
2011-11-01 09:22:05 +08:00
public TypeInfo(T arg) {
2011-11-01 06:58:19 +08:00
this.arg = arg;
}
2013-01-19 20:03:57 +08:00
public void Add(TypeSig type) {
Add(type, false);
2012-07-07 13:11:32 +08:00
}
2013-01-19 20:03:57 +08:00
public void Add(TypeSig type, bool wasNewobj) {
if (wasNewobj) {
if (!newobjTypes)
2013-01-19 20:03:57 +08:00
Clear();
newobjTypes = true;
}
else if (newobjTypes)
return;
2012-11-02 04:09:09 +08:00
types[type] = true;
}
2013-01-19 20:03:57 +08:00
public void Clear() {
types.Clear();
}
2013-01-19 20:03:57 +08:00
public bool UpdateNewType(ModuleDef module) {
2011-11-01 09:22:05 +08:00
if (types.Count == 0)
return false;
2012-11-02 04:09:09 +08:00
TypeSig theNewType = null;
2011-11-01 09:22:05 +08:00
foreach (var key in types.Keys) {
if (theNewType == null) {
2012-11-02 04:09:09 +08:00
theNewType = key;
2011-11-01 09:22:05 +08:00
continue;
}
2013-01-19 20:03:57 +08:00
theNewType = GetCommonBaseClass(module, theNewType, key);
2011-11-01 09:22:05 +08:00
if (theNewType == null)
break;
}
if (theNewType == null)
return false;
2012-11-02 04:09:09 +08:00
if (new SigComparer().Equals(theNewType, newType))
2011-11-01 09:22:05 +08:00
return false;
2011-11-01 09:22:05 +08:00
newType = theNewType;
return true;
}
}
2012-11-01 21:39:39 +08:00
public TypesRestorerBase(ModuleDef module) {
this.module = module;
}
2013-01-19 20:03:57 +08:00
UpdatedMethod GetUpdatedMethod(MethodDef method) {
2012-11-01 21:39:39 +08:00
int token = method.MDToken.ToInt32();
UpdatedMethod updatedMethod;
if (updatedMethods.TryGetValue(token, out updatedMethod))
return updatedMethod;
return updatedMethods[token] = new UpdatedMethod(method);
}
2013-01-19 20:03:57 +08:00
UpdatedField GetUpdatedField(FieldDef field) {
2012-11-01 21:39:39 +08:00
int token = field.MDToken.ToInt32();
UpdatedField updatedField;
if (updatedFields.TryGetValue(token, out updatedField))
return updatedField;
return updatedFields[token] = new UpdatedField(field);
}
2013-01-19 20:03:57 +08:00
public void Deobfuscate() {
2012-11-01 21:39:39 +08:00
allMethods = new List<MethodDef>();
2012-04-06 02:45:16 +08:00
2013-01-19 20:03:57 +08:00
AddAllMethods();
AddAllFields();
2012-04-06 02:45:16 +08:00
2013-01-19 20:03:57 +08:00
DeobfuscateLoop();
2012-04-06 02:45:16 +08:00
2013-01-19 20:03:57 +08:00
RestoreFieldTypes();
RestoreMethodTypes();
2012-04-06 02:45:16 +08:00
}
2013-01-19 20:03:57 +08:00
void AddAllMethods() {
2011-11-01 06:58:19 +08:00
foreach (var type in module.GetTypes())
2013-01-19 20:03:57 +08:00
AddMethods(type.Methods);
2012-04-06 02:45:16 +08:00
}
2011-11-01 06:58:19 +08:00
2013-01-19 20:03:57 +08:00
void AddMethods(IEnumerable<MethodDef> methods) {
2012-04-06 02:45:16 +08:00
allMethods.AddRange(methods);
}
2013-01-19 20:03:57 +08:00
void AddMethod(MethodDef method) {
2012-04-06 02:45:16 +08:00
allMethods.Add(method);
}
2013-01-19 20:03:57 +08:00
void AddAllFields() {
foreach (var type in module.GetTypes()) {
foreach (var field in type.Fields) {
2013-01-19 20:03:57 +08:00
if (!IsUnknownType(field))
continue;
2012-11-03 05:53:24 +08:00
fieldWrites[field] = new TypeInfo<FieldDef>(field);
}
}
2012-04-06 02:45:16 +08:00
}
2013-01-19 20:03:57 +08:00
void DeobfuscateLoop() {
for (int i = 0; i < 10; i++) {
2013-04-30 18:15:07 +08:00
bool modified = false;
modified |= DeobfuscateFields();
modified |= DeobfuscateMethods();
if (!modified)
break;
}
2012-04-06 02:45:16 +08:00
}
2011-11-01 06:58:19 +08:00
2013-01-19 20:03:57 +08:00
void RestoreFieldTypes() {
var fields = new List<UpdatedField>(updatedFields.Values);
2012-04-06 02:45:16 +08:00
if (fields.Count == 0)
return;
Logger.v("Changing field types to real type");
2012-11-01 23:42:02 +08:00
fields.Sort((a, b) => a.token.CompareTo(b.token));
2013-01-19 20:03:57 +08:00
Logger.Instance.Indent();
2012-04-06 02:45:16 +08:00
foreach (var updatedField in fields)
2013-01-19 20:03:57 +08:00
Logger.v("Field {0:X8}: type {1} ({2:X8})", updatedField.token, Utils.RemoveNewlines(updatedField.newFieldType.FullName), updatedField.newFieldType.MDToken.ToInt32());
Logger.Instance.DeIndent();
2012-04-06 02:45:16 +08:00
}
2011-11-01 06:58:19 +08:00
2013-01-19 20:03:57 +08:00
void RestoreMethodTypes() {
var methods = new List<UpdatedMethod>(updatedMethods.Values);
2012-04-06 02:45:16 +08:00
if (methods.Count == 0)
return;
Logger.v("Changing method args and return types to real type");
2012-11-01 23:42:02 +08:00
methods.Sort((a, b) => a.token.CompareTo(b.token));
2013-01-19 20:03:57 +08:00
Logger.Instance.Indent();
2012-04-06 02:45:16 +08:00
foreach (var updatedMethod in methods) {
Logger.v("Method {0:X8}", updatedMethod.token);
2013-01-19 20:03:57 +08:00
Logger.Instance.Indent();
2012-04-06 02:45:16 +08:00
if (updatedMethod.newReturnType != null) {
Logger.v("ret: {0} ({1:X8})",
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(updatedMethod.newReturnType.FullName),
2012-11-01 21:39:39 +08:00
updatedMethod.newReturnType.MDToken.ToInt32());
2012-04-06 02:45:16 +08:00
}
for (int i = 0; i < updatedMethod.newArgTypes.Length; i++) {
var updatedArg = updatedMethod.newArgTypes[i];
if (updatedArg == null)
continue;
Logger.v("arg {0}: {1} ({2:X8})",
2012-04-06 02:45:16 +08:00
i,
2013-01-19 20:03:57 +08:00
Utils.RemoveNewlines(updatedArg.FullName),
2012-11-01 21:39:39 +08:00
updatedArg.MDToken.ToInt32());
2011-11-01 09:22:05 +08:00
}
2013-01-19 20:03:57 +08:00
Logger.Instance.DeIndent();
2011-11-01 09:22:05 +08:00
}
2013-01-19 20:03:57 +08:00
Logger.Instance.DeIndent();
}
2011-11-01 06:58:19 +08:00
2013-01-19 20:03:57 +08:00
bool DeobfuscateMethods() {
2013-04-30 18:15:07 +08:00
bool modified = false;
foreach (var method in allMethods) {
2012-11-02 04:09:09 +08:00
methodReturnInfo = new TypeInfo<Parameter>(method.Parameters.ReturnParameter);
2013-01-19 20:03:57 +08:00
DeobfuscateMethod(method);
2013-01-19 20:03:57 +08:00
if (methodReturnInfo.UpdateNewType(module)) {
GetUpdatedMethod(method).newReturnType = methodReturnInfo.newType;
2012-11-02 04:09:09 +08:00
method.MethodSig.RetType = methodReturnInfo.newType;
2013-04-30 18:15:07 +08:00
modified = true;
2011-11-01 06:58:19 +08:00
}
2011-11-01 09:22:05 +08:00
foreach (var info in argInfos.Values) {
2013-01-19 20:03:57 +08:00
if (info.UpdateNewType(module)) {
GetUpdatedMethod(method).newArgTypes[info.arg.Index] = info.newType;
2012-11-02 04:09:09 +08:00
info.arg.Type = info.newType;
2013-04-30 18:15:07 +08:00
modified = true;
}
}
}
2013-04-30 18:15:07 +08:00
return modified;
2011-11-01 06:58:19 +08:00
}
2013-01-19 20:03:57 +08:00
static int SortTypeInfos(TypeInfo<Parameter> a, TypeInfo<Parameter> b) {
2012-11-01 21:39:39 +08:00
if (a.arg.Method.MDToken.ToInt32() < b.arg.Method.MDToken.ToInt32()) return -1;
if (a.arg.Method.MDToken.ToInt32() > b.arg.Method.MDToken.ToInt32()) return 1;
2011-11-02 01:56:44 +08:00
2012-11-02 04:09:09 +08:00
return a.arg.Index.CompareTo(b.arg.Index);
2011-11-01 09:22:05 +08:00
}
2013-01-19 20:03:57 +08:00
void DeobfuscateMethod(MethodDef method) {
if (!method.IsStatic || method.Body == null)
2011-11-01 06:58:19 +08:00
return;
2013-01-19 20:03:57 +08:00
bool fixReturnType = IsUnknownType(method.MethodSig.GetRetType());
2011-11-01 09:22:05 +08:00
2011-11-01 06:58:19 +08:00
argInfos.Clear();
foreach (var arg in method.Parameters) {
if (arg.IsHiddenThisParameter)
continue;
2013-01-19 20:03:57 +08:00
if (!IsUnknownType(arg))
2011-11-01 06:58:19 +08:00
continue;
2012-11-01 21:39:39 +08:00
argInfos[arg] = new TypeInfo<Parameter>(arg);
2011-11-01 06:58:19 +08:00
}
2011-11-01 09:22:05 +08:00
if (argInfos.Count == 0 && !fixReturnType)
2011-11-01 06:58:19 +08:00
return;
2012-11-02 04:09:09 +08:00
var methodParams = method.Parameters;
2011-11-04 06:01:51 +08:00
PushedArgs pushedArgs;
var instructions = method.Body.Instructions;
2011-11-01 06:58:19 +08:00
for (int i = 0; i < instructions.Count; i++) {
var instr = instructions[i];
switch (instr.OpCode.Code) {
2011-11-01 09:22:05 +08:00
case Code.Ret:
if (!fixReturnType)
break;
bool wasNewobj;
2013-01-19 20:03:57 +08:00
var type = GetLoadedType(method, method, instructions, i, out wasNewobj);
2011-11-01 09:22:05 +08:00
if (type == null)
break;
2013-01-19 20:03:57 +08:00
methodReturnInfo.Add(type);
2011-11-01 09:22:05 +08:00
break;
2011-11-01 06:58:19 +08:00
case Code.Call:
case Code.Calli:
case Code.Callvirt:
2011-11-04 07:09:51 +08:00
case Code.Newobj:
2013-01-19 20:03:57 +08:00
pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i);
2012-11-02 04:09:09 +08:00
var calledMethod = instr.Operand as IMethod;
2011-11-01 06:58:19 +08:00
if (calledMethod == null)
break;
2013-01-19 20:03:57 +08:00
var calledMethodParams = DotNetUtils.GetArgs(calledMethod);
2011-11-04 06:01:51 +08:00
for (int j = 0; j < pushedArgs.NumValidArgs; j++) {
2011-11-01 06:58:19 +08:00
int calledMethodParamIndex = calledMethodParams.Count - j - 1;
2013-01-19 20:03:57 +08:00
var ldInstr = pushedArgs.GetEnd(j);
2011-11-01 06:58:19 +08:00
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:
2013-01-19 20:03:57 +08:00
AddMethodArgType(method, GetParameter(methodParams, ldInstr), DotNetUtils.GetArg(calledMethodParams, calledMethodParamIndex));
2011-11-01 06:58:19 +08:00
break;
default:
break;
}
}
break;
case Code.Castclass:
2013-01-19 20:03:57 +08:00
pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i);
2011-11-04 06:01:51 +08:00
if (pushedArgs.NumValidArgs < 1)
2011-11-01 06:58:19 +08:00
break;
2013-01-19 20:03:57 +08:00
AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), instr.Operand as ITypeDefOrRef);
2011-11-01 06:58:19 +08:00
break;
case Code.Stloc:
case Code.Stloc_S:
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
2013-01-19 20:03:57 +08:00
pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i);
2011-11-04 06:01:51 +08:00
if (pushedArgs.NumValidArgs < 1)
2011-11-01 06:58:19 +08:00
break;
2013-01-19 20:03:57 +08:00
AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), instr.GetLocal(method.Body.Variables));
2011-11-01 06:58:19 +08:00
break;
case Code.Stsfld:
2013-01-19 20:03:57 +08:00
pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i);
2011-11-04 06:01:51 +08:00
if (pushedArgs.NumValidArgs < 1)
2011-11-01 06:58:19 +08:00
break;
2013-01-19 20:03:57 +08:00
AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), instr.Operand as IField);
2011-11-01 06:58:19 +08:00
break;
case Code.Stfld:
2013-01-19 20:03:57 +08:00
pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i);
2011-11-04 06:01:51 +08:00
if (pushedArgs.NumValidArgs >= 1) {
2012-11-02 04:09:09 +08:00
var field = instr.Operand as IField;
2013-01-19 20:03:57 +08:00
AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), field);
2011-11-04 06:01:51 +08:00
if (pushedArgs.NumValidArgs >= 2 && field != null)
2013-01-19 20:03:57 +08:00
AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(1)), field.DeclaringType);
2011-11-01 06:58:19 +08:00
}
break;
case Code.Ldfld:
case Code.Ldflda:
2013-01-19 20:03:57 +08:00
pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i);
2011-11-04 06:01:51 +08:00
if (pushedArgs.NumValidArgs < 1)
break;
2013-01-19 20:03:57 +08:00
AddMethodArgType(method, GetParameter(methodParams, pushedArgs.GetEnd(0)), instr.Operand as IField);
break;
2011-11-01 06:58:19 +08:00
//TODO: For better results, these should be checked:
case Code.Starg:
case Code.Starg_S:
case Code.Ldelema:
2012-11-01 21:39:39 +08:00
case Code.Ldelem:
2011-11-01 06:58:19 +08:00
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:
2012-11-01 21:39:39 +08:00
case Code.Stelem:
2011-11-01 06:58:19 +08:00
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;
}
}
}
2013-01-19 20:03:57 +08:00
static Parameter GetParameter(IList<Parameter> parameters, Instruction instr) {
2011-11-01 06:58:19 +08:00
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:
2012-11-02 04:09:09 +08:00
return instr.GetParameter(parameters);
2011-11-01 06:58:19 +08:00
default:
return null;
}
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType(IGenericParameterProvider gpp, Parameter methodParam, IField field) {
2012-11-18 07:20:07 +08:00
if (field == null)
2011-11-01 06:58:19 +08:00
return false;
2013-01-19 20:03:57 +08:00
return AddMethodArgType(gpp, methodParam, field.FieldSig.GetFieldType());
2011-11-01 06:58:19 +08:00
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType(IGenericParameterProvider gpp, Parameter methodParam, Local otherLocal) {
2011-11-01 06:58:19 +08:00
if (otherLocal == null)
return false;
2013-01-19 20:03:57 +08:00
return AddMethodArgType(gpp, methodParam, otherLocal.Type);
2011-11-01 06:58:19 +08:00
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType(IGenericParameterProvider gpp, Parameter methodParam, Parameter otherParam) {
2011-11-01 06:58:19 +08:00
if (otherParam == null)
return false;
2013-01-19 20:03:57 +08:00
return AddMethodArgType(gpp, methodParam, otherParam.Type);
2011-11-01 06:58:19 +08:00
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType(IGenericParameterProvider gpp, Parameter methodParam, ITypeDefOrRef type) {
return AddMethodArgType(gpp, methodParam, type.ToTypeSig());
2012-11-02 04:09:09 +08:00
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType(IGenericParameterProvider gpp, Parameter methodParam, TypeSig type) {
2011-11-01 06:58:19 +08:00
if (methodParam == null || type == null)
return false;
2013-01-19 20:03:57 +08:00
if (!IsValidType(gpp, type))
2011-11-01 06:58:19 +08:00
return false;
2012-11-01 21:39:39 +08:00
TypeInfo<Parameter> info;
2011-11-01 06:58:19 +08:00
if (!argInfos.TryGetValue(methodParam, out info))
return false;
2012-11-02 04:09:09 +08:00
if (info.Types.ContainsKey(type))
2011-11-01 06:58:19 +08:00
return false;
2013-01-19 20:03:57 +08:00
info.Add(type);
2011-11-01 06:58:19 +08:00
return true;
}
2013-01-19 20:03:57 +08:00
bool DeobfuscateFields() {
foreach (var info in fieldWrites.Values)
2013-01-19 20:03:57 +08:00
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];
2012-11-02 04:09:09 +08:00
TypeSig fieldType = null;
2012-11-01 21:39:39 +08:00
TypeInfo<FieldDef> info = null;
2012-11-02 04:09:09 +08:00
IField field;
2011-11-04 06:01:51 +08:00
switch (instr.OpCode.Code) {
case Code.Stfld:
case Code.Stsfld:
2012-11-02 04:09:09 +08:00
field = instr.Operand as IField;
2011-11-04 06:01:51 +08:00
if (field == null)
continue;
2012-11-03 05:53:24 +08:00
if (!fieldWrites.TryGetValue(field, out info))
2011-11-04 06:01:51 +08:00
continue;
bool wasNewobj;
2013-01-19 20:03:57 +08:00
fieldType = GetLoadedType(info.arg.DeclaringType, method, instructions, i, out wasNewobj);
2011-11-04 06:01:51 +08:00
if (fieldType == null)
continue;
2013-01-19 20:03:57 +08:00
info.Add(fieldType, wasNewobj);
2011-11-04 06:01:51 +08:00
break;
2011-11-04 06:01:51 +08:00
case Code.Call:
case Code.Calli:
case Code.Callvirt:
case Code.Newobj:
2013-01-19 20:03:57 +08:00
var pushedArgs = MethodStack.GetPushedArgInstructions(instructions, i);
2012-11-02 04:09:09 +08:00
var calledMethod = instr.Operand as IMethod;
2011-11-04 06:01:51 +08:00
if (calledMethod == null)
continue;
2012-11-18 01:57:36 +08:00
var calledMethodDefOrRef = calledMethod as IMethodDefOrRef;
var calledMethodSpec = calledMethod as MethodSpec;
if (calledMethodSpec != null)
calledMethodDefOrRef = calledMethodSpec.Method;
if (calledMethodDefOrRef == null)
continue;
2013-01-19 20:03:57 +08:00
IList<TypeSig> calledMethodArgs = DotNetUtils.GetArgs(calledMethodDefOrRef);
calledMethodArgs = DotNetUtils.ReplaceGenericParameters(calledMethodDefOrRef.DeclaringType.TryGetGenericInstSig(), calledMethodSpec, calledMethodArgs);
2011-11-04 06:01:51 +08:00
for (int j = 0; j < pushedArgs.NumValidArgs; j++) {
2013-01-19 20:03:57 +08:00
var pushInstr = pushedArgs.GetEnd(j);
2011-11-04 06:01:51 +08:00
if (pushInstr.OpCode.Code != Code.Ldfld && pushInstr.OpCode.Code != Code.Ldsfld)
continue;
2012-11-02 04:09:09 +08:00
field = pushInstr.Operand as IField;
2011-11-04 06:01:51 +08:00
if (field == null)
continue;
2012-11-03 05:53:24 +08:00
if (!fieldWrites.TryGetValue(field, out info))
2011-11-04 06:01:51 +08:00
continue;
fieldType = calledMethodArgs[calledMethodArgs.Count - 1 - j];
2013-01-19 20:03:57 +08:00
if (!IsValidType(info.arg.DeclaringType, fieldType))
2011-11-04 06:01:51 +08:00
continue;
2013-01-19 20:03:57 +08:00
info.Add(fieldType);
2011-11-04 06:01:51 +08:00
}
break;
2011-11-04 06:01:51 +08:00
default:
continue;
2011-11-04 06:01:51 +08:00
}
2011-11-01 09:22:05 +08:00
}
}
2013-04-30 18:15:07 +08:00
bool modified = false;
2012-11-01 21:39:39 +08:00
var removeThese = new List<FieldDef>();
foreach (var info in fieldWrites.Values) {
2013-01-19 20:03:57 +08:00
if (info.UpdateNewType(module)) {
removeThese.Add(info.arg);
2013-01-19 20:03:57 +08:00
GetUpdatedField(info.arg).newFieldType = info.newType;
2012-11-02 04:09:09 +08:00
info.arg.FieldSig.Type = info.newType;
2013-04-30 18:15:07 +08:00
modified = true;
}
}
foreach (var field in removeThese)
2012-11-03 05:53:24 +08:00
fieldWrites.Remove(field);
2013-04-30 18:15:07 +08:00
return modified;
2011-11-01 09:22:05 +08:00
}
2013-01-19 20:03:57 +08:00
TypeSig GetLoadedType(IGenericParameterProvider gpp, MethodDef method, IList<Instruction> instructions, int instrIndex, out bool wasNewobj) {
var fieldType = MethodStack.GetLoadedType(method, instructions, instrIndex, out wasNewobj);
if (fieldType == null || !IsValidType(gpp, fieldType))
2011-11-01 09:22:05 +08:00
return null;
return fieldType;
}
2013-01-19 20:03:57 +08:00
protected virtual bool IsValidType(IGenericParameterProvider gpp, TypeSig type) {
2011-11-01 09:22:05 +08:00
if (type == null)
return false;
2012-11-02 04:09:09 +08:00
if (type.ElementType == ElementType.Void)
2011-11-01 09:22:05 +08:00
return false;
while (type != null) {
2012-11-02 04:09:09 +08:00
switch (type.ElementType) {
case ElementType.GenericInst:
foreach (var ga in ((GenericInstSig)type).GenericArguments) {
2013-01-19 20:03:57 +08:00
if (!IsValidType(gpp, ga))
return false;
}
break;
2012-11-02 04:09:09 +08:00
case ElementType.SZArray:
case ElementType.Array:
case ElementType.Ptr:
case ElementType.Class:
case ElementType.ValueType:
2012-11-18 07:20:07 +08:00
case ElementType.Void:
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
case ElementType.I8:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.TypedByRef:
case ElementType.I:
case ElementType.U:
case ElementType.String:
case ElementType.Object:
break;
2012-11-02 04:09:09 +08:00
case ElementType.Var:
case ElementType.MVar:
// TODO: Return false for now. We don't know whether the Var is a Var in
// this type or from some other type.
return false;
2012-11-02 04:09:09 +08:00
case ElementType.ByRef:
case ElementType.FnPtr:
case ElementType.CModOpt:
case ElementType.CModReqd:
case ElementType.Pinned:
case ElementType.Sentinel:
2012-11-18 07:20:07 +08:00
case ElementType.ValueArray:
case ElementType.R:
case ElementType.End:
case ElementType.Internal:
case ElementType.Module:
default:
return false;
}
2012-11-18 01:57:36 +08:00
if (type.Next == null)
break;
2012-11-02 04:09:09 +08:00
type = type.Next;
}
return type != null;
}
2013-01-19 20:03:57 +08:00
protected abstract bool IsUnknownType(object o);
2012-04-06 02:45:16 +08:00
2013-01-19 20:03:57 +08:00
static TypeSig GetCommonBaseClass(ModuleDef module, TypeSig a, TypeSig b) {
if (DotNetUtils.IsDelegate(a) && DotNetUtils.DerivesFromDelegate(module.Find(b.ToTypeDefOrRef())))
2011-11-04 07:09:51 +08:00
return b;
2013-01-19 20:03:57 +08:00
if (DotNetUtils.IsDelegate(b) && DotNetUtils.DerivesFromDelegate(module.Find(a.ToTypeDefOrRef())))
2011-11-04 07:09:51 +08:00
return a;
return null; //TODO:
}
}
2012-04-06 02:45:16 +08:00
public class TypesRestorer : TypesRestorerBase {
2012-11-01 21:39:39 +08:00
public TypesRestorer(ModuleDef module)
2012-04-06 02:45:16 +08:00
: base(module) {
}
2013-01-19 20:03:57 +08:00
protected override bool IsValidType(IGenericParameterProvider gpp, TypeSig type) {
2012-04-06 02:45:16 +08:00
if (type == null)
return false;
2012-11-06 02:21:33 +08:00
if (type.IsValueType)
2012-04-06 02:45:16 +08:00
return false;
2012-11-02 04:09:09 +08:00
if (type.ElementType == ElementType.Object)
2012-04-06 02:45:16 +08:00
return false;
2013-01-19 20:03:57 +08:00
return base.IsValidType(gpp, type);
2012-04-06 02:45:16 +08:00
}
2013-01-19 20:03:57 +08:00
protected override bool IsUnknownType(object o) {
2012-11-01 21:39:39 +08:00
var arg = o as Parameter;
2012-04-06 02:45:16 +08:00
if (arg != null)
2012-11-18 07:20:07 +08:00
return arg.Type.GetElementType() == ElementType.Object;
2012-04-06 02:45:16 +08:00
2012-11-01 21:39:39 +08:00
var field = o as FieldDef;
2012-04-06 02:45:16 +08:00
if (field != null)
return field.FieldSig.GetFieldType().GetElementType() == ElementType.Object;
2012-04-06 02:45:16 +08:00
2012-11-17 22:46:02 +08:00
var sig = o as TypeSig;
if (sig != null)
return sig.ElementType == ElementType.Object;
2012-04-06 02:45:16 +08:00
throw new ApplicationException(string.Format("Unknown type: {0}", o.GetType()));
}
}
}