娜璋AI安全之家于2020年8月18日开通,将专注于Python和安全技术,主要分享Web渗透、系统安全、CVE复现、威胁情报分析、人工智能、大数据分析、恶意代码检测等文章。真心想把自己近十年的所学所做所感分享出来,与大家一起进步。
系统安全系列作者将深入研究恶意样本分析、逆向分析、攻防实战等,通过在线笔记和实践操作的形式分享与博友们学习。前文普及了OllyDbg的基础用法,这篇文章将详细讲解OllyDbg和Cheat Engine工具逆向分析用法,完成植物大战僵尸的游戏辅助器,包括修改阳光值和自动拾取阳光两个功能。话不多说,让我们开始新的征程吧!希望对入门的同学有帮助,作者的目的是与安全人共同进步,加油~
文章目录:
作者逆向github资源:
声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。(参考文献见后)
在讲解OllyDbg和Cheat Engine工具逆向分析游戏之前,我想先给大家普及下内存地址的基础概念,以及通过创建项目来讲解下内存、地址、值它们的关系。
第一步,打开VS2019创建空项目,然后添加main.cpp源文件。
如下图所示,选中项目右键“添加”->“新建项”,然后创建main.cpp文件。
第二步,添加代码如下所示,我们尝试在内存中查看变量的位置。
其中%#表示输出提示方式,如果是8进制在前面加0,如果是十进制不加任何字符,如果是十六进制会加上0x。
#include "stdio.h"
int main()
{
int x = 1000;
//内存中查看值的位置
printf("%#X\n", &x);
//暂停
getchar();
return 0;
}
我们尝试添加个断点,然后运行程序。
第三步,按下F5调试,输出结果为0x12FFCDC。
第四步,接着我们需要在内存中查看这个值,选择“调试”->“窗口”->“内存”,然后随便选择一个“内存”。
输入地址“0x12FFCDC”即可。
接着我们打开程序员型计算机,可以看到1000对应的十六进制就是3E8,刚好和上面的 E8 03 00 00 一致。
注意这里仅显示了一个字节,我们如果右键选中转换为4字节,则可以显示完整的数值,如下图所示。
写到这里,VS简单查看内存的方法就介绍完毕了,其原理类比为:
那么,我们怎么将“旅客A”换成“旅客B”呢?这就需要通过门牌号在旅馆中找到“旅客A”再替换,但之前需要进行权限提升,才能进行后续的操作。同样,在游戏中,如果我们想在内存中修改值,也是通过地址访问这个值再进行修改,修改前也需要提升权限。具体操作主要包括四个步骤:
讲解完这个基础知识,接着我们开始植物大战僵尸的逆向吧!
修改阳光值其实就是修改游戏的分数、能量、血量、攻击力之类的,其原理是通过地址修改内存中的值,这里主要使用的是Cheat Engine工具。
第一步,通过Cheat Engine工具打开运行着的植物大战僵尸游戏。
第二步,输入数字“100”,点击“首次扫描”。
返回结果为762个。
第三步,接着反复玩游戏,并输入对应的数字进行“再次扫描”,比如输入数字“150”,点击“再次扫描”。
最终我们得到了一个结果,其地址为:
第四步,打开任务管理器,然后选中植物大战僵尸游戏,右键选择“转到详细信息”按钮。
显示结果如下图所示,这里获取了植物大战僵尸的进程ID。
原理搞懂之后,接下来就需要编写代码完成阳光值的修改。
第五步,在编写C语言代码修改阳关的参数前,先讲解Spy++的查找窗口功能和FindWindow函数。
我们在VS中可以看到查找窗口函数FindWindow包括两个参数,即窗口的类型和窗口的标题。
FindWindow(
lpClassName, {窗口的类名}
lpWindowName: PChar {窗口的标题}
);
这里我们可以通过Spy++来进行辅助讲解。
在弹出的界面中选择这个查找窗口(从左数第五个)按钮。
然后移动选择游戏窗口,查看对应的信息,它包括窗口句柄,如下图所示。所以接下来我们可以通过标题和类进行查找。
第六步,编写核心C语言代码,实现相关游戏修改功能。
通过GetWindowThreadProcessld函数找到进程ID。
DWORD GetWindowThreadProcessld(
HWND hwnd, //窗口句柄
LPDWORD lpdwProcessld //接收进程标识的32位值的地址
);
通过OpenProcess函数打开一个已存在的进程对象,并返回进程的句柄。
HANDLE OpenProcess(
DWORD dwDesiredAccess, //渴望得到的访问权限(标志)
BOOL bInheritHandle, //是否继承句柄
DWORD dwProcessId //进程标示符
);
通过WriteProcessMemory函数写入某一进程的内存区域。注意,直接写入会出Access Violation错误,故需此函数入口区必须可以访问,否则操作将失败。
BOOL WriteProcessMemory(
HANDLE hProcess, //由OpenProcess返回的进程句柄
LPVOID lpBaseAddress, //要写的内存首地址
LPVOID lpBuffer, //指向要写的数据的指针
DWORD nSize, //要写入的字节数
LPDWORD lpNumberOfBytesWritten
);
完整代码如下:
#include "stdio.h"
#include "windows.h"
int main()
{
//输入值作为修改阳光参数
int x;
scanf("%d", &x);
//进程ID
DWORD pid;
//1.找到游戏窗口 窗口类型、窗口标题
HWND hwnd = FindWindow(NULL,L"植物大战僵尸中文版");
//2.通过窗口找到进程ID
GetWindowThreadProcessId(hwnd,&pid);
//3.通过进程ip打开进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
//4.通过打开进程修改游戏内容
WriteProcessMemory(hProcess, (LPVOID)0x207FB5A0,
(LPVOID)&x,sizeof(x),&pid);
return 0;
}
第七步,当我们进行数值修改时,我们的植物大战僵尸阳光也就行对应的修改。
先设置为“0”,如下图所示修改成功,哈哈!是不是完成了一个简单的游戏辅助器呢?
接着我们修改成10086,如果360提示警告(==识别远程线程注入==),我们点击“允许本次修改”即可,最终成功将阳光值修改为“10086”。我们终于可以愉快的玩耍了,妈妈再也不用担心我的阳光!
同样第二关我们也可以进行修改,但此时的窗口地址会有变化,它变为了0x2099AE60,修改核心函数:
注意,如果游戏存在地址保护的情况,我们可以尝试注入进行修改。本系列文章仅分析经典的本地游戏,至于网络游戏一律禁止大家去修改或破坏,原理普及安全防护为主。
第八步,编程中遇到的错误一定要学会独立百度、谷歌解决,这是至关重要的一种能力提升。
注意,如果提示错误“error C4996: 'scanf': This function or variable may be unsafe. ”,则因为VS认为scanf函数是不安全的,进行安全开发生命周期SDL检查设置即可。
自动捡取的关键是点击鼠标,如果你点击到了阳光上它才会增加。所以我们希望在阳光下落的时候触发点击阳光事件,然后阳光地址会增加,初步预测涉及两个CALL函数。
第一步,当我们使用Cheat Engine定位到阳光的地址后,可以选中该地址右键设置“找出是什么修改了这个地址”。
首先,植物大战僵尸此时定位的地址为:0x2099AE60;然后选中改地址右键,设置“找出是什么修改了这个地址”。
第二步,等待下一个阳光捡起后,可以在下图所示窗口中获取新产生的值,即0x00430A11。接着点击0x00430A11地址,将扩展信息记录下来,方便接下来的自动拾取功能。
同时,点击“显示反汇编程序”会形成下图所示的效果图。
第三步,利用OllyDbg软件打开“PlantsVsZombies.exe”游戏。
第四步,前面我们已经定位到了阳光的窗口地址0x00430A11,接着按下Ctrl+G或者右键“转到”->“表达式”,然后跳转到指定位置。
跳转0x00430A11如下图所示:
第五步,按下F2给它增加个断点以及注释,游戏运行到点击阳光增加数值时就会断到这里。
我们可以查看ECX数值,它应该是19,对应十进制的25,所以猜测这里是增加阳关值。
运行程序直到捡起阳光,它会自动停到断点位置,并且ECX修改为0x19,对应的阳光值增加25分。观察汇编代码,发现它是一个增加语句,即验证了它是阳光的增加语句。
第六步,点击“调试”->“执行到返回”按钮(快捷键Ctrl+F9)。
接着跳转到0x00430AB4位置,如下图所示,注意返回到0x004314FD位置。
第七步,在RETN返回处按下F7,执行单步步入,会看到CALL函数执行完毕。我们不难推测这个函数就是增加阳光的函数。
接着我们给它增加一个断点,然后再次运行程序,点击拾取阳光后会自动定位到该位置。
第八步,选中该条语句进行nop操作。
NOP指令相当于空指令,不执行任何动作,对应16进制字节码为90。当我们的软件有广告弹窗时,我们可以通过nop设置过滤掉弹窗。
接着选中0x004313F8该行,右键“汇编”,然后在弹出的窗口中设置为nop即可。
如下图所示,设置之后0x004313F8位置变成了NOP空指令。我们可以把这个语句NOP设置后,发现点击阳光数值是不增加的,从而确定了增加函数。
第九步,然后右键撤销修改,接着分析汇编代码JNZ操作。
这时可以看到,在CALL函数之前有一个JNZ操作,也就是说它可能需要判断值才会进入增加阳光的函数,我们在这个JNZ下断点,再进入游戏点击阳光。
多次运行程序放行之后会发现,当我们点击阳光之后,阳光会往上走,只有当阳光完全到达指定位置(左上角)之后,才会执行call增加阳光值,由此得知这个JNZ主要是判断阳关是否到位。
注意,这里需要多次在0x004313F4处下断点再取消运行游戏,反复操作之后会发现实现JNZ操作后阳光会向左上角移动,否则会停止状态。作者也是一点点摸着过河,加油!
第十步,继续执行程序定位点击函数。
在增加阳光的CALL函数(0x0043159B)前有个跳转,当JNZ执行成功之后才会增加这个CALL。我们在JNZ处下断点调试它的执行流程。
当我们在JNZ处下断点后,运行游戏会突然跳转到断点处停止,如下图所示,并且游戏屏幕没有任何操作,接着按下F7运行发现阳光即将出现。
阳光出现如下图所示。
由于JNZ断点会让游戏很卡,接着我们将该处断点取消,而在0x0043159B位置CALL增加断点,执行程序后会发现当我们点击阳光的时候会被断下,所以判断它是阳光采集函数。这是个很典型的if-else语句, 如果没有被点击就会一直执行动画CALL,如果被点击那么就会执行增加阳光的CALL。
第十一步,最重要的步骤出现,我们将jnz修改为jmp,从而实现自动捡取阳光。
当我们修改完成之后,会发现阳光一出现就自动增加,根本不需要手动去点击,最终完成了该辅助功能。同样,我们可以尝试编写C语言实现相关自动化修改,这里不再进行讲解。
注意,CMP BYTE PTR DS:[EBX+50],0 是判断是否收集阳光的标志,然后才执行JNZ或JMP操作。当我们点击一个植物时,程序断了下来,可以看到赋值0,JNZ是不会跳转的;当我们点击阳光的时候才会赋值1,调用函数采集阳光。
写到这里,这篇文章就介绍完毕,希望对您有所帮助,最后进行简单的总结下。
学安全一年,认识了很多安全大佬和朋友,希望大家一起进步。这篇文章中如果存在一些不足,还请海涵。作者作为网络安全初学者的慢慢成长路吧!希望未来能更透彻撰写相关文章。同时非常感谢参考文献中的安全大佬们的文章分享,深知自己很菜,得努力前行。
很多朋友问我如何学逆向分析?
下面给出推荐的学习路线和安全书籍。软件逆行其实就是搬砖活,你需要的是任性和基本功。可能大佬们会有很多技巧,但我希望你能扎扎实实去躺过那些坑,会看懂代码,会写代码,然后IDA和OD工具(倚天屠龙)用好,每天泡在代码中,肯定能行的。你应该这样学习:
下图开发和逆向项目非常推荐你去完成,开发远控软件有助于你分析木马,CAD软件能提升你C++分析能力,做一个调制器或许反调试就不再那么难,自制一个小操作系统、小编译器、任务管理器,或许逆向原理就懂了。
编程没有捷径,逆向也没有捷径,它们都是搬砖活,少琢磨技巧,干就对了。什么时候你把攻击对手按在地上摩擦,你就赢了,也会慢慢形成了自己的安全经验和技巧。加油吧,少年希望这个路线对你有所帮助,共勉。
系统安全前文赏析:
2020年8月18新开的“娜璋AI安全之家”,主要围绕Python大数据分析、网络空间安全、人工智能、Web渗透及攻防技术进行讲解,同时分享论文的算法实现。娜璋之家会更加系统,并重构作者的所有文章,从零讲解Python和安全,写了近十年文章,真心想把自己所学所感所做分享出来,还请各位多多指教,谢谢。