《云之遥》随时存档研究及实现

时间:2013-05-20 00:00 作者:网络 手机订阅 神评论

新闻导语

这是我的第一篇关于逆向的文章,若有错误,欢迎指正!在《云之遥》中,部分地图是无法存档的,本文便介绍如何用OD对云之遥程序进行调试并找到相应地方实现随时存档首先,OD附加入云之遥主程序,F9让他先跑起来(若线程Suspend则Resume即可)然后返回程序领空,右键查找参考字串,有

这是我的第一篇关于逆向的文章,若有错误,欢迎指正!


在《云之遥》中,部分地图是无法存档的,本文便介绍如何用OD对云之遥程序进行调试并找到相应地方实现随时存档

首先,OD附加入云之遥主程序,F9让他先跑起来(若线程Suspend则Resume即可)

然后返回程序领空,右键查找参考字串,有如下这样一行:

0041B1DA    68 F8C27900     PUSH SwdCF.0079C2F8  ; ASCII “%s\%c\S%02d.sav”

这不就是存档路径吗?往上看,我们在0041B168下一个断点,单击“储存”,OD就会断下来,F8下去,会看到函数会返回到004FE286,继续在004FE1C0下一个断点,F9运行,然后再单击“储存”,断下来后,观察堆栈,有如下两条:

0012FBCC   004FC0DC  返回到 SwdCF.004FC0DC 来自 SwdCF.004FE1C0

0012FBD8   004FFDAD  返回到 SwdCF.004FFDAD 来自 SwdCF.004FC0A0

到004FFDAD去看下,往上在004FFB34下一个断点,再次单击“储存”可以被断下,根据刚才记录,可以看到存档CALL的地址在004FFDA8:

 

004FFDA8    E8 F3C2FFFF     CALL SwdCF.004FC0A0                      ; 存档 CALL

只要走到这里便能存档,此时我们F8一路单步走,在004FFC18处有一个JMP到存档CALL的上面,先标记一下

此时读取一个无法存档的地图的存档,直接来到储存界面单击“储存”,程序被断下来了,可以看到在这里会跳走从而无法存档

004FFBCC   74 4F           JE SHORT SwdCF.004FFC1D

于是我们把这段代码整理一下:

