首先打开植物大战僵尸,进入游戏,初始阳光为50.

打开CE修改器,搜索50

进入游戏,种植向日葵,阳光变成0,再次搜索

再进入游戏,收取阳光,阳光变成25,搜索25

显然地址0x144344C8保存的就是阳光,现在退出游戏重新打开,重复上面步骤

现在地址变成0x1408EDC0了,说明阳光的地址并不是固定的。对这个地址进行检测,查看是哪条指令在修改

我刚刚进行了种植和收集阳光两个步骤,显然mov是减少阳光,add是增加阳光。查看详细信息

得到EAX = 0x14089860,这个0x5560其实就是二级偏移.然而EAX也是动态变化的,我们需要在内存中搜索EAX,来查找它到底保存在哪个地方

由于这个地址保存了阳光的地址,所以它应该是不变的,否则就找不到阳光的地址了,所以可以多次重复扫描,确保把会改变的量排除。

逐一查看哪个操作码访问了上面地址,发现地址0x028CA730很有趣

列表里清一色的都是0x768,证明[EAX + 0x028CA730]保存了结构体地址,查看EAX地址

这里不管是查看EAX还是ECX,结果肯定是一样的,因为它们都指向同一个地址,且偏移也相同。EAX = 0x028C9FC8,而0x768就是一级偏移。继续搜索EAX

列表里出现绿色的基址,查找结束。

开始写代码,C#无法直接修改内存,需要动态调用kernel32.dll

[DllImport("kernel32.dll", EntryPoint = "OpenProcess")]
public static extern IntPtr OpenProcess(int desiredAccess, bool heritHandle, int pocessID);[DllImport("kernel32.dll", EntryPoint = "CloseHandle")]
public static extern void CloseHandle(IntPtr hObject);[DllImport("kernel32.dll", EntryPoint = "ReadProcessMemory")]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr baseaddress, IntPtr buffer, int nsize, IntPtr bytesread);[DllImport("kernel32.dll", EntryPoint = "WriteProcessMemory")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr baseaddress, long[] buffer, int nSize, IntPtr byteswrite);

读写内存需要用到OpenProcess,官方文档里告诉我们第一个参数是访问权限,PROCESS_ALL_ACCESS指所有能获得的最高权限,但是PROCESS_ALL_ACCESS是在C++里定义的,C#里却没有,注意到这个值的类型是int,我们可以在C++里打印出这个值,然后直接写在C#里

所以我们只要输入0x1F0FFF就行了

private int ReadMemory(int pid,IntPtr toBase)
{byte[] bytes = new byte[4];IntPtr address = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0);IntPtr process = OpenProcess(0x1F0FFF, false, pid);ReadProcessMemory(process, toBase, address, 4, IntPtr.Zero);CloseHandle(process);return Marshal.ReadInt32(address);
}
private void WriteMemory(int pid,IntPtr toBase,int num)
{IntPtr process = OpenProcess(0x1F0FFF, false, pid);WriteProcessMemory(process, toBase, new long[] { num }, 4, IntPtr.Zero);CloseHandle(process);
}

获取进程PID

private int GetPid()
{Process[] processes = Process.GetProcessesByName(ProcessName);if(processes.Length == 0){ShowDialog("没有检测到游戏进程.");return -1;}if(processes.Length > 1){ShowDialog("检测到多个进程,这可能是因为您开启了多个相同进程名的软件,请关闭多余软件.");return -1;}return processes[0].Id;
}

定义全局变量

private const string ProcessName = "PlantsVsZombies";//进程名称
private const int sun = 9990;//每次修改的阳光数值private int pid;//进程PID
private IntPtr intPtr;//阳光的地址

获取进程信息

private void GetInfo()
{pid = GetPid();if (pid == -1) return;int num1 = ReadMemory(pid, (IntPtr)0x006A9EC0);int num2 = ReadMemory(pid, (IntPtr)(num1 + 0x768));intPtr = (IntPtr)(num2 + 0x5560);
}

添加两个按钮,第一个按钮用来读取进程信息,第二个按钮用来修改阳光

private void button1_Click(object sender, EventArgs e)
{GetInfo();
}
private void button2_Click(object sender, EventArgs e)
{WriteMemory(pid, intPtr, sun);
}

修改成功

关闭植物大战僵尸,重新打开,再次尝试。

修改成功,修改器制作完成。接下来是优化

MemoryIO.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;namespace PVZ_Cheater
{static class MemoryIO{[DllImport("kernel32.dll", EntryPoint = "OpenProcess")]public static extern IntPtr OpenProcess(int desiredAccess, bool heritHandle, int pocessID);[DllImport("kernel32.dll", EntryPoint = "CloseHandle")]public static extern void CloseHandle(IntPtr hObject);[DllImport("kernel32.dll", EntryPoint = "ReadProcessMemory")]public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr baseaddress, IntPtr buffer, int nsize, IntPtr bytesread);[DllImport("kernel32.dll", EntryPoint = "WriteProcessMemory")]public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr baseaddress, long[] buffer, int nSize, IntPtr byteswrite);public static int GetPid(string ProcessName){Process[] processes = Process.GetProcessesByName(ProcessName);if (processes.Length == 0){throw new Exception("没有检测到游戏进程.");}if (processes.Length > 1){throw new Exception("检测到多个进程,这可能是因为您开启了多个相同进程名的软件,请关闭多余软件.");}return processes[0].Id;}public static int ReadMemory(int pid, IntPtr toBase){byte[] bytes = new byte[4];IntPtr address = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0);IntPtr process = OpenProcess(0x1F0FFF, false, pid);ReadProcessMemory(process, toBase, address, 4, IntPtr.Zero);CloseHandle(process);return Marshal.ReadInt32(address);}public static void WriteMemory(int pid, IntPtr toBase, int num){IntPtr process = OpenProcess(0x1F0FFF, false, pid);WriteProcessMemory(process, toBase, new long[] { num }, 4, IntPtr.Zero);CloseHandle(process);}}
}

PVZInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace PVZ_Cheater
{static class PVZInfo{public const string ProcessName = "PlantsVsZombies";public static int Pid;public static IntPtr Sun_Address;public static int Sun_Value = 9990;public static bool isReady = false;public static void GetInfo(){isReady = false;Pid = MemoryIO.GetPid(ProcessName);int num1 = MemoryIO.ReadMemory(Pid, (IntPtr)0x006A9EC0);int num2 = MemoryIO.ReadMemory(Pid, (IntPtr)(num1 + 0x768));Sun_Address = (IntPtr)(num2 + 0x5560);isReady = true;}public static void SetSun(){if(isReady) MemoryIO.WriteMemory(Pid, Sun_Address, Sun_Value);}}
}

增加一个Timer计时器,当选中"锁定阳光"选项时,每隔1秒将阳光赋值为9990,成功实现无限阳光

源文件:https://dearx.lanzoui.com/ibVLJrm95be

PVZ逆向分析与C#内存操作(含源文件)相关推荐

  1. [系统安全] 二十四.逆向分析之OllyDbg调试INT3断点、反调试、硬件断点与内存断点

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  2. [系统安全] 二十三.逆向分析之OllyDbg动态调试复习及TraceMe案例分析

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  3. [安全攻防进阶篇] 六.逆向分析之OllyDbg逆向CrackMe01-02及加壳判断

    前文作者讲解了OllyDbg和在线沙箱的逆向分析过程,分享了恶意软件如何通过宏脚本发送勒索信息或密码至用户邮箱.这篇文件将带领大家逆向分析两个CrackMe程序,包括逆向分析和源码还原,基础性文章,希 ...

  4. [安全攻防进阶篇] 一.什么是逆向分析、逆向分析应用及经典扫雷游戏逆向

    从2019年7月开始,我来到了一个陌生的专业--网络空间安全.初入安全领域,是非常痛苦和难受的,要学的东西太多.涉及面太广,但好在自己通过分享100篇"网络安全自学"系列文章,艰难 ...

  5. 知物由学 | 干货!一文了解安卓APP逆向分析与保护机制

    "知物由学"是网易云易盾打造的一个品牌栏目,词语出自汉·王充<论衡·实知>.人,能力有高下之分,学习才知道事物的道理,而后才有智慧,不去求问就不会知道."知物 ...

  6. Android 逆向分析大全

    转载:Android 逆向分析大全:https://www.jianshu.com/p/a12d04fc748f 1. 概述 1.1 分析步骤 通用逆向分析步骤 1. 了解该模块正向编程相关方法 2. ...

  7. 二进制函数_Go二进制文件逆向分析从基础到进阶——MetaInfo、函数符号和源码文件路径列表...

    书接前文,本文主要介绍 Go 二进制文件中 Meta Information 的解析,与函数符号和源码文件路径列表的提取.最后详细介绍一下 Moduledata 这个结构.传送门:Go二进制文件逆向分 ...

  8. 逆向so_安卓逆向 | 分析调试与so调用实战

    声明:本教程用于学习交流,如有侵权联系本人删除! 点击上方"逆向小白",选择"加为星标" 第一时间关注逆向技术干货! 使用fiddler抓取某app登录接口的时 ...

  9. 安卓逆向之基于Xposed-ZjDroid脱壳 逆向分析(脱壳)

    安卓逆向--某力播逆向分析(脱壳) 一.环境 这一步真的头疼,环境很重要,各种测试,一下是我测试的环境,由于没有真机,就拿虚拟机做测试 1.  Xposed       2. FDex2        ...

最新文章

  1. 微软好绝情:Windows 7再无重大更新!
  2. java 小坑_关于Java子父类关系的小坑
  3. # C# 学习笔记(4) 类
  4. [20161219]关于LANGUAGE_MISMATCH.txt
  5. block才会执行 mono_C-BLOCK录制《我要上春晚》,目测会上湖南分会场
  6. SQL2005中的XXproperty() 函数归纳
  7. 万能无线鼠标对码软件_400元就能买ROG无线游戏鼠标,ROG影刃2无线版使用体验...
  8. Win32 程序运行原理
  9. 在vue文件引入echarts_vue文件中使用echarts.js的两种方式
  10. SQL Server中数据透视表的Python脚本
  11. Linux开发_调试与安全_gdb_peda简介
  12. WAVE族函数的使用
  13. 【转】多态与 new [C#]
  14. Kali渗透测试之五社会工程学
  15. 外国科学家有哪些黑历史? - 易智编译EaseEditing
  16. 【概念】椭球面在球面上的投影
  17. gts测试提示 Test failed due to unrecognized service account for this product, please submit an initial G
  18. 微信小程序--订单查询页面
  19. 主分区和逻辑分区的区别
  20. python 报价机器人_100行代码实现报价机器人公众号后台

热门文章

  1. 基于Bluemix快速构建部署一款Java小程序——微博影响力分析器
  2. Newtonsoft.Json版本不一致问题解决
  3. 贵州省六盘水谷歌卫星地图下载
  4. 双11的大型电商活动服务器崩溃是怎么回事?
  5. 口琴简谱_卡农(晓月版)_C大调
  6. 【java】1000问2SpringBoot项目打成war和jar有什么区别
  7. ios 科大讯飞错误码11201解决办法
  8. Android中静态方式破解某App实现所有视频app去除广告功能
  9. vue中如何使用和风天气插件
  10. 职场上不得不知的六大潜规则