实例游戏内存修改器----CUI版本模拟
实现说明:
目标进程内存中很可能存在多个你要搜索的值, 所以在进行第一次搜索的时候, 要把搜索到的地址记录下来,然后让用户改变要搜索的值,再在记录的地址中搜索,直到搜索到的地址惟一为止。为此写两个辅助函数和 3 个全局变量。
BOOL FindFirst(DWORD dwValue); // 在目标进程空间进行第一次查找
BOOL FindNext(DWORD dwValue); // 在目标进程地址空间进行第2、3、4……次查找
DWORD g_arList[1024]; // 地址列表
int g_nListCnt; // 有效地址的个数
HANDLE g_hProcess; // 目标进程句柄
上面这 5 行代码就组成了一个比较实用的搜索系统。比如游戏中显示的金钱值是 12345,首先将 12345 传给 FindFirst 函数进行第一次搜索,FindFirst 函数会将游戏进程内存中所有内容为 12345 的地址保存在 g_arList 全局数组中,将这样地址的个数记录在 g_nListCnt 变量中。FindFirst 函数返回以后,检查 g_nListCnt 的值,如果大于 1 就说明搜索到的地址多于 1 个。这时应该做一些事情改变游戏显示的金钱值。比如改变后金钱值变成了 13345,你要以 13345 为参数调用 FindNext 函数。这个函数会在 g_arList 数组记录的地址中进行查找,并更新g_arList 数组的记录, 将所有内容为 13345 的地址写到里面, 将这样地址的个数写到 g_nListCnt 变量中。FindNext 函数返回后,检查 g_nListCnt 的值,如果不等于 1 还继续改变金钱值,调用函数 FindNext,直到最终 g_nListCnt 的值为 1 为止。这时,g_arList[0]的值就是目标进程中保存金钱值的地址。
程序运行说明:
现在基本功能都有了,启动程序。
(1)输入 199,发现找出的地址不惟一。
(2)在 TestExe.exe 窗口敲下回车,改变后再进行一次查找,这样循环直到找到的地址惟
一为止。
(3)输入期待的值,修改成功!
TestExe.cpp
1 // 辅助测试程序------类比于游戏程序
#include <stdio.h> int g_nNum; // 全局变量测试 int main()
{
int i = ; // 局部变量测试
g_nNum = ; while ()
{
printf("i = %d, address = %08lX; g_nNum = %d, address = %08lX\n", ++i, &i, ++g_nNum, &g_nNum);
getchar(); // 按回车可以使两个变量值递增变化一,但是地址是不变的,为的是在MemRepair中正确找到该变量的唯一地址。
}
return ;
}
MemRepair.cpp
1 #include <windows.h>
#include <stdio.h> HANDLE g_hProcess;
int g_nListCnt;
int g_arList[]; /*
Windows 采用了分页机制来管理内存,每页的大小是 4KB(在 x86 处理器上) 。也就是说
Windows 是以 4KB 为单位来为应用程序分配内存的。所以可以按页来搜索目标内存,以提高
搜索效率。
*/
//读取一页内存
BOOL CompareAPage(DWORD dwBaseAddress, DWORD dwValue)
{
BYTE arBytes[];
if (!::ReadProcessMemory(g_hProcess, (LPVOID)dwBaseAddress, arBytes, , NULL))
{
return FALSE; // 此页不可读
}
// 在这一页内存中查找
DWORD* pdw;
for (int i = ; i < *-; ++i)
{
pdw = (DWORD*)&arBytes[i];
if (pdw[] == dwValue) // 等于要查找的值
{
if (g_nListCnt >= )
{
return FALSE;
}
// 添加到全局变量中
g_arList[g_nListCnt++] = dwBaseAddress + i;
}
}
return TRUE;
} /*
应该在目标进程的整个用户地址空间进行搜索。在进程的整个 4GB(即2^32) 地址中,Windows 98
系列的操作系统为应用程序预留的是 4MB 到 2GB 部分,Windows 2000 系列的操作系统预留
的是 64KB 到 2GB 部分,
*/ // FindFirst 函数将所有符合条件的内存地址都记录到了全局数组 g_arList 中。
BOOL FindFirst(DWORD dwValue)
{
const DWORD dwOneGB = * * ; // 1GB
const DWORD dwOnePage = * ; // 4KB
if (g_hProcess == NULL)
{
return FALSE;
} // 查看操作系统类型,以决定开始地址
DWORD dwBase;
OSVERSIONINFO vi = {sizeof(vi)};
::GetVersionEx(&vi);
if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
dwBase = * * ; // Windows 98 系列,4MB
}
else
{
dwBase = * ; // Windows NT 系列,64KB
} // 在开始地址到2GB的地址空间进行查找
for (; dwBase < * dwOneGB; dwBase += dwOnePage)
{
// 比较一页的内存
CompareAPage(dwBase, dwValue);
}
return TRUE;
} BOOL FindNext(DWORD dwValue)
{
// 保存m_arList数组中有效地址的个数,初始化新的m_nListCnt值
int nOrgCnt = g_nListCnt;
g_nListCnt = ; // 在m_arList数组记录的地址处查找
BOOL bRet = FALSE;
DWORD dwReadValue;
for (int i = ; i < nOrgCnt; ++i)
{
if (::ReadProcessMemory(g_hProcess, (LPVOID)g_arList[i], &dwReadValue, sizeof(DWORD), NULL))
{
if (dwReadValue == dwValue)
{
g_arList[g_nListCnt++] = g_arList[i];
bRet = TRUE;
}
}
}
return bRet;
} // 打印出搜索到的地址
void ShowList()
{
for (int i = ; i < g_nListCnt; ++i)
{
printf("%08lX\n", g_arList[i]);
}
} // 重写指定地址的值
BOOL WriteMemory(DWORD dwAddr, DWORD dwValue)
{
return::WriteProcessMemory(g_hProcess, (LPVOID)dwAddr, &dwValue, sizeof(DWORD), NULL);
} int main()
{
// 启动TestExe.exe进程
char szFileName[] = "..\\TestExe\\Debug\\TestExe.exe";
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
::CreateProcess(NULL, szFileName, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); // 关闭线程句柄,既然我们不使用
::CloseHandle(pi.hThread);
g_hProcess = pi.hProcess; // 输入要修改的值
int iVal;
printf("Input value = ");
scanf("%d", &iVal); // 进行第一次查找
FindFirst(iVal); // 打印出搜索的结果
ShowList(); while(g_nListCnt > )
{
printf("Input val = ");
scanf("%d", &iVal); // 进行下次搜索
FindNext(iVal);
// 显示搜索结果
ShowList();
} if (g_nListCnt == ) // 已经锁定了要修改的地址
{
// 设置新值
printf("New value = ");
scanf("%d", &iVal);
// 写入新值
if (WriteMemory(g_arList[], iVal))
{
printf("Write data successfully\n");
}
}
::CloseHandle(g_hProcess);
return ;
}
运行结果:
(1)在MemRepair.exe中输入值199查找,发现地址不唯一,有一百多个;
(2)在TestExe中打回车,使变量变为200,在MemRepair.exe中输入200查找,发现唯一一个地址,并且与TestExe中的地址相同;
(3)在MEMRepair.exe中输入希望修改的新值300,回车之后,在TestExe.exe中再打回车,发现变量已经变为301而不是201了。
截图如下:

