Added a methods rewriter class

This commit is contained in:
de4dot 2011-09-27 01:48:47 +02:00
parent 9945b8b47c
commit e14a18971b
17 changed files with 1795 additions and 27 deletions

View File

@ -40,6 +40,18 @@
<Compile Include="EmuStringDecrypter.cs" />
<Compile Include="IAssemblyService.cs" />
<Compile Include="IStringDecrypter.cs" />
<Compile Include="methodsrewriter\AssemblyResolver.cs" />
<Compile Include="methodsrewriter\CodeGenerator.cs" />
<Compile Include="methodsrewriter\IMethodsRewriter.cs" />
<Compile Include="methodsrewriter\MethodsRewriter.cs" />
<Compile Include="methodsrewriter\MField.cs" />
<Compile Include="methodsrewriter\MMethod.cs" />
<Compile Include="methodsrewriter\MModule.cs" />
<Compile Include="methodsrewriter\MType.cs" />
<Compile Include="methodsrewriter\Operand.cs" />
<Compile Include="methodsrewriter\Resolver.cs" />
<Compile Include="methodsrewriter\ResolverUtils.cs" />
<Compile Include="methodsrewriter\TypeResolver.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SimpleData.cs" />
<Compile Include="Utils.cs" />

View File

@ -19,18 +19,17 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using AssemblyData.methodsrewriter;
namespace AssemblyData {
class EmuStringDecrypter : IStringDecrypter {
delegate string DecryptString(object[] args);
List<DecryptInfo> decryptInfos = new List<DecryptInfo>();
MethodsRewriter methodsRewriter = new MethodsRewriter();
class DecryptInfo {
public MethodInfo method;
public DecryptString decryptString;
public RewrittenMethod decryptString;
public DecryptInfo(MethodInfo method) {
this.method = method;
@ -53,8 +52,9 @@ namespace AssemblyData {
return result;
}
DecryptString createDecryptString(MethodInfo method) {
throw new System.NotImplementedException(); //TODO:
RewrittenMethod createDecryptString(MethodInfo method) {
methodsRewriter.createMethod(method);
return methodsRewriter.createDelegate(method);
}
}
}

View File

@ -23,9 +23,30 @@ using System.Reflection.Emit;
using System.Text;
namespace AssemblyData {
// Yes, I did type this by hand.
internal delegate void Action();
internal delegate void Action<in T1>(T1 arg1);
internal delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
internal delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);
internal delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17, in T18>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18);
internal delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17, in T18, in T19>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19);
// No that was a lie.
internal delegate TResult Func<out TResult>();
internal delegate TResult Func<in T1, out TResult>(T1 arg);
internal delegate TResult Func<in T1, out TResult>(T1 arg1);
internal delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
internal delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);
internal delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
@ -34,30 +55,78 @@ namespace AssemblyData {
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17, in T18, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18);
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17, in T18, in T19, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19);
static class Utils {
static Random random = new Random();
public static Type getDelegateType(MethodInfo method) {
var parameters = method.GetParameters();
var types = new Type[parameters.Length + 1];
for (int i = 0; i < parameters.Length; i++)
types[i] = parameters[i].ParameterType;
types[types.Length - 1] = method.ReturnType;
public static Type getDelegateType(Type returnType, Type[] args) {
Type[] types;
if (returnType == typeof(void)) {
types = args;
switch (types.Length) {
case 0: return typeof(Action).MakeGenericType(types);
case 1: return typeof(Action<>).MakeGenericType(types);
case 2: return typeof(Action<,>).MakeGenericType(types);
case 3: return typeof(Action<,,>).MakeGenericType(types);
case 4: return typeof(Action<,,,>).MakeGenericType(types);
case 5: return typeof(Action<,,,,>).MakeGenericType(types);
case 6: return typeof(Action<,,,,,>).MakeGenericType(types);
case 7: return typeof(Action<,,,,,,>).MakeGenericType(types);
case 8: return typeof(Action<,,,,,,,>).MakeGenericType(types);
case 9: return typeof(Action<,,,,,,,,>).MakeGenericType(types);
case 10: return typeof(Action<,,,,,,,,,>).MakeGenericType(types);
case 11: return typeof(Action<,,,,,,,,,,>).MakeGenericType(types);
case 12: return typeof(Action<,,,,,,,,,,,>).MakeGenericType(types);
case 13: return typeof(Action<,,,,,,,,,,,,>).MakeGenericType(types);
case 14: return typeof(Action<,,,,,,,,,,,,,>).MakeGenericType(types);
case 15: return typeof(Action<,,,,,,,,,,,,,,>).MakeGenericType(types);
case 16: return typeof(Action<,,,,,,,,,,,,,,,>).MakeGenericType(types);
case 17: return typeof(Action<,,,,,,,,,,,,,,,,>).MakeGenericType(types);
case 18: return typeof(Action<,,,,,,,,,,,,,,,,,>).MakeGenericType(types);
case 19: return typeof(Action<,,,,,,,,,,,,,,,,,,>).MakeGenericType(types);
default:
throw new ApplicationException(string.Format("Too many delegate type arguments: {0}", types.Length));
}
}
else {
types = new Type[args.Length + 1];
Array.Copy(args, types, args.Length);
types[types.Length - 1] = returnType;
switch (types.Length) {
case 1: return typeof(Func<>).MakeGenericType(types);
case 2: return typeof(Func<,>).MakeGenericType(types);
case 3: return typeof(Func<,,>).MakeGenericType(types);
case 4: return typeof(Func<,,,>).MakeGenericType(types);
case 5: return typeof(Func<,,,,>).MakeGenericType(types);
case 6: return typeof(Func<,,,,,>).MakeGenericType(types);
case 7: return typeof(Func<,,,,,,>).MakeGenericType(types);
case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types);
case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types);
case 10:return typeof(Func<,,,,,,,,,>).MakeGenericType(types);
default:
throw new ApplicationException(string.Format("Too many arguments: {0}", method));
switch (types.Length) {
case 1: return typeof(Func<>).MakeGenericType(types);
case 2: return typeof(Func<,>).MakeGenericType(types);
case 3: return typeof(Func<,,>).MakeGenericType(types);
case 4: return typeof(Func<,,,>).MakeGenericType(types);
case 5: return typeof(Func<,,,,>).MakeGenericType(types);
case 6: return typeof(Func<,,,,,>).MakeGenericType(types);
case 7: return typeof(Func<,,,,,,>).MakeGenericType(types);
case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types);
case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types);
case 10: return typeof(Func<,,,,,,,,,>).MakeGenericType(types);
case 11: return typeof(Func<,,,,,,,,,,>).MakeGenericType(types);
case 12: return typeof(Func<,,,,,,,,,,,>).MakeGenericType(types);
case 13: return typeof(Func<,,,,,,,,,,,,>).MakeGenericType(types);
case 14: return typeof(Func<,,,,,,,,,,,,,>).MakeGenericType(types);
case 15: return typeof(Func<,,,,,,,,,,,,,,>).MakeGenericType(types);
case 16: return typeof(Func<,,,,,,,,,,,,,,,>).MakeGenericType(types);
case 17: return typeof(Func<,,,,,,,,,,,,,,,,>).MakeGenericType(types);
case 18: return typeof(Func<,,,,,,,,,,,,,,,,,>).MakeGenericType(types);
case 19: return typeof(Func<,,,,,,,,,,,,,,,,,,>).MakeGenericType(types);
case 20: return typeof(Func<,,,,,,,,,,,,,,,,,,,>).MakeGenericType(types);
default:
throw new ApplicationException(string.Format("Too many delegate type arguments: {0}", types.Length));
}
}
}

