导读

背景

  • 上已篇的篇幅已经太长了,所以在开这个篇幅,继续分享.

  • 本篇幅内,大部分都是log都已被手动格式化

需要技能

  • 1.js基础,ios开发基础.

  • 2.会使用Xcode,safari,有基础js编写能力.

MonkeyDev-自动化,非越狱,逆向神器

逆向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));