Skip to content

Commit e968a29

Browse files
committed
Reduced IRemoteMemoryReader interface size.
1 parent e7d0513 commit e968a29

File tree

7 files changed

+183
-255
lines changed

7 files changed

+183
-255
lines changed

ReClass.NET/AddressParser/DynamicCompiler.cs

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ public static Func<IProcessReader, IntPtr> CompileExpression(IExpression express
2929
).Compile();
3030
}
3131

32-
private static Expression GenerateMethodBody(IExpression expression, Expression parameter)
32+
private static Expression GenerateMethodBody(IExpression expression, Expression processParameter)
3333
{
3434
Contract.Requires(expression != null);
35-
Contract.Requires(parameter != null);
35+
Contract.Requires(processParameter != null);
36+
37+
static MethodInfo GetIntPtrExtension(string name) => typeof(IntPtrExtension).GetRuntimeMethod(name, new[] { typeof(IntPtr), typeof(IntPtr) });
3638

3739
switch (expression)
3840
{
@@ -44,37 +46,37 @@ private static Expression GenerateMethodBody(IExpression expression, Expression
4446
}
4547
case NegateExpression negateExpression:
4648
{
47-
var argument = GenerateMethodBody(negateExpression.Expression, parameter);
49+
var argument = GenerateMethodBody(negateExpression.Expression, processParameter);
4850

4951
var negateFn = typeof(IntPtrExtension).GetRuntimeMethod(nameof(IntPtrExtension.Negate), new[] { typeof(IntPtr) });
5052

5153
return Expression.Call(null, negateFn, argument);
5254
}
5355
case AddExpression addExpression:
5456
{
55-
var argument1 = GenerateMethodBody(addExpression.Lhs, parameter);
56-
var argument2 = GenerateMethodBody(addExpression.Rhs, parameter);
57+
var argument1 = GenerateMethodBody(addExpression.Lhs, processParameter);
58+
var argument2 = GenerateMethodBody(addExpression.Rhs, processParameter);
5759

5860
return Expression.Call(null, GetIntPtrExtension(nameof(IntPtrExtension.Add)), argument1, argument2);
5961
}
6062
case SubtractExpression subtractExpression:
6163
{
62-
var argument1 = GenerateMethodBody(subtractExpression.Lhs, parameter);
63-
var argument2 = GenerateMethodBody(subtractExpression.Rhs, parameter);
64+
var argument1 = GenerateMethodBody(subtractExpression.Lhs, processParameter);
65+
var argument2 = GenerateMethodBody(subtractExpression.Rhs, processParameter);
6466

6567
return Expression.Call(null, GetIntPtrExtension(nameof(IntPtrExtension.Sub)), argument1, argument2);
6668
}
6769
case MultiplyExpression multiplyExpression:
6870
{
69-
var argument1 = GenerateMethodBody(multiplyExpression.Lhs, parameter);
70-
var argument2 = GenerateMethodBody(multiplyExpression.Rhs, parameter);
71+
var argument1 = GenerateMethodBody(multiplyExpression.Lhs, processParameter);
72+
var argument2 = GenerateMethodBody(multiplyExpression.Rhs, processParameter);
7173

7274
return Expression.Call(null, GetIntPtrExtension(nameof(IntPtrExtension.Mul)), argument1, argument2);
7375
}
7476
case DivideExpression divideExpression:
7577
{
76-
var argument1 = GenerateMethodBody(divideExpression.Lhs, parameter);
77-
var argument2 = GenerateMethodBody(divideExpression.Rhs, parameter);
78+
var argument1 = GenerateMethodBody(divideExpression.Lhs, processParameter);
79+
var argument2 = GenerateMethodBody(divideExpression.Rhs, processParameter);
7880

7981
return Expression.Call(null, GetIntPtrExtension(nameof(IntPtrExtension.Div)), argument1, argument2);
8082
}
@@ -84,7 +86,7 @@ private static Expression GenerateMethodBody(IExpression expression, Expression
8486
var moduleNameConstant = Expression.Constant(moduleExpression.Name);
8587

8688
var moduleVariable = Expression.Variable(typeof(Memory.Module));
87-
var assignExpression = Expression.Assign(moduleVariable, Expression.Call(parameter, getModuleByNameFunc, moduleNameConstant));
89+
var assignExpression = Expression.Assign(moduleVariable, Expression.Call(processParameter, getModuleByNameFunc, moduleNameConstant));
8890

8991
return Expression.Block(
9092
new[] { moduleVariable },
@@ -98,28 +100,15 @@ private static Expression GenerateMethodBody(IExpression expression, Expression
98100
}
99101
case ReadMemoryExpression readMemoryExpression:
100102
{
101-
var argument = GenerateMethodBody(readMemoryExpression.Expression, parameter);
102-
103-
var functionName = readMemoryExpression.ByteCount == 4 ? nameof(IRemoteMemoryReader.ReadRemoteInt32) : nameof(IRemoteMemoryReader.ReadRemoteInt64);
104-
var readRemoteIntFn = typeof(IRemoteMemoryReader).GetRuntimeMethod(functionName, new[] { typeof(IntPtr) });
103+
var addressParameter = GenerateMethodBody(readMemoryExpression.Expression, processParameter);
105104

106-
var callExpression = Expression.Call(parameter, readRemoteIntFn, argument);
105+
var readRemoteIntPtrFn = typeof(IRemoteMemoryReaderExtension).GetRuntimeMethod(nameof(IRemoteMemoryReaderExtension.ReadRemoteIntPtr), new[] { typeof(IRemoteMemoryReader), typeof(IntPtr) });
107106

108-
var paramType = readMemoryExpression.ByteCount == 4 ? typeof(int) : typeof(long);
109-
var convertFn = typeof(IntPtrExtension).GetRuntimeMethod(nameof(IntPtrExtension.From), new[] { paramType });
110-
111-
return Expression.Call(null, convertFn, callExpression);
107+
return Expression.Call(null, readRemoteIntPtrFn, processParameter, addressParameter);
112108
}
113109
}
114110

115111
throw new ArgumentException($"Unsupported operation '{expression.GetType().FullName}'.");
116112
}
117-
118-
private static MethodInfo GetIntPtrExtension(string name)
119-
{
120-
Contract.Requires(name != null);
121-
122-
return typeof(IntPtrExtension).GetRuntimeMethod(name, new[] { typeof(IntPtr), typeof(IntPtr) });
123-
}
124113
}
125114
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
using System;
2+
using System.Diagnostics.Contracts;
3+
using System.Text;
4+
using ReClassNET.Memory;
5+
using ReClassNET.MemoryScanner;
6+
7+
namespace ReClassNET.Extensions
8+
{
9+
public static class IRemoteMemoryReaderExtension
10+
{
11+
public static sbyte ReadRemoteInt8(this IRemoteMemoryReader reader, IntPtr address)
12+
{
13+
var data = reader.ReadRemoteMemory(address, sizeof(sbyte));
14+
15+
return (sbyte)data[0];
16+
}
17+
18+
public static byte ReadRemoteUInt8(this IRemoteMemoryReader reader, IntPtr address)
19+
{
20+
var data = reader.ReadRemoteMemory(address, sizeof(byte));
21+
22+
return data[0];
23+
}
24+
25+
public static short ReadRemoteInt16(this IRemoteMemoryReader reader, IntPtr address)
26+
{
27+
var data = reader.ReadRemoteMemory(address, sizeof(short));
28+
29+
return reader.BitConverter.ToInt16(data, 0);
30+
}
31+
32+
public static ushort ReadRemoteUInt16(this IRemoteMemoryReader reader, IntPtr address)
33+
{
34+
var data = reader.ReadRemoteMemory(address, sizeof(ushort));
35+
36+
return reader.BitConverter.ToUInt16(data, 0);
37+
}
38+
39+
public static int ReadRemoteInt32(this IRemoteMemoryReader reader, IntPtr address)
40+
{
41+
var data = reader.ReadRemoteMemory(address, sizeof(int));
42+
43+
return reader.BitConverter.ToInt32(data, 0);
44+
}
45+
46+
public static uint ReadRemoteUInt32(this IRemoteMemoryReader reader, IntPtr address)
47+
{
48+
var data = reader.ReadRemoteMemory(address, sizeof(uint));
49+
50+
return reader.BitConverter.ToUInt32(data, 0);
51+
}
52+
53+
public static long ReadRemoteInt64(this IRemoteMemoryReader reader, IntPtr address)
54+
{
55+
var data = reader.ReadRemoteMemory(address, sizeof(long));
56+
57+
return reader.BitConverter.ToInt64(data, 0);
58+
}
59+
60+
public static ulong ReadRemoteUInt64(this IRemoteMemoryReader reader, IntPtr address)
61+
{
62+
var data = reader.ReadRemoteMemory(address, sizeof(ulong));
63+
64+
return reader.BitConverter.ToUInt64(data, 0);
65+
}
66+
67+
public static float ReadRemoteFloat(this IRemoteMemoryReader reader, IntPtr address)
68+
{
69+
var data = reader.ReadRemoteMemory(address, sizeof(float));
70+
71+
return reader.BitConverter.ToSingle(data, 0);
72+
}
73+
74+
public static double ReadRemoteDouble(this IRemoteMemoryReader reader, IntPtr address)
75+
{
76+
var data = reader.ReadRemoteMemory(address, sizeof(double));
77+
78+
return reader.BitConverter.ToDouble(data, 0);
79+
}
80+
81+
public static IntPtr ReadRemoteIntPtr(this IRemoteMemoryReader reader, IntPtr address)
82+
{
83+
#if RECLASSNET64
84+
return (IntPtr)reader.ReadRemoteInt64(address);
85+
#else
86+
return (IntPtr)reader.ReadRemoteInt32(address);
87+
#endif
88+
}
89+
90+
public static string ReadRemoteString(this IRemoteMemoryReader reader, IntPtr address, Encoding encoding, int length)
91+
{
92+
Contract.Requires(encoding != null);
93+
Contract.Requires(length >= 0);
94+
Contract.Ensures(Contract.Result<string>() != null);
95+
96+
var data = reader.ReadRemoteMemory(address, length * encoding.GuessByteCountPerChar());
97+
98+
try
99+
{
100+
var sb = new StringBuilder(encoding.GetString(data));
101+
for (var i = 0; i < sb.Length; ++i)
102+
{
103+
if (sb[i] == '\0')
104+
{
105+
sb.Length = i;
106+
break;
107+
}
108+
if (!sb[i].IsPrintable())
109+
{
110+
sb[i] = '.';
111+
}
112+
}
113+
return sb.ToString();
114+
}
115+
catch
116+
{
117+
return string.Empty;
118+
}
119+
}
120+
121+
public static string ReadRemoteStringUntilFirstNullCharacter(this IRemoteMemoryReader reader, IntPtr address, Encoding encoding, int length)
122+
{
123+
Contract.Requires(encoding != null);
124+
Contract.Requires(length >= 0);
125+
Contract.Ensures(Contract.Result<string>() != null);
126+
127+
var data = reader.ReadRemoteMemory(address, length * encoding.GuessByteCountPerChar());
128+
129+
// TODO We should cache the pattern per encoding.
130+
var index = PatternScanner.FindPattern(BytePattern.From(new byte[encoding.GuessByteCountPerChar()]), data);
131+
if (index == -1)
132+
{
133+
index = data.Length;
134+
}
135+
136+
try
137+
{
138+
return encoding.GetString(data, 0, Math.Min(index, data.Length));
139+
}
140+
catch
141+
{
142+
return string.Empty;
143+
}
144+
}
145+
}
146+
}

ReClass.NET/Memory/IRemoteMemoryReader.cs

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Text;
32
using ReClassNET.Util.Conversion;
43

54
namespace ReClassNET.Memory
@@ -26,75 +25,6 @@ public interface IRemoteMemoryReader
2625
/// <returns>An array of bytes.</returns>
2726
byte[] ReadRemoteMemory(IntPtr address, int size);
2827

29-
/// <summary>Reads a <see cref="sbyte"/> from the address in the remote process.</summary>
30-
/// <param name="address">The address to read from.</param>
31-
/// <returns>The data read as <see cref="sbyte"/> or 0 if the read fails.</returns>
32-
sbyte ReadRemoteInt8(IntPtr address);
33-
34-
/// <summary>Reads a <see cref="byte"/> from the address in the remote process.</summary>
35-
/// <param name="address">The address to read from.</param>
36-
/// <returns>The data read as <see cref="byte"/> or 0 if the read fails.</returns>
37-
byte ReadRemoteUInt8(IntPtr address);
38-
39-
/// <summary>Reads a <see cref="short"/> from the address in the remote process.</summary>
40-
/// <param name="address">The address to read from.</param>
41-
/// <returns>The data read as <see cref="short"/> or 0 if the read fails.</returns>
42-
short ReadRemoteInt16(IntPtr address);
43-
44-
/// <summary>Reads a <see cref="ushort"/> from the address in the remote process.</summary>
45-
/// <param name="address">The address to read from.</param>
46-
/// <returns>The data read as <see cref="ushort"/> or 0 if the read fails.</returns>
47-
ushort ReadRemoteUInt16(IntPtr address);
48-
49-
/// <summary>Reads a <see cref="int"/> from the address in the remote process.</summary>
50-
/// <param name="address">The address to read from.</param>
51-
/// <returns>The data read as <see cref="int"/> or 0 if the read fails.</returns>
52-
int ReadRemoteInt32(IntPtr address);
53-
54-
/// <summary>Reads a <see cref="uint"/> from the address in the remote process.</summary>
55-
/// <param name="address">The address to read from.</param>
56-
/// <returns>The data read as <see cref="uint"/> or 0 if the read fails.</returns>
57-
uint ReadRemoteUInt32(IntPtr address);
58-
59-
/// <summary>Reads a <see cref="long"/> from the address in the remote process.</summary>
60-
/// <param name="address">The address to read from.</param>
61-
/// <returns>The data read as <see cref="long"/> or 0 if the read fails.</returns>
62-
long ReadRemoteInt64(IntPtr address);
63-
64-
/// <summary>Reads a <see cref="ulong"/> from the address in the remote process.</summary>
65-
/// <param name="address">The address to read from.</param>
66-
/// <returns>The data read as <see cref="ulong"/> or 0 if the read fails.</returns>
67-
ulong ReadRemoteUInt64(IntPtr address);
68-
69-
/// <summary>Reads a <see cref="float"/> from the address in the remote process.</summary>
70-
/// <param name="address">The address to read from.</param>
71-
/// <returns>The data read as <see cref="float"/> or 0 if the read fails.</returns>
72-
float ReadRemoteFloat(IntPtr address);
73-
74-
/// <summary>Reads a <see cref="double"/> from the address in the remote process.</summary>
75-
/// <param name="address">The address to read from.</param>
76-
/// <returns>The data read as <see cref="double"/> or 0 if the read fails.</returns>
77-
double ReadRemoteDouble(IntPtr address);
78-
79-
/// <summary>Reads a <see cref="IntPtr"/> from the address in the remote process.</summary>
80-
/// <param name="address">The address to read from.</param>
81-
/// <returns>The data read as <see cref="IntPtr"/> or 0 if the read fails.</returns>
82-
IntPtr ReadRemoteIntPtr(IntPtr address);
83-
84-
/// <summary>Reads a string from the address in the remote process with the given length using the provided encoding.</summary>
85-
/// <param name="encoding">The encoding used by the string.</param>
86-
/// <param name="address">The address of the string.</param>
87-
/// <param name="length">The length of the string.</param>
88-
/// <returns>The string.</returns>
89-
string ReadRemoteString(Encoding encoding, IntPtr address, int length);
90-
91-
/// <summary>Reads a string from the address in the remote process with the given length and encoding. The string gets truncated at the first zero character.</summary>
92-
/// <param name="encoding">The encoding used by the string.</param>
93-
/// <param name="address">The address of the string.</param>
94-
/// <param name="length">The maximum length of the string.</param>
95-
/// <returns>The string.</returns>
96-
string ReadRemoteStringUntilFirstNullCharacter(Encoding encoding, IntPtr address, int length);
97-
9828
/// <summary>Reads remote runtime type information for the given address from the remote process.</summary>
9929
/// <param name="address">The address.</param>
10030
/// <returns>A string containing the runtime type information or null if no information could get found.</returns>

0 commit comments

Comments
 (0)