起因是前几天在Github上刷到了这个 https://github.com/amineross/showcase 仓库。大概意思是找一个旧平板,停掉系统BTStack还有Wifi自己接管。然后就能和iPhone建立iAP2连接,最后协商连接手机Wifi,就能拿到Carplay画面。
这让我非常震惊,因为在 上一篇文章 里面,我写过关于MFi改定位的一小个想法,但是由于MFi改定位会需要手机和真实MFi chip进行交互认证,而这个iPhone可以直接不用MFi chip里的证书就通过认证?
于是我找到了MFi的specification:

可以看到这里五步:
RequestAuthenticationCertificate:请求证书(iPhone → MFi)0xAA00AuthenticationCertificate:发送证书(MFi → iPhone) 0xAA01RequestAuthenticationChallengeResponse:请求challenge,这里会发送一个nonce交给MFi进行签名(iPhone → MFi)0XAA02AuthenticationResponse:返回签名完成的challenge(MFi → iPhone)0xAA03AuthenticationFailed:失败(iPhone → MFi)0xAA04
然后我就去对比了下showcase里的MFi认证的逻辑函数,是这个:
然后是证书申请:
static void issue_baa_cert(void) { printf("[BAA] Issuing certificate...\n"); void *di = dlopen("/System/Library/PrivateFrameworks/DeviceIdentity.framework/DeviceIdentity", RTLD_NOW); if (!di) di = dlopen("/System/Library/PrivateFrameworks/MobileActivation.framework/MobileActivation", RTLD_NOW); if (!di) { printf("[BAA] Cannot load framework!\n"); return; } typedef void (^DIBlock)(id, id, id); typedef void (*DIFunc)(id, id, DIBlock); DIFunc fn = (DIFunc)dlsym(di, "DeviceIdentityIssueClientCertificateWithCompletion"); if (!fn) { printf("[BAA] No issuance func!\n"); return; } dispatch_semaphore_t sem = dispatch_semaphore_create(0); fn(nil, [NSDictionary dictionary], ^(id k, id c, id e) { if (e) { NSLog(@"[BAA] Error: %@", e); dispatch_semaphore_signal(sem); return; } NSArray *ca = (NSArray *)c; if ([ca count] < 2) { dispatch_semaphore_signal(sem); return; } baa_private_key = (SecKeyRef)CFBridgingRetain(k); CFDataRef d1 = SecCertificateCopyData((__bridge SecCertificateRef)ca[0]); baa_leaf_len = (int)CFDataGetLength(d1); baa_leaf_der = malloc(baa_leaf_len); memcpy(baa_leaf_der, CFDataGetBytePtr(d1), baa_leaf_len); CFRelease(d1); CFDataRef d2 = SecCertificateCopyData((__bridge SecCertificateRef)ca[1]); baa_inter_len = (int)CFDataGetLength(d2); baa_inter_der = malloc(baa_inter_len); memcpy(baa_inter_der, CFDataGetBytePtr(d2), baa_inter_len); CFRelease(d2); baa_ready = 1; printf("[BAA] Leaf=%d Inter=%d — ready\n", baa_leaf_len, baa_inter_len); dispatch_semaphore_signal(sem); }); dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, 30LL * NSEC_PER_SEC));}这里是用的DeviceIdentity/MobileActivation的私有框架完成的。诶你他娘的还真是个天才
这样居然能过iPhone的证书信任链,那AnyGo这个东西我就再也不用付费了嘿嘿嘿。
接下来简单实验了下发现,一般adhoc的二进制过不了amfi,过了之后函数内还有其他的白名单限制。逆向发现这三个进程名字都可以过
CarPlay SimulatorCarDisplaySimCarplay Sim
于是我们可以简易写一个小注入去绕一下AnyGo的注册登录逻辑,然后把他们的服务端模拟一下,就可以正常修改定位了。并且这个修改在大部分情况下不会被过滤:
过滤的绝大部分是isSimulatedBySoftware,但是这里用的是isProducedByAccessory 。
然后是关于Location Information的Specs:同样是手机侧先请求,后续再发送位置信息。

非常不错啊,但是我懒得处理细节了,于是就有了这个~

What’s More
同时我们可以注意到苹果自带的Additional Tool里有一个Carplay Simulator:它的连接/认证方式是usb。也就是,理论上这个MFi连接是可以从手机到浏览器的,那么接下来下一步就是把做成有线修改Accessory定位了。
检查之后发现这里Carplay Simulator用的是lockdownd的com.apple.carkit.service 并且在这上面封装了iAP2流。