Added a methods rewriter class
This commit is contained in:
parent
9945b8b47c
commit
e14a18971b
|
@ -40,6 +40,18 @@
|
||||||
<Compile Include="EmuStringDecrypter.cs" />
|
<Compile Include="EmuStringDecrypter.cs" />
|
||||||
<Compile Include="IAssemblyService.cs" />
|
<Compile Include="IAssemblyService.cs" />
|
||||||
<Compile Include="IStringDecrypter.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="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SimpleData.cs" />
|
<Compile Include="SimpleData.cs" />
|
||||||
<Compile Include="Utils.cs" />
|
<Compile Include="Utils.cs" />
|
||||||
|
|
|
@ -19,18 +19,17 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using AssemblyData.methodsrewriter;
|
||||||
|
|
||||||
namespace AssemblyData {
|
namespace AssemblyData {
|
||||||
class EmuStringDecrypter : IStringDecrypter {
|
class EmuStringDecrypter : IStringDecrypter {
|
||||||
delegate string DecryptString(object[] args);
|
|
||||||
List<DecryptInfo> decryptInfos = new List<DecryptInfo>();
|
List<DecryptInfo> decryptInfos = new List<DecryptInfo>();
|
||||||
|
MethodsRewriter methodsRewriter = new MethodsRewriter();
|
||||||
|
|
||||||
class DecryptInfo {
|
class DecryptInfo {
|
||||||
public MethodInfo method;
|
public MethodInfo method;
|
||||||
public DecryptString decryptString;
|
public RewrittenMethod decryptString;
|
||||||
|
|
||||||
public DecryptInfo(MethodInfo method) {
|
public DecryptInfo(MethodInfo method) {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
|
@ -53,8 +52,9 @@ namespace AssemblyData {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecryptString createDecryptString(MethodInfo method) {
|
RewrittenMethod createDecryptString(MethodInfo method) {
|
||||||
throw new System.NotImplementedException(); //TODO:
|
methodsRewriter.createMethod(method);
|
||||||
|
return methodsRewriter.createDelegate(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,30 @@ using System.Reflection.Emit;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace AssemblyData {
|
namespace AssemblyData {
|
||||||
|
// Yes, I did type this by hand.
|
||||||
internal delegate void Action();
|
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<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, 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, 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);
|
internal delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
|
||||||
|
@ -34,16 +55,53 @@ 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, 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, 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, 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 class Utils {
|
||||||
static Random random = new Random();
|
static Random random = new Random();
|
||||||
|
|
||||||
public static Type getDelegateType(MethodInfo method) {
|
public static Type getDelegateType(Type returnType, Type[] args) {
|
||||||
var parameters = method.GetParameters();
|
Type[] types;
|
||||||
var types = new Type[parameters.Length + 1];
|
if (returnType == typeof(void)) {
|
||||||
for (int i = 0; i < parameters.Length; i++)
|
types = args;
|
||||||
types[i] = parameters[i].ParameterType;
|
switch (types.Length) {
|
||||||
types[types.Length - 1] = method.ReturnType;
|
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) {
|
switch (types.Length) {
|
||||||
case 1: return typeof(Func<>).MakeGenericType(types);
|
case 1: return typeof(Func<>).MakeGenericType(types);
|
||||||
|
@ -56,8 +114,19 @@ namespace AssemblyData {
|
||||||
case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types);
|
case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types);
|
||||||
case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types);
|
case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types);
|
||||||
case 10: 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:
|
default:
|
||||||
throw new ApplicationException(string.Format("Too many arguments: {0}", method));
|
throw new ApplicationException(string.Format("Too many delegate type arguments: {0}", types.Length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
136
AssemblyData/methodsrewriter/AssemblyResolver.cs
Normal file
136
AssemblyData/methodsrewriter/AssemblyResolver.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
293
AssemblyData/methodsrewriter/CodeGenerator.cs
Normal file
293
AssemblyData/methodsrewriter/CodeGenerator.cs
Normal 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
AssemblyData/methodsrewriter/IMethodsRewriter.cs
Normal file
30
AssemblyData/methodsrewriter/IMethodsRewriter.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
37
AssemblyData/methodsrewriter/MField.cs
Normal file
37
AssemblyData/methodsrewriter/MField.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
AssemblyData/methodsrewriter/MMethod.cs
Normal file
36
AssemblyData/methodsrewriter/MMethod.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
147
AssemblyData/methodsrewriter/MModule.cs
Normal file
147
AssemblyData/methodsrewriter/MModule.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
AssemblyData/methodsrewriter/MType.cs
Normal file
104
AssemblyData/methodsrewriter/MType.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
371
AssemblyData/methodsrewriter/MethodsRewriter.cs
Normal file
371
AssemblyData/methodsrewriter/MethodsRewriter.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
AssemblyData/methodsrewriter/Operand.cs
Normal file
44
AssemblyData/methodsrewriter/Operand.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
99
AssemblyData/methodsrewriter/Resolver.cs
Normal file
99
AssemblyData/methodsrewriter/Resolver.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
250
AssemblyData/methodsrewriter/ResolverUtils.cs
Normal file
250
AssemblyData/methodsrewriter/ResolverUtils.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
AssemblyData/methodsrewriter/TypeResolver.cs
Normal file
93
AssemblyData/methodsrewriter/TypeResolver.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -206,6 +206,10 @@ namespace de4dot.blocks {
|
||||||
return type != null && type.BaseType != null && type.BaseType.FullName == "System.MulticastDelegate";
|
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) {
|
public static bool isMethod(MethodReference method, string returnType, string parameters) {
|
||||||
return method != null && method.FullName == returnType + " " + method.DeclaringType.FullName + "::" + method.Name + 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));
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,33 @@ namespace de4dot.blocks {
|
||||||
TypeReference,
|
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 {
|
public class FieldReferenceKey {
|
||||||
FieldReference fieldRef;
|
FieldReference fieldRef;
|
||||||
|
|
||||||
|
@ -255,7 +282,7 @@ namespace de4dot.blocks {
|
||||||
return string.Format("[{0}]{1}", getCanonicalizedScopeName(scope), fullName);
|
return string.Format("[{0}]{1}", getCanonicalizedScopeName(scope), fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string getCanonicalizedScopeName(IMetadataScope scope) {
|
public static string getCanonicalizedScopeName(IMetadataScope scope) {
|
||||||
var name = scope.Name.ToLowerInvariant();
|
var name = scope.Name.ToLowerInvariant();
|
||||||
if (scope is ModuleDefinition) {
|
if (scope is ModuleDefinition) {
|
||||||
if (name.EndsWith(".exe", StringComparison.Ordinal) || name.EndsWith(".dll", StringComparison.Ordinal))
|
if (name.EndsWith(".exe", StringComparison.Ordinal) || name.EndsWith(".dll", StringComparison.Ordinal))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user