XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEExtension.NetCore.MemoryEditor

【DLL】内存读写工具/编辑器

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFEExtension.NetCore.MemoryEditor

大幅度优化结构,完善监听器

87452f5
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

3 个文件 +220 -50
Modified XFEExtension.NetCore.MemoryEditor/MemoryEditor.cs +115 -32
@@ -1,5 +1,4 @@
1 1 using System.Diagnostics;
2 using System.Net;
3 2 using System.Runtime.InteropServices;
4 3 using XFEExtension.NetCore.DelegateExtension;
5 4
@@ -8,12 +7,14 @@ namespace XFEExtension.NetCore.MemoryEditor;
8 7 /// <summary>
9 8 /// 内存编辑器
10 9 /// </summary>
11 public partial class MemoryEditor
10 public partial class MemoryEditor : IDisposable
12 11 {
12 private bool disposedValue;
13
13 14 /// <summary>
14 15 /// 当指定地址的内存值变化时触发
15 16 /// </summary>
16 public event XFEEventHandler<nint, MemoryValue>? ValueChanged;
17 public event XFEEventHandler<nint?, MemoryValue>? ValueChanged;
17 18 /// <summary>
18 19 /// 目标进程
19 20 /// </summary>
@@ -35,15 +36,17 @@ public partial class MemoryEditor
35 36 /// </summary>
36 37 /// <typeparam name="T">目标类型(int,float,long等)</typeparam>
37 38 /// <param name="address">指定地址</param>
38 /// <returns></returns>
39 public T ReadMemory<T>(nint address) where T : struct => ReadMemory<T>(ProcessHandle, address);
39 /// <param name="result">读取结果</param>
40 /// <returns>是否读取成功</returns>
41 public bool ReadMemory<T>(nint address, out T result) where T : struct => ReadMemory<T>(ProcessHandle, address, out result);
40 42 /// <summary>
41 43 /// 在指定内存地址中写入数据
42 44 /// </summary>
43 45 /// <typeparam name="T">数据类型(int,float,long等)</typeparam>
44 46 /// <param name="address">目标地址</param>
45 47 /// <param name="source">待写入值</param>
46 public void WriteMemory<T>(nint address, T source) where T : struct => WriteMemory<T>(ProcessHandle, address, source);
48 /// <returns>是否写入成功</returns>
49 public bool WriteMemory<T>(nint address, T source) where T : struct => WriteMemory<T>(ProcessHandle, address, source);
47 50 /// <summary>
48 51 /// 添加监听器
49 52 /// </summary>
@@ -60,11 +63,40 @@ public partial class MemoryEditor
60 63 /// <param name="customName">自定义监听器标识名</param>
61 64 public void AddListener<T>(nint address, int delay, string customName = "") where T : struct => _ = Listener.StartListen<T>(address, delay, customName);
62 65 /// <summary>
66 /// 添加监听器
67 /// </summary>
68 /// <typeparam name="T">待监听的内存的数据类型(int,float,long等)</typeparam>
69 /// <param name="address">待监听的内存地址</param>
70 /// <param name="delay">检测频率</param>
71 /// <param name="customName">自定义监听器标识名</param>
72 public void AddListener<T>(nint address, TimeSpan delay, string customName = "") where T : struct => _ = Listener.StartListen<T>(address, delay, customName);
73 /// <summary>
74 /// 添加监听器
75 /// </summary>
76 /// <typeparam name="T">待监听的内存的数据类型(int,float,long等)</typeparam>
77 /// <param name="getMemoryAddressFunc">动态获取内存地址的方法</param>
78 /// <param name="delay">检测频率,以毫秒为单位</param>
79 /// <param name="customName">自定义监听器标识名</param>
80 public void AddListener<T>(Func<nint?> getMemoryAddressFunc, int delay, string customName = "") where T : struct => _ = Listener.StartListen<T>(getMemoryAddressFunc, delay, customName);
81 /// <summary>
82 /// 添加监听器
83 /// </summary>
84 /// <typeparam name="T">待监听的内存的数据类型(int,float,long等)</typeparam>
85 /// <param name="getMemoryAddressFunc">动态获取内存地址的方法</param>
86 /// <param name="delay">检测频率</param>
87 /// <param name="customName">自定义监听器标识名</param>
88 public void AddListener<T>(Func<nint?> getMemoryAddressFunc, TimeSpan delay, string customName = "") where T : struct => _ = Listener.StartListen<T>(getMemoryAddressFunc, delay, customName);
89 /// <summary>
63 90 /// 移除并停止指定监听器
64 91 /// </summary>
65 92 /// <param name="address">监听地址</param>
66 93 public void RemoveListener(nint address) => Listener.StopListener(address);
67 94 /// <summary>
95 /// 移除并停止指定监听器
96 /// </summary>
97 /// <param name="customName">自定义名称</param>
98 public void RemoveListener(string customName) => Listener.StopListener(customName);
99 /// <summary>
68 100 /// 移除所有监听器
69 101 /// </summary>
70 102 public void RemoveListeners() => Listener.StopListener();
@@ -75,7 +107,15 @@ public partial class MemoryEditor
75 107 /// <param name="baseAddress">基址的地址部分</param>
76 108 /// <param name="offsets">基址的偏移组</param>
77 109 /// <returns>实际地址</returns>
78 public nint ResolvePointerAddress(string moduleName, int baseAddress, params int[] offsets) => ResolvePointerAddress(TargetProcess.ProcessName, moduleName, baseAddress, ProcessBiteType, offsets);
110 public nint ResolvePointerAddress(string moduleName, int baseAddress, params nint[] offsets) => ResolvePointerAddress(TargetProcess, moduleName, baseAddress, ProcessBiteType, offsets);
111 /// <summary>
112 /// 解析基址对应的实际地址
113 /// </summary>
114 /// <param name="moduleBaseAddress">模块地址(基址的进程部分,可以是DLL等)</param>
115 /// <param name="baseAddress">基址的地址部分</param>
116 /// <param name="offsets">基址的偏移组</param>
117 /// <returns>实际地址</returns>
118 public nint ResolvePointerAddress(nint moduleBaseAddress, int baseAddress, params nint[] offsets) => ResolvePointerAddress(TargetProcess, moduleBaseAddress, baseAddress, ProcessBiteType, offsets);
79 119 /// <summary>
80 120 /// 内存编辑器
81 121 /// </summary>
@@ -118,6 +158,41 @@ public partial class MemoryEditor
118 158 Listener = new(ProcessHandle);
119 159 Listener.ValueChanged += (sender, e) => ValueChanged?.Invoke(sender, e);
120 160 }
161 /// <summary>
162 /// 释放资源
163 /// </summary>
164 /// <param name="disposing"></param>
165 protected virtual void Dispose(bool disposing)
166 {
167 if (!disposedValue)
168 {
169 if (disposing)
170 {
171 Listener.Dispose();
172 }
173
174 // TODO: 释放未托管的资源(未托管的对象)并重写终结器
175 // TODO: 将大型字段设置为 null
176 disposedValue = true;
177 }
178 }
179
180 // // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
181 // ~MemoryEditor()
182 // {
183 // // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
184 // Dispose(disposing: false);
185 // }
186
187 /// <summary>
188 /// 释放资源
189 /// </summary>
190 public void Dispose()
191 {
192 // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
193 Dispose(disposing: true);
194 GC.SuppressFinalize(this);
195 }
121 196 #region 静态方法
122 197 /// <summary>
123 198 /// 获取程序句柄
@@ -147,18 +222,20 @@ public partial class MemoryEditor
147 222 /// <typeparam name="T">目标类型(int,float,long等)</typeparam>
148 223 /// <param name="processHandle">进程句柄</param>
149 224 /// <param name="address">指定地址</param>
150 /// <returns></returns>
151 public static T ReadMemory<T>(nint processHandle, nint address) where T : struct
225 /// <param name="result">读取结果</param>
226 /// <returns>是否读取成功</returns>
227 public static bool ReadMemory<T>(nint processHandle, nint address, out T result) where T : struct
152 228 {
153 229 unsafe
154 230 {
155 231 var size = Marshal.SizeOf<T>();
156 232 var buffer = new byte[size];
157 ReadProcessMemory(processHandle, address, buffer, (uint)size, out _);
233 var boolResult = ReadProcessMemory(processHandle, address, buffer, (uint)size, out _);
158 234 fixed (byte* pBuffer = buffer)
159 235 {
160 return Marshal.PtrToStructure<T>((nint)pBuffer);
236 result = Marshal.PtrToStructure<T>((nint)pBuffer);
161 237 }
238 return boolResult;
162 239 }
163 240 }
164 241 /// <summary>
@@ -168,46 +245,52 @@ public partial class MemoryEditor
168 245 /// <param name="processHandle">进程句柄</param>
169 246 /// <param name="address">目标地址</param>
170 247 /// <param name="source">待写入值</param>
171 public static void WriteMemory<T>(nint processHandle, nint address, T source) where T : struct
248 /// <returns>是否写入成功</returns>
249 public static bool WriteMemory<T>(nint processHandle, nint address, T source) where T : struct
172 250 {
173 251 var buffer = StructureToByteArray(source);
174 WriteProcessMemory(processHandle, address, buffer, (uint)buffer.Length, out _);
252 return WriteProcessMemory(processHandle, address, buffer, (uint)buffer.Length, out _);
175 253 }
176 254 /// <summary>
177 255 /// 解析基址对应的实际地址
178 256 /// </summary>
179 /// <param name="processName">进程名称</param>
257 /// <param name="process">主进程</param>
180 258 /// <param name="moduleName">模块名称(基址的进程部分,可以是DLL等)</param>
181 259 /// <param name="baseAddress">基址的地址部分</param>
182 260 /// <param name="processType">目标进程类型</param>
183 261 /// <param name="offsets">基址的偏移组</param>
184 262 /// <returns>实际地址</returns>
185 public static nint ResolvePointerAddress(string processName, string moduleName, int baseAddress, ProcessType processType, params int[] offsets)
263 public static nint ResolvePointerAddress(Process process, string moduleName, int baseAddress, ProcessType processType, params nint[] offsets) => ResolvePointerAddress(process, GetModuleBaseAddress(process, moduleName), baseAddress, processType, offsets);
264 /// <summary>
265 /// 解析基址对应的实际地址
266 /// </summary>
267 /// <param name="process">主进程</param>
268 /// <param name="moduleBaseAddress">模块地址(基址的进程部分,可以是DLL等)</param>
269 /// <param name="baseAddress">基址的地址部分</param>
270 /// <param name="processType">目标进程类型</param>
271 /// <param name="offsets">基址的偏移组</param>
272 /// <returns>实际地址</returns>
273 public static nint ResolvePointerAddress(Process process, nint moduleBaseAddress, int baseAddress, ProcessType processType, params nint[] offsets)
186 274 {
187 var gameProcess = GetGameProcessByName(processName);
188 if (gameProcess == null)
189 {
190 Trace.WriteLine("游戏进程未找到!");
191 return nint.Zero;
192 }
193 var moduleBaseAddress = GetModuleBaseAddress(gameProcess, moduleName);
194 if (moduleBaseAddress == nint.Zero)
195 {
196 Trace.WriteLine($"未找到模块:{moduleName}");
197 return nint.Zero;
198 }
199 275 var resolvedAddress = nint.Add(moduleBaseAddress, baseAddress);
200 foreach (int offset in offsets)
276 if (processType == ProcessType.Bit32)
201 277 {
202 if (processType == ProcessType.Bit32)
278 foreach (int offset in offsets)
203 279 {
204 var nextAddress = ReadMemory<int>(gameProcess.Handle, resolvedAddress);
280 var success = ReadMemory(process.Handle, resolvedAddress, out int nextAddress);
281 if (!success || nextAddress == nint.Zero)
282 return nint.Zero;
205 283 var pointerValue = new nint(nextAddress);
206 284 resolvedAddress = nint.Add(pointerValue, offset);
207 285 }
208 else
286 }
287 else
288 {
289 foreach (int offset in offsets)
209 290 {
210 var nextAddress = ReadMemory<long>(gameProcess.Handle, resolvedAddress);
291 var success = ReadMemory(process.Handle, resolvedAddress, out long nextAddress);
292 if (!success || nextAddress == nint.Zero)
293 return nint.Zero;
211 294 var pointerValue = new nint(nextAddress);
212 295 resolvedAddress = nint.Add(pointerValue, offset);
213 296 }
Modified XFEExtension.NetCore.MemoryEditor/MemoryListener.cs +102 -17
@@ -10,10 +10,11 @@ public class MemoryListener : IDisposable
10 10 {
11 11 private bool disposedValue;
12 12 private readonly Dictionary<nint, bool> listeningList = [];
13 private readonly Dictionary<string, bool> listeningFuncList = [];
13 14 /// <summary>
14 15 /// 当监听值发生改变时触发
15 16 /// </summary>
16 public event XFEEventHandler<nint, MemoryValue>? ValueChanged;
17 public event XFEEventHandler<nint?, MemoryValue>? ValueChanged;
17 18 /// <summary>
18 19 /// 进程句柄
19 20 /// </summary>
@@ -29,13 +30,14 @@ public class MemoryListener : IDisposable
29 30 /// <param name="memoryAddress">待监听的内存地址</param>
30 31 /// <param name="customName">自定义监听器标识名</param>
31 32 /// <returns></returns>
32 public async Task StartListen<T>(nint memoryAddress, string customName = "") where T : struct
33 public async Task StartListen<T>(nint memoryAddress, string? customName = null) where T : struct
33 34 {
34 35 IsListening = true;
35 36 await Task.Run(() =>
36 37 {
38 bool lastSuccess = false;
37 39 var lastValue = default(T);
38 try { lastValue = MemoryEditor.ReadMemory<T>(ProcessHandler, memoryAddress); } catch { }
40 try { lastSuccess = MemoryEditor.ReadMemory(ProcessHandler, memoryAddress, out lastValue); } catch { }
39 41 listeningList.Add(memoryAddress, true);
40 42 ReStart:
41 43 try
@@ -44,11 +46,12 @@ public class MemoryListener : IDisposable
44 46 {
45 47 try
46 48 {
47 var currentValue = MemoryEditor.ReadMemory<T>(ProcessHandler, memoryAddress);
48 if (!currentValue.Equals(lastValue))
49 var currentSuccess = MemoryEditor.ReadMemory<T>(ProcessHandler, memoryAddress, out var currentValue);
50 if (!currentValue.Equals(lastValue) || lastSuccess != currentSuccess)
49 51 {
50 ValueChanged?.Invoke(memoryAddress, new(lastValue, currentValue, customName));
52 ValueChanged?.Invoke(memoryAddress, new(lastSuccess, currentSuccess, lastValue, currentValue, customName));
51 53 lastValue = currentValue;
54 lastSuccess = currentSuccess;
52 55 }
53 56 }
54 57 catch { }
@@ -69,13 +72,23 @@ public class MemoryListener : IDisposable
69 72 /// <param name="delay">检测频率,以毫秒为单位</param>
70 73 /// <param name="customName">自定义监听器标识名</param>
71 74 /// <returns></returns>
72 public async Task StartListen<T>(nint memoryAddress, int delay, string customName = "") where T : struct
75 public async Task StartListen<T>(nint memoryAddress, int delay, string? customName = null) where T : struct => await StartListen<T>(memoryAddress, TimeSpan.FromMilliseconds(delay), customName);
76 /// <summary>
77 /// 开始监听
78 /// </summary>
79 /// <typeparam name="T">待监听的内存的数据类型(int,float,long等)</typeparam>
80 /// <param name="memoryAddress">待监听的内存地址</param>
81 /// <param name="delay">检测频率</param>
82 /// <param name="customName">自定义监听器标识名</param>
83 /// <returns></returns>
84 public async Task StartListen<T>(nint memoryAddress, TimeSpan delay, string? customName = null) where T : struct
73 85 {
74 86 IsListening = true;
75 await Task.Run(() =>
87 await Task.Run(async () =>
76 88 {
89 bool lastSuccess = false;
77 90 var lastValue = default(T);
78 try { lastValue = MemoryEditor.ReadMemory<T>(ProcessHandler, memoryAddress); } catch { }
91 try { lastSuccess = MemoryEditor.ReadMemory(ProcessHandler, memoryAddress, out lastValue); } catch { }
79 92 listeningList.Add(memoryAddress, true);
80 93 ReStart:
81 94 try
@@ -84,23 +97,90 @@ public class MemoryListener : IDisposable
84 97 {
85 98 try
86 99 {
87
88 var currentValue = MemoryEditor.ReadMemory<T>(ProcessHandler, memoryAddress);
89 if (!currentValue.Equals(lastValue))
100 var currentSuccess = MemoryEditor.ReadMemory<T>(ProcessHandler, memoryAddress, out var currentValue);
101 if (!currentValue.Equals(lastValue) || lastSuccess != currentSuccess)
90 102 {
91 ValueChanged?.Invoke(memoryAddress, new(lastValue, currentValue, customName));
92 currentValue = lastValue;
103 ValueChanged?.Invoke(memoryAddress, new(lastSuccess, currentSuccess, lastValue, currentValue, customName));
104 lastValue = currentValue;
105 lastSuccess = currentSuccess;
93 106 }
94 Thread.Sleep(delay);
107 await Task.Delay(delay);
95 108 }
96 109 catch { }
97 110 }
111 listeningList.Remove(memoryAddress);
112 }
113 catch
114 {
115 goto ReStart;
116 }
117 });
118 }
119 /// <summary>
120 /// 开始监听
121 /// </summary>
122 /// <typeparam name="T">待监听的内存的数据类型(int,float,long等)</typeparam>
123 /// <param name="getMemoryAddressFunc">动态获取内存地址的方法</param>
124 /// <param name="delay">检测频率</param>
125 /// <param name="customName">自定义监听器标识名</param>
126 /// <returns></returns>
127 public async Task StartListen<T>(Func<nint?> getMemoryAddressFunc, int delay, string customName) where T : struct => await StartListen<T>(getMemoryAddressFunc, TimeSpan.FromMilliseconds(delay), customName);
128 /// <summary>
129 /// 开始监听
130 /// </summary>
131 /// <typeparam name="T">待监听的内存的数据类型(int,float,long等)</typeparam>
132 /// <param name="getMemoryAddressFunc">动态获取内存地址的方法</param>
133 /// <param name="delay">检测频率</param>
134 /// <param name="customName">自定义监听器标识名</param>
135 /// <returns></returns>
136 public async Task StartListen<T>(Func<nint?> getMemoryAddressFunc, TimeSpan delay, string customName) where T : struct
137 {
138 IsListening = true;
139 await Task.Run(async () =>
140 {
141 var memoryAddress = getMemoryAddressFunc.Invoke();
142 bool lastSuccess = false;
143 var lastValue = default(T);
144 if (memoryAddress is not null)
145 try { lastSuccess = MemoryEditor.ReadMemory(ProcessHandler, memoryAddress.Value, out lastValue); } catch { }
146 listeningFuncList.Add(customName, true);
147 ReStart:
148 try
149 {
150 while (listeningFuncList[customName] && IsListening)
151 {
152 try
153 {
154 memoryAddress = getMemoryAddressFunc.Invoke();
155 if (memoryAddress == 0)
156 {
157 if (lastSuccess)
158 ValueChanged?.Invoke(memoryAddress, new(lastSuccess, false, lastValue, null, customName));
159 lastSuccess = false;
160 lastValue = default;
161 while (memoryAddress == 0 && listeningFuncList[customName] && IsListening)
162 {
163 memoryAddress = getMemoryAddressFunc.Invoke();
164 await Task.Delay(delay);
165 }
166 }
167 var currentSuccess = MemoryEditor.ReadMemory<T>(ProcessHandler, memoryAddress!.Value, out var currentValue);
168 if (!currentValue.Equals(lastValue) || lastSuccess != currentSuccess)
169 {
170 ValueChanged?.Invoke(memoryAddress, new(lastSuccess, currentSuccess, lastValue, currentValue, customName));
171 lastValue = currentValue;
172 lastSuccess = currentSuccess;
173 }
174 await Task.Delay(delay);
175 }
176 catch { }
177 }
178 listeningFuncList.Remove(customName);
98 179 }
99 180 catch
100 181 {
101 182 goto ReStart;
102 183 }
103 listeningList.Remove(memoryAddress);
104 184 });
105 185 }
106 186 /// <summary>
@@ -110,9 +190,14 @@ public class MemoryListener : IDisposable
110 190 /// <summary>
111 191 /// 停止指定进程的监听
112 192 /// </summary>
113 /// <param name="memoryAddress"></param>
193 /// <param name="memoryAddress">内存地址</param>
114 194 public void StopListener(nint memoryAddress) => listeningList[memoryAddress] = false;
115 195 /// <summary>
196 /// 停止指定进程的监听
197 /// </summary>
198 /// <param name="customName">自定义名称</param>
199 public void StopListener(string customName) => listeningFuncList[customName] = false;
200 /// <summary>
116 201 /// 内存监听器
117 202 /// </summary>
118 203 /// <param name="processName">进程名称</param>
Modified XFEExtension.NetCore.MemoryEditor/MemoryValue.cs +3 -1
@@ -3,7 +3,9 @@
3 3 /// <summary>
4 4 /// 内存记录值
5 5 /// </summary>
6 /// <param name="PreviousValueGetSuccessful">上个值是否被成功获取</param>
7 /// <param name="CurrentValueGetSuccessful">当前值是否成功获取</param>
6 8 /// <param name="PreviousValue">改变前的值</param>
7 9 /// <param name="CurrentValue">当前值</param>
8 10 /// <param name="CustomName">自定义标识名</param>
9 public record struct MemoryValue(object PreviousValue, object CurrentValue, string? CustomName) { }
11 public record struct MemoryValue(bool PreviousValueGetSuccessful, bool CurrentValueGetSuccessful, object? PreviousValue, object? CurrentValue, string? CustomName) { }