View File

@ -0,0 +1,136 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using de4dot.blocks;
namespace AssemblyData.methodsrewriter {
class MGenericParameter {
}
class AssemblyResolver {
Dictionary<string, List<TypeResolver>> types = new Dictionary<string, List<TypeResolver>>(StringComparer.Ordinal);
List<MethodBase> globalMethods;
List<FieldInfo> globalFields;
Assembly assembly;
public AssemblyResolver(string asmName) {
assembly = Assembly.Load(new AssemblyName(asmName));
initTypes();
}
void initTypes() {
foreach (var type in assembly.GetTypes()) {
string key = (type.Namespace ?? "") + "." + type.Name;
List<TypeResolver> list;
if (!types.TryGetValue(key, out list))
types[key] = list = new List<TypeResolver>();
list.Add(new TypeResolver(type));
}
}
TypeResolver getTypeResolver(TypeReference typeReference) {
var key = typeReference.Namespace + "." + typeReference.Name;
List<TypeResolver> list;
if (!types.TryGetValue(key, out list))
return null;
foreach (var resolver in list) {
if (ResolverUtils.compareTypes(resolver.type, typeReference))
return resolver;
}
return null;
}
public FieldInfo resolve(FieldReference fieldReference) {
var resolver = getTypeResolver(fieldReference.DeclaringType);
if (resolver != null)
return resolver.resolve(fieldReference);
return resolveGlobalField(fieldReference);
}
FieldInfo resolveGlobalField(FieldReference fieldReference) {
initGlobalFields();
foreach (var globalField in globalFields) {
if (ResolverUtils.compareFields(globalField, fieldReference))
return globalField;
}
return null;
}
void initGlobalFields() {
if (globalFields != null)
return;
globalFields = new List<FieldInfo>();
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
foreach (var module in assembly.GetModules(true)) {
foreach (var method in module.GetFields(flags))
globalFields.Add(method);
}
}
public MethodBase resolve(MethodReference methodReference) {
var resolver = getTypeResolver(methodReference.DeclaringType);
if (resolver != null)
return resolver.resolve(methodReference);
return resolveGlobalMethod(methodReference);
}
MethodBase resolveGlobalMethod(MethodReference methodReference) {
initGlobalMethods();
foreach (var globalMethod in globalMethods) {
if (ResolverUtils.compareMethods(globalMethod, methodReference))
return globalMethod;
}
return null;
}
void initGlobalMethods() {
if (globalMethods != null)
return;
globalMethods = new List<MethodBase>();
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
foreach (var module in assembly.GetModules(true)) {
foreach (var method in module.GetMethods(flags))
globalMethods.Add(method);
}
}
public Type resolve(TypeReference typeReference) {
var resolver = getTypeResolver(typeReference);
if (resolver != null)
return resolver.type;
if (typeReference.IsGenericParameter)
return typeof(MGenericParameter);
return null;
}
public override string ToString() {
return assembly.ToString();
}
}
}

View File

