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这两个数据。为什么这两个数据这么重要?如果用扫描内存的方式来开发记牌器的话,就会遇到这种麻烦。但你的子吃敌方子而牺牲时,到底是吃的哪个子呢?这就是麻烦的地方。