请选择 进入手机版 | 继续访问电脑版
您好,欢迎访问! 登录

QQ登录

只需一步,快速开始

立即注册 切换到窄版
查看: 2181|回复: 1

[转载] IOS游戏辅助--QQ欢乐斗地主记牌器的实现

[复制链接]

  离线 

25

主题

51

帖子

159

积分

版主

Rank: 7Rank: 7Rank: 7

积分
159
发表于 2014-6-9 11:25:14 | 显示全部楼层 |阅读模式
最近分析了一下叉叉助手中的QQ欢乐斗地主的记牌器,抛砖引玉,和大家一块探讨下IOS/Android游戏辅助的分析和实现.

1. Cydia Substrate
    使用 TheOS 做越狱开发的同学,肯定都知道 Cydia Substrate 这个东西,其实所谓的 Substrate 就是类似Windows上的Hook框架(Detours,MHook),提供了一套标准的Hook函数: MSHookFunction,MSHookMessage,MSFindSymbol 等等给大家使用. 根据官网的介绍,这套框架不仅支持IOS,而且还支持Android平台. 游戏辅助的开发者,也是期望能迅速开发,所以也是会利用Substrate来实现的. 所以我们分析游戏辅助插件的时候,只需要紧紧盯着这几个 MSHook** 的函数,就能迅速定位到关键所在.

2. 获取二进制文件
    AppStore下载QQ欢乐斗地主,使用iTools,将名为QQHLDDZ的文件导入到电脑上. 同样下载好叉叉助手,安装好欢乐斗地主记牌器插件,然后使用itools,从 MobileSubstrate\DynamicLibrary 目录下获取 xxHLDDZPlugin.dylib.

3. 反汇编 xxHLDDZPlugin.dylib
   使用IDA Pro 或者 Hopper 打开 xxHLDDZPlugin.dylib. 对 MSHookFunction 函数查找引用,我们会发现在一个名为 sethook()的函数里面会调用MSHookFunction(), 使用Hopper的伪代码功能可以看到:
attachment.jpg

提醒下Hopper的伪代码功能不是特别好用,仅供参考(还有就是Hopper的反汇编识别函数的能力也比IDA Pro 弱太多了). 所以这里只看到 MSHookFunction() 只调用了一次,看看sethook()的汇编,这里应该是调用了两次 MSHookFunction().

所以 sethook()里面的实现应该是:
MSHookFunction(_offset_new_add + module_base ,func_hook_xx_new_add,&func_orig_xx_new_add)
MSHookFunction(_offset_new_start + module_base,func_hook_xx_new_start,&func_orig_xx_new_start)


根据 MSHookFunction() 函数的定义:
void MSHookFunction(void*function,void* replacement,void** p_original);
所以第一个参数就是我们要hook的函数.找到第一个参数 _offset_new_add和 _offset_new_start定义的地方,我们会看到:
_offset_new_add =  0x004b2b68;
_offset_new_start = 0x004f0978;

这里记牌器插件使用的 Offset + 基地址 来动态获取函数的地址,然后再进行Hook.

4. 反汇编 QQHLDDZ
  使用IDA Pro 或者 Hopper 打开 QQHLDDZ,然后跳转到那两个offset.

  对于 _offset_new_add = 0x004b2b68; 我们能看到一个名为: “__ZN12XOutCardCtrl14AddNormalCardsEjPhjj”的函数,Hopper 伪代码如下,从函数名猜测下这个 XOutCardCtrl::AddNormalCards,应该是记录了每个玩家的出牌.
attachment.jpg

  对于 _offset_new_start = 0x004f0978; 我们也能看到一个名为: “ __ZN8XGameMgr11OnGameStartEv “的函数, Hopper伪代码如下,同样从函数名看到,这个函数 XGameMgr::OnGameStart,应该是表示新一轮游戏的开始.
attachment.jpg

5. 分析待Hook函数的定义
从上面我们可以看到函数的定义,XOutCardCtrl::AddNormalCards函数有4个参数,但是无法得知每个参数的具体用途,这里就需要自己去分析和调试了,过程比较琐碎和需要耐心,这里就不仔细叙述了.

