-
Notifications
You must be signed in to change notification settings - Fork 396
Expand file tree
/
Copy pathDynamicCompiler.cs
More file actions
120 lines (98 loc) · 4.84 KB
/
DynamicCompiler.cs
File metadata and controls
120 lines (98 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
using System;
using System.Diagnostics.Contracts;
using System.Linq.Expressions;
using System.Reflection;
using ReClassNET.Extensions;
using ReClassNET.Memory;
namespace ReClassNET.AddressParser
{
public class DynamicCompiler : IExecutor
{
public IntPtr Execute(IExpression expression, IProcessReader processReader)
{
Contract.Requires(expression != null);
Contract.Requires(processReader != null);
return CompileExpression(expression)(processReader);
}
public static Func<IProcessReader, IntPtr> CompileExpression(IExpression expression)
{
Contract.Requires(expression != null);
var processParameter = Expression.Parameter(typeof(IProcessReader));
return Expression.Lambda<Func<IProcessReader, IntPtr>>(
GenerateMethodBody(expression, processParameter),
processParameter
).Compile();
}
private static Expression GenerateMethodBody(IExpression expression, Expression processParameter)
{
Contract.Requires(expression != null);
Contract.Requires(processParameter != null);
static MethodInfo GetIntPtrExtension(string name) => typeof(IntPtrExtension).GetRuntimeMethod(name, new[] { typeof(IntPtr), typeof(IntPtr) });
switch (expression)
{
case ConstantExpression constantExpression:
{
var convertFn = typeof(IntPtrExtension).GetRuntimeMethod(nameof(IntPtrExtension.From), new[] { typeof(long) });
return Expression.Call(null, convertFn, Expression.Constant(constantExpression.Value));
}
case NegateExpression negateExpression:
{
var argument = GenerateMethodBody(negateExpression.Expression, processParameter);
var negateFn = typeof(IntPtrExtension).GetRuntimeMethod(nameof(IntPtrExtension.Negate), new[] { typeof(IntPtr) });
return Expression.Call(null, negateFn, argument);
}
case AddExpression addExpression:
{
var argument1 = GenerateMethodBody(addExpression.Lhs, processParameter);
var argument2 = GenerateMethodBody(addExpression.Rhs, processParameter);
return Expression.Call(null, GetIntPtrExtension(nameof(IntPtrExtension.Add)), argument1, argument2);
}
case SubtractExpression subtractExpression:
{
var argument1 = GenerateMethodBody(subtractExpression.Lhs, processParameter);
var argument2 = GenerateMethodBody(subtractExpression.Rhs, processParameter);
return Expression.Call(null, GetIntPtrExtension(nameof(IntPtrExtension.Sub)), argument1, argument2);
}
case MultiplyExpression multiplyExpression:
{
var argument1 = GenerateMethodBody(multiplyExpression.Lhs, processParameter);
var argument2 = GenerateMethodBody(multiplyExpression.Rhs, processParameter);
return Expression.Call(null, GetIntPtrExtension(nameof(IntPtrExtension.Mul)), argument1, argument2);
}
case DivideExpression divideExpression:
{
var argument1 = GenerateMethodBody(divideExpression.Lhs, processParameter);
var argument2 = GenerateMethodBody(divideExpression.Rhs, processParameter);
return Expression.Call(null, GetIntPtrExtension(nameof(IntPtrExtension.Div)), argument1, argument2);
}
case ModuleExpression moduleExpression:
{
var getModuleByNameFunc = typeof(IProcessReader).GetRuntimeMethod(nameof(IProcessReader.GetModuleByName), new[] { typeof(string) });
var moduleNameConstant = Expression.Constant(moduleExpression.Name);
var moduleVariable = Expression.Variable(typeof(Memory.Module));
var assignExpression = Expression.Assign(moduleVariable, Expression.Call(processParameter, getModuleByNameFunc, moduleNameConstant));
return Expression.Block(
new[] { moduleVariable },
assignExpression,
Expression.Condition(
Expression.Equal(moduleVariable, Expression.Constant(null)),
Expression.Constant(IntPtr.Zero),
Expression.MakeMemberAccess(moduleVariable, typeof(Memory.Module).GetProperty(nameof(Memory.Module.Start))!)
)
);
}
case ReadMemoryExpression readMemoryExpression:
{
var addressParameter = GenerateMethodBody(readMemoryExpression.Expression, processParameter);
var functionName = readMemoryExpression.ByteCount == 4 ? nameof(IRemoteMemoryReaderExtension.ReadRemoteInt32) : nameof(IRemoteMemoryReaderExtension.ReadRemoteInt64);
var readRemoteIntPtrFn = typeof(IRemoteMemoryReaderExtension).GetRuntimeMethod(functionName, new[] { typeof(IRemoteMemoryReader), typeof(IntPtr) });
var callExpression = Expression.Call(null, readRemoteIntPtrFn, processParameter, addressParameter);
var paramType = readMemoryExpression.ByteCount == 4 ? typeof(int) : typeof(long);
var convertFn = typeof(IntPtrExtension).GetRuntimeMethod(nameof(IntPtrExtension.From), new[] { paramType });
return Expression.Call(null, convertFn, callExpression);
}
}
throw new ArgumentException($"Unsupported operation '{expression.GetType().FullName}'.");
}
}
}