实例游戏内存修改器----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 ...
随机推荐
- Lucene 3.0 输出相似度
http://www.cnblogs.com/ibook360/archive/2011/10/19/2217638.html Lucene3.0之结果排序(原理篇) 传统上,人们将信息检索系统返回结 ...
- 如何在Windows服务程序中添加U盘插拔的消息
研究了下这个问题,主要要在一般的windows服务程序中修改两个地方: 一.调用RegisterServiceCtrlHandlerEx VOID WINAPI SvcMain( DWORD dwAr ...
- springboot中配置druid允许一次执行多条sql
原文:https://blog.csdn.net/jiangjun0130/article/details/77868578 1:在配置文件中不需要指定wall防火墙filter. 配置如下: spr ...
- java根据模板HTML动态生成PDF
原文:https://segmentfault.com/a/1190000009160184 一.需求说明:根据业务需要,需要在服务器端生成可动态配置的PDF文档,方便数据可视化查看. 二.解决方案: ...
- TMS WEB CORE直接从HTML&CSS设计的页面布局
TMS WEB CORE直接从HTML&CSS设计的页面布局 TMS WEB CORE支持DELPHI IDE中拖放控件,生成HTML UI.这种方式适合DELPHI和C++ BUILDER的 ...
- iOS-如何让xcode自动检查内存泄露
在project-setting中找到 “Run Static Analyzer” 键,然后把值修改为“YES”.这样在编码的时候,xcode就可以自动为我们检查内存泄露了.
- 使用VMWare虚拟机创建CentOS版本号的Linux学习环境(每一步都有截图与说明)
学习Android开发.假设不学习Linux的基本使用,总感觉心里过意不去,由于毕竟Android还是搭载在Linux的基础之上的. 因此.学习一种Linux系统的基本操作.对我们以后的学习还是非常有 ...
- HBase的JavaAPI使用
Java Client API Overview HBase是用Java写的,支持用编程语言来动态操作管理数据库,能用命令行做的都能够用API来做. 主要的使用步骤例如以下: 1.创建一个 Confi ...
- Linux学习18-gitlab新建项目提交代码
前言 gitlab前面已经搭建好了,如果我们想用把代码上传到gitlab仓库上的话,先要新建一个项目仓库.然后本地安装git环境,就可以提交了 root用户 gitlab首次在浏览器上打开web页面, ...
- [LNU.Machine Learning.Question.1]梯度下降方法的一些理解
曾经学习machine learning,在regression这一节,对求解最优化问题的梯度下降方法,理解总是处于字面意义上的生吞活剥. 对梯度的概念感觉费解?到底是标量还是矢量?为什么沿着负梯度方 ...