具体定义如下:
int AddNormalCards(void* self, int player,unsigned char* cards,int count);
第一个参数  self,是 self 指针.
第二个参数 player,是int 类型,表示的每个玩家的编号. 范围是 0 - 2 (实际调试发现,我自己是2,左玩家是 0 ,右玩家是 1)
第三个参数 cards, 是个 unsigned char类型数组,用来记录玩家每次出的牌.
第四个参数 count, 用来表示 参数3 cards 数组的大小,也就是出牌的数量.

int XGameMgr::OnGameStart()
无参数,用来表示每次牌局的开始.

6. 实现记牌器
使用TheOS 创建一个 Tweak 工程. 在Tweak.xm 里面添加我们自己的代码.
%ctor
{
    initPokerTable();
     MSHookFunction((void*)MSFindSymbol(NULL,"__ZN12XOutCardCtrl14AddNormalCardsEjPhjj"),(void*)my_newadd,(void **)&orig_newadd);
     MSHookFunction((void*)MSFindSymbol(NULL,"__ZN8XGameMgr11OnGameStartEv"),(void*)my_newstart,(void **)&orig_newstart);
}

initPokerTable(); 初始化了一个NSMutableArray的全局变量,名为PokerTable,里面存储了从 黑桃A 到 大王 的 54 张扑克牌,方便我们查看调试信息.
MSHookFunction(),会调用MSFindSymbol()函数来查找原始函数的地址.
为什么使用MSFindSymbol(),而不是使用xx记牌器里面的 module_base + offset 的方式,其实尝试了使用 offset 这种硬编码的方式,但是很容易造成程序崩溃,多次尝试下,还是改为MSFindSymbol()函数,这个函数的实现其实是查找Mach-o文件格式的symbol表,然后获得函数地址. 这个和Windows 里面查找PE文件的 Import(Export) Address Table 函数的方式类似. 所以这种方式更加稳定可靠.

my_newadd()函数只是打印了每一轮牌局(GameRound),每个玩家(Player) 出的牌. (也就是实现了记牌器的功能.)
int my_newadd(void* self, int player,unsigned char* cards,int count)
{
     for(int i = 0; i < count; i++)
     {
          NSLog(@"GameRound%d:player%d:%@",Round,player,[PokerTable objectAtIndex:cards - 1]);
     }
     NSLog(@"GameRound ---------------------------------------");
     return orig_newadd(self,player,cards,count);
}

my_newstart()函数,会对 Round 变量递增,然后打印信息,表示新一轮游戏开始了.
int my_newstart()
{
     Round++;
     NSLog(@"GameRound%d begin!",Round);
     return orig_newstart();
}

7. 查看调试输出
在 terminal 输入 make package install,对工程编译打包,并发送到设备上.
再 ssh root@你的IP. 到设备上.
然后你开始玩一局QQ欢乐斗地主,
然后在teminal上输入 grep GameRound /var/log/syslog   (注意,请安装好syslogd插件) 会看到如下的调试信息:

attachment.jpg

这里,你能清楚的看到每个玩家所出的牌. 这样我们就实现了一个记牌器所需要的核心功能.

8. 总结
其实上面的调试输出只是一个简单的演示罢了,要做成产品给用户使用,还需要像叉叉助手一样,在QQ欢乐斗地主那,添加自己的subview,然后再绘制控件,再将信息展现给用户,还有很多事情需要完善.
再说说其他游戏辅助插件的分析原理,其实分析和这个类似.按照这个思路一步一步耐心分析,就能实现同样的功能了.
再补充一下Android平台,叉叉助手的Android平台其实也是使用同样的技术,和上面的分析大同小异.
最后,此文抛砖引玉,还希望各位朋友对此不吝赐教! ( 欢迎各位同仁交流和认识)
我不会告诉你,在游源签到是一种执着!
回复

使用道具 举报

  离线 

0

主题

17

帖子

33

积分

游源小侠

Rank: 2Rank: 2

积分
33
发表于 2016-11-4 07:53:34 | 显示全部楼层
楼主很棒!












回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站点统计|Archiver|手机版|小黑屋|游源网 ( 冀ICP备14006073号-1

Copyright 2013 最新最精彩-社区论坛 版权所有 discuz 模板All Rights Reserved.

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表