百度小程序逆向分析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));