@ -0,0 +1,293 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
using OpCode = Mono.Cecil.Cil.OpCode;
using OpCodes = Mono.Cecil.Cil.OpCodes;
using OperandType = Mono.Cecil.Cil.OperandType;
using ROpCode = System.Reflection.Emit.OpCode;
using ROpCodes = System.Reflection.Emit.OpCodes;
namespace AssemblyData.methodsrewriter {
class CodeGenerator {
static Dictionary<OpCode, ROpCode> cecilToReflection = new Dictionary<OpCode, ROpCode>();
static CodeGenerator() {
var refDict = new Dictionary<short, ROpCode>(0x100);
foreach (var f in typeof(ROpCodes).GetFields(BindingFlags.Static | BindingFlags.Public)) {
if (f.FieldType != typeof(ROpCode))
continue;
var ropcode = (ROpCode)f.GetValue(null);
refDict[ropcode.Value] = ropcode;
}
foreach (var f in typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public)) {
if (f.FieldType != typeof(OpCode))
continue;
var opcode = (OpCode)f.GetValue(null);
ROpCode ropcode;
if (!refDict.TryGetValue(opcode.Value, out ropcode))
continue;
cecilToReflection[opcode] = ropcode;
}
}
IMethodsRewriter methodsRewriter;
IList<Instruction> allInstructions;
IList<ExceptionHandler> allExceptionHandlers;
ILGenerator ilg;
Type methodReturnType;
Type[] methodParameters;
Type delegateType;
MMethod methodInfo;
LocalBuilder tempObjLocal;
LocalBuilder tempObjArrayLocal;
int thisArgIndex;
List<LocalBuilder> locals;
List<Label> labels;
Dictionary<Instruction, int> instrToIndex;
public Type DelegateType {
get { return delegateType; }
}
public CodeGenerator(IMethodsRewriter methodsRewriter) {
this.methodsRewriter = methodsRewriter;
}
public void setMethodInfo(MMethod methodInfo) {
this.methodInfo = methodInfo;
methodReturnType = ResolverUtils.getReturnType(methodInfo.methodBase);
methodParameters = getMethodParameterTypes(methodInfo.methodBase);
delegateType = Utils.getDelegateType(methodReturnType, methodParameters);
}
public Delegate generate(IList<Instruction> allInstructions, IList<ExceptionHandler> allExceptionHandlers) {
this.allInstructions = allInstructions;
this.allExceptionHandlers = allExceptionHandlers;
var dm = new DynamicMethod("emulated_" + methodInfo.methodBase.Name, methodReturnType, methodParameters, methodsRewriter.GetType(), true);
var lastInstr = allInstructions[allInstructions.Count - 1];
ilg = dm.GetILGenerator(lastInstr.Offset + lastInstr.GetSize());
initInstrToIndex();
initLocals();
initLabels();
for (int i = 0; i < allInstructions.Count; i++) {
var instr = allInstructions[i];
ilg.MarkLabel(labels[i]);
if (instr.Operand is Operand)
writeSpecialInstr(instr, (Operand)instr.Operand);
else
writeInstr(instr);
}
return dm.CreateDelegate(delegateType);
}
void initInstrToIndex() {
instrToIndex = new Dictionary<Instruction, int>(allInstructions.Count);
for (int i = 0; i < allInstructions.Count; i++)
instrToIndex[allInstructions[i]] = i;
}
void initLocals() {
locals = new List<LocalBuilder>();
foreach (var local in methodInfo.methodDefinition.Body.Variables)
locals.Add(ilg.DeclareLocal(methodsRewriter.getRtType(local.VariableType), local.IsPinned));
tempObjLocal = ilg.DeclareLocal(typeof(object));
tempObjArrayLocal = ilg.DeclareLocal(typeof(object[]));
}
void initLabels() {
labels = new List<Label>(allInstructions.Count);
for (int i = 0; i < allInstructions.Count; i++)
labels.Add(ilg.DefineLabel());
}
Type[] getMethodParameterTypes(MethodBase method) {
var list = new List<Type>();
if (ResolverUtils.hasThis(method))
list.Add(method.DeclaringType);
foreach (var param in method.GetParameters())
list.Add(param.ParameterType);
thisArgIndex = list.Count;
list.Add(methodsRewriter.GetType());
return list.ToArray();
}
void writeSpecialInstr(Instruction instr, Operand operand) {
BindingFlags flags;
switch (operand.type) {
case Operand.Type.ThisArg:
ilg.Emit(convertOpCode(instr.OpCode), (short)thisArgIndex);
break;
case Operand.Type.TempObj:
ilg.Emit(convertOpCode(instr.OpCode), tempObjLocal);
break;
case Operand.Type.TempObjArray:
ilg.Emit(convertOpCode(instr.OpCode), tempObjArrayLocal);
break;
case Operand.Type.OurMethod:
flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
var methodName = (string)operand.data;
var ourMethod = methodsRewriter.GetType().GetMethod(methodName, flags);
if (ourMethod == null)
throw new ApplicationException(string.Format("Could not find method {0}", methodName));
ilg.Emit(convertOpCode(instr.OpCode), ourMethod);
break;
case Operand.Type.NewMethod:
var methodBase = (MethodBase)operand.data;
var delegateType = methodsRewriter.getDelegateType(methodBase);
flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
var invokeMethod = delegateType.GetMethod("Invoke", flags);
ilg.Emit(convertOpCode(instr.OpCode), invokeMethod);
break;
case Operand.Type.ReflectionType:
ilg.Emit(convertOpCode(instr.OpCode), (Type)operand.data);
break;
default:
throw new ApplicationException(string.Format("Unknown operand type: {0}", operand.type));
}
}
Label getLabel(Instruction target) {
return labels[instrToIndex[target]];
}
Label[] getLabels(Instruction[] targets) {
var labels = new Label[targets.Length];
for (int i = 0; i < labels.Length; i++)
labels[i] = getLabel(targets[i]);
return labels;
}
int getArgIndex(ParameterDefinition arg) {
return arg.Index;
}
int getLocalIndex(VariableDefinition local) {
return local.Index;
}
void writeInstr(Instruction instr) {
var opcode = convertOpCode(instr.OpCode);
switch (instr.OpCode.OperandType) {
case OperandType.InlineNone:
ilg.Emit(opcode);
break;
case OperandType.InlineBrTarget:
case OperandType.ShortInlineBrTarget:
ilg.Emit(opcode, getLabel((Instruction)instr.Operand));
break;
case OperandType.InlineSwitch:
ilg.Emit(opcode, getLabels((Instruction[])instr.Operand));
break;
case OperandType.ShortInlineI:
if (instr.OpCode.Code == Code.Ldc_I4_S)
ilg.Emit(opcode, (sbyte)instr.Operand);
else
ilg.Emit(opcode, (byte)instr.Operand);
break;
case OperandType.InlineI:
ilg.Emit(opcode, (int)instr.Operand);
break;
case OperandType.InlineI8:
ilg.Emit(opcode, (long)instr.Operand);
break;
case OperandType.InlineR:
ilg.Emit(opcode, (double)instr.Operand);
break;
case OperandType.ShortInlineR:
ilg.Emit(opcode, (float)instr.Operand);
break;
case OperandType.InlineString:
ilg.Emit(opcode, (string)instr.Operand);
break;
case OperandType.InlineTok:
case OperandType.InlineType:
case OperandType.InlineMethod:
case OperandType.InlineField:
var obj = methodsRewriter.getRtObject((MemberReference)instr.Operand);
if (obj is ConstructorInfo)
ilg.Emit(opcode, (ConstructorInfo)obj);
else if (obj is MethodInfo)
ilg.Emit(opcode, (MethodInfo)obj);
else if (obj is FieldInfo)
ilg.Emit(opcode, (FieldInfo)obj);
else if (obj is Type)
ilg.Emit(opcode, (Type)obj);
else
throw new ApplicationException(string.Format("Unknown type: {0}", obj.GetType()));
break;
case OperandType.InlineArg:
ilg.Emit(opcode, checked((short)getArgIndex((ParameterDefinition)instr.Operand)));
break;
case OperandType.ShortInlineArg:
ilg.Emit(opcode, checked((byte)getArgIndex((ParameterDefinition)instr.Operand)));
break;
case OperandType.InlineVar:
ilg.Emit(opcode, checked((short)getLocalIndex((VariableDefinition)instr.Operand)));
break;
case OperandType.ShortInlineVar:
ilg.Emit(opcode, checked((byte)getLocalIndex((VariableDefinition)instr.Operand)));
break;
case OperandType.InlineSig: //TODO:
default:
throw new ApplicationException(string.Format("Unknown OperandType {0}", instr.OpCode.OperandType));
}
}
ROpCode convertOpCode(OpCode opcode) {
return cecilToReflection[opcode];
}
}
}

View File

@ -0,0 +1,30 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Reflection;
using Mono.Cecil;
namespace AssemblyData.methodsrewriter {
interface IMethodsRewriter {
Type getRtType(TypeReference typeReference);
object getRtObject(MemberReference memberReference);
Type getDelegateType(MethodBase methodBase);
}
}

View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2011 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/>.
*/
using System.Reflection;
using Mono.Cecil;
namespace AssemblyData.methodsrewriter {
class MField {
public FieldInfo fieldInfo;
public FieldDefinition fieldDefinition;
public MField(FieldInfo fieldInfo, FieldDefinition fieldDefinition) {
this.fieldInfo = fieldInfo;
this.fieldDefinition = fieldDefinition;
}
public override string ToString() {
return fieldDefinition.ToString();
}
}
}

View File

@ -0,0 +1,36 @@
/*
Copyright (C) 2011 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/>.
*/
using System.Reflection;
using Mono.Cecil;
namespace AssemblyData.methodsrewriter {
class MMethod {
public MethodBase methodBase;
public MethodDefinition methodDefinition;
public MMethod(MethodBase methodBase, MethodDefinition methodDefinition) {
this.methodBase = methodBase;
this.methodDefinition = methodDefinition;
}
public override string ToString() {
return methodDefinition.ToString();
}
}
}

View File