实例游戏内存修改器----CUI版本模拟的更多相关文章
- 只需要一点点C++基础,新手也可以制作单机游戏内存修改器
声明:本文只是为了初学C++的,能够做出一些实用的东西,跳出管理系统的束缚,提升学习的兴趣,在这里选取了单机游戏,请不要尝试在线游戏,违发而已未必可行.序:首先我们需要一个Qt+VS环境Qt从http ...
- ce游戏内存修改器(Cheat Engine)
ce修改器(Cheat Engine)一款专门修改内存修改编辑的游戏工具它包括16进制编辑,反汇编程序,内存查找工具新版6.1 版的CE与6.0 最大的区别就是添加了修改器制作工具,比之前 5.6.1 ...
- UWP游戏防内存修改器的方法
最近我一直在编写适用于Windows 10商店的游戏.这款游戏比较怕玩家用修改器改金钱,因为这种修改会导致某些内购失效并且损害公平性.于是我把自己见过的三种反修改器的方法给网友们介绍一下. 首先说明一 ...
- Android For JNI(二)——C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器
Android For JNI(二)--C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器 当我们把Hello World写完之后,我们就可以迈入C的大门了,今天就来讲讲基本的一些数据类型 ...
- C++内存修改器开源代码
我们玩单机游戏时,游戏难度可能过大, 或者游戏已经比较熟练,想要增加游戏的玩法,这时候可以使用修改器. 内存式游戏修改器主要对游戏内存修改 修改时有两种方式,一是定时对内存数值进行修改.实现类似锁定的 ...
- 防止apk反编译的技术分析浅谈--内存修改器篇
声明: 1.本帖转载自http://jingyan.baidu.com/article/a24b33cd509eb719fe002b94.html,仅供自用,勿喷 Apk反编译修改器有很多.拿其中的比 ...
- Steam游戏《Nine Parchments(九张羊皮纸)》修改器制作-[先使用CE写,之后有时间的话改用C#](2020年寒假小目标02)
日期:2020.01.09 博客期:122 星期四 [温馨提示]: 只是想要修改器的网友,可以直接点击此链接下载: 只是想要部分CT文件的网友,可以直接点击此链接下载: 没有博客园账号的网友,可以将页 ...
- Steam游戏《Northgard(北境之地)》修改器制作
日期:2021.06.07 博客期:181 星期一 [温馨提示]: 我现在把资源先放到开头,不想研究学习的就直接取用.如果修改器失效了,你们可以在博客园本页直接评论,也可以给我发邮件告诉我,就是不要到 ...
- oracle11g rac asm 实例内存修改
ASM实例内存修改 memory_max_target(它为静态参数,修改完成后需要重启实例) memory_target(它为动态参数,不需要重启实例) SQL> select name,is ...
随机推荐
- 我的Python之旅第五天---迭代器和生成器
h3,#nv_portal .vw .d .h3 {display: block; font-weight: 500; background-image: linear-gradient(to rig ...
- Codeforces Round #369 (Div. 2) D. Directed Roads 数学
D. Directed Roads 题目连接: http://www.codeforces.com/contest/711/problem/D Description ZS the Coder and ...
- HDU 5813 Elegant Construction 构造
Elegant Construction 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5813 Description Being an ACMer ...
- 重写对象ToString方法
重写对象ToString方法,引入Newtonsoft.Json public override string ToString() { JsonSerializerSettings settings ...
- myeclipse优化 Maven
1.禁用myeclipse updating indexes MyEclipse 总是不停的在 Update index,研究发现Update index...是Maven在下载更新,但很是影响mye ...
- no acceptable C compiler found in $PATH
安装gcc编译器 yum install -y gcc 参考: http://blog.51cto.com/raulkang/573151
- [置顶] 从零开始学C++之STL(二):实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)
首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下: C++ Code 1 2 template < class _Ty, ...
- TIDB VS COCKROACHEB
分布式事务 要支持分布式事务,首先要解决的就是分布式系统时间的问题,也就是我们用什么来标识不同事务的顺序.通常有几种做法: TrueTime,TrueTime 是 Google Spanner 使用的 ...
- deeplearningbook-chinese
https://exacity.github.io/deeplearningbook-chinese/
- C#程序中判断DEBUG和RELEASE状态
编辑 删除 习惯了用老方式(注释的方式)来对程序进行调试,不过昨天才发现这样调试存在很大的隐患:在工程发布的时候如果忘记把该注释的代码注释掉,而让这些调试信息随工程一起发布,如果是可见的调试信息倒好发 ...