1.验证MFI:没有苹果认证的硬件芯片,蓝牙无法连接。 BLE4.0除外,MFi是苹果的一个开发者计划,针对硬件的。硬件和app配合使用。所以审核app肯定也很严格。因为MFi的硬件和app都要审核,app里用到蓝牙的。
在操作moga手柄时玩appstore下的原包,通过连接手柄弹出UI,抓到这个UI函数,然后动态调试传输字符串,发现其是一DES加密的验证码,破解难度较大,而且其验证码每次开启游戏时不同,是MFI芯片随机生成类似UUID服务码。
新游手柄N1是蓝牙4.0,但是他们的手柄向下兼容,也支持2.0以上手机,越狱不越狱都不限制,MFI只支持非越狱,icade模式只支持少量游戏,故新游手柄并无破解MFI,只是个独立协议,通过在安装包导入dylib链接库
2.分析新游协议:首先sdk应该是用swift写的,因为用classdump不出结果,听新游人员说而且键值均自定义,并没参照xbox或者ps手柄协议,由于ios设备侧键值还不清楚方法所以未验证,新游sdk的frameworks中封装了大量swizzling接口,他们是<objc/runtime.h>以下方法,method_exchangeImplementations 来交换2个方法中的IMP,method_setImplementation 来直接设置某个方法的IMP,在分析反汇编时发现大量swizzle操作
反编译代码:
r0 = objc_getClass("GCController");
*0x10724 = r0;
*0x10728 = object_getClass(r0);
r0 = class_getSuperclass(r0);
*0x1072c = r0;
r5 = class_getInstanceMethod(*0x10728, @selector(controllers));
if (r5 != 0x0) {
r0 = method_getImplementation(r5);
*(__MergedGlobals + 0x10) = r0;
method_setImplementation(r5, 0x24e1);
该方法替换了GCcontroller官方手柄api,替换了方法是[GCController controllers],替换的方法是void *__fastcall $GCController_controllers_method(),该方法调用了controllersWithMFIControllers:,该方法判断&OBJC_CLASS___NGDSDevice是不是"connected",而NGDSDevice定义了回调方法,调用自定义摁键键值类,判断摁键和蓝牙 回调调用了setValueChangedHandler方法,
void * +[NGGameController controllersWithMFIControllers:](void * self, void * _cmd, void * arg2) {
sp = sp - 0x4;
r4 = @selector(sharedInstance);
r0 = [NGDSDevice sharedInstance];
if (([r0 connected] & 0xff) != 0x0) {
r0 = [NGGameController sharedInstance];
var_0 = r0;
r0 = [NSArray arrayWithObjects:sp count:0x1];
}
else {
r0 = 0x0;
}
return r0;
}
一.NGDSDevice类中调用了NGgamepad的sharedgamepad方法 该方法负责回调
二.调用了NGGamecontroller的extendgamepad和gamepad方法,extendgamepad的init调了NGExtendedgamepad的init其中也调用了ngextendedgamepad和NGcgamepad的SETngcontroller方法
NGEXtendedGamepad主要是调用了NGControllerButtonInput的类负责摁键
三.同时NGDSDevice中有Hardwarekeyboardstatuschanged-updategamepad connectionstate 负责更新状态
四.在每个回调函数 都有block 比如(NGDSDevice_init_block_invoke)他们其实调用了NGControllerDirectionpad的上层Buttoninput
一个Buttoninput对象负责接收摁键
一个GCController对象表示连接的物理游戏控制器。
一个GCControllerDirectionPad对象表示二维控制,如方向键或摇杆。
一个GCExtendedGamepad对象实现了一组游戏手柄控制逻辑轮廓。
替换的第二个方法是startWirelessControllerDiscoveryWithCompletionHandler,替换的方法是startWirelessControllerDiscoveryWithCompletionHandler,以及block,__74__NGGameController_startWirelessControllerDiscoveryWithCompletionHandler___block_invoke,其目的是游戏控制器的Connet和Disconnet状态进行事件注册
r5 = class_getInstanceMethod(*(__MergedGlobals + 0x18), @selector(startWirelessControllerDiscoveryWithCompletionHandler:));
if (r5 != 0x0) {
r0 = method_getImplementation(r5);
*(__MergedGlobals + 0xc) = r0;
method_setImplementation(r5, 0x24a5);
至于UUID当时分析的不对,应该就是在游戏中定下的私有服务创建的唯一标示符。
曾经尝试 暴力nop掉swizzle,发现手柄以及无法操作了。
3. 新游sdk分析:NGGamepadDemo
按键 NGGamepadButton 成员变量pressed表⽰按键是否按下
摇杆 NGGamepadThumbStick 摇杆向量坐标, x,y轴取值为-1.0~1.0
⼗字键 NGGamepadDirectionPad 同时提供向量坐标和4个⽅向按键对象
响应手柄的方式是注册回调函数和读取手柄当前状态更新游戏。
NGGamepad* gamepad = [NGGamepad sharedGamepad];
gamepad.buttonA.valueChangedHandler = ^(NGGamepadButton* button, BOOL
pressed, float value) {
if (pressed) {//A键按下
[self fireLasers];
}};
由于iOS系统的限制,目前SDK⽆法判断⼿柄是否连接。游戏可以通过设置NGGamepad的valueChangedHandler,如果收到事件则说明⼿柄连接上。
并且新游手柄的api均是私有api
Log分析:主要调用了NGGameController类 该类就是自定义摁键类
Apr 28 19:51:30 zangxuetongde-iPad routined[2140] <Warning>: BTM: attempting to connect to service 0x00000020 on device "NewGamepad N1" 00:15:83:AC:47:40
Apr 28 19:51:32 zangxuetongde-iPad SpringBoard[42] <Warning>: BTM: connection to service 0x00000020 on device "NewGamepad N1" 00:15:83:AC:47:40 succeeded
Apr 29 11:06:20 zangxuetongde-iPad gamecontrollerd[4000] <Notice>: MS:Notice: Injecting: (null) [gamecontrollerd] (1141.16)
Apr 28 19:18:00 zangxuetongde-iPad TheKingOfFighters97[3079] <Warning>: Finished finding controllers
Apr 28 19:18:00 zangxuetongde-iPad TheKingOfFighters97[3079] <Warning>: Assigning ExtendedGamepad to player 0
Apr 28 19:52:01 zangxuetongde-iPad TheKingOfFighters97[3254] <Warning>: authentification error : The requested operation could not be completed because this application is not recognized by Game Center.(不能联网)
补充之前调试方法:
动态调试方法:
先在ipad安装openssh,再安装gdb
.PC 端运行 SSH 客户端一般是putty,连接到设备,输入用户名:
root,默认密码: alpine,
1.动态调试,主要工具gdb
首先,ps -ax|grep "要破解的程序名",得到其进程id,如1234
接着,使用gdb,用attach “进程id”
然后,bt查看函数调用栈,找到可疑函数后,使用up
继续,用si等命令单步跟踪,set等命令改变参数的值
再来,使用disassemble命令,查看确认要修改的二进制字符串
最后,用十六进制编辑器查找并修改二进制字符串
2. 动静结合,主要工具otool + gdb
a. otool -tV "目标程序" > dis.asm
b. 文本编辑器打开 dis.asm,查找可疑的函数
c. 使用gdb打开目标程序,并在可疑的函数中设置断点,如 b *0x00001234
d. run 运行程序,断点处,si 等跟踪, set 设置关键参数值
e. 用计算器计算需要修改的序列偏移,或disassemble命令
f. 用十六进制编辑器查找并修改二进制字符串
常用的命令
attach 1234; b *0x1234;clear *0x1234;bt;disassemble;si;finish;set $eax
gcc test.c -o test;otool -tV target > dis.asm
另一种方法是,加壳源程序在运行时候会自动解密,运行应用时动态调试 dump出关键代码 再用IDA分析。
IDA左边 Functions window 看出来,函数是以“ sub_”开头的说明已经加密
root# gdb -e ./iRead
(gdb) dump memory dec.bin 0x3000 0x837000
做了hack,伪装成MFI手柄
在响应手柄事件的地方调用原先触屏事件处理的逻辑。
不改原来的逻辑,是添加控制处理。
每个人物动作控制逻辑应该会对应一个接口,在手柄处理这边调用对应的接口。
u3d需要把手柄事件传递到u3d里面, cocos2dx可以直接调用objective-C的代码响应手柄事件。
触屏上,人物移动是靠虚拟摇杆的方向,手柄摇杆事件响应的可以得到摇杆的方向。
gamepad.leftThumbStick.valueChangedHandler = ^(NGGamepadThumbStick* stick, float xAxis, float yAxis) {
[self moveWithVector:CGPointMake(xAxis, yAxis)];
};
每个摇杆对象都有当前的摇杆坐标值的
实现回调