@ -0,0 +1,147 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using de4dot.blocks;
namespace AssemblyData.methodsrewriter {
class MModule {
public Module module;
public ModuleDefinition moduleDefinition;
Dictionary<TypeReferenceKey, MType> typeReferenceToType = new Dictionary<TypeReferenceKey, MType>();
Dictionary<int, MType> tokenToType = new Dictionary<int, MType>();
Dictionary<int, MMethod> tokenToGlobalMethod;
Dictionary<int, MField> tokenToGlobalField;
TypeDefinition moduleType;
public MModule(Module module, ModuleDefinition moduleDefinition) {
this.module = module;
this.moduleDefinition = moduleDefinition;
initTokenToType();
}
void initTokenToType() {
var tmpTokenToType = new Dictionary<int, Type>();
var tmpTokenToTypeDefinition = new Dictionary<int, TypeDefinition>();
foreach (var t in module.GetTypes())
tmpTokenToType[t.MetadataToken] = t;
foreach (var t in moduleDefinition.GetTypes()) {
tmpTokenToTypeDefinition[t.MetadataToken.ToInt32()] = t;
if (moduleType == null && t.FullName == "<Module>")
moduleType = t;
}
foreach (var token in tmpTokenToType.Keys) {
var mtype = new MType(tmpTokenToType[token], tmpTokenToTypeDefinition[token]);
tokenToType[token] = mtype;
typeReferenceToType[new TypeReferenceKey(mtype.typeDefinition)] = mtype;
}
}
public MType getType(TypeReference typeReference) {
MType type;
typeReferenceToType.TryGetValue(new TypeReferenceKey(typeReference), out type);
return type;
}
public MMethod getMethod(MethodReference methodReference) {
var type = getType(methodReference.DeclaringType);
if (type != null)
return type.getMethod(methodReference);
if (!MemberReferenceHelper.compareTypes(moduleType, methodReference.DeclaringType))
return null;
initGlobalMethods();
foreach (var method in tokenToGlobalMethod.Values) {
if (MemberReferenceHelper.compareMethodReference(methodReference, method.methodDefinition))
return method;
}
return null;
}
public MField getField(FieldReference fieldReference) {
var type = getType(fieldReference.DeclaringType);
if (type != null)
return type.getField(fieldReference);
if (!MemberReferenceHelper.compareTypes(moduleType, fieldReference.DeclaringType))
return null;
initGlobalFields();
foreach (var field in tokenToGlobalField.Values) {
if (MemberReferenceHelper.compareFieldReference(fieldReference, field.fieldDefinition))
return field;
}
return null;
}
public MMethod getMethod(MethodBase method) {
if (method.Module != module)
throw new ApplicationException("Not our module");
if (method.DeclaringType == null)
return getGlobalMethod(method);
var type = tokenToType[method.DeclaringType.MetadataToken];
return type.getMethod(method.MetadataToken);
}
public MMethod getGlobalMethod(MethodBase method) {
initGlobalMethods();
return tokenToGlobalMethod[method.MetadataToken];
}
void initGlobalMethods() {
if (tokenToGlobalMethod != null)
return;
tokenToGlobalMethod = new Dictionary<int, MMethod>();
var tmpTokenToGlobalMethod = new Dictionary<int, MethodInfo>();
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
foreach (var m in module.GetMethods(flags))
tmpTokenToGlobalMethod[m.MetadataToken] = m;
foreach (var m in moduleType.Methods) {
if (m.Name == ".cctor") //TODO: Use module.GetMethod(token) to get .cctor method
continue;
var token = m.MetadataToken.ToInt32();
tokenToGlobalMethod[token] = new MMethod(tmpTokenToGlobalMethod[token], m);
}
}
void initGlobalFields() {
if (tokenToGlobalField != null)
return;
tokenToGlobalField = new Dictionary<int, MField>();
var tmpTokenToGlobalField = new Dictionary<int, FieldInfo>();
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
foreach (var f in module.GetFields(flags))
tmpTokenToGlobalField[f.MetadataToken] = f;
foreach (var f in moduleType.Fields) {
var token = f.MetadataToken.ToInt32();
tokenToGlobalField[token] = new MField(tmpTokenToGlobalField[token], f);
}
}
public override string ToString() {
return moduleDefinition.FullyQualifiedName;
}
}
}

View File

@ -0,0 +1,104 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using de4dot.blocks;
namespace AssemblyData.methodsrewriter {
class MType {
public Type type;
public TypeDefinition typeDefinition;
Dictionary<int, MMethod> tokenToMethod;
Dictionary<MethodReferenceKey, MMethod> methodReferenceToMethod;
Dictionary<int, MField> tokenToField;
Dictionary<FieldReferenceKey, MField> fieldReferenceToField;
public MType(Type type, TypeDefinition typeDefinition) {
this.type = type;
this.typeDefinition = typeDefinition;
}
public MMethod getMethod(MethodReference methodReference) {
initMethods();
MMethod method;
methodReferenceToMethod.TryGetValue(new MethodReferenceKey(methodReference), out method);
return method;
}
public MField getField(FieldReference fieldReference) {
initFields();
MField field;
fieldReferenceToField.TryGetValue(new FieldReferenceKey(fieldReference), out field);
return field;
}
public MMethod getMethod(int token) {
initMethods();
return tokenToMethod[token];
}
public MField getField(int token) {
initFields();
return tokenToField[token];
}
void initMethods() {
if (tokenToMethod != null)
return;
tokenToMethod = new Dictionary<int, MMethod>(typeDefinition.Methods.Count);
methodReferenceToMethod = new Dictionary<MethodReferenceKey, MMethod>();
var tmpTokenToMethod = new Dictionary<int, MethodBase>();
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
foreach (var m in ResolverUtils.getMethodBases(type, flags))
tmpTokenToMethod[m.MetadataToken] = m;
foreach (var m in typeDefinition.Methods) {
var token = m.MetadataToken.ToInt32();
var method = new MMethod(tmpTokenToMethod[token], m);
tokenToMethod[token] = method;
methodReferenceToMethod[new MethodReferenceKey(method.methodDefinition)] = method;
}
}
void initFields() {
if (tokenToField != null)
return;
tokenToField = new Dictionary<int, MField>(typeDefinition.Fields.Count);
fieldReferenceToField = new Dictionary<FieldReferenceKey, MField>();
var tmpTokenToField = new Dictionary<int, FieldInfo>();
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
foreach (var f in type.GetFields(flags))
tmpTokenToField[f.MetadataToken] = f;
foreach (var f in typeDefinition.Fields) {
var token = f.MetadataToken.ToInt32();
var field = new MField(tmpTokenToField[token], f);
tokenToField[token] = field;
fieldReferenceToField[new FieldReferenceKey(field.fieldDefinition)] = field;
}
}
public override string ToString() {
return string.Format("{0:X8} - {1}", typeDefinition.MetadataToken.ToUInt32(), typeDefinition.FullName);
}
}
}

View File

@ -0,0 +1,371 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
using OpCode = Mono.Cecil.Cil.OpCode;
using OpCodes = Mono.Cecil.Cil.OpCodes;
using ROpCode = System.Reflection.Emit.OpCode;
using ROpCodes = System.Reflection.Emit.OpCodes;
namespace AssemblyData.methodsrewriter {
delegate object RewrittenMethod(object[] args);
class MethodsRewriter : IMethodsRewriter {
Dictionary<Module, MModule> modules = new Dictionary<Module, MModule>();
Dictionary<MethodBase, NewMethodInfo> realMethodToNewMethod = new Dictionary<MethodBase, NewMethodInfo>();
List<NewMethodInfo> newMethodInfos = new List<NewMethodInfo>();
class NewMethodInfo {
// Original method
public MethodBase oldMethod;
public Type delegateType;
// The modified code is here
public Delegate delegateInstance;
// newMethodInfos index
public int delegateIndex;
public RewrittenMethod rewrittenMethod;
public NewMethodInfo(MethodBase oldMethod) {
this.oldMethod = oldMethod;
}
}
MModule loadAssembly(Module module) {
MModule info;
if (modules.TryGetValue(module, out info))
return info;
info = new MModule(module, ModuleDefinition.ReadModule(module.FullyQualifiedName));
modules[module] = info;
return info;
}
MModule getModule(ModuleDefinition moduleDefinition) {
foreach (var mm in modules.Values) {
if (mm.moduleDefinition == moduleDefinition)
return mm;
}
return null;
}
MModule getModule(AssemblyNameReference assemblyRef) {
foreach (var mm in modules.Values) {
var asm = mm.moduleDefinition.Assembly;
if (asm.Name.FullName == assemblyRef.FullName)
return mm;
}
return null;
}
MModule getModule(IMetadataScope scope) {
if (scope is ModuleDefinition)
return getModule((ModuleDefinition)scope);
else if (scope is AssemblyNameReference)
return getModule((AssemblyNameReference)scope);
return null;
}
MType getType(TypeReference typeReference) {
var module = getModule(typeReference.Scope);
if (module != null)
return module.getType(typeReference);
return null;
}
MMethod getMethod(MethodReference methodReference) {
var module = getModule(methodReference.DeclaringType.Scope);
if (module != null)
return module.getMethod(methodReference);
return null;
}
MField getField(FieldReference fieldReference) {
var module = getModule(fieldReference.DeclaringType.Scope);
if (module != null)
return module.getField(fieldReference);
return null;
}
public object getRtObject(MemberReference memberReference) {
if (memberReference is TypeReference)
return getRtType((TypeReference)memberReference);
else if (memberReference is FieldReference)
return getRtField((FieldReference)memberReference);
else if (memberReference is MethodReference)
return getRtMethod((MethodReference)memberReference);
throw new ApplicationException(string.Format("Unknown MemberReference: {0}", memberReference));
}
public Type getRtType(TypeReference typeReference) {
var mtype = getType(typeReference);
if (mtype != null)
return mtype.type;
return Resolver.resolve(typeReference);
}
public FieldInfo getRtField(FieldReference fieldReference) {
var mfield = getField(fieldReference);
if (mfield != null)
return mfield.fieldInfo;
return Resolver.resolve(fieldReference);
}
public MethodBase getRtMethod(MethodReference methodReference) {
var mmethod = getMethod(methodReference);
if (mmethod != null)
return mmethod.methodBase;
return Resolver.resolve(methodReference);
}
public Type getDelegateType(MethodBase methodBase) {
return realMethodToNewMethod[methodBase].delegateType;
}
public RewrittenMethod createDelegate(MethodBase realMethod) {
var newMethodInfo = realMethodToNewMethod[realMethod];
if (newMethodInfo.rewrittenMethod != null)
return newMethodInfo.rewrittenMethod;
var dm = new DynamicMethod("method_" + newMethodInfo.oldMethod.Name, typeof(object), new Type[] { GetType(), typeof(object[]) }, GetType(), true);
var ilg = dm.GetILGenerator();
ilg.Emit(ROpCodes.Ldarg_0);
ilg.Emit(ROpCodes.Ldc_I4, newMethodInfo.delegateIndex);
ilg.Emit(ROpCodes.Call, GetType().GetMethod("rtGetDelegateInstance", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance));
var args = newMethodInfo.oldMethod.GetParameters();
for (int i = 0; i < args.Length; i++) {
var arg = args[i].ParameterType;
ilg.Emit(ROpCodes.Ldarg_1);
ilg.Emit(ROpCodes.Ldc_I4, i);
ilg.Emit(ROpCodes.Ldelem_Ref);
if (arg.IsValueType)
ilg.Emit(ROpCodes.Unbox_Any, arg);
else
ilg.Emit(ROpCodes.Castclass, arg);
}
ilg.Emit(ROpCodes.Ldarg_0);
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
var invokeMethod = newMethodInfo.delegateType.GetMethod("Invoke", flags);
ilg.Emit(ROpCodes.Call, invokeMethod);
if (ResolverUtils.getReturnType(newMethodInfo.oldMethod) == typeof(void))
ilg.Emit(ROpCodes.Ldnull);
ilg.Emit(ROpCodes.Ret);
newMethodInfo.rewrittenMethod = (RewrittenMethod)dm.CreateDelegate(typeof(RewrittenMethod), this);
return newMethodInfo.rewrittenMethod;
}
public void createMethod(MethodBase realMethod) {
if (realMethodToNewMethod.ContainsKey(realMethod))
return;
var newMethodInfo = new NewMethodInfo(realMethod);
newMethodInfo.delegateIndex = newMethodInfos.Count;
newMethodInfos.Add(newMethodInfo);
realMethodToNewMethod[realMethod] = newMethodInfo;
var moduleInfo = loadAssembly(realMethod.Module);
var methodInfo = moduleInfo.getMethod(realMethod);
if (!methodInfo.methodDefinition.HasBody || methodInfo.methodDefinition.Body.Instructions.Count == 0)
throw new ApplicationException(string.Format("Method {0} ({1:X8}) has no body", methodInfo.methodDefinition, methodInfo.methodDefinition.MetadataToken.ToUInt32()));
var codeGenerator = new CodeGenerator(this);
codeGenerator.setMethodInfo(methodInfo);
newMethodInfo.delegateType = codeGenerator.DelegateType;
var blocks = new Blocks(methodInfo.methodDefinition);
foreach (var block in blocks.MethodBlocks.getAllBlocks())
update(block, newMethodInfo);
IList<Instruction> allInstructions;
IList<ExceptionHandler> allExceptionHandlers;
blocks.getCode(out allInstructions, out allExceptionHandlers);
newMethodInfo.delegateInstance = codeGenerator.generate(allInstructions, allExceptionHandlers);
}
static Instruction create(OpCode opcode, object operand) {
return new Instruction {
OpCode = opcode,
Operand = operand,
};
}
// Inserts ldarg THIS, and returns number of instructions inserted at 'i'
int insertLoadThis(Block block, int i) {
block.insert(i, create(OpCodes.Ldarg, new Operand(Operand.Type.ThisArg)));
return 1;
}
int insertCallOurMethod(Block block, int i, string methodName) {
block.insert(i, create(OpCodes.Call, new Operand(Operand.Type.OurMethod, methodName)));
return 1;
}
void update(Block block, NewMethodInfo currentMethodInfo) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
if (instr.OpCode == OpCodes.Newobj) {
var ctor = (MethodReference)instr.Operand;
if (MemberReferenceHelper.verifyType(ctor.DeclaringType, "mscorlib", "System.Diagnostics.StackTrace")) {
insertLoadThis(block, i + 1);
insertCallOurMethod(block, i + 2, "static_rtFixStackTrace");
i += 2;
continue;
}
}
if (instr.OpCode == OpCodes.Call || instr.OpCode == OpCodes.Callvirt) {
var calledMethod = (MethodReference)instr.Operand;
if (DotNetUtils.isSameAssembly(calledMethod.DeclaringType, "mscorlib")) {
if (calledMethod.ToString() == "System.Reflection.Assembly System.Reflection.Assembly::GetAssembly(System.Type)") {
block.replace(i, 1, Instruction.Create(OpCodes.Nop));
insertLoadThis(block, i + 1);
insertCallOurMethod(block, i + 2, "static_rtGetAssembly_TypeArg");
i += 2;
continue;
}
else if (calledMethod.ToString() == "System.Reflection.Assembly System.Reflection.Assembly::GetCallingAssembly()" ||
calledMethod.ToString() == "System.Reflection.Assembly System.Reflection.Assembly::GetEntryAssembly()" ||
calledMethod.ToString() == "System.Reflection.Assembly System.Reflection.Assembly::GetExecutingAssembly()") {
block.replace(i, 1, Instruction.Create(OpCodes.Nop));
insertLoadThis(block, i + 1);
block.insert(i + 2, Instruction.Create(OpCodes.Ldc_I4, currentMethodInfo.delegateIndex));
insertCallOurMethod(block, i + 3, "rtGetAssembly");
i += 3;
continue;
}
}
var method = getMethod((MethodReference)instr.Operand);
if (method != null) {
createMethod(method.methodBase);
var newMethodInfo = realMethodToNewMethod[method.methodBase];
block.replace(i, 1, Instruction.Create(OpCodes.Nop));
int n = i + 1;
// Pop all pushed args to a temp array
var mparams = getParameters(method.methodDefinition);
if (mparams.Count > 0) {
block.insert(n++, Instruction.Create(OpCodes.Ldc_I4, mparams.Count));
var objectType = method.methodDefinition.Module.TypeSystem.Object;
block.insert(n++, Instruction.Create(OpCodes.Newarr, objectType));
block.insert(n++, create(OpCodes.Stloc, new Operand(Operand.Type.TempObjArray)));
for (int j = mparams.Count - 1; j >= 0; j--) {
var argType = mparams[j];
if (argType.IsValueType)
block.insert(n++, Instruction.Create(OpCodes.Box, argType));
block.insert(n++, create(OpCodes.Stloc, new Operand(Operand.Type.TempObj)));
block.insert(n++, create(OpCodes.Ldloc, new Operand(Operand.Type.TempObjArray)));
block.insert(n++, Instruction.Create(OpCodes.Ldc_I4, j));
block.insert(n++, create(OpCodes.Ldloc, new Operand(Operand.Type.TempObj)));
block.insert(n++, Instruction.Create(OpCodes.Stelem_Ref));
}
}
// Push delegate instance
insertLoadThis(block, n++);
block.insert(n++, Instruction.Create(OpCodes.Ldc_I4, newMethodInfo.delegateIndex));
insertCallOurMethod(block, n++, "rtGetDelegateInstance");
block.insert(n++, create(OpCodes.Castclass, new Operand(Operand.Type.ReflectionType, newMethodInfo.delegateType)));
// Push all popped args
if (mparams.Count > 0) {
for (int j = 0; j < mparams.Count; j++) {
block.insert(n++, create(OpCodes.Ldloc, new Operand(Operand.Type.TempObjArray)));
block.insert(n++, Instruction.Create(OpCodes.Ldc_I4, j));
block.insert(n++, Instruction.Create(OpCodes.Ldelem_Ref));
var argType = mparams[j];
if (argType.IsValueType)
block.insert(n++, Instruction.Create(OpCodes.Unbox_Any, argType));
else
block.insert(n++, Instruction.Create(OpCodes.Castclass, argType));
}
}
insertLoadThis(block, n++);
block.insert(n++, create(OpCodes.Call, new Operand(Operand.Type.NewMethod, method.methodBase)));
i = n - 1;
continue;
}
}
}
}
static List<TypeReference> getParameters(MethodDefinition method) {
int count = method.Parameters.Count + (method.HasThis ? 1 : 0);
var list = new List<TypeReference>(count);
if (method.HasThis)
list.Add(method.DeclaringType);
foreach (var argType in method.Parameters)
list.Add(argType.ParameterType);
return list;
}
// Called after the StackTrace ctor has been called.
static StackTrace static_rtFixStackTrace(StackTrace stackTrace, MethodsRewriter self) {
return self.rtFixStackTrace(stackTrace);
}
StackTrace rtFixStackTrace(StackTrace stackTrace) {
//TODO:
return stackTrace;
}
// Called when the code calls GetCallingAssembly(), GetEntryAssembly(), or GetExecutingAssembly()
Assembly rtGetAssembly(int delegateIndex) {
return newMethodInfos[delegateIndex].oldMethod.Module.Assembly;
}
// Called when the code calls GetAssembly(Type)
static Assembly static_rtGetAssembly_TypeArg(Type type, MethodsRewriter self) {
return self.rtGetAssembly_TypeArg(type);
}
Assembly rtGetAssembly_TypeArg(Type type) {
return Assembly.GetAssembly(type); //TODO:
}
Delegate rtGetDelegateInstance(int delegateIndex) {
return newMethodInfos[delegateIndex].delegateInstance;
}
}
}

