【前言】:
小弟我前几天才刚刚接触到《兽人必须死》这个游戏,发现主角真的很贱,不过玩起来很过瘾。一直想下载个修改器来痛快虐虐兽人,但是下载的都报毒,不知道是真毒还是误报,反正老婆大人是不同意在她电脑上用。无奈,自己动手丰衣足食吧。
【工具】
CE,这个就不说了,没他啥也甭干了。
OD,就是OllyDbg,小弟我从事软件安全工作,这个工具必不可少。
VC++,我就会C和汇编,其他不会。
【过程】
我打算就做2个功能,1个是锁定钱,一个是锁定魔法值。
先来做锁定钱的,钱因为是数字,好分析。
1 先用CE找到金钱的地址,动态地址就可以,不用找基址。如图1.这个过程巨简单吧,我就不多说了。不会的童鞋可以看诸位大大的教程或者问我。
2.找到后,右键这个地址,选择“什么改写这个地址”。然后切换到游戏,花点钱,就能发现图2的窗口。选择显示汇编,就是红圈的那个。因为我们要分析汇编语言。
3.接下来,选择显示汇编后,我们看见这个界面:
大家注意到,被高亮显示的那句话就是我们的钱被改写的汇编指令。我们可以看到,这句话在内存地址00794B77的位置。当然,各位童鞋要注意,你们显示的地址肯定和我不一样,我每次显示的都不一样。因为这是一个动态链接库(DLL),所以地址是动态的。不过没关系,下面我教大家怎么确定他的动态地址。
4.知道了这个地址,我们就可以改了,但是,就像我说的,他每次都会在00794B77的位置上吗?答案是否定的,退出游戏再进来,地址就变了,因此我们可以肯定的是,这部分代码应该在动态链接库中。好,我们看看他在哪一个动态链接库中。点击如下图的菜单:
会显示《兽人必须死》这个游戏所有加载进来的动态链接库。如图:
5.从此图中我们看到,动态链接库SaberPlugin的开始地址是00730000,和我们的00794B77位置最近,因此,我们可以确定,刚才位于00794B77的指令在SaberPlugin的动态库中。
6.对于windows系统,我们不知道每次动态库会被加载到内存哪里,但是,我们可以通过系统一些功能函数得到动态库加载的基址,然后根据基址+偏移,最后得到目的地址。接下来,我们计算偏移。请看公式1:
目的地址 = 基址 + 偏移
偏移 = 目的地址 – 基址, 所以我们的偏移地址 = 00794B77 – 00730000 = 64B77。
7.接下来,OD出场了,呵呵,久等了。用OD 附加到游戏进程,然后跳转到指令00794B77的位置,童鞋们要注意了,这时候,要退出CE的调试,否者OD会报告进程被其他程序加载而失败。如图所示:
8.从OD中了解到,该地址的指令是把寄存器EDI中的数值放到EAX+70的地址中,可以肯定的是,EDI中的数值就是金钱。该地址的二进制指令从图中可以看到,是:89 78 70。上图红圈处。为了简单起见,我直接将二进制指令改成89 60 70,也就是把ESP中的数值放在EAX+70的地址中。肯定好多童鞋问为啥。说实话,就是我懒,因为这是个3字节的指令,如果我添加的指令长度超过3字节,就会覆盖程序正常的指令,导致游戏崩溃。如果实在想添加多于3字节的指令,大家可以去看看远程代码注入的知识,做起来比较复杂,100楼之内也说不清。所以,为了省时间,我直接就修改成ESP了。又有童鞋问了,为啥是ESP?呵呵,其实EAX,EBP,ECX…..等等,都成。因为ESP数值肯定不会是0,所以钱肯定就不是0啊。我是偷懒。大家看我图中,ESP的值是16进制的0018E554,换成10进制,大约是1631572这么多。好家伙,160多万块钱,够了吧!
9.然后就是确定动态库基址的问题,大家请看代码:
HMODULE checkModuleAddr(DWORD id)
{
HMODULE addr = 0;
MODULEENTRY32 me32={0};
//在本进程中拍一个所有模块的快照
HANDLE hModuleSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,id);
if(hModuleSnap==INVALID_HANDLE_VALUE)
return 0;
//遍历快照中记录模块
me32.dwSize=sizeof(MODULEENTRY32);
//cout<<"模块名称及地址";
do
{
if(wcscmp(me32.szModule, modName) == 0)
{
addr = me32.hModule;
break;
}
}
while(::Module32Next(hModuleSnap,&me32));
CloseHandle(hModuleSnap);
return addr;
}
这段代码就是获得动态库的代码,得到动态地址后,加上刚才算的偏移(64B77),我们就能够每次都算出目的地址啦,然后用WriteProcessMemory函数改写成赋值ESP的二进制,就大功告成啦。如图(注意左下角的金钱):