论坛: 编程破解 标题: [转帖]快乐传说脱机破解分析 复制本贴地址    
作者: 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号