|
![]() | 作者: yongmin [yongmin]
![]() |
登录 |
【文章标题】: 快乐传说脱机 破解分析 【文章作者】: goodcode 【软件名称】: 快乐传说脱机 1.39 【下载地址】: 自己搜索下载 【加壳方式】: ASPack 2.12 -> Alexey Solodovnikov 【保护方式】: 网络验证 【编写语言】: Delphi 【使用工具】: OD+DEDE+IDA 【操作平台】: Win32 【软件介绍】: 一款游戏的脱机外挂 【作者声明】: 外挂已经停止更新,并且不能正常连接验证服务器. -------------------------------------------------------------------------------- 【详细过程】 打开程序通过"快乐传说脱机.exe"打开"gjmain.dat", 确定外挂主程序为"gjmain.dat". 将"gjmain.dat"改名为"gjmain.exe", peid查壳为"ASPack 2.12 -> Alexey Solodovnikov",通 过脱壳机自动脱壳. 启动"gjmain.exe", 输入帐号密码日志窗口提示如下,请稍等)...... 7:27:55 连接验证服务器失败 7:28:01 登陆成功 可以进入游戏,但是挂机功能不能正常使用(不能寻怪) 通过dede分析"gjmain.exe", 然后创建项目文件. 打开"main.dfm", 游览窗口上的组件发现ClientSocket1很有可能用于验证, 内容如下 object ClientSocket1: TClientSocket Active = False ClientType = ctNonBlocking Host = 'www.csjpwg.com' Port = 80 OnConnect = ClientSocket1Connect OnRead = ClientSocket1Read OnError = ClientSocket1Error Left = 177 Top = 417 end 打开"main.pas", 查找上面组件相关的事件代码 procedure TGjForm.ClientSocket1Connect(Sender : TObject); begin (* 004EDB28 53 push ebx 004EDB29 8BD8 mov ebx, eax 004EDB2B A154234F00 mov eax, dword ptr [$004F2354] 004EDB30 833800 cmp dword ptr [eax], +$00 004EDB33 7423 jz 004EDB58 004EDB35 8B1554234F00 mov edx, [$004F2354] 004EDB3B 8B12 mov edx, [edx] * Reference to control ClientSocket1 : N.A. | 004EDB3D 8B8378040000 mov eax, [ebx+$0478] 004EDB43 8B8090000000 mov eax, [eax+$0090] * Reference to: ScktComp.TCustomWinSocket.SendText(TCustomWinSocket;AnsiString):Integer; | 004EDB49 E8BA8EFAFF call 00496A08 004EDB4E A154234F00 mov eax, dword ptr [$004F2354] * Reference to: System.@LStrClr(void;void); | 004EDB53 E8B066F1FF call 00404208 004EDB58 5B pop ebx 004EDB59 C3 ret *) end; procedure TGjForm.ClientSocket1Error(Sender : TObject); begin (* 004EDB5C 55 push ebp 004EDB5D 8BEC mov ebp, esp * Possible String Reference to: '连接验证服务器失败' | 004EDB5F B980DB4E00 mov ecx, $004EDB80 004EDB64 BA00800000 mov edx, $00008000 004EDB69 A160464F00 mov eax, dword ptr [$004F4660] | 004EDB6E E8C1D8FFFF call 004EB434 004EDB73 5D pop ebp 004EDB74 C20800 ret $0008 *) end; 通过ClientSocket1Error确认这个组件与网络验证密切相关. 查看ClientSocket1的属性Host与Port得知验证是用web方式进行的,现在"www.csjpwg.com"已经不能打开, 所以我们通过winhex修改"www.csjpwg.com"属性为"www.baidu.com"多余字节以00填充. 输入帐号密码进入游戏,点击自动战斗发现依旧是不能寻怪. 我们下面的重点放在ClientSocket1Read事件处理过程. 因为已经不能连接原始的验证服务器,所以也不能跟踪出正确的验证路线,所以大部分也就只能猜测了-_-... 用ida展开exe文件, 来到ClientSocket1Read过程 CODE:004EDB94 ClientSocket1Read proc near CODE:004EDB94 CODE:004EDB94 var_20 = dword ptr -20h CODE:004EDB94 struseredit2 = dword ptr -1Ch CODE:004EDB94 var_18 = dword ptr -18h CODE:004EDB94 var_14 = dword ptr -14h CODE:004EDB94 strUseredit = dword ptr -10h CODE:004EDB94 var_C = dword ptr -0Ch CODE:004EDB94 RecvText = dword ptr -8 CODE:004EDB94 CustomWinSocket = dword ptr -4 CODE:004EDB94 CODE:004EDB94 push ebp CODE:004EDB95 mov ebp, esp CODE:004EDB97 push 0 CODE:004EDB99 push 0 CODE:004EDB9B push 0 CODE:004EDB9D push 0 CODE:004EDB9F push 0 CODE:004EDBA1 push 0 CODE:004EDBA3 push 0 CODE:004EDBA5 push 0 CODE:004EDBA7 push ebx CODE:004EDBA8 push esi CODE:004EDBA9 push edi CODE:004EDBAA mov [ebp+CustomWinSocket], ecx CODE:004EDBAD mov ebx, eax ; 保存self指针 CODE:004EDBAF xor eax, eax CODE:004EDBB1 push ebp CODE:004EDBB2 push offset loc_4EDCD9 CODE:004EDBB7 push dword ptr fs:[eax] CODE:004EDBBA mov fs:[eax], esp CODE:004EDBBD lea edx, [ebp+RecvText] CODE:004EDBC0 mov eax, [ebp+CustomWinSocket] CODE:004EDBC3 call @Scktcomp@TCustomWinSocket@ReceiveText$qqrv ; 返回数据 CODE:004EDBC8 mov eax, [ebx+478h] CODE:004EDBCE cmp dword ptr [eax+34h], 50h CODE:004EDBD2 jz short loc_4EDC14 ; 客户端执行时跳转 CODE:004EDBD4 lea eax, [ebp+var_C] CODE:004EDBD7 mov edx, [ebp+RecvText] CODE:004EDBDA call @System@@LStrLAsg$qqrv ; System::__linkproc__ LStrLAsg(void) CODE:004EDBDF lea edx, [ebp+strUseredit] CODE:004EDBE2 mov eax, [ebx+324h] ; useredit控件 CODE:004EDBE8 call @TControl@GetText$qqrv ; TControl::GetText(void) CODE:004EDBED mov eax, [ebp+strUseredit] CODE:004EDBF0 push eax CODE:004EDBF1 lea edx, [ebp+var_14] CODE:004EDBF4 mov eax, ebx CODE:004EDBF6 call sub_4EB218 CODE:004EDBFB mov eax, [ebp+var_14] CODE:004EDBFE mov ecx, [ebp+var_C] CODE:004EDC01 pop edx CODE:004EDC02 call sub_4E3C58 CODE:004EDC07 mov eax, [ebp+CustomWinSocket] CODE:004EDC0A call @Scktcomp@TCustomWinSocket@Close$qqrv ; Scktcomp::TCustomWinSocket::Close(void) CODE:004EDC0F jmp loc_4EDC99 CODE:004EDC14 ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE:004EDC14 CODE:004EDC14 loc_4EDC14: ; CODE XREF: ClientSocket1Read+3Ej CODE:004EDC14 mov edx, [ebp+RecvText] CODE:004EDC17 mov eax, offset dword_4EDCF0 ; 字符串 REG: 将此字符串前3字符串修改为ver(因为www.baidu.com返回的数据中 CODE:004EDC17 ; 会包含这些字符串) CODE:004EDC1C call @System@@LStrPos$qqrv ; System::__linkproc__ LStrPos(void) CODE:004EDC21 mov esi, eax ; 在返回字符串中查找 CODE:004EDC23 test esi, esi CODE:004EDC25 jle short loc_4EDC99 ; 如果发现字符串不跳转 CODE:004EDC27 lea eax, [ebp+var_C] CODE:004EDC2A call @System@@LStrClr$qqrr17System@AnsiString ; System::__linkproc__ LStrClr(System::AnsiString & CODE:004EDC2F add esi, 4 ; 上面查找返回的pos+4 CODE:004EDC32 mov eax, [ebp+RecvText] CODE:004EDC35 call @System@_16823 ; System::_16823 CODE:004EDC3A mov edi, eax ; 取字符串内某成员 CODE:004EDC3C sub edi, esi ; 计算出一个长度 CODE:004EDC3E jl short loc_4EDC69 CODE:004EDC40 inc edi ; 循环 取数据然后连接吧 CODE:004EDC41 CODE:004EDC41 loc_4EDC41: ; CODE XREF: ClientSocket1Read+D3j CODE:004EDC41 mov eax, [ebp+RecvText] CODE:004EDC44 cmp byte ptr [eax+esi-1], 0Dh ; 判断当前pos是否指向0dh内容的字节 CODE:004EDC49 jz short loc_4EDC69 ; 指向0dh跳转 CODE:004EDC4B lea eax, [ebp+var_18] CODE:004EDC4E mov edx, [ebp+RecvText] CODE:004EDC51 mov dl, [edx+esi-1] CODE:004EDC55 call unknown_libname_13 ; Borland Visual Component Library & Packages CODE:004EDC5A mov edx, [ebp+var_18] CODE:004EDC5D lea eax, [ebp+var_C] ; 接到这个字符串后 CODE:004EDC60 call @System@@LStrCat$qqrv ; System::__linkproc__ LStrCat(void) CODE:004EDC65 inc esi ; 接字符串 CODE:004EDC66 dec edi CODE:004EDC67 jnz short loc_4EDC41 CODE:004EDC69 CODE:004EDC69 loc_4EDC69: ; CODE XREF: ClientSocket1Read+AAj CODE:004EDC69 ; ClientSocket1Read+B5j CODE:004EDC69 lea edx, [ebp+struseredit2] CODE:004EDC6C mov eax, [ebx+324h] CODE:004EDC72 call @TControl@GetText$qqrv ; TControl::GetText(void) CODE:004EDC77 mov eax, [ebp+struseredit2] ; 从某控件取字符串(Useredit) CODE:004EDC7A push eax CODE:004EDC7B lea edx, [ebp+var_20] ; 此变量还未初始化过 CODE:004EDC7E mov eax, ebx ; self指针 CODE:004EDC80 call sub_4EB218 ; 功能未知 返回服务器登陆字符串的某一部分吧 CODE:004EDC85 mov eax, [ebp+var_20] CODE:004EDC88 mov ecx, [ebp+var_C] CODE:004EDC8B pop edx CODE:004EDC8C call sub_4E3C58 ; 外挂验证检测函数 CODE:004EDC91 mov eax, [ebp+CustomWinSocket] CODE:004EDC94 call @Scktcomp@TCustomWinSocket@Close$qqrv ; Scktcomp::TCustomWinSocket::Close(void) CODE:004EDC99 CODE:004EDC99 loc_4EDC99: ; CODE XREF: ClientSocket1Read+7Bj CODE:004EDC99 ; ClientSocket1Read+91j CODE:004EDC99 xor eax, eax CODE:004EDC9B pop edx CODE:004EDC9C pop ecx CODE:004EDC9D pop ecx CODE:004EDC9E mov fs:[eax], edx CODE:004EDCA1 push offset loc_4EDCE0 CODE:004EDCA6 CODE:004EDCA6 loc_4EDCA6: ; CODE XREF: ClientSocket1Read+14Aj CODE:004EDCA6 lea eax, [ebp+var_20] CODE:004EDCA9 call @System@@LStrClr$qqrr17System@AnsiString ; System::__linkproc__ LStrClr(System::AnsiString & CODE:004EDCAE lea eax, [ebp+struseredit2] CODE:004EDCB1 call @System@@LStrClr$qqrr17System@AnsiString ; System::__linkproc__ LStrClr(System::AnsiString & CODE:004EDCB6 lea eax, [ebp+var_18] CODE:004EDCB9 mov edx, 2 CODE:004EDCBE call @System@@LStrArrayClr$qqrv ; System::__linkproc__ LStrArrayClr(void) CODE:004EDCC3 lea eax, [ebp+strUseredit] CODE:004EDCC6 call @System@@LStrClr$qqrr17System@AnsiString ; System::__linkproc__ LStrClr(System::AnsiString & CODE:004EDCCB lea eax, [ebp+var_C] CODE:004EDCCE mov edx, 2 CODE:004EDCD3 call @System@@LStrArrayClr$qqrv ; System::__linkproc__ LStrArrayClr(void) CODE:004EDCD8 retn CODE:004EDCD9 ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE:004EDCD9 CODE:004EDCD9 loc_4EDCD9: ; DATA XREF: ClientSocket1Read+1Eo CODE:004EDCD9 jmp @System@@HandleFinally$qqrv ; System::__linkproc__ HandleFinally(void) CODE:004EDCDE ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE:004EDCDE jmp short loc_4EDCA6 CODE:004EDCE0 ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE:004EDCE0 CODE:004EDCE0 loc_4EDCE0: ; DATA XREF: ClientSocket1Read+10Do CODE:004EDCE0 pop edi CODE:004EDCE1 pop esi CODE:004EDCE2 pop ebx CODE:004EDCE3 mov esp, ebp CODE:004EDCE5 pop ebp CODE:004EDCE6 retn CODE:004EDCE6 ClientSocket1Read endp 来到验证函数内 CODE:004E3C58 sub_4E3C58 proc near ; CODE XREF: sub_4E26DC+4Ap CODE:004E3C58 ; ClientSocket1Read+6Ep ... CODE:004E3C58 CODE:004E3C58 var_18 = dword ptr -18h CODE:004E3C58 var_14 = dword ptr -14h CODE:004E3C58 var_10 = dword ptr -10h CODE:004E3C58 var_C = dword ptr -0Ch CODE:004E3C58 var_8 = dword ptr -8 CODE:004E3C58 var_4 = dword ptr -4 CODE:004E3C58 CODE:004E3C58 push ebp CODE:004E3C59 mov ebp, esp CODE:004E3C5B add esp, 0FFFFFFE8h CODE:004E3C5E push ebx CODE:004E3C5F push esi CODE:004E3C60 push edi CODE:004E3C61 xor ebx, ebx CODE:004E3C63 mov [ebp+var_14], ebx CODE:004E3C66 mov [ebp+var_18], ebx CODE:004E3C69 mov [ebp+var_10], ebx CODE:004E3C6C mov [ebp+var_C], ecx CODE:004E3C6F mov [ebp+var_8], edx CODE:004E3C72 mov [ebp+var_4], eax CODE:004E3C75 mov eax, [ebp+var_4] CODE:004E3C78 call @System@@LStrAddRef$qqrv ; System::__linkproc__ LStrAddRef(void) CODE:004E3C7D mov eax, [ebp+var_8] CODE:004E3C80 call @System@@LStrAddRef$qqrv ; System::__linkproc__ LStrAddRef(void) CODE:004E3C85 mov eax, [ebp+var_C] CODE:004E3C88 call @System@@LStrAddRef$qqrv ; System::__linkproc__ LStrAddRef(void) CODE:004E3C8D xor eax, eax CODE:004E3C8F push ebp CODE:004E3C90 push offset sub_4E3D73 CODE:004E3C95 push dword ptr fs:[eax] CODE:004E3C98 mov fs:[eax], esp CODE:004E3C9B push [ebp+var_4] CODE:004E3C9E push [ebp+var_8] CODE:004E3CA1 lea edx, [ebp+var_18] CODE:004E3CA4 mov eax, dsff_4F2404 CODE:004E3CA9 mov eax, [eax] ; 这是堆栈上能看到登陆帐号,服务器名称等信息 CODE:004E3CAB call @TControl@GetText$qqrv ; TControl::GetText(void) CODE:004E3CB0 push [ebp+var_18] CODE:004E3CB3 lea eax, [ebp+var_14] CODE:004E3CB6 mov edx, 3 CODE:004E3CBB call sub_404588 ; LStrCat CODE:004E3CC0 mov eax, [ebp+var_14] CODE:004E3CC3 call sub_48F58C ; TIdTCPClient._PROC_0048F58C() CODE:004E3CC8 imul ebx, eax, 3039h CODE:004E3CCE mov edx, ds:dword_4F4604 CODE:004E3CD4 mov eax, ebx CODE:004E3CD6 call sub_48F5F0 ; * Reference to : TIdTCPClient._PROC_0048F5F0() CODE:004E3CDB imul eax, 3039h CODE:004E3CE1 mov ebx, eax CODE:004E3CE3 lea ecx, [ebp+var_10] CODE:004E3CE6 mov edx, [ebp+var_C] CODE:004E3CE9 mov eax, ebx ; 执行到这里会异常 也许是上面的字符串有问题吧 CODE:004E3CEB call @Dbclient@TClientDataSet@CreateDSCursor$qqr44System@_DelphiInterface$t16Dsintf@IDSCursor_ ; * Reference to : TIdTCPClient._PROC_0048F694() ;nop掉这里 CODE:004E3CF0 mov ds:dword_4F4608, 0FFFFFFFFh ; 一处验证标志 >0就算通过验证吧 CODE:004E3CFA xor eax, eax CODE:004E3CFC push ebp CODE:004E3CFD push offset loc_4E3D1F CODE:004E3D02 push dword ptr fs:[eax] CODE:004E3D05 mov fs:[eax], esp CODE:004E3D08 mov eax, [ebp+var_10] ; 这里装的应该是含有数字的字符串 CODE:004E3D0B call @Sysutils@StrToInt$qqrx17System@AnsiString ; 修改为mov eax, 1 替换掉这个call CODE:004E3D10 mov ds:dword_4F4608, eax ; 一处验证标志 >0就算通过验证吧 CODE:004E3D15 xor eax, eax CODE:004E3D17 pop edx CODE:004E3D18 pop ecx CODE:004E3D19 pop ecx CODE:004E3D1A mov fs:[eax], edx CODE:004E3D1D jmp short loc_4E3D30 CODE:004E3D1F ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE:004E3D1F CODE:004E3D1F loc_4E3D1F: ; DATA XREF: sub_4E3C58+A5o CODE:004E3D1F jmp sub_4038D4 CODE:004E3D24 ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE:004E3D24 call @@DoneExcept$qqrv ; __linkproc__ DoneExcept(void) CODE:004E3D29 jmp short loc_4E3D50 CODE:004E3D2B ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE:004E3D2B call @@DoneExcept$qqrv ; __linkproc__ DoneExcept(void) CODE:004E3D30 CODE:004E3D30 loc_4E3D30: ; CODE XREF: sub_4E3C58+C5j CODE:004E3D30 cmp ds:dword_4F4608, 0 ; 一处验证标志 >0就算通过验证吧 CODE:004E3D37 jl short loc_4E3D50 ; >0 CODE:004E3D39 mov eax, offset dword_4F4610 CODE:004E3D3E mov edx, [ebp+var_C] CODE:004E3D41 call @System@@LStrAsg$qqrv ; System::__linkproc__ LStrAsg(void) CODE:004E3D46 mov ds:dword_4F460C, 31589h CODE:004E3D50 CODE:004E3D50 loc_4E3D50: ; CODE XREF: sub_4E3C58+D1j CODE:004E3D50 ; sub_4E3C58+DFj CODE:004E3D50 xor eax, eax CODE:004E3D52 pop edx CODE:004E3D53 pop ecx CODE:004E3D54 pop ecx CODE:004E3D55 mov fs:[eax], edx CODE:004E3D58 push offset loc_4E3D7A CODE:004E3D5D CODE:004E3D5D loc_4E3D5D: ; CODE XREF: CODE:004E3D78j CODE:004E3D5D lea eax, [ebp+var_18] CODE:004E3D60 call @System@@LStrClr$qqrr17System@AnsiString ; System::__linkproc__ LStrClr(System::AnsiString & CODE:004E3D65 lea eax, [ebp+var_14] CODE:004E3D68 mov edx, 5 CODE:004E3D6D call @System@@LStrArrayClr$qqrv ; System::__linkproc__ LStrArrayClr(void) CODE:004E3D72 retn CODE:004E3D72 sub_4E3C58 endp ; sp = -38h 修改过以上3处后继续使用外挂登陆, 进入游戏点自动战斗. 已经可以正常战斗了,到此破解完成. -------------------------------------------------------------------------------- 【经验总结】 外挂是一次验证, 判断标志也非常少, 使用压缩壳加壳, 字符串明码出现这些对破解来说带来很多方便. 不知道会不会有烂人看完文章自己写个loader在加一个广告拿出去忽悠... -------------------------------------------------------------------------------- 【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢! |
地主 发表时间: 07-01-06 10:33 |
|
20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon
粤ICP备05087286号