百度小程序逆向分析2 - 初步分析百度小程序之主从通讯约定
导读
背景
- 
上已篇的篇幅已经太长了,所以在开这个篇幅,继续分享. 
- 
本篇幅内,大部分都是log都已被手动格式化 
需要技能
- 
1.js基础,ios开发基础. 
- 
2.会使用Xcode,safari,有基础js编写能力. 
逆向ipa
- 
这里不细说了,使用monkeydev,非常简单.上网资源一搜一大堆,另外,本人之前也写了一个简单的使用说明. 
- 
另外,再次集成了flex,这个机器上调试神器. 
从最根源的webview交互系统api分析
从masterWebView 逻辑容器 (唯一)方向分析
hook (WKWebView) 与 (BBAMNPJSBridge) 方法继续分析,其中BBAMNPJSBridge继承自WKScriptMessageHandler
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
- (void)userContentController:(id)arg1 didReceiveScriptMessage:(id)arg2;
这个是一个小程序的api请求
- 
先把log格式化,然后观察一下 
- 
逻辑容器,运行js,然后通过WKScriptMessageHandler调起原生的方法,通过字符串的格式传递需要调起那个方法,并带上该方法活动结构后需要返回给js的callback函数.swapCore每次发出这个的请求时,都会重新创建一个callback函数 
2019-02-02 14:47:19.672201+0800 BaiduBoxApp[585:45879] [DEBUG] > void $BBAMNPJSBridge_userContentController$didReceiveScriptMessage$_method(BBAMNPJSBridge *__strong, SEL, WKUserContentController *__strong, WKScriptMessage *__strong) [Line 261] arg1:<WKUserContentController: 0x28243ff40> 
name:BBAMNPJSBridge 
body:baiduboxapp://v19/swan/request?params={"url":"https://api.itouchtv.cn/supplementservice/v1/baiduApp/extraInfo","header":{"content-type":"application/json","Authorization":"","X-ITOUCHTV-Ca-Key":"28778826534697375418351580924221","X-ITOUCHTV-Ca-Timestamp":"1549090039664","X-ITOUCHTV-Ca-Signature":"WfHH6lWa88PViyV7EWWWIBpGSxARzlbSPGd46/y3wTQ=","X-ITOUCHTV-DEVICE-ID":"BAIDUAPP_98487-969-468-648-885298617","X-ITOUCHTV-CLIENT":"BAIDUAPP_VIDEO","X-ITOUCHTV-APP-VERSION":"1.0.2"},"method":"GET","cb":"_bdbox_pjs_946"}&callback=__jsna_16
2019-02-02 14:47:19.674565+0800 BaiduBoxApp[585:45879] [DEBUG] > void $WKWebView_evaluateJavaScript$completionHandler$_method(WKWebView *__strong, SEL, NSString *__strong, __strong id) [Line 274] 
arg1:__jsna_16("{\"status\":\"0\",\"message\":\"调起成功\",\"data\":{\"taskIdentifier\":\"16C1C877-0A29-4EC7-B49B-23907E4BE3A6\"}}") 
2019-02-02 14:47:19.749741+0800 BaiduBoxApp[585:45879] [DEBUG] > void $WKWebView_evaluateJavaScript$completionHandler$_method(WKWebView *__strong, SEL, NSString *__strong, __strong id) [Line 274] 
arg1:_bdbox_pjs_946("{\"status\":\"0\",\"message\":\"调起成功\",\"data\":\"{"header":{"Server":"Tengine","x-b3-traceid":"76cba298792148ef","Content-Type":"application\\\\/json;charset=UTF-8","x-b3-spanid":"76cba298792148ef","Date":"Sat, 02 Feb 2019 06:47:19 GMT","x-application-context":"zuulserver:prod-zone1:8090","x-b3-sampled":"1"},"statusCode":200,"data":{"description":""}}\"}")
arg2:<__NSStackBlock__: 0x16f6763f8>
这个是一个获取app信息
- 其实不难看出,基本上js调用原生方法都是通过 baiduboxapp:// 这种协议调用原生方法
2019-02-02 14:47:19.674973+0800 BaiduBoxApp[585:45879] [DEBUG] > void $BBAMNPJSBridge_userContentController$didReceiveScriptMessage$_method(BBAMNPJSBridge *__strong, SEL, WKUserContentController *__strong, WKScriptMessage *__strong) [Line 261] arg1:<WKUserContentController: 0x28243ff40> 
name:BBAMNPJSBridge 
body:baiduboxapp://v19/utils/getSystemInfo?callback=__jsna_17
2019-02-02 14:47:19.675569+0800 BaiduBoxApp[585:45879] [DEBUG] > void $WKWebView_evaluateJavaScript$completionHandler$_method(WKWebView *__strong, SEL, NSString *__strong, __strong id) [Line 274] 
arg1:__jsna_17("{\"status\":\"0\",\"message\":\"调起成功\",\"data\":{\"batteryLevel\":1,\"version\":\"11.3.5.10\",\"system\":\"iOS 12.0\",\"navigationBarHeight\":44,\"brand\":\"iPhone\",\"windowHeight\":603,\"host\":\"baiduboxapp\",\"pixelRatio\":2,\"screenHeight\":667,\"SDKVersion\":\"3.15.103\",\"statusBarHeight\":20,\"language\":\"zh_CN\",\"platform\":\"ios\",\"devicePixelRatio\":2,\"windowWidth\":375,\"model\":\"iPhone 7 <iPhone9,1>\",\"screenWidth\":375,\"fontSizeSetting\":2}}") 
arg2:<__NSStackBlock__: 0x16f675ba8>
masterWebView-> slaveWebView 总结
- 
js调原生格式均为 “版本” / “类名或组件名..” / “方法名” ? params=“参数” & callback=“回调函数” 
- 
原生返回js格式 “js回调函数名”,参数为只有一个字符串json 
从 slaveWebView 渲染容器 (不唯一)分析
hook (WKWebView) 与 (BBAMNPJSBridge),(SWANSlaveWebViewController) 方法继续分析
- 其中BBAMNPJSBridge继承自WKScriptMessageHandler, SWANSlaveWebViewController为单个页面渲染
分析响应流程 masterWebView-> slaveWebView
- masterWebView先调用slaveWebView的dispatchToSlaveEventName,分发js事件,然后slaveWebView调用自己的js事件,生成一个js通知,在slaveWebView中渲染新的ui.
2019-02-02 15:24:01.479256+0800 BaiduBoxApp[585:45879] [DEBUG] > void $SWANSlaveWebViewController_dispatchToSlaveEventName$eventParam$completionHandler$_method(SWANSlaveWebViewController *__strong, SEL, __strong id, __strong id, __strong id) [Line 186] dispatchToSlaveEventName 
 arg1:message 
 arg2:{
	"message" : "{"type":"setData","slaveId":"1","setObject":{"isRequesting":true},"pageUpdateStart":"1549092241473"}"
} 
 arg3:(null)
 
2019-02-02 15:24:01.479890+0800 BaiduBoxApp[585:45879] [DEBUG] > void $WKWebView_evaluateJavaScript$completionHandler$_method(WKWebView *__strong, SEL, NSString *__strong, __strong id) [Line 274] 
arg1:var event = new Event("message");event.message="{"type":"setData","slaveId":"1","setObject":{"isRequesting":true},"pageUpdateStart":"1549092241473"}";document.dispatchEvent(event); 
 arg2:<__NSStackBlock__: 0x16f676160>
分析响应流程 slaveWebView -> masterWebView
- 
这个场景是从某个信息流,点击进入一个视频详情页时,的log,通过该log可以分析出slaveWebView到master的流程 
- 
slaveWebView通过dispatchToMasterEventName方法,分发事件,然后masterWebView接收事件后,通过js回调更新逻辑环境对应数值 
2019-02-02 15:39:48.081525+0800 BaiduBoxApp[585:45879] [DEBUG] > void $SWANApp_dispatchToMasterEventName$eventParam$completionHandler$_method(SWANApp *__strong, SEL, __strong id, __strong id, __strong id) [Line 235] dispatchToMasterEventName 
 arg1:message 
 arg2:{
	"message" : "{"type":"event","value":{"eventType":"timeupdate","reflectMethod":"videoUpdate","e":{"detail":{"videoId":"detailVideo","duration":486,"currentTime":25.617},"target":{"id":"detailVideo","offsetLeft":0,"offsetTop":0,"dataset":{}},"currentTarget":{"id":"detailVideo","offsetLeft":0,"offsetTop":0,"dataset":{}},"timeStamp":26379,"type":"timeupdate"}},"slaveId":"3"}"
} 
 arg3:(null)
 
2019-02-02 15:39:48.081891+0800 BaiduBoxApp[585:45879] [DEBUG] > void $WKWebView_evaluateJavaScript$completionHandler$_method(WKWebView *__strong, SEL, NSString *__strong, __strong id) [Line 274] 
arg1:var event = new Event("message");event.message="{"type":"event","value":{"eventType":"timeupdate","reflectMethod":"videoUpdate","e":{"detail":{"videoId":"detailVideo","duration":486,"currentTime":25.617},"target":{"id":"detailVideo","offsetLeft":0,"offsetTop":0,"dataset":{}},"currentTarget":{"id":"detailVideo","offsetLeft":0,"offsetTop":0,"dataset":{}},"timeStamp":26379,"type":"timeupdate"}},"slaveId":"3"}";document.dispatchEvent(event); 
slaveWebView -> masterWebView 总结
- 
这个和 masterWebView->slaveWebView通讯基本一致,主要区别就是这里由渲染容器触发这个动作,而masterWebView->slaveWebView是有逻辑容器触发这个动作. 
- 
addEventListener,dispatchEvent,目标事件对象,为HTML DOM的自带api 
从Web标注分析方向分析
- 这个是猜测js,对document对象增加Listener,然后原生直接dispatchEvent,分发给对应的slaveWebView,然后做响应更新处理.
document.addEventListener('message', function (event) {
	if(type == "event"){
		//处理系统实际
	}
	else if (type == "setData){
		//更新数值并对document,更新节点列表
	}
}, false);
document.dispatchEvent(new Event(eventName));
