C# 读写内存

代码

var processName = "War3";
var process = MemoryUtils.GetProcessByProcessName(processName);
if (process == null)
{
    throw new Exception($"没有找到进程:{processName },请先启动后,再使用该功能");
} 

var _memoryUtils = new MemoryUtils(process.Id);

// 读写 ↓

// 计算实际地址 ( 返回值是一个地址,需要自己写代码读不同类型的值)
var address = _memoryUtils.GetMemoryAddress("Game.dll", 0x00BE87A4, 0x30, 0x1F0, 0x8C)

// 如果有 for 循环中动态计算的偏移, 还可以继续操作..
// 举例 : 人物结构体 偏移是 0x480, 循环可以取出 100个人物的数据
//for (int i = 0; i < 100; i++)
//{
//    address += 0x480 * i; 
//    var hp = _memoryUtils.ReadToInt(address + 0x4);
//    var mp = _memoryUtils.ReadToInt(address + 0x8);
//}

// 读取 int
var myValue1 = _memoryUtils.ReadToInt(address)
// 写入 int 4字节 类型
_memoryUtils.WriteInt(address, 99999);


//读取 float
var myValue2 = _memoryUtils.ReadToFloat(address)

//写入 float 单浮点 类型
_memoryUtils.WriteFloat(address, 0.5f);

// 更多类型请查看 MemoryUtils 源码

MemoryUtils.cs

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

namespace MyUtils;

public class MemoryUtils
{
    #region API

    //从指定内存中读取字节集数据
    [DllImport("kernel32.dll", EntryPoint = "ReadProcessMemory")]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, IntPtr lpNumberOfBytesRead);

    //从指定内存中写入字节集数据
    [DllImport("kernel32.dll", EntryPoint = "WriteProcessMemory")]
    private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, IntPtr lpNumberOfBytesWritten);

    //打开一个已存在的进程对象,并返回进程的句柄
    [DllImport("kernel32.dll", EntryPoint = "OpenProcess")]
    private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    //关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。
    [DllImport("kernel32.dll")]
    private static extern void CloseHandle(IntPtr hObject);

    #endregion

    // byte		(字节   1字节)
    // int16    (short 2字节),
    // int32    (int   4字节),
    // int64    (long  8字节)
    // float    (单浮点 Single 4字节
    // double   (双浮点 8字节)
    // string	(字符串)
    // byte[]	(字节数组)

    private IntPtr _handle = IntPtr.Zero;
    private int _pid = 0;
    public MemoryUtils(int pid)
    {
        _pid = pid;
        _handle = OpenProcess(0x1F0FFF, false, pid);
    }

    ~MemoryUtils()
    {
        CloseHandle(_handle);
    }

    #region Read
    public byte[] ReadToBytes(IntPtr address, int size)
    {
        byte[] buffer = new byte[size];
        ReadProcessMemory(_handle, address, buffer, size, IntPtr.Zero);
        return buffer;
    }
    public T ReadObject<T>(IntPtr address) where T : struct
    {
        var buffer = ReadToBytes(address, Marshal.SizeOf(typeof(T)));

        var bufferAddress = Marshal.AllocHGlobal(buffer.Length);

        Marshal.Copy(buffer, 0, bufferAddress, buffer.Length);

        var structure = (T)Marshal.PtrToStructure(bufferAddress, typeof(T));

        Marshal.FreeHGlobal(bufferAddress);

        return structure;
    }

    public char ReadToChar(IntPtr address)
    {
        byte[] buffer = ReadToBytes(address, sizeof(char));
        return BitConverter.ToChar(buffer, 0);
    }
    public short ReadToShort(IntPtr address)
    {
        byte[] buffer = ReadToBytes(address, sizeof(short));
        return BitConverter.ToInt16(buffer, 0);
    }

    public int ReadToInt(IntPtr address)
    {
        byte[] buffer = ReadToBytes(address, sizeof(int));

        return BitConverter.ToInt32(buffer, 0);
    }

    public long ReadToLong(IntPtr address)
    {
        byte[] buffer = ReadToBytes(address, sizeof(long));
        return BitConverter.ToInt64(buffer, 0);
    }

    public float ReadToFloat(IntPtr address)
    {
        byte[] buffer = ReadToBytes(address, sizeof(float));
        return BitConverter.ToSingle(buffer, 0);
    }

    public double ReadToDouble(IntPtr address)
    {
        byte[] buffer = ReadToBytes(address, sizeof(double));
        return BitConverter.ToDouble(buffer, 0);
    }

    public string ReadToString(IntPtr address, int stringSize)
    {
        byte[] buffer = ReadToBytes(address, stringSize);
        return BitConverter.ToString(buffer);
    }

    #endregion

    #region Write

    public bool WriteByteArray(IntPtr address, byte[] byteData)
    {
        return WriteProcessMemory(_handle, address, byteData, byteData.Length, IntPtr.Zero);
    }

    public bool WriteChar(IntPtr address, char value)
    {
        return WriteByteArray(address, BitConverter.GetBytes(value));
    }

    public bool WriteShort(IntPtr address, short value)
    {
        return WriteByteArray(address, BitConverter.GetBytes(value));
    }

    public bool WriteInt(IntPtr address, int value)
    {
        return WriteByteArray(address, BitConverter.GetBytes(value));
    }

    public bool WriteLong(IntPtr address, long value)
    {
        return WriteByteArray(address, BitConverter.GetBytes(value));
    }

    public bool WriteFloat(IntPtr address, float value)
    {
        return WriteByteArray(address, BitConverter.GetBytes(value));
    }

    public bool WriteDouble(IntPtr address, double value)
    {
        return WriteByteArray(address, BitConverter.GetBytes(value));
    }

    public bool WriteString(IntPtr address, string value)
    {
        return WriteByteArray(address, Encoding.Default.GetBytes(value));
    }

    #endregion

    #region Utils

    /// <summary>
    /// 根据 进程名 获取 PID
    /// </summary>    
    public static int GetPidByProcessName(string processName)
    {
        return GetProcessByProcessName(processName)?.Id ?? 0;
    }

    /// <summary>
    /// 通过 进程名(不加exe后缀) 获取 进程对象
    /// </summary>      
    public static Process GetProcessByProcessName(string processName)
    {
        var processArr = Process.GetProcessesByName(processName);
        if (processArr.Length > 0)
        {
            return processArr[0];
        }

        return null;
    }

    /// <summary>
    /// 根据窗体标题查找窗口句柄(支持模糊匹配)
    /// </summary>    
    public static IntPtr FindWindow(string title)
    {
        var processArray = Process.GetProcesses();
        foreach (var item in processArray)
        {
            if (item.MainWindowTitle.IndexOf(title) != -1)
            {
                return item.MainWindowHandle;
            }
        }

        return IntPtr.Zero;
    }

    /// <summary>
    /// 获取进程中模块的基址 (例如: Game.dll / War3.exe)
    /// </summary>  
    public IntPtr GetModuleBaseAddress(string moduleName)
    {
        var process = Process.GetProcessById(_pid);
        IntPtr baseAddress = default;

        for (int i = 0; i < process.Modules.Count; i++)
        {
            var item = process.Modules[i];
            if (item.ModuleName == moduleName)
            {
                baseAddress = item.BaseAddress;
                break;
            }
        }

        return baseAddress;
    }

    /// <summary>
    /// 计算地址偏移
    /// </summary>   
    public IntPtr GetMemoryAddress(string moduleName, params IntPtr[] offsetArray)
    {
        if ((offsetArray?.Length ?? 0) == 0)
        {
            throw new Exception("至少需要一个偏移");
        }

        IntPtr addr = IntPtr.Zero;

        // 模块的地址
        var addrVal = GetModuleBaseAddress(moduleName);

        // 计算剩下的多级偏移
        for (int i = 0; i < offsetArray.Length; i++)
        {
            addr = addrVal + offsetArray[i];
            addrVal = (IntPtr)ReadToInt(addr);
        }

        // 最终的地址 (只是一个地址, 需要手动去读里面的值)
        return addr;
    }

    /// <summary>
    /// 通过进程名 获取窗口句柄
    /// </summary>
    /// <param name="processName"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static IntPtr GetWindowHwndByProcessName(string processName)
    {
        var hwnd = MemoryUtils.GetProcessByProcessName(processName)?.MainWindowHandle ?? IntPtr.Zero;

        if (hwnd == IntPtr.Zero)
        {
            throw new Exception($"没有找到[{processName}]进程..");
        }
        return hwnd;
    }

    #endregion

    #region 进制转换

    /// <summary>
    /// 16进制(0x41)转为10进制(65)
    /// </summary>   
    public static int ConvertFrom16To10(string value)
    {
        return Convert.ToInt32(value, 16);
    }

    /// <summary>
    /// 16进制(0x41)转为10进制(65)
    /// </summary>    
    public static int ConvertFrom16To10(IntPtr value)
    {
        return Convert.ToInt32(Convert.ToString(value, 10));
    }

    /// <summary>
    /// 10进制(65)转为16进制(0x41)
    /// </summary>   
    public static string ConvertFrom10To16(IntPtr value)
    {
        //x4 0补齐4位
        //x8 0补齐8位
        return value.ToString("x");
    }

    /// <summary>
    /// 16/10进制转为2进制
    /// </summary>     
    public static string ConvertFrom16Or10To2(IntPtr value)
    {
        return Convert.ToString(value, 2);
    }

    /// <summary>
    /// 2进制(1010)到10进制(2)
    /// </summary>    
    public static int ConvertFrom2To10(string value)
    {
        return Convert.ToInt32(value, 2);
    }

    #endregion

}

例子

https://github.com/xxxxue/war3-72bian

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值