C# 操作地址 从内存中读取写入数据(初级)

摘要:
[DllImport]privatestaticexternvoidCloseHandle;#endregion#region使用方法//根据进程名获取PIDpublicstaticintGetPidByProcessName{Process[]arrayProcess=Process.GetProcessesByName;foreach{returnp.Id;}return0;}//读取内存中的值publicstaticintReadMemoryValue{try{byte[]buffer=newbyte[4];//获取缓冲区地址IntPtrbyteAddress=Marshal.UnsafeAddrOfPinnedArrayElement;//打开一个已存在的进程对象0x1F0FFF最高权限IntPtrhProcess=OpenProcess;//将制定内存中的值读入缓冲区ReadProcessMemory;//关闭操作CloseHandle;//从非托管内存中读取一个32位带符号整数。

本示例以植物大战僵尸为例, 实现功能为 每1秒让阳光刷新为 9999.本示例使用的游戏版本为 [植物大战僵尸2010年度版], 使用的辅助查看内存地址的工具是 CE.

由于每次启动游戏, 游戏中阳光地址都是变的, 唯一不变的基址1, 我们要通过CE工具找到基址1的地址, 可以算出阳光的地址.

基址2的地址 = 基址1中的值 + 偏移1;

阳光的的地址 = 基址2中的值 + 偏移2;

以下为简单示例: 窗口界面一个按钮 和 一个定时器

C# 操作地址 从内存中读取写入数据(初级)第1张C# 操作地址 从内存中读取写入数据(初级)第2张
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Runtime.InteropServices;
usingSystem.Diagnostics;

namespaceZhiWuDaZhanJiangShi
{
    public partial classForm1 : Form
    {
        publicForm1()
        {
            InitializeComponent();
        }

        #region API

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

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

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

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

        #endregion

        #region 使用方法

        //根据进程名获取PID
        public static int GetPidByProcessName(stringprocessName)
        {
            Process[] arrayProcess =Process.GetProcessesByName(processName);
            foreach (Process p inarrayProcess)
            {
                returnp.Id;
            }
            return 0;
        }

        //读取内存中的值
        public static int ReadMemoryValue(int baseAddress, stringprocessName)
        {
            try{
                byte[] buffer = new byte[4];
                //获取缓冲区地址
                IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
                //打开一个已存在的进程对象  0x1F0FFF 最高权限
                IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName));
                //将制定内存中的值读入缓冲区
                ReadProcessMemory(hProcess, (IntPtr)baseAddress, byteAddress, 4, IntPtr.Zero); 
                //关闭操作
CloseHandle(hProcess);
                //从非托管内存中读取一个 32 位带符号整数。
                returnMarshal.ReadInt32(byteAddress);
            }
            catch{
                return 0;
            }
        }

        //将值写入指定内存地址中
        public static void WriteMemoryValue(int baseAddress, string processName, intvalue)
        {
            try{
                //打开一个已存在的进程对象  0x1F0FFF 最高权限
                IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName));
                //从指定内存中写入字节集数据
                WriteProcessMemory(hProcess, (IntPtr)baseAddress, new int[] { value }, 4, IntPtr.Zero);
                //关闭操作
CloseHandle(hProcess);
            }
            catch{ }
        }

        #endregion

        //游戏内存基址
        private int baseAddress = 0x0015E944;
        //游戏进程名字
        private string processName = "PlantsVsZombies";

        //开启/关闭 功能 的按钮
        private void button1_Click(objectsender, EventArgs e)
        {
            if (GetPidByProcessName(processName) == 0)
            {
                MessageBox.Show("游戏没有运行!");
                return;
            }
            if (button1.Text == "开启")
            {
                button1.Text = "关闭";
                timer1.Enabled = true;
            }
            else{
                button1.Text = "开启";
                timer1.Enabled = false;
            }
        }

        //定时器
        private void timer1_Tick(objectsender, EventArgs e)
        {
            if (GetPidByProcessName(processName) == 0)
            {
                timer1.Enabled = false;
            }
            //baseAddress : 游戏内存基址   processName : 游戏进程名
            //读取 基址1 中存放的值
            int address =ReadMemoryValue(baseAddress, processName);
            //计算 基址2的地址 = 基址1中的值 + 偏移量1
            address = address + 0x868;
            //读取 基址2 中存放的值
            address =ReadMemoryValue(address, processName);
            //计算 阳光的地址 = 基址2中的值 + 偏移量2
            address = address + 0x5578;
            //给阳光地址中写入数值,0x378 : 888
            WriteMemoryValue(address, processName, 0x378);
        } 
    }
}
View Code

下面增加了一个刷新金币的示例 (注意, 金币值是界面的金币输 除以 10 , 我们刷100 在界面里面显示为1000)

C# 操作地址 从内存中读取写入数据(初级)第3张

C# 操作地址 从内存中读取写入数据(初级)第4张C# 操作地址 从内存中读取写入数据(初级)第5张
        private void button2_Click(objectsender, EventArgs e)
        {
            if (GetPidByProcessName(processName) == 0)
            {
                MessageBox.Show("游戏没有运行!");
                return;
            }

            //baseAddress : 游戏内存基址   processName : 游戏进程名
            //读取 基址1 中存放的值
            int address =ReadMemoryValue(baseAddress, processName);
            //计算 基址2的地址 = 基址1中的值 + 偏移量1
            address = address + 0x950;
            //读取 基址2 中存放的值
            address =ReadMemoryValue(address, processName);
            //计算 阳光的地址 = 基址2中的值 + 偏移量2
            address = address + 0x50;
            //给阳光地址中写入数值,0x378 : 888
WriteMemoryValue(address, processName, GetInt(textBox2.Text));
        }

        private int GetInt(strings)
        {
            int n = 0;
            int.TryParse(s, outn);
            if (n <= 0)
            {
                n = 100;
            }
            returnn;
        }
View Code

今天又增加了无植物无冷却时间的功能

C# 操作地址 从内存中读取写入数据(初级)第6张

C# 操作地址 从内存中读取写入数据(初级)第7张C# 操作地址 从内存中读取写入数据(初级)第8张
        int count = 0;
        private void Form1_Load(objectsender, EventArgs e)
        {
            if (GetPidByProcessName(processName) != 0)
            {
                int address =ReadMemoryValue(baseAddress, processName);
                address = address + 0x868;
                address =ReadMemoryValue(address, processName);
                address = address + 0x15c;
                address =ReadMemoryValue(address, processName);
                address = address + 0x24;
                address =ReadMemoryValue(address, processName);
                count =address;
                label3.Text = "植物栏个数: " + address.ToString() + "";
            }
        }

        private void timer2_Tick(objectsender, EventArgs e)
        {
            if (GetPidByProcessName(processName) == 0)
            {
                timer2.Enabled = false;
            }
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    int address =ReadMemoryValue(baseAddress, processName);
                    address = address + 0x868;//一级地址
                    address =ReadMemoryValue(address, processName);
                    address = address + 0x15c;//二级地址
                    address =ReadMemoryValue(address, processName);
                    address = address + 0x4c;//第一栏 植物的地址
                    //每后一个植物 地址 偏移 50 (在十进制里是80)
                    //偏移 0x24 的地址 是标示是否在冷却中 值 :( 0 :  为冷却中, 1 为冷却完成)
                    address = address + 80 * i + 0x24;
                    WriteMemoryValue(address, processName, 1);
                    //如果不偏移 0x24 的地址为冷却时间地址, 值不确定, 一般最大设为6000  也可以完成此功能
                    //address = address + 80 * i;
                    //WriteMemoryValue(address, processName, 6000);
}
            }
            else{
                int address =ReadMemoryValue(baseAddress, processName);
                address = address + 0x868;
                address =ReadMemoryValue(address, processName);
                address = address + 0x15c;
                address =ReadMemoryValue(address, processName);
                address = address + 0x24;
                address =ReadMemoryValue(address, processName);
                count =address;
                label3.Text = "植物栏个数: " + address.ToString() + "";
            }
        }

        private void button3_Click(objectsender, EventArgs e)
        {
            if (GetPidByProcessName(processName) == 0)
            {
                MessageBox.Show("游戏没有运行!");
                return;
            }
            if (button3.Text == "有冷却")
            {
                button3.Text = "无冷却";
                timer2.Enabled = true;
            }
            else{
                button3.Text = "有冷却";
                timer2.Enabled = false;
            }
        }
View Code

免责声明:文章转载自《C# 操作地址 从内存中读取写入数据(初级)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇理解并运用TP5.1-FacadeMac搭建kubernetes dashboard全流程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

WinRAR 激活的小办法

WinRAR是一个强大的压缩文件管理工具。它可以备份数据,减少电子邮件附件的大小,解压缩从Internet下载的RAR、ZIP和其他压缩文件,并以RAR和ZIP格式创建压缩文件。如果您使用的正版WinRAR未激活,请将以下注册代码复制到新文档并将其重命名为rarreg。键,然后复制rarreg。键到WinRAR根目录以激活它。...

CAD转DXF怎么转换?教你三种转换方法

2.进入到CAD版本转换的界面中后,在选择“点击选择文件”,在跳转出的“打开”界面中打开需要转换的CAD图纸。...

爬虫发起抓取被服务器拒绝访问返回403禁止访问解决方案

目前,许多网站的API接口返回的http代码返回代码为403,表示禁止访问。如果您也遇到这种情况,请不要急于首先修改网站的相关参数,即高级api的网站。使用浏览器访问。如果浏览器访问api接口,它可以成功。表示已设置权限。接口可能已被修改或无效,此时无法访问。调用此接口时,将捕获异常中的responseBody。数据很可能在该区域。这就是作者遇到的问题。直接...

html,js简单保存textarea换行格式

有时我们需要在提交表单时保存html标记,但textarea不保存换行信息,因此我们需要使用js保存HTM标记,例如textarea的换行。˃˃g、 “”);这只是一个允许在js中保留HTML文本区域中的换行符和其他格式的模型。你需要开发它来满足你的需求。希望岑溪网站开发分享的内容对您有所帮助!...

MySQL 字段类型占用空间

MySQL支持多种列类型:数值类型、日期/时间类型和字符串(字符)类型。)1或2个字节,取决于枚举值的个数SET(‘value1’,’value2’,…)1、2、3、4或者8个字节,取决于set成员的数目上表的M只是为了说明占用空间大小,在实际创建表中char、varchar,20指的是字符而不是字节;那么字符和字节的转换要看字符集,utf-8下,1字符=3...

scan chain的原理和实现——5.UDTP

UDTP(用户定义的测试点)指示DFTC在设计中用户指定的位置插入控制点和观察点。1.为什么使用UDTP?修复不可控的时钟和/或异步输入;增加设计的测试覆盖率;减少模式数量2.UDTP类型① 力0、力1、力01、力z0、力z1、力z01②控制_ 0...