View File

@ -0,0 +1,44 @@
/*
Copyright (C) 2011 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/>.
*/
namespace AssemblyData.methodsrewriter {
class Operand {
public enum Type {
ThisArg, // Replace operand with the 'this' arg
TempObj, // Replace operand with temp object local variable
TempObjArray, // Replace operand with temp object[] local variable
OurMethod, // Replace operand with a call to our method. methodName must be unique.
NewMethod, // Replace operand with a call to new method. data is realMethod
ReflectionType, // Replace operand with a .NET type
}
public Type type;
public object data;
public Operand(Type type) {
this.type = type;
this.data = null;
}
public Operand(Type type, object data) {
this.type = type;
this.data = data;
}
}
}

View File

@ -0,0 +1,99 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using de4dot.blocks;
namespace AssemblyData.methodsrewriter {
public static class Resolver {
static Dictionary<string, AssemblyResolver> assemblyResolvers = new Dictionary<string, AssemblyResolver>(StringComparer.Ordinal);
static AssemblyResolver getAssemblyResolver(IMetadataScope scope) {
var asmName = DotNetUtils.getFullAssemblyName(scope);
AssemblyResolver resolver;
if (!assemblyResolvers.TryGetValue(asmName, out resolver))
assemblyResolvers[asmName] = resolver = new AssemblyResolver(asmName);
return resolver;
}
public static Type resolve(TypeReference typeReference) {
var elemType = typeReference.GetElementType();
var resolver = getAssemblyResolver(elemType.Scope);
var resolvedType = resolver.resolve(elemType);
if (resolvedType != null)
return fixType(typeReference, resolvedType);
throw new ApplicationException(string.Format("Could not resolve type {0} ({1:X8}) in assembly {2}", typeReference, typeReference.MetadataToken.ToUInt32(), resolver));
}
public static FieldInfo resolve(FieldReference fieldReference) {
var resolver = getAssemblyResolver(fieldReference.DeclaringType.Scope);
var fieldInfo = resolver.resolve(fieldReference);
if (fieldInfo != null)
return fieldInfo;
throw new ApplicationException(string.Format("Could not resolve field {0} ({1:X8}) in assembly {2}", fieldReference, fieldReference.MetadataToken.ToUInt32(), resolver));
}
public static MethodBase resolve(MethodReference methodReference) {
var resolver = getAssemblyResolver(methodReference.DeclaringType.Scope);
var methodBase = resolver.resolve(methodReference);
if (methodBase != null)
return methodBase;
throw new ApplicationException(string.Format("Could not resolve method {0} ({1:X8}) in assembly {2}", methodReference, methodReference.MetadataToken.ToUInt32(), resolver));
}
static Type fixType(TypeReference typeReference, Type type) {
while (typeReference is TypeSpecification) {
var ts = (TypeSpecification)typeReference;
if (typeReference is ArrayType) {
var arrayType = (ArrayType)typeReference;
if (arrayType.IsVector)
type = type.MakeArrayType();
else
type = type.MakeArrayType(arrayType.Rank);
}
else if (typeReference is ByReferenceType) {
type = type.MakeByRefType();
}
else if (typeReference is PointerType) {
type = type.MakePointerType();
}
else if (typeReference is GenericInstanceType) {
var git = (GenericInstanceType)typeReference;
var args = new Type[git.GenericArguments.Count];
bool isGenericTypeDef = true;
for (int i = 0; i < args.Length; i++) {
var typeRef = git.GenericArguments[i];
if (!(typeRef.GetElementType() is GenericParameter))
isGenericTypeDef = false;
args[i] = Resolver.resolve(typeRef);
}
if (!isGenericTypeDef)
type = type.MakeGenericType(args);
}
typeReference = ts.ElementType;
}
return type;
}
}
}

