qq四国军旗2.1 beat03 builde017记牌器开发思路(二)

接着前文《qq四国军旗2.1 beat03 builde017记牌器开发思路(一)》讲,暂时不讨论内存扫描和协议解析,先重点分析HOOK API。要HOOK API,就要找到API,API怎么找?上文已经找到了播放行进音乐的CALL,一个CALL可以理解为一个函数。那么走路的过程是同级调用,还是上级调用还是下级调用呢?

先来解释下这个“级”的问题。先定义两个函数:
void PlayMusic(){

      //这个编译完后,就是一个CALL,用来播放音乐的

void DisplayMove(){

  //这个编译完后,就是一个移动的CALL

所谓同级调用,那么就是

bool FrameFunc(){

       PlayMusic();
       DisplayMove();

而上级调用呢,就是在DisplayMove中调用了PlayMusic,下级调用就是PlayMusic调用DisplayMove。根据调试的步骤,同级的话,就在当前函数找;上级的话,就要返回,步出该函数;而下级就要切入进去。操作上不一样,所以这个很重要。OD里,如果是同级调用,那么就是按F8慢慢找;上级调用,就要CTRL+F9返回到上级函数;下级的话就要在PlayMusic CALL的地方按F7切入进去。当然,我们不知道是怎么调用的,可以用排除法,搞这个就是要有耐心,呵呵。

首先是同级函数。

00411540  /$  8B4424 04     MOV EAX,DWORD PTR SS:[ESP+4]

00411544  |.  53            PUSH EBX

00411545  |.  05 17FCFFFF   ADD EAX,-3E9                             ;  Switch (cases 3E9..3ED)

0041154A  |.  55            PUSH EBP

0041154B  |.  56            PUSH ESI

0041154C  |.  83F8 04       CMP EAX,4

0041154F  |.  57            PUSH EDI

00411550  |.  8BD9          MOV EBX,ECX

00411552  |.  0F87 DF010000 JA JunQiRpg.00411737

00411558  |.  FF2485 401741>JMP DWORD PTR DS:[EAX*4+411740]

0041155F  |>  8B83 10010000 MOV EAX,DWORD PTR DS:[EBX+110]           ;  Case 3E9 of switch 00411545

上面的代码是同级函数的开头部分。可以看出,这是一个switch语句。在00411540处下断点,发现状态显示:

堆栈 SS:[0012F240]=000003EC

EAX=00000000

本地调用来自 004267AE

也就是说,这个函数是被上级函数在地址为004267AE的地方调用的。而一直按F9,发现,这是一个无限循环。使用框架开发游戏都知道,一般的游戏框架有两个无限循环。一个是用来更新数据的,做逻辑操作的,而另外一个是用来写屏幕的。那么,这个函数可以理解成HGE(C++ 2d 游戏引擎)里的FrameFunc,或者XNA(.Net的一个3D游戏开发框架)离得Update函数。那么这段代码的意思呢,就是相当于:
 bool FrameFunc(){

     switch()

          case 1:

              break;

          case 2

              break;

在CASE1处,汇编代码

0041155F  |>  8B83 10010000 MOV EAX,DWORD PTR DS:[EBX+110]           ;  Case 3E9 of switch 00411545

的地方下断点,发现,确实是走动会触发断点。这就表明,已经找到了正确的地方,至于这个CALL是在这段代码里,还是在这段代码调用的方法的里面,就需要再去分析。

开发游戏都知道,FrameFunc调用频率是跟FPS有关的,一般来说一秒钟最少要调用24次。case1的代码必然带有对多线程的处理方式,这就给分析带来了很大的难度。在0041155F处下断点后,按F9,发现这段代码不只执行一次,原理上和一个栈相似。 压入步骤,然后在RenderFunc里按步骤写入屏幕。

在004976F4地址上记录了操作数,在

0041158B  |> \A1 F4764900   MOV EAX,DWORD PTR DS:[4976F4]

处被读取,操作数被赋予EAX。在0041155F 和0041158B之间没有任何CALL,这段代码很可能与我们要找的东西有关,当然在下面肯定也能找到。一个棋子从一个地方移动到另外一个地方,上面可能已经赋予了From什么地方,TO什么地方这样的形式,而下面是对路径进行分析。

实际上我们要拿的数据也就仅仅是From和To这两个数据。为什么这两个数据这么重要?如果用扫描内存的方式来开发记牌器的话,就会遇到这种麻烦。但你的子吃敌方子而牺牲时,到底是吃的哪个子呢?这就是麻烦的地方。

posted @ 2009-09-10 03:57 Birdshover 阅读(...) 评论(...) 编辑 收藏