C#读写进程内存的值

新建窗体应用程序MemoryReadWriteDemo,将默认的Form1重命名为FormReadWriteMemory。窗体FormReadWriteMemory设计如下:

一、新建内存读写类MemoryUtil.cs.源程序如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace MemoryReadWriteDemo
{
    ///

    /// 内存操作【读、写】类
    /// 模仿CE软件(Cheat Engine)读写单机游戏内存
    ///

    public class MemoryUtil
    {
        ///

        /// 打开进程,返回进程句柄
        ///

        /// 渴望得到的访问权限(标志),0x1F0FFF表示最高权限         /// 是否继承句柄         /// 进程标示符         ///
        [DllImport(“kernel32.dll”, EntryPoint = “OpenProcess”)]
        public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

        ///

        /// 读内存
        ///

        /// 远程进程句柄。 被读取者         /// 远程进程中内存地址。 从具体何处读取         /// 本地进程中内存地址. 函数将读取的内容写入此处         /// 要传送的字节数。要写入多少         /// 实际传送的字节数. 函数返回时 告实际写入多少         ///
        [DllImport(“kernel32.dll”, EntryPoint = “ReadProcessMemory”)]
        public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, IntPtr lpNumberOfBytesRead);

        ///

        /// 写内存
        ///

        /// 由OpenProcess返回的进程句柄         /// 要写的内存首地址         /// 指向要写的数据的指针         /// 要写入的字节数         /// 实际数据的长度         ///
        [DllImport(“kernel32.dll”, EntryPoint = “WriteProcessMemory”)]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, int[] lpBuffer, int nSize, IntPtr lpNumberOfBytesWritten);

        ///

        /// 关闭内核对象
        ///

        /// 欲关闭的对象句柄         [DllImport(“kernel32.dll”)]
        private static extern void CloseHandle(IntPtr hObject);

        ///

        /// 读取指定内存的值
        ///

        /// 进程名         /// 内存地址         /// 返回的内存值         ///
        public static bool ReadMemoryInt(string processName, int baseAddress, out int memoryValue)
        {
            memoryValue = -1;
            int processId = -1;
            //找出指定进程名的第一个进程
            System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(processName);
            if (processes.Length > 0)
            {
                processId = processes[0].Id;
            }
            byte[] buffer = new byte[4];
            try
            {
                //获取缓冲区地址 :固定数组元素的不安全地址
                IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
                //获取进程的最高权限
                IntPtr hProcess = OpenProcess(0x1F0FFF, false, processId);
                //将指定内存中的值读入缓冲区 
                ReadProcessMemory(hProcess, (IntPtr)baseAddress, byteAddress, 4, IntPtr.Zero);
                CloseHandle(hProcess);
                memoryValue = Marshal.ReadInt32(byteAddress);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($”读取内存出错:{ex.Message}”);
                return false;
            }
        }

        ///

        /// 向指定的内存写入值
        ///

        /// 进程名         /// 内存地址         /// 写入的内存值         ///
        public static bool WriteMemoryInt(string processName, int baseAddress, int memoryValue)
        {
            int processId = -1;
            //找出指定进程名的第一个进程
            System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(processName);
            if (processes.Length > 0)
            {
                processId = processes[0].Id;
            }
            try
            {
                IntPtr hProcess = OpenProcess(0x1F0FFF, false, processId); //0x1F0FFF 最高权限 
                WriteProcessMemory(hProcess, (IntPtr)baseAddress, new int[] { memoryValue }, 4, IntPtr.Zero);
                CloseHandle(hProcess);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($”写入内存出错:{ex.Message}”);
                return false;
            }
        }

    }
}
 

二、FormReadWriteMemory窗体按钮绑定事件如下:(忽略设计器自动生成的代码)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MemoryReadWriteDemo
{
    public partial class FormReadWriteMemory : Form
    {
        public FormReadWriteMemory()
        {
            InitializeComponent();
        }

        private void btnOpenProcess_Click(object sender, EventArgs e)
        {
            int processId = -1;
            //找出指定进程名的第一个进程
            string processName = txtProcessName.Text.Trim();            
            System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(processName);
            if (processes.Length > 0)
            {
                processId = processes[0].Id;
            }
            if (processId != -1)
            {
                MessageBox.Show($”仙剑奇侠传三游戏进程已打开,进程ID:{processId}”);
            }
            else 
            {
                MessageBox.Show(“没有找到仙剑奇侠传三游戏进程!n请先打开运行游戏”);
            }
        }

        private void btnReadMemory_Click(object sender, EventArgs e)
        {
            int memoryValue;
            MemoryUtil.ReadMemoryInt(txtProcessName.Text.Trim(), Convert.ToInt32(txtMemoryAddress.Text.Trim(), 16), out memoryValue);
            txtMemoryValueDecimal.Text = memoryValue.ToString();
            txtMemoryValue.Text = memoryValue.ToString(“X8”);
            MessageBox.Show($”{memoryValue}”);
        }

        private void btnWriteMemory_Click(object sender, EventArgs e)
        {
            bool result = MemoryUtil.WriteMemoryInt(txtProcessName.Text.Trim(), Convert.ToInt32(txtMemoryAddress.Text.Trim(), 16), int.Parse(txtMemoryValueDecimal.Text));
            MessageBox.Show($”写入值的结果:{result}”);
        }
    }
}
三、程序测试运行如图:

 

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年8月1日
下一篇 2020年8月1日

相关推荐