View File

@ -0,0 +1,250 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using de4dot.blocks;
namespace AssemblyData.methodsrewriter {
static class ResolverUtils {
public static bool compareTypes(Type a, TypeReference b) {
if (a == null && b == null)
return true;
if (a == null || b == null)
return false;
var type = MemberReferenceHelper.getMemberReferenceType(b);
switch (type) {
case CecilType.ArrayType:
return compareArrayTypes(a, (ArrayType)b);
case CecilType.ByReferenceType:
return compareByReferenceTypes(a, (ByReferenceType)b);
case CecilType.FunctionPointerType:
return compareFunctionPointerTypes(a, (FunctionPointerType)b);
case CecilType.GenericInstanceType:
return compareGenericInstanceTypes(a, (GenericInstanceType)b);
case CecilType.GenericParameter:
return compareGenericParameters(a, (GenericParameter)b);
case CecilType.OptionalModifierType:
return compareOptionalModifierTypes(a, (OptionalModifierType)b);
case CecilType.PinnedType:
return comparePinnedTypes(a, (PinnedType)b);
case CecilType.PointerType:
return comparePointerTypes(a, (PointerType)b);
case CecilType.RequiredModifierType:
return compareRequiredModifierTypes(a, (RequiredModifierType)b);
case CecilType.SentinelType:
return compareSentinelTypes(a, (SentinelType)b);
case CecilType.TypeDefinition:
return compareTypeDefinitions(a, (TypeDefinition)b);
case CecilType.TypeReference:
return compareTypeReferences(a, (TypeReference)b);
default:
throw new ApplicationException(string.Format("Unknown cecil type {0}", type));
}
}
static bool compareArrayTypes(Type a, ArrayType b) {
if (!a.IsArray)
return false;
if (a.GetArrayRank() != b.Rank)
return false;
return compareTypes(a.GetElementType(), b.ElementType);
}
static bool compareByReferenceTypes(Type a, ByReferenceType b) {
if (!a.IsByRef)
return false;
return compareTypes(a.GetElementType(), b.ElementType);
}
static bool compareFunctionPointerTypes(Type a, FunctionPointerType b) {
return compareTypes(a, b.ElementType);
}
static bool compareGenericInstanceTypes(Type a, GenericInstanceType b) {
if (!a.IsGenericType)
return false;
var aGpargs = a.GetGenericArguments();
var bGpargs = b.GenericArguments;
if (aGpargs.Length != bGpargs.Count)
return false;
for (int i = 0; i < aGpargs.Length; i++) {
var aArg = aGpargs[i];
if (aArg.IsGenericParameter)
continue;
if (!compareTypes(aArg, bGpargs[i]))
return false;
}
return compareTypes(a, b.ElementType);
}
static bool compareGenericParameters(Type a, GenericParameter b) {
if (!a.IsGenericParameter)
return false;
if (a.GenericParameterPosition != b.Position)
return false;
return true;
}
static bool compareOptionalModifierTypes(Type a, OptionalModifierType b) {
return compareTypes(a, b.ElementType);
}
static bool comparePinnedTypes(Type a, PinnedType b) {
return compareTypes(a, b.ElementType);
}
static bool comparePointerTypes(Type a, PointerType b) {
if (!a.IsPointer)
return false;
return compareTypes(a.GetElementType(), b.ElementType);
}
static bool compareRequiredModifierTypes(Type a, RequiredModifierType b) {
return compareTypes(a, b.ElementType);
}
static bool compareSentinelTypes(Type a, SentinelType b) {
return compareTypes(a, b.ElementType);
}
static bool compareTypeDefinitions(Type a, TypeDefinition b) {
return compareTypeReferences(a, b);
}
static bool compareTypeReferences(Type a, TypeReference b) {
if (a.IsGenericParameter || a.IsPointer || a.IsByRef || a.IsArray)
return false;
if (a.Name != b.Name)
return false;
if ((a.Namespace ?? "") != b.Namespace)
return false;
var asmRef = DotNetUtils.getAssemblyNameReference(b.Scope);
var asmName = a.Assembly.GetName();
if (asmRef.Name != asmName.Name)
return false;
return compareTypes(a.DeclaringType, b.DeclaringType);
}
public static bool compareFields(FieldInfo a, FieldReference b) {
if (a == null && b == null)
return true;
if (a == null || b == null)
return false;
return a.Name == b.Name &&
compareTypes(a.FieldType, b.FieldType);
}
public static bool hasThis(MethodBase method) {
return (method.CallingConvention & CallingConventions.HasThis) != 0;
}
public static bool explicitThis(MethodBase method) {
return (method.CallingConvention & CallingConventions.ExplicitThis) != 0;
}
public static bool compareMethods(MethodBase a, MethodReference b) {
if (a == null && b == null)
return true;
if (a == null || b == null)
return false;
if (a.Name != b.Name)
return false;
if (hasThis(a) != b.HasThis || explicitThis(a) != b.ExplicitThis)
return false;
CallingConventions aCallingConvention = a.CallingConvention & (CallingConventions)7;
switch (b.CallingConvention) {
case MethodCallingConvention.Default:
if (aCallingConvention != CallingConventions.Standard && aCallingConvention != CallingConventions.Any)
return false;
break;
case MethodCallingConvention.VarArg:
if (aCallingConvention != CallingConventions.VarArgs && aCallingConvention != CallingConventions.Any)
return false;
break;
default:
return false;
}
if (!compareTypes(getReturnType(a), b.MethodReturnType.ReturnType))
return false;
var aParams = a.GetParameters();
var bParams = b.Parameters;
if (aParams.Length != bParams.Count)
return false;
for (int i = 0; i < aParams.Length; i++) {
if (!compareTypes(aParams[i].ParameterType, bParams[i].ParameterType))
return false;
}
var aGparams = getGenericArguments(a);
var bGparams = b.GenericParameters;
if (aGparams.Length != bGparams.Count)
return false;
return true;
}
public static Type getReturnType(MethodBase methodBase) {
var methodInfo = methodBase as MethodInfo;
if (methodInfo != null)
return methodInfo.ReturnType;
var ctorInfo = methodBase as ConstructorInfo;
if (ctorInfo != null)
return typeof(void);
throw new ApplicationException(string.Format("Could not figure out return type: {0} ({1:X8})", methodBase, methodBase.MetadataToken));
}
public static Type[] getGenericArguments(MethodBase methodBase) {
try {
return methodBase.GetGenericArguments();
}
catch (NotSupportedException) {
return new Type[0];
}
}
public static IEnumerable<MethodBase> getMethodBases(Type type, BindingFlags flags) {
if (type.TypeInitializer != null)
yield return type.TypeInitializer;
foreach (var ctor in type.GetConstructors(flags))
yield return ctor;
foreach (var m in type.GetMethods(flags))
yield return m;
}
}
}

View File

@ -0,0 +1,93 @@
/*
Copyright (C) 2011 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/>.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
namespace AssemblyData.methodsrewriter {
class TypeResolver {
public Type type;
Dictionary<string, List<MethodBase>> methods;
Dictionary<string, List<FieldInfo>> fields;
public TypeResolver(Type type) {
this.type = type;
}
public FieldInfo resolve(FieldReference fieldReference) {
initFields();
List<FieldInfo> list;
if (!fields.TryGetValue(fieldReference.Name, out list))
return null;
foreach (var field in list) {
if (ResolverUtils.compareFields(field, fieldReference))
return field;
}
return null;
}
void initFields() {
if (fields != null)
return;
fields = new Dictionary<string, List<FieldInfo>>(StringComparer.Ordinal);
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
foreach (var field in type.GetFields(flags)) {
List<FieldInfo> list;
if (!fields.TryGetValue(field.Name, out list))
fields[field.Name] = list = new List<FieldInfo>();
list.Add(field);
}
}
public MethodBase resolve(MethodReference methodReference) {
initMethods();
List<MethodBase> list;
if (!methods.TryGetValue(methodReference.Name, out list))
return null;
foreach (var method in list) {
if (ResolverUtils.compareMethods(method, methodReference))
return method;
}
return null;
}
void initMethods() {
if (methods != null)
return;
methods = new Dictionary<string, List<MethodBase>>(StringComparer.Ordinal);
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
foreach (var method in ResolverUtils.getMethodBases(type, flags)) {
List<MethodBase> list;
if (!methods.TryGetValue(method.Name, out list))
methods[method.Name] = list = new List<MethodBase>();
list.Add(method);
}
}
}
}

View File

@ -206,6 +206,10 @@ namespace de4dot.blocks {
return type != null && type.BaseType != null && type.BaseType.FullName == "System.MulticastDelegate";
}
public static bool isSameAssembly(TypeReference type, string assembly) {
return MemberReferenceHelper.getCanonicalizedScopeName(type.Scope) == assembly.ToLowerInvariant();
}
public static bool isMethod(MethodReference method, string returnType, string parameters) {
return method != null && method.FullName == returnType + " " + method.DeclaringType.FullName + "::" + method.Name + parameters;
}
@ -564,5 +568,21 @@ namespace de4dot.blocks {
throw new ApplicationException(string.Format("Unknown pop StackBehavior {0}", stackBehavior));
}
}
public static AssemblyNameReference getAssemblyNameReference(IMetadataScope scope) {
if (scope is ModuleDefinition) {
var moduleDefinition = (ModuleDefinition)scope;
return moduleDefinition.Assembly.Name;
}
else if (scope is AssemblyNameReference)
return (AssemblyNameReference)scope;
throw new ApplicationException(string.Format("Unknown IMetadataScope type: {0}", scope.GetType()));
}
public static string getFullAssemblyName(IMetadataScope scope) {
var asmRef = getAssemblyNameReference(scope);
return asmRef.FullName;
}
}
}

View File

@ -44,6 +44,33 @@ namespace de4dot.blocks {
TypeReference,
}
public class TypeReferenceKey {
TypeReference typeRef;
public TypeReference TypeReference {
get { return typeRef; }
}
public TypeReferenceKey(TypeReference typeRef) {
this.typeRef = typeRef;
}
public override int GetHashCode() {
return MemberReferenceHelper.typeHashCode(typeRef);
}
public override bool Equals(object obj) {
var other = obj as TypeReferenceKey;
if (other == null)
return false;
return MemberReferenceHelper.compareTypes(typeRef, other.typeRef);
}
public override string ToString() {
return typeRef.ToString();
}
}
public class FieldReferenceKey {
FieldReference fieldRef;
@ -255,7 +282,7 @@ namespace de4dot.blocks {
return string.Format("[{0}]{1}", getCanonicalizedScopeName(scope), fullName);
}
static string getCanonicalizedScopeName(IMetadataScope scope) {
public static string getCanonicalizedScopeName(IMetadataScope scope) {
var name = scope.Name.ToLowerInvariant();
if (scope is ModuleDefinition) {
if (name.EndsWith(".exe", StringComparison.Ordinal) || name.EndsWith(".dll", StringComparison.Ordinal))