using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Shooan.Tools
{
#region 内存操作相关的权限 枚举
[Flags]
enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
#endregion
public class MemoryHelper
{
#region 内存操纵相关的库和方法
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(int hProcess, int lpBaseAddress,
byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern bool ReadProcessMemory(int hProcess,
int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
public void Write(int location, byte[] buffer)
{
if (IsProcessExitedOrNoExist)
{
throw new InvalidOperationException("尝试向已经关闭了的或者不存在的线程写入数据");
}
IntPtr processWriteHandle = OpenProcess((int)ProcessAccessFlags.All, false, _process.Id);
int bytesWritten = 0;
WriteProcessMemory((int)processWriteHandle, location, buffer, buffer.Length, ref bytesWritten);
}
public byte[] Read(int location, int size)
{
if (IsProcessExitedOrNoExist)
{
throw new InvalidOperationException("尝试从已经关闭了的或者不存在的线程读取数据");
}
IntPtr processReadHandle = OpenProcess((int)ProcessAccessFlags.VirtualMemoryRead, false, _process.Id);
int bytesRead = 0;
byte[] buffer = new byte[size];
ReadProcessMemory((int)processReadHandle, location, buffer, size, ref bytesRead);
return buffer;
}
/// <summary>
/// 传入基址和偏移,计算出最终的内存地址
/// </summary>
/// <returns>地址</returns>
public int GetLocation(int basePtr, params int[] offsets)
{
// x86 环境,一个指针大小为4个字节
const int size = 4;
byte[] buffer;
buffer = Read(basePtr, size);
int temp = BitConverter.ToInt32(buffer, 0);
for (int i = 0; i < offsets.Length-1; i++)
{
buffer = Read(temp + offsets[i], size);
temp = BitConverter.ToInt32(buffer, 0);
}
int finalLocation = temp + offsets[offsets.Length - 1];
return finalLocation;
}
#endregion
public MemoryHelper(string processName)
{
_processName = processName;
_process = null;
SetUpTimer();
}
// 用来检测线程是否退出或者不合法
public bool IsProcessExitedOrNoExist { get { return _process == null || _process.HasExited; } }
#region 内部
private string _processName;
private Process _process;
private Process GetProcess()
{
Process process = null;
try
{
process = Process.GetProcessesByName(_processName)[0];
}
catch (IndexOutOfRangeException) { }
return process;
}
private void SetUpTimer()
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += MonitorProcess;
timer.Interval = 300;
timer.Start();
}
private readonly object lockObj = new object();
private void MonitorProcess(object sender, System.Timers.ElapsedEventArgs e)
{
lock (lockObj)
{
// 检测进程是否退出,如果退出的话 触发ProcessExited 事件
if (_process != null && _process.HasExited)
{
ProcessExited?.Invoke(this, new EventArgs());
_process = null;
}
Process process = GetProcess();
if (process == null)
{
return;
}
// 如果 "之前的" Process已经关闭了或者不存在,
// 并且当前获得的线程是可用的
if (IsProcessExitedOrNoExist)
{
EventArgs eventArgs = new EventArgs();
// 触发进程启动事件
ProcessStarted?.Invoke(this, eventArgs);
// 更新对象
_process = process;
}
}
}
#endregion
#region 事件
public event EventHandler ProcessStarted;
public event EventHandler ProcessExited;
#endregion
}
}