一个大型网游多开实例
找到一个没加壳的半免费网游(网游的名字就不说了),分析其双开方式。大概“某人们”早就对它动过手脚了,只是没看到有人公布。
经过几天的试用,至今没有发现这种破法有问题。(由于是几天以前破的,现在回忆起来可能会有点出入,还是希望读者以实际为准,灵活应变^_^)
本文仅仅作为研究用,不可作其他用途……
///////////////////////////////////
经过简单的观察,猜测执行桌面快捷方式后打开的是一个自动Update的程序,该程序每天更新其核心。
继续观察,发现Update程序完成后直接用CreateProcess之类的方法运行那个核心文件。核心文件通过分析命令行参数来指定登陆服务器(官服,不是私的)。
于是开始下手:
首先自己写一个程序 ShowCmdLine.asm :
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
include macro.asm
.data
mytitleA db 'GetCmdLine()',0
.data?
bufferdb 100 dup(?)
.CODE
START:
invoke GetCommandLine
invoke MessageBox,NULL,eax,offset mytitleA,MB_OK
invoke ExitProcess,0
end START
编译它,重命名成网游的核心文件名,放到网游目录下。正常步骤运行之…………
Oh,Ja!事实证明了猜想。选择任意一个服务器测试,记下那个服务器所对应的参数(我玩的服务器参数是1rag21,这个字眼熟悉吧~应该有许多人知道这是什么网游了,我也不能多说,不知道的自己google一下吧)。
打开IDA,分析原来的核心(文件满大的~要有耐心)。在等待IDA分析的时候多看看import table,找找看有什么可疑的函数……
大多人首先会找FindWindow之类的……没错!
从IDA的Imports中看到
CreateMutexA 和 FindWindowA
不管怎样,这两个不可不防。
改之!
在FindWindowA上按下'X',得到FindWindowA函数的xrefs(嘻嘻,只有一处):
..........
..... call FindWindowA
.text:0064CFCF test eax, eax
.text:0064CFD1 jz short loc_64CFDC
.......
如果没有FindWindow到,就注册个窗体类,再建立一个窗口。
没话说,改成 xor eax,eax (只改动了一个字节的机器码,不能改长度)。
然后处理CreateMutexA:
同样按下'x',得到xrefs
这里的CreateMutexA的调用大概有5处左右。
每处的代码类似:
.text:006517F2 call ebx ; CreateMutexA
.text:006517F4 mov esi, eax
.text:006517F6 test esi, esi
.text:006517F8 jnz .....
jnz到的每个地方(只有两个实例,其他都是重复的)一开始都是GetLastError,如:
.text:00651843 call ds:GetLastError
.text:00651849 cmp eax, ERROR_ALREADY_EXISTS
这里有个技巧,把 cmp eax, ERROR_ALREADY_EXISTS 改成比如 cmp eax,00000001 之类的其他错误代码,建议直接修改机器码,否则要注意不能改变文件长度,或者应该用nop填充……
保存修改完的结果。
为了绕过Updater,迅速启动游戏,由于那个核心文件不是.exe为后缀的。写个程序来调用它:
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
include macro.asm
.data
ErrorTitle db 'Error',0
ErrorMsg db '不能运行',0
.data?
bufferdb 100 dup(?)
.CODE
START:
invoke StdIn,offset buffer,100
invoke lstrlen,offset buffer
dec eax
mov BYTE PTR buffer,0
dec eax
mov BYTE PTR buffer,0
invoke WinExec,offset buffer,SW_SHOW
cmp eax,31D
jg @f
invoke MessageBox,NULL,offset ErrorMsg,offset ErrorMsg,MB_OK
@@:invoke ExitProcess,0
end START
link的时候加上 /subsystem:console。
通过这个程序间接调用游戏核心程序(其实应该说成是主程序),别忘了加上参数指定服务器(否则……)。
…………
………………
……………………
……………………………
…………………………………
…………………………………………
………………汗~~还是不能双开。
别着急,来动态调试它。
我用OllyDebug,主要因为它和Tc的快捷键基本相同,以前TC用了相当长的时间……
我用的计算机速度相当慢(P3-667,15G硬盘)。
有经验的无产阶级们不必等着OllyDbg分析完整个程序,在OD进度调缓慢移动的时候按下空格,阻止OD分析。
(虽然本菜鸟没有经验,但是由于计算机配置的限制,也只能加载完不等分析把它停了。)如果实在对动态加载显示的Call来Call去摸不着头脑,可以对照着刚才IDA的分析结果。但是相信只要稍微熟悉VC6的rtl就不会有大问题。
大可在很后面的地方按下F4,因为前面的障碍在静态分析的时候都已经扫除了!
跳跃着动态F4在其中一个可疑的地方停下(似乎应该是这里,记得不是很清楚了。不过,既然本菜鸟都可以一眼看出来,相信大家……)
.text:0064E1E9 call ds:CreateMutexA
.text:0064E1EF push eax ; hHandle
.text:0064E1F0 call ds:WaitForSingleObject
.text:0064E1F6 test eax, eax ;!!!!!!!!!!!
.text:0064E1F8 jz short loc_64E208
大概是刚才分析CreateMutexA的时候漏了这里,把这里也补成 xor eax,eax
再运行一遍……Gut!成功了。
顺便针对玩家(不是为了研究的那种)说一下,该文件每天更新,如果用旧版本则无法进入游戏,写个程序打打补丁吧。
总共Patch了4个字节,应该算是改动比较少的,其他几组核心程序改法也类似。
总结:
这个程序利用了普遍应用的CreateMutex以及FindWindow来保证程序只运行一个实例。该破解过程属于简单类型。
!!!再次声明,本文仅为讨论技术,作者不承担任何责任。
顶你一下吧
static/image/common/sigline.gif
北京商标注册代理
页:
[1]