004FFB34    57              PUSH EDI
004FFB35    85C0            TEST EAX,EAX
004FFB37    0F85 00030000   JNZ SwdCF.004FFE3D                       ; EAX 不为 0 跳走
004FFB3D    A1 283F7E00     MOV EAX,DWORD PTR DS:[7E3F28]
004FFB42    BF 01000000     MOV EDI,1
004FFB47    C680 CC000000 0>MOV BYTE PTR DS:[EAX+CC],0               ; [7E3F28+CC] 置0
004FFB4E    8B4424 08       MOV EAX,DWORD PTR SS:[ESP+8]             ; [ESP+8] -> EAX
004FFB52    3B05 243E8300   CMP EAX,DWORD PTR DS:[833E24]
004FFB58    75 09           JNZ SHORT SwdCF.004FFB63                 ; EAX 不等于 [833E24] 跳走
004FFB5A    33C0            XOR EAX,EAX                              ; EAX 清零
004FFB5C    A3 A03C8300     MOV DWORD PTR DS:[833CA0],EAX            ; [833CA0] = EAX
004FFB61    EB 52           JMP SHORT SwdCF.004FFBB5
004FFB63    3B05 283E8300   CMP EAX,DWORD PTR DS:[833E28]
004FFB69    75 09           JNZ SHORT SwdCF.004FFB74                 ; EAX 不等于 [833E28] 跳走
004FFB6B    8BC7            MOV EAX,EDI
004FFB6D    A3 A03C8300     MOV DWORD PTR DS:[833CA0],EAX
004FFB72    EB 41           JMP SHORT SwdCF.004FFBB5
004FFB74    3B05 2C3E8300   CMP EAX,DWORD PTR DS:[833E2C]
004FFB7A    75 0C           JNZ SHORT SwdCF.004FFB88                 ; EAX 不等于 [833E2C] 跳走
004FFB7C    B8 02000000     MOV EAX,2
004FFB81    A3 A03C8300     MOV DWORD PTR DS:[833CA0],EAX
004FFB86    EB 2D           JMP SHORT SwdCF.004FFBB5
004FFB88    3B05 303E8300   CMP EAX,DWORD PTR DS:[833E30]
004FFB8E    75 0C           JNZ SHORT SwdCF.004FFB9C                 ; EAX 不等于 [833E30] 跳走
004FFB90    B8 03000000     MOV EAX,3
004FFB95    A3 A03C8300     MOV DWORD PTR DS:[833CA0],EAX
004FFB9A    EB 19           JMP SHORT SwdCF.004FFBB5
004FFB9C    3B05 343E8300   CMP EAX,DWORD PTR DS:[833E34]
004FFBA2    75 0C           JNZ SHORT SwdCF.004FFBB0                 ; EAX 不等于 [833E34] 跳走
004FFBA4    B8 04000000     MOV EAX,4
004FFBA9    A3 A03C8300     MOV DWORD PTR DS:[833CA0],EAX
004FFBAE    EB 05           JMP SHORT SwdCF.004FFBB5
004FFBB0    A1 A03C8300     MOV EAX,DWORD PTR DS:[833CA0]            ; EAX = [833CA0]
004FFBB5    83F8 04         CMP EAX,4
004FFBB8    0F87 75020000   JA SwdCF.004FFE33                        ; EAX 大于 4 跳走
004FFBBE    FF2485 44FE4F00 JMP DWORD PTR DS:[EAX*4+4FFE44]
004FFBC5    A0 C13D8300     MOV AL,BYTE PTR DS:[833DC1]              ; AL = [833DC1]
004FFBCA    84C0            TEST AL,AL
004FFBCC    74 4F           JE SHORT SwdCF.004FFC1D                  ; AL 为 0 跳走
004FFBCE    A0 F9FA8300     MOV AL,BYTE PTR DS:[83FAF9]              ; AL = [83FAF9]
004FFBD3    84C0            TEST AL,AL
004FFBD5    75 46           JNZ SHORT SwdCF.004FFC1D                 ; AL 不为 0 跳走
004FFBD7    B9 983C8300     MOV ECX,SwdCF.00833C98
004FFBDC    E8 5FE7FFFF     CALL SwdCF.004FE340
004FFBE1    B9 983C8300     MOV ECX,SwdCF.00833C98
004FFBE6    E8 65EEFFFF     CALL SwdCF.004FEA50
004FFBEB    B9 983C8300     MOV ECX,SwdCF.00833C98
004FFBF0    E8 7BEEFFFF     CALL SwdCF.004FEA70
004FFBF5    A1 5C257E00     MOV EAX,DWORD PTR DS:[7E255C]
004FFBFA    893D A43C8300   MOV DWORD PTR DS:[833CA4],EDI
004FFC00    3BC7            CMP EAX,EDI
004FFC02    75 0D           JNZ SHORT SwdCF.004FFC11
004FFC04    6A 0F           PUSH 0F
004FFC06    57              PUSH EDI
004FFC07    B9 A8088300     MOV ECX,SwdCF.008308A8
004FFC0C    E8 3F2BFDFF     CALL SwdCF.004D2750
004FFC11    8B0D 3C257E00   MOV ECX,DWORD PTR DS:[7E253C]
004FFC17    51              PUSH ECX
004FFC18    E9 75010000     JMP SwdCF.004FFD92                       ; 这里去存档
004FFC1D    6A FF           PUSH -1

很明显,如果条件跳转到4FFC1D这个地址,便无法进行存档,因此必须让以下两个条件为假:

004FFBCC    74 4F           JE SHORT SwdCF.004FFC1D                  ; AL 为 0 跳走
004FFBD5    75 46           JNZ SHORT SwdCF.004FFC1D                 ; AL 不为 0 跳走

因此,若要实现随时存档,写一个内存修改程序,将0x833CA0地址上的这个byte值保持为1,0x83FAF9地址上的这个byte值保持为0即可

以上研究是在繁体版云之遥上进行的,用同样的方法可以得到简体版的这两个地址,分别为0x82B779和0x8374B1

附ASM实现代码(对应简体版,建议以Timer方式启动):

.const

ProcessName            db “SwdCF”,0
ErrMsg                 db “Error Open Process!”,0
ErrMsgT                db “Error”,0

.data?

ProcessPID             dd ?
ProcessHWND            dd ?

———————–分割线———————–

MemoryModifyProc proc;

     LOCAL Found        : byte
     LOCAL hWnd1        : DWORD
     LOCAL bWrite       : byte

         mov Found, 0
         .While !Found
              invoke FindWindow, offset ProcessName, offset ProcessName
              .if eax != 0
                   mov Found, 1
                   invoke GetWindowThreadProcessId, eax, offset ProcessPID
                   invoke OpenProcess, PROCESS_ALL_ACCESS, FALSE, ProcessPID
                   mov ProcessHWND, eax
                   .if eax != 0
                       mov bWrite, 1
                       invoke WriteProcessMemory,ProcessHWND,0082B779h,addr bWrite,1,NULL
                       mov bWrite, 0
                       invoke WriteProcessMemory,ProcessHWND,008374B1h,addr bWrite,1,NULL
                   .else
                       invoke MessageBox, ThisProWND, offset sErrMsg, offset sErrMsgT, MB_ICONERROR
                   .endif
                   invoke  CloseHandle, ProcessHWND
              .else
                   ret
              .endif
         .endW
     ret

MemoryModifyProc endp

相关阅读: