有三种实现途径
1. WKScriptMessageHandler
OC部分:注册并实现Handler
将OC中的方法"nativeMethod"注册为JavaScript Message Handler,从而WebView中的JavaScript代码可以调用该方法
// Register in Objective-C code
- (void)setupWKWebView
{
// [WKWebViewConfiguration alloc]返回一个被分配和初始化的WKWebViewConfiguration对象的指针
// init方法是WKWebViewConfiguration类的实例方法
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.userContentController = [[WKUserContentController alloc] init];
// 将OC中的方法"nativeMethod"注册为JavaScript Message Handler,从而可以在WebView中执行JavaScript代码时调用该方法
[configuration.userContentController
addScriptMessageHandler:self // addScriptMessageHandler是方法名,self是参数1
name:@"nativeMethod"]; // name是参数2
// 初始化WKWebView
WKWebView *webView =
[[WKWebView alloc]
initWithFrame:self.view.frame
configuration:configuration];
}
// Handler method defined in WKScriptMessageHandler
- (void)userContentController:
(WKUserContentController *)userContentController //userContentController是参数1
didReceiveScriptMessage:(WKScriptMessage *)message //message是参数2
{
if ([message.name isEqualToString:@"nativeMethod"]) // 当JS端调用的是nativeMethod时
{
... //OC端的handler逻辑实现
}
}
JS部分:调用Handler
调用"nativeMethod"
// Invoke in JavaScript code
window.webkit.messageHandlers.nativeMethod.postMessage();
2. WebViewJavascriptBridge
OC部分:注册并实现Handler
注册名为"nativeMethod"的Handler
// OC中 调用bridgeForWebView:方法,来初始化WebViewJavascriptBridge
// self.bridge将被设置为WKWebView的navigationDelegate属性
self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
[self.bridge registerHandler:@"nativeMethod" //参数1,JS端以这个函数名调用该注册的native方法
handler: //参数2的参数名,冒号后面跟着参数2的参数值,是一个block;当JS端调用nativeMethod方法时,OC端执行该block
^(id data, WVJBResponseCallback responseCallback)
// ^代表后面是一个block
// data是JS端传递过来的数据
// responseCallback是 OC端的 block 执行完毕之后,往 JS 端传递的数据
{
... // block中的代码,这些代码在JS端调用nativeMethod时被执行
}
];
JS部分:调用Handler
WebViewJavascriptBridge.callHandler('nativeMethod', data, function(responseData) {
// 处理来自Objective-C的响应数据
console.log(response);
});
例如我们使用Frida分析出来,某app的wkwebview中有如下handler:
{
callNavigationSelectView = "<__NSMallocBlock__: 0x281d4a440>";
checkNotificationPermission = "<__NSMallocBlock__: 0x281d4b240>";
clickControlToShare = "<__NSMallocBlock__: 0x281d4bf00>";
couponPaySuccess = "<__NSMallocBlock__: 0x281d4a780>";
doQRScan = "<__NSMallocBlock__: 0x281d4bf80>";
faceDetect = "<__NSMallocBlock__: 0x281d4bcc0>";
getDeviceAlipay = "<__NSMallocBlock__: 0x281d4a4c0>";
getDeviceId = "<__NSMallocBlock__: 0x281d4a800>";
getDeviceInfo = "<__NSMallocBlock__: 0x281d4a680>";
getLocation = "<__NSMallocBlock__: 0x281d4a600>";
getNetworkStatus = "<__NSMallocBlock__: 0x281d4b0c0>";
getOtherDeviceInfo = "<__NSMallocBlock__: 0x281d4b540>";
getSMDeviceId = "<__NSMallocBlock__: 0x281d4a2c0>";
getTripEmail = "<__NSMallocBlock__: 0x281db04c0>";
getUserInfo = "<__NSMallocBlock__: 0x281d4a540>";
goToKF = "<__NSMallocBlock__: 0x281d4a340>";
goToVideoPlayer = "<__NSMallocBlock__: 0x281d4a700>";
hideLoadingDialog = "<__NSMallocBlock__: 0x281d4b3c0>";
jdPayHandle = "<__NSMallocBlock__: 0x281d4b900>";
jumpToMiniPro = "<__NSMallocBlock__: 0x281d4a380>";
requestNotificationPermission = "<__NSMallocBlock__: 0x281d4af00>";
saveImage = "<__NSMallocBlock__: 0x281d4a500>";
sendMsg = "<__NSMallocBlock__: 0x281d4a5c0>";
shareOnTheWebviewPage = "<__NSMallocBlock__: 0x281d4a640>";
shareWxImages = "<__NSMallocBlock__: 0x281d4b4c0>";
shareWxMinipg = "<__NSMallocBlock__: 0x281d4a580>";
startAuthoritySetting = "<__NSMallocBlock__: 0x281d4a300>";
startNetworkSetting = "<__NSMallocBlock__: 0x281d4a7c0>";
statusBarShare = "<__NSMallocBlock__: 0x281d4ad40>";
uploadTripEmail = "<__NSMallocBlock__: 0x281d49b40>";
webviewClose = "<__NSMallocBlock__: 0x281d4a740>";
webviewGoBack = "<__NSMallocBlock__: 0x281d4a480>";
}
这时候在JS端就可以这么调用:
WebViewJavascriptBridge.callHandler('getLocation', function(response) {
console.log(response);
});
确实能调用起来
3. DSBridge
这个不是很常见
OC部分:
@implementation JsObject
- (NSString *) nativeMethod:(NSString *) msg
{
...
}
@end
DWKWebView* dwebview = [[DWKWebView alloc] initWithFrame:bounds];
[dwebview addJavascriptObject:[[JsObject alloc] init] namespace:nil];
JS部分:
var dsBridge=require("dsbridge");
var str=dsBridge.call("nativeMethod","arg");
参考:
Medusa Attack: Exploring Security Hazards of {In-App}{QR} Code Scanning[C]//32nd USENIX Security Symposium (USENIX Security 23). 2023: 4607-4624.