知道内存地址后如何rpg制作大师修改器修改器

本教程面向有C\C++基础的人,最好还要懂一些Windows编程知识
代码一律用Visual Studio 2013编译,如果你还在用VC6请趁早丢掉它...
写这个教程只是为了让玩家更好地体验所爱的单机游戏,顺便学到些逆向知识,我不会用网络游戏做示范,请自重
上一章讲了用CE读写内存,本章讲如何自己编程实现
用到的API:
BOOL WINAPI ReadProcessMemory(
LPCVOID lpBaseAddress,
_Out_ LPVOID
_Out_ SIZE_T
*lpNumberOfBytesRead
BOOL WINAPI WriteProcessMemory(
lpBaseAddress,
LPCVOID lpBuffer,
_Out_ SIZE_T
*lpNumberOfBytesWritten
// 打开进程
HANDLE WINAPI OpenProcess(
& _In_&DWORD dwDesiredAccess,
& _In_&BOOL &bInheritHandle,
& _In_&DWORD dwProcessId
本章开始最好学习汇编知识了,也不用太深,能做逆向工程就行了
&这篇文章讲得不错
另外VS2013(我就不告诉你VC6也有)调试时在菜单-调试-窗口-反汇编可以看到C/C++代码的对应汇编代码,多看看就熟悉了
本章以制作东方辉针城修改器的实战讲解读写内存
首先分析一下目标进程的内存
用CE搜索一下HP地址,找到0x004F5864,然后用分析数据/结构分析一下它附近的内存(其实这些变量并不在一个struct或class内,但看看附近的内存总会有惊喜)
这是一个指向资源信息的指针
然后是关于游戏数据的
然后提取出有用的数据
要读写一个进程的内存首先要打开进程,打开进程需要进程ID(PID)
一般有两种方式获取PID,第一种通过窗口句柄:
HWND hwnd = FindWindow(_T(&BASE&), NULL);
GetWindowThreadProcessId(hwnd, &pid);
第二种通过进程名:
#include &tlhelp32.h&
DWORD GetPid(LPCTSTR name)
DWORD pid = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSE***Y32 processE
processEntry.dwSize = sizeof(PROCESSE***Y32);
// 枚举进程
BOOL hasNext = Process32First(snapshot, &processEntry);
while (hasNext)
// 比较进程名
if (_tcsicmp(processEntry.szExeFile, name) == 0)
pid = processEntry.th32ProcessID;
hasNext = Process32Next(snapshot, &processEntry);
CloseHandle(snapshot);
DWORD pid = GetPid(_T(&th14.exe&));
没什么好讲的,读内存需要PROCESS_VM_READ权限,写内存需要PROCESS_VM_WRITE和PROCESS_VM_OPERATION权限
HANDLE process = OpenProcess(/*PROCESS_ALL_ACCESS*/ PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
需要注意的是静态地址也不是不变的,准确来说应该用模块基址+偏移量来表示,因为模块基址可能会变,如果模块基址会变的话还要取模块基址(其实就是模块句柄)
不过大部分exe模块的基址是不变的(32位默认0x位默认0x)
WriteProcessMemory(m_process, (LPVOID)0x004F5864, &(buffer = 8), sizeof(DWORD), NULL);
东方辉针城修改器
然后我们就可以实现这个修改器了,依然用到了MFC(为了少写UI代码)
// 处理定时器
void CTH14CheatDlg::OnTimer(UINT_PTR nIDEvent)
HWND hwnd = ::FindWindow(_T(&BASE&), NULL);
if (hwnd == NULL) // 进程已关闭
if (m_process != NULL)
// 释放句柄
CloseHandle(m_process);
m_process = NULL;
// 打开进程
if (m_process == NULL)
GetWindowThreadProcessId(hwnd, &pid);
m_process = OpenProcess(/*PROCESS_ALL_ACCESS*/ PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
if (m_process == NULL)
msg.Format(_T(&打开进程失败,错误代码:%u&), GetLastError());
MessageBox(msg, NULL, MB_ICONERROR);
CDialogEx::OnTimer(nIDEvent);
if (m_lockHp)
WriteProcessMemory(m_process, (LPVOID)0x004F5864, &(buffer = 8), sizeof(DWORD), NULL);
if (m_lockBomb)
WriteProcessMemory(m_process, (LPVOID)0x004F5870, &(buffer = 8), sizeof(DWORD), NULL);
if (m_lockPower)
WriteProcessMemory(m_process, (LPVOID)0x004F5858, &(buffer = 400), sizeof(DWORD), NULL);
CDialogEx::OnTimer(nIDEvent);
东方辉针城修改器V2
每秒钟写内存的方法看上去太蠢了,而且会影响性能,一劳永逸的方法就是修改代码
首先找出减少残机数的指令
地址是0x,机器码A3 64 58 4F 00,把它全部改成90(nop指令)
减少bomb的指令
地址0x0041218A,机器码A3 70 58 4F 00,改成nop
然后是判断bomb够不够用的指令
要修改的是下面的jle指令(小于或等于时跳转),把它改成nop
地址0x0044DD68,机器码7E 0E
然后是游戏刚开始时赋值灵力的
直接改这条指令长度会变长,改上面的mov eax吧,改成赋&#
地址0x00435DAF,原机器码A3 58 58 4F 00,修改成B8 90 01 00 00
死亡后赋值灵力的
这堆代码的意思是把灵力读到ecx寄存器,减少后写回内存,改成赋&#吧
地址0x0044DDB8,原机器码03 C8 3B CE 0F 4C CE,修改成B9 90 01 00 00 90 90
实现代码(完整源码地址同上):
// 修改关于残机的代码
void CTH14CheatDlg::modifyHpCode()
static const BYTE originalCode[] = { 0xA3, 0x64, 0x58, 0x4F, 0x00 };
static const BYTE modifiedCode[] = { 0x90, 0x90, 0x90, 0x90, 0x90 };
if (m_process != NULL)
WriteProcessMemory(m_process, (LPVOID)0x, m_lockHp ? modifiedCode : originalCode, sizeof(originalCode), NULL);
// 修改关于炸弹的代码
void CTH14CheatDlg::modifyBombCode()
static const BYTE originalCode1[] = { 0xA3, 0x70, 0x58, 0x4F, 0x00 };
static const BYTE modifiedCode1[] = { 0x90, 0x90, 0x90, 0x90, 0x90 };
static const BYTE originalCode2[] = { 0x7E, 0x0E };
static const BYTE modifiedCode2[] = { 0x90, 0x90 };
if (m_process != NULL)
WriteProcessMemory(m_process, (LPVOID)0x0041218A, m_lockBomb ? modifiedCode1 : originalCode1, sizeof(originalCode1), NULL);
WriteProcessMemory(m_process, (LPVOID)0x0044DD68, m_lockBomb ? modifiedCode2 : originalCode2, sizeof(originalCode2), NULL);
// 修改关于灵力的代码
void CTH14CheatDlg::modifyPowerCode()
static const BYTE originalCode1[] = { 0xA3, 0x58, 0x58, 0x4F, 0x00 };
static const BYTE modifiedCode1[] = { 0xB8, 0x90, 0x01, 0x00, 0x00 };
static const BYTE originalCode2[] = { 0x03, 0xC8, 0x3B, 0xCE, 0x0F, 0x4C, 0xCE };
static const BYTE modifiedCode2[] = { 0xB9, 0x90, 0x01, 0x00, 0x00, 0x90, 0x90 };
if (m_process != NULL)
WriteProcessMemory(m_process, (LPVOID)0x00435DAF, m_lockPower ? modifiedCode1 : originalCode1, sizeof(originalCode1), NULL);
WriteProcessMemory(m_process, (LPVOID)0x0044DDB8, m_lockPower ? modifiedCode2 : originalCode2, sizeof(originalCode2), NULL);
if (m_lockPower)
WriteProcessMemory(m_process, (LPVOID)0x004F5858, &(buffer = 400), sizeof(DWORD), NULL);
本文已收录于以下专栏:
相关文章推荐
这一课 将用CE来找出对对碰游戏 坐位号基址,棋盘数组基址并把它读出来
教学目的:学会用API函数读出内存数据
 1、预备知识
   4种数据类型
   字节 Byte=00-FF          ...
windows内存管理知识:
1.分段或分页内存管理
2.物理地址和虚拟地址,虚拟地址空间.
3.虚拟内存布局,内存分工,堆,栈.
4.内存存取权限.
5.标准C内存管理函数与windows...
人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..
记得我的博客第一篇文章是写的《仙剑奇侠传3 外传》存档文件修改器(请参看:《[vb6]仙剑3外传的存档修改器》),当时是用vb6写的。
想想也是十多年过去了。
十多年过去已经很少在电脑上玩游戏了,还好...
计算机程序所有的变量、代码都是储存在内存里的,包括游戏里那些HP、MP、金钱等,那么只要能修改内存就能自由改变玩家的HP、金钱了(当然对于网游是没用的,这些数据都储存在服务器,客户端里的只是一个副本)...
在第二章介绍了hook机制,本章要自己实现hook,实现调用某个函数时我们能截获、修改、取消这次调用
CE也不是专门用来调试的,本章将介绍几款调试工具,并且完善上一章的东方辉针城修改器
本章介绍怎么hook D3D函数,实现在游戏画面中显示自己的文字
注入的代码就是目标进程的一部分了,可以直接用指针读写目标进程内存,还可以hook目标进程的函数
先从最简单的模拟操作讲起
模拟键盘鼠标有很多方法,我大体分为消息模拟、API模拟、驱动模拟
对于网页的话还可以用JavaScript模拟,虽然这不在本教程范围
他的最新文章
讲师: 许鹏
讲师:董付国
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

参考资料

 

随机推荐