frida_proxy_bypass

First Post:

Last Update:

这里的代码块貌似只加载前516行代码,我把附件放在这里,包含原apk包,脱壳后脱出来的dex,以及hook脚本(bypass部分)
场景加载中…

信息收集


frida检测

上frida发现闪退,猜测有frida-server检测。绕过方式如下https://blog.csdn.net/2503_90751938/article/details/146265892?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-6-146265892-blog-145873893.235%5Ev43%5Epc_blog_bottom_relevance_base7&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-6-146265892-blog-145873893.235%5Ev43%5Epc_blog_bottom_relevance_base7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
function hook_dlopen(so_name) {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
if (path.indexOf(so_name) !== -1) {
this.match = true;
}
}
},
onLeave: function (retval) {
if (this.match) {
console.log(so_name, "加载成功");
var base = Module.findBaseAddress("libDexHelper.so");
patch_func_nop(base.add(282068));
patch_func_nop(base.add(322656));
patch_func_nop(base.add(323320));
patch_func_nop(base.add(208136));
patch_func_nop(base.add(290200));
patch_func_nop(base.add(288908));
patch_func_nop(base.add(330520));
//===============> libDexHelper.so 0x76f08dddd4 282068 44dd4
//===============> libDexHelper.so 0x76f08e7c60 322656 4ec60
//===============> libDexHelper.so 0x76f08e7ef8 323320 4eef8
//===============> libDexHelper.so 0x76f08cbd08 208136 32d08
//===============> libDexHelper.so 0x76f08dfd98 290200 46d98
//===============> libDexHelper.so 0x76f08dfd98 290200 46d98
//===============> libDexHelper.so 0x76f08df88c 288908 4688c
//============> libDexHelper.so 0x76f08e9b18 330520 50b18

}
}
});
}

function patch_func_nop(addr) {
Memory.patchCode(addr, 8, function (code) {
code.writeByteArray([0xE0, 0x03, 0x00, 0xAA]);
code.writeByteArray([0xC0, 0x03, 0x5F, 0xD6]);
console.log("patch code at " + addr);
});
}

hook_dlopen("libDexHelper.so");

function hajimi() {
var clone = Module.findExportByName('libc.so', 'clone');
Interceptor.attach(clone, {
onEnter: function (args) {
if (args[3] != 0) {
var addr = args[3].add(96).readPointer();
var so_name = Process.findModuleByAddress(addr).name;
var so_base = Module.getBaseAddress(so_name);
var offset = (addr - so_base);
console.log("===============>", so_name, addr, offset, offset.toString(16));
}
},
onLeave: function (retval) {}
});
}

//hajimi(); // 这一部分不需要每次都执行,只在需要时调用

hookokhttp3

bp和httpcanary抓不到包,脱壳后拖入jadx发现有okhttp3包,尝试hook okhttp3框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
* Android okhttp3 Traffic Interceptor
* Author: Vinay Kumar Rasala (Xplo8E)
* Organization: XYSec Labs (Appknox)
* Description: Intercepts network traffic using Frida for specified target hosts, logging API calls and WebView URL loads.
* Supported Libraries: okhttp3
*/

setImmediate(function() {
console.log("[*] Waiting for Traffic");
console.warn("[*] Please Check Target Hosts section in the code, if u dont see requests");

Java.perform(function() {
var okhttp3 = Java.use('okhttp3.OkHttpClient');
var webViewClient = Java.use('android.webkit.WebViewClient');

// ANSI escape code for red color
var redColor = '\u001b[31m';
// ANSI escape code for green color
var greenColor = '\u001b[32m';
// ANSI escape code to reset color
var resetColor = '\u001b[0m';

var targetHosts = [];
// Replace with your target hosts to set your scope
// eg: targetHosts = ["google.com", "frida.re", "github.com"]
// leave empty (eg: []) to print all requests


// Intercept API calls
var originalNewCall = okhttp3.newCall.overload('okhttp3.Request');
originalNewCall.implementation = function(request) {
// Get the request's URL and extract the host
var requestUrl = request.url().toString();
var urlParts = requestUrl.split("/");
var extractedHost = urlParts[2]; // Assumes the host is at index 2
// console.log("request url: ", requestUrl)
// console.log("request parts: ", urlParts)
// console.log("extractedHost: ", extractedHost)


if (targetHosts.includes(extractedHost) || targetHosts.length === 0) {

var requestEndpoint = requestUrl.replace(/^(https?:\/\/[^\/]+)(\/.*)$/, '$2');
// Construct and print request headers
var requestHeaders = request.headers();
console.log(redColor + "[API Call]" + resetColor);
console.log(" ");
console.log(greenColor + request.method() + " " + requestEndpoint);
// Add the Host header with the extracted host
requestHeaders = requestHeaders.newBuilder()
.add("Host", extractedHost)
.build();
// console.log(greenColor + "Request Headers:");
var requestHeaderNames = requestHeaders.names();
var requestHeaderNamesArray = requestHeaderNames.toArray();

for (var i = 0; i < requestHeaderNamesArray.length; i++) {
var headerName = requestHeaderNamesArray[i];
var headerValue = requestHeaders.get(headerName);
headerValue = decodeURIComponent(headerValue); // Decode header value
console.log(greenColor + headerName + ": " + headerValue + resetColor);
}
console.log(" ");
console.log(" ");


console.log(greenColor + requestBodyToString(request.body()) + resetColor);
console.log(redColor + "============================" + resetColor);

var newRequest = request.newBuilder().headers(requestHeaders).build();
var response = this.newCall(newRequest).execute();

// Construct and print response headers
console.log(redColor + "[API Response]" + " - [" + requestEndpoint + "]" + resetColor);
console.log(" ");
console.log(greenColor + response.code() + " " + response.message() + resetColor);
var responseHeaders = response.headers();
var responseHeaderNames = responseHeaders.names();
var responseHeaderNamesArray = responseHeaderNames.toArray();
for (var i = 0; i < responseHeaderNamesArray.length; i++) {
var responseHeaderName = responseHeaderNamesArray[i];
var responseHeaderValue = responseHeaders.get(responseHeaderName);
console.log(greenColor + responseHeaderName + ": " + responseHeaderValue + resetColor);
}
console.log(" ");

// console.log(greenColor + response.message());
var responseBody = response.body();
if (responseBody !== null) {
if (response.isSuccessful()) {
console.log(greenColor + responseBody.string() + resetColor + resetColor);
} else {
console.log(redColor + "Error: Response not successful" + resetColor);
}
} else {
console.log(greenColor + "Error: Empty response body" + resetColor);
}
console.log(redColor + "============================" + resetColor);
return this.newCall(request);

} else {
// Return a new Call instance for Frida to continue instrumenting
return this.newCall(request);
}
};

// Intercept WebView URL loads
var shouldOverrideUrlLoading = webViewClient.shouldOverrideUrlLoading.overload('android.webkit.WebView', 'java.lang.String');
shouldOverrideUrlLoading.implementation = function(view, url) {
console.log(redColor + "[WebView URL]: " + url + resetColor);
return shouldOverrideUrlLoading.call(this, view, url);
};
});
});

function requestBodyToString(requestBody) {
if (requestBody === null) {
return '';
}

var buffer = Java.use('okio.Buffer').$new();
requestBody.writeTo(buffer);
return buffer.readUtf8();
}

纳尼?情报是假的?

hookwebsocket

尝试hook websocket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
function jhexdump(array) {
var ptr = Memory.alloc(array.length);
for(var i = 0; i < array.length; ++i)
Memory.writeS8(ptr.add(i), array[i]);
//console.log(hexdump(ptr, { offset: off, length: len, header: false, ansi: false }));
console.log(hexdump(ptr, { offset: 0, length: array.length, header: false, ansi: false }));
}
function hookAddress(){
Java.perform(function(){
// java.net.InetSocketAddress.InetSocketAddress(java.net.InetAddress, int)
Java.use('java.net.InetSocketAddress').$init.overload('java.net.InetAddress', 'int').implementation = function(addr,port){
var result = this.$init(addr,port)

//console.log('addr,port =>',addr.toString(),port)
if(addr.isSiteLocalAddress()){
console.log('Local address =>',addr.toString(),', port is ',port)
}else{
console.log('Server address =>',addr.toString(),', port is ',port)
}

return result
}
})
}
function hookSocket() {
Java.perform(function () {


// java.net.SocketOutputStream.write
// java.net.SocketOutputStream.socketWrite
Java.use('java.net.SocketOutputStream').socketWrite.overload('[B', 'int', 'int').implementation = function (bytearray1, int1, int2) {
var result = this.socketWrite(bytearray1, int1, int2)

console.log('socketWrite result,bytearray1,int1,int2=>', result, bytearray1, int1, int2)

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
// console.log('contents: => ', ByteString.of(bytearray1).hex())

jhexdump(bytearray1)
return result
}

// java.net.SocketInputStream.read
// java.net.SocketInputStream.socketRead0
Java.use('java.net.SocketInputStream').read.overload('[B', 'int', 'int').implementation = function (bytearray1, int1, int2) {
var result = this.read(bytearray1, int1, int2)

console.log('read result,bytearray1,int1,int2=>', result, bytearray1, int1, int2)

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
//console.log('contents: => ', ByteString.of(bytearray1).hex())
jhexdump(bytearray1)


return result
}
})

}
function hookSSLSocketAndroid8(){

Java.perform(function () {


// com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream.write
Java.use('com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream').write.overload('[B', 'int', 'int').implementation = function (bytearray1, int1, int2) {
var result = this.write(bytearray1, int1, int2)

console.log('write result,bytearray1,int1,int2=>', result, bytearray1, int1, int2)

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
console.log('contents: => ', ByteString.of(bytearray1).hex())


return result
}

// com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream.read
Java.use('com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream').read.overload('[B', 'int', 'int').implementation = function (bytearray1, int1, int2) {
var result = this.read(bytearray1, int1, int2)

console.log('read result,bytearray1,int1,int2=>', result, bytearray1, int1, int2)

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
//console.log('contents: => ', ByteString.of(bytearray1).hex())
jhexdump(bytearray1)


return result
}
})
}
function main(){
//hookAddress()
hookSocket()
//hookSSLSocketAndroid8()
}

setImmediate(main)

hookAddress()能获取到服务器域名

hookSocket()hook到数据(向服务器的请求包)

写个脚本保存下来到本地

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import frida
import sys
import os

# 创建一个文件来保存hook数据
def create_output_file(filename):
output_file = open(filename, "w")
return output_file

# 关闭文件
def close_output_file(output_file):
output_file.close()

# 处理hook到的数据
def on_message(message, data):
if message['type'] == 'send':
payload = message['payload']
if payload['type'] == 'local_address':
output_file.write(f"Local address => {payload['address']}, port is {payload['port']}\n")
elif payload['type'] == 'server_address':
output_file.write(f"Server address => {payload['address']}, port is {payload['port']}\n")
elif payload['type'] == 'socket_write':
handle_socket_write(payload['hex_contents'])
elif payload['type'] == 'socket_read':
handle_socket_read(payload['hex_contents'])
elif message['type'] == 'error':
print(f"Error: {message['stack']}")

# 处理socket_write数据
def handle_socket_write(hex_contents):
output_file.write(f"socketWrite hex_contents => {hex_contents}\n")

# 处理socket_read数据
def handle_socket_read(hex_contents):
output_file.write(f"socketRead hex_contents => {hex_contents}\n")

def main():
process_name = "com.eshore.mall" # 替换为您的目标应用的包名
output_filename = os.path.join(os.getcwd(), "captured_traffic.txt")
global output_file
output_file = create_output_file(output_filename)

device = frida.get_usb_device()
pid = device.spawn([process_name])
session = device.attach(pid)
with open("exp.js", "r", encoding="utf-8") as f: # 明确指定编码为UTF-8
script = session.create_script(f.read())
script.on('message', on_message)
script.load()
device.resume(pid)
sys.stdin.read() # 保持脚本运行,直到手动停止

close_output_file(output_file)

if __name__ == "__main__":
main()

最终读到这么的一个包

1
2
3
4
5
6
7
8
9
10
POST /mall/newmobile/module/update_version!getLatestVersion.action/Qwhg1hl4WJzU/ HTTP/1.1
yjao6ggv: Bm5yBGi-XKTkOD5mFLTcBMy0CwbJKKKfY13VEwtargrng1ef2l0_xAQhQDL7oHwmq0fCMn4eK_8-wRJsV39ucLHJabjDKrXDbLcIOI8QPB16T87eIO5W9pMu3CVA7ZIEfOYxqGmTP2RAO6CtqAtL2cd9TSh3T6Kog3Osl4UGXS8GmR3eA5qeLAbpjH62GWVskbrPAWlbVl5bvBul66KFAOZGqZ0xzkVT0HFEaGMmkb2l2MR82QE5bBiPxOUEdOn4Y8efBXEbu1Jo_ja6i-vlq0U7SSHnbVttJqnLIGBegCHNfv14zFex8BiiGmFJ8TPCro8Ps_ZWUdvGoL95CHVEGu4rpSMQ0PS8iaAjqoniHdYoPi0_3PD3uuiLU20KxJgE1DdYDJvYarpEF0kFJWGRL1Qt2LJJ1Ew2SRHmdgm7i..4O563Q84
Content-Type: application/x-www-form-urlencoded
User-Agent: Dalvik/2.1.0 (Linux; U; Android 12; Mi 10 Pro Build/SKQ1.211006.001)
Host: iscm.gdtel.com.cn
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 140

051572f5ddfdc2e3a3bff5e869d8c23109e8d5adf8550c0bafbca267d50f55c9c01f646af8ce9113c1d5b6cca83bf8b9c59ec2e95a862dd4e03374bd1cd744c3586aa0e07ae594c94b246cbcbef70e89404c359035891be61615ae281c6a6c784f95c74a659822df603bf94c600000000000000000000000000000000

能重放,但是这个数据不太对,且程序卡在版本检查处,猜测还有vpn检测

bettercap

https://github.com/r0ysue/r0capture
通杀。但没有frida-server bypass 和vpn bypass,需要在script.js中修改

proxybypass&&betterbettercap

使用以下脚本进行ssl解密和vpn检测bypass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
/*
* This script combines, fixes & extends a long list of other scripts, most notably including:
*
* - https://codeshare.frida.re/@akabe1/frida-multiple-unpinning/
* - https://codeshare.frida.re/@avltree9798/universal-android-ssl-pinning-bypass/
* - https://pastebin.com/TVJD63uM
*/

setTimeout(function () {
Java.perform(function () {
console.log("---");
console.log("Unpinning Android app...");

/// -- Generic hook to protect against SSLPeerUnverifiedException -- ///

// In some cases, with unusual cert pinning approaches, or heavy obfuscation, we can't
// match the real method & package names. This is a problem! Fortunately, we can still
// always match built-in types, so here we spot all failures that use the built-in cert
// error type (notably this includes OkHttp), and after the first failure, we dynamically
// generate & inject a patch to completely disable the method that threw the error.
try {
const UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException');
UnverifiedCertError.$init.implementation = function (str) {
console.log(' --> Unexpected SSL verification failure, adding dynamic patch...');

try {
const stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace();
const exceptionStackIndex = stackTrace.findIndex(stack =>
stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException"
);
const callingFunctionStack = stackTrace[exceptionStackIndex + 1];

const className = callingFunctionStack.getClassName();
const methodName = callingFunctionStack.getMethodName();

console.log(` Thrown by ${className}->${methodName}`);

const callingClass = Java.use(className);
const callingMethod = callingClass[methodName];

if (callingMethod.implementation) return; // Already patched by Frida - skip it

console.log(' Attempting to patch automatically...');
const returnTypeName = callingMethod.returnType.type;

callingMethod.implementation = function () {
console.log(` --> Bypassing ${className}->${methodName} (automatic exception patch)`);

// This is not a perfect fix! Most unknown cases like this are really just
// checkCert(cert) methods though, so doing nothing is perfect, and if we
// do need an actual return value then this is probably the best we can do,
// and at least we're logging the method name so you can patch it manually:

if (returnTypeName === 'void') {
return;
} else {
return null;
}
};

console.log(` [+] ${className}->${methodName} (automatic exception patch)`);
} catch (e) {
console.log(' [ ] Failed to automatically patch failure');
}

return this.$init(str);
};
console.log('[+] SSLPeerUnverifiedException auto-patcher');
} catch (err) {
console.log('[ ] SSLPeerUnverifiedException auto-patcher');
}

/// -- Specific targeted hooks: -- ///

// HttpsURLConnection
try {
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
HttpsURLConnection.setDefaultHostnameVerifier.implementation = function (hostnameVerifier) {
console.log(' --> Bypassing HttpsURLConnection (setDefaultHostnameVerifier)');
return; // Do nothing, i.e. don't change the hostname verifier
};
console.log('[+] HttpsURLConnection (setDefaultHostnameVerifier)');
} catch (err) {
console.log('[ ] HttpsURLConnection (setDefaultHostnameVerifier)');
}
try {
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
HttpsURLConnection.setSSLSocketFactory.implementation = function (SSLSocketFactory) {
console.log(' --> Bypassing HttpsURLConnection (setSSLSocketFactory)');
return; // Do nothing, i.e. don't change the SSL socket factory
};
console.log('[+] HttpsURLConnection (setSSLSocketFactory)');
} catch (err) {
console.log('[ ] HttpsURLConnection (setSSLSocketFactory)');
}
try {
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
HttpsURLConnection.setHostnameVerifier.implementation = function (hostnameVerifier) {
console.log(' --> Bypassing HttpsURLConnection (setHostnameVerifier)');
return; // Do nothing, i.e. don't change the hostname verifier
};
console.log('[+] HttpsURLConnection (setHostnameVerifier)');
} catch (err) {
console.log('[ ] HttpsURLConnection (setHostnameVerifier)');
}

// SSLContext
try {
const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
const SSLContext = Java.use('javax.net.ssl.SSLContext');

const TrustManager = Java.registerClass({
// Implement a custom TrustManager
name: 'dev.asd.test.TrustManager',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function (chain, authType) { },
checkServerTrusted: function (chain, authType) { },
getAcceptedIssuers: function () { return []; }
}
});

// Prepare the TrustManager array to pass to SSLContext.init()
const TrustManagers = [TrustManager.$new()];

// Get a handle on the init() on the SSLContext class
const SSLContext_init = SSLContext.init.overload(
'[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
);

// Override the init method, specifying the custom TrustManager
SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
console.log(' --> Bypassing Trustmanager (Android < 7) request');
SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
};
console.log('[+] SSLContext');
} catch (err) {
console.log('[ ] SSLContext');
}

// TrustManagerImpl (Android > 7)
try {
const array_list = Java.use("java.util.ArrayList");
const TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');

// This step is notably what defeats the most common case: network security config
TrustManagerImpl.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) {
console.log(' --> Bypassing TrustManagerImpl checkTrusted ');
return array_list.$new();
}

TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
console.log(' --> Bypassing TrustManagerImpl verifyChain: ' + host);
return untrustedChain;
};
console.log('[+] TrustManagerImpl');
} catch (err) {
console.log('[ ] TrustManagerImpl');
}

// OkHTTPv3 (quadruple bypass)
try {
// Bypass OkHTTPv3 {1}
const okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');
okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
console.log(' --> Bypassing OkHTTPv3 (list): ' + a);
return;
};
console.log('[+] OkHTTPv3 (list)');
} catch (err) {
console.log('[ ] OkHTTPv3 (list)');
}
try {
// Bypass OkHTTPv3 {2}
// This method of CertificatePinner.check could be found in some old Android app
const okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');
okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {
console.log(' --> Bypassing OkHTTPv3 (cert): ' + a);
return;
};
console.log('[+] OkHTTPv3 (cert)');
} catch (err) {
console.log('[ ] OkHTTPv3 (cert)');
}
try {
// Bypass OkHTTPv3 {3}
const okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');
okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (a, b) {
console.log(' --> Bypassing OkHTTPv3 (cert array): ' + a);
return;
};
console.log('[+] OkHTTPv3 (cert array)');
} catch (err) {
console.log('[ ] OkHTTPv3 (cert array)');
}
try {
// Bypass OkHTTPv3 {4}
const okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');
okhttp3_Activity_4['check$okhttp'].implementation = function (a, b) {
console.log(' --> Bypassing OkHTTPv3 ($okhttp): ' + a);
return;
};
console.log('[+] OkHTTPv3 ($okhttp)');
} catch (err) {
console.log('[ ] OkHTTPv3 ($okhttp)');
}

// Trustkit (triple bypass)
try {
// Bypass Trustkit {1}
const trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
console.log(' --> Bypassing Trustkit OkHostnameVerifier(SSLSession): ' + a);
return true;
};
console.log('[+] Trustkit OkHostnameVerifier(SSLSession)');
} catch (err) {
console.log('[ ] Trustkit OkHostnameVerifier(SSLSession)');
}
try {
// Bypass Trustkit {2}
const trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
console.log(' --> Bypassing Trustkit OkHostnameVerifier(cert): ' + a);
return true;
};
console.log('[+] Trustkit OkHostnameVerifier(cert)');
} catch (err) {
console.log('[ ] Trustkit OkHostnameVerifier(cert)');
}
try {
// Bypass Trustkit {3}
const trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
trustkit_PinningTrustManager.checkServerTrusted.implementation = function () {
console.log(' --> Bypassing Trustkit PinningTrustManager');
};
console.log('[+] Trustkit PinningTrustManager');
} catch (err) {
console.log('[ ] Trustkit PinningTrustManager');
}

// Appcelerator Titanium
try {
const appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
appcelerator_PinningTrustManager.checkServerTrusted.implementation = function () {
console.log(' --> Bypassing Appcelerator PinningTrustManager');
};
console.log('[+] Appcelerator PinningTrustManager');
} catch (err) {
console.log('[ ] Appcelerator PinningTrustManager');
}

// OpenSSLSocketImpl Conscrypt
try {
const OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, JavaObject, authMethod) {
console.log(' --> Bypassing OpenSSLSocketImpl Conscrypt');
};
console.log('[+] OpenSSLSocketImpl Conscrypt');
} catch (err) {
console.log('[ ] OpenSSLSocketImpl Conscrypt');
}

// OpenSSLEngineSocketImpl Conscrypt
try {
const OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function (a, b) {
console.log(' --> Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);
};
console.log('[+] OpenSSLEngineSocketImpl Conscrypt');
} catch (err) {
console.log('[ ] OpenSSLEngineSocketImpl Conscrypt');
}

// OpenSSLSocketImpl Apache Harmony
try {
const OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function (asn1DerEncodedCertificateChain, authMethod) {
console.log(' --> Bypassing OpenSSLSocketImpl Apache Harmony');
};
console.log('[+] OpenSSLSocketImpl Apache Harmony');
} catch (err) {
console.log('[ ] OpenSSLSocketImpl Apache Harmony');
}

// PhoneGap sslCertificateChecker (https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin)
try {
const phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {
console.log(' --> Bypassing PhoneGap sslCertificateChecker: ' + a);
return true;
};
console.log('[+] PhoneGap sslCertificateChecker');
} catch (err) {
console.log('[ ] PhoneGap sslCertificateChecker');
}

// IBM MobileFirst pinTrustedCertificatePublicKey (double bypass)
try {
// Bypass IBM MobileFirst {1}
const WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');
WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function (cert) {
console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string): ' + cert);
return;
};
console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string)');
} catch (err) {
console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string)');
}
try {
// Bypass IBM MobileFirst {2}
const WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');
WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function (cert) {
console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string array): ' + cert);
return;
};
console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string array)');
} catch (err) {
console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string array)');
}

// IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass)
try {
// Bypass IBM WorkLight {1}
const worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function (a, b) {
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket): ' + a);
return;
};
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)');
} catch (err) {
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)');
}
try {
// Bypass IBM WorkLight {2}
const worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (cert): ' + a);
return;
};
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)');
} catch (err) {
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)');
}
try {
// Bypass IBM WorkLight {3}
const worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function (a, b) {
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (string string): ' + a);
return;
};
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)');
} catch (err) {
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)');
}
try {
// Bypass IBM WorkLight {4}
const worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession): ' + a);
return true;
};
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)');
} catch (err) {
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)');
}

// Conscrypt CertPinManager
try {
const conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
console.log(' --> Bypassing Conscrypt CertPinManager: ' + a);
return true;
};
console.log('[+] Conscrypt CertPinManager');
} catch (err) {
console.log('[ ] Conscrypt CertPinManager');
}

// CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager
try {
const cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
console.log(' --> Bypassing CWAC-Netsecurity CertPinManager: ' + a);
return true;
};
console.log('[+] CWAC-Netsecurity CertPinManager');
} catch (err) {
console.log('[ ] CWAC-Netsecurity CertPinManager');
}

// Worklight Androidgap WLCertificatePinningPlugin
try {
const androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');
androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {
console.log(' --> Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);
return true;
};
console.log('[+] Worklight Androidgap WLCertificatePinningPlugin');
} catch (err) {
console.log('[ ] Worklight Androidgap WLCertificatePinningPlugin');
}

// Netty FingerprintTrustManagerFactory
try {
const netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function (type, chain) {
console.log(' --> Bypassing Netty FingerprintTrustManagerFactory');
};
console.log('[+] Netty FingerprintTrustManagerFactory');
} catch (err) {
console.log('[ ] Netty FingerprintTrustManagerFactory');
}

// Squareup CertificatePinner [OkHTTP<v3] (double bypass)
try {
// Bypass Squareup CertificatePinner {1}
const Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');
Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {
console.log(' --> Bypassing Squareup CertificatePinner (cert): ' + a);
return;
};
console.log('[+] Squareup CertificatePinner (cert)');
} catch (err) {
console.log('[ ] Squareup CertificatePinner (cert)');
}
try {
// Bypass Squareup CertificatePinner {2}
const Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');
Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
console.log(' --> Bypassing Squareup CertificatePinner (list): ' + a);
return;
};
console.log('[+] Squareup CertificatePinner (list)');
} catch (err) {
console.log('[ ] Squareup CertificatePinner (list)');
}

// Squareup OkHostnameVerifier [OkHTTP v3] (double bypass)
try {
// Bypass Squareup OkHostnameVerifier {1}
const Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
console.log(' --> Bypassing Squareup OkHostnameVerifier (cert): ' + a);
return true;
};
console.log('[+] Squareup OkHostnameVerifier (cert)');
} catch (err) {
console.log('[ ] Squareup OkHostnameVerifier (cert)');
}
try {
// Bypass Squareup OkHostnameVerifier {2}
const Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
console.log(' --> Bypassing Squareup OkHostnameVerifier (SSLSession): ' + a);
return true;
};
console.log('[+] Squareup OkHostnameVerifier (SSLSession)');
} catch (err) {
console.log('[ ] Squareup OkHostnameVerifier (SSLSession)');
}

// Android WebViewClient (double bypass)
try {
// Bypass WebViewClient {1} (deprecated from Android 6)
const AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');
AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
console.log(' --> Bypassing Android WebViewClient (SslErrorHandler)');
};
console.log('[+] Android WebViewClient (SslErrorHandler)');
} catch (err) {
console.log('[ ] Android WebViewClient (SslErrorHandler)');
}
try {
// Bypass WebViewClient {2}
const AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');
AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function (obj1, obj2, obj3) {
console.log(' --> Bypassing Android WebViewClient (WebResourceError)');
};
console.log('[+] Android WebViewClient (WebResourceError)');
} catch (err) {
console.log('[ ] Android WebViewClient (WebResourceError)');
}

// Apache Cordova WebViewClient
try {
const CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');
CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
console.log(' --> Bypassing Apache Cordova WebViewClient');
obj3.proceed();
};
} catch (err) {
console.log('[ ] Apache Cordova WebViewClient');
}

// Boye AbstractVerifier
try {
const boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');
boye_AbstractVerifier.verify.implementation = function (host, ssl) {
console.log(' --> Bypassing Boye AbstractVerifier: ' + host);
};
} catch (err) {
console.log('[ ] Boye AbstractVerifier');
}

// Appmattus
try {
const appmatus_Activity = Java.use('com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyInterceptor');
appmatus_Activity['intercept'].implementation = function (a) {
console.log(' --> Bypassing Appmattus (Transparency)');
return a.proceed(a.request());
};
console.log('[+] Appmattus (CertificateTransparencyInterceptor)');
} catch (err) {
console.log('[ ] Appmattus (CertificateTransparencyInterceptor)');
}

try {
const CertificateTransparencyTrustManager = Java.use(
'com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyTrustManager'
);
CertificateTransparencyTrustManager['checkServerTrusted'].overload(
'[Ljava.security.cert.X509Certificate;',
'java.lang.String'
).implementation = function (x509CertificateArr, str) {
console.log(' --> Bypassing Appmattus (CertificateTransparencyTrustManager)');
};
CertificateTransparencyTrustManager['checkServerTrusted'].overload(
'[Ljava.security.cert.X509Certificate;',
'java.lang.String',
'java.lang.String'
).implementation = function (x509CertificateArr, str, str2) {
console.log(' --> Bypassing Appmattus (CertificateTransparencyTrustManager)');
return Java.use('java.util.ArrayList').$new();
};
console.log('[+] Appmattus (CertificateTransparencyTrustManager)');
} catch (err) {
console.log('[ ] Appmattus (CertificateTransparencyTrustManager)');
}

console.log("Unpinning setup completed");
console.log("---");
});

}, 0);

Java.perform(function () {
// 获取 WebView 类
var WebView = Java.use('android.webkit.WebView');

// Hook loadUrl 方法
WebView.loadUrl.overload('java.lang.String').implementation = function (url) {
// 在加载 URL 之前打印原始 URL
console.log("[*] Original URL: " + url);

// 这里可以添加修改 URL 的逻辑
// 例如,将所有的 http 链接替换为 https 链接
// var newUrl = url.replace('http://', 'https://');
//var newUrl = "http://www.baidu.com"

// 打印修改后的 URL
console.log("[*] Modified URL: " + newUrl);

// 调用原始的 loadUrl 方法加载修改后的 URL
var result = this.loadUrl(newUrl);

return result;
};

// 如果需要 Hook 带有额外参数的 loadUrl 方法,可以添加以下代码
WebView.loadUrl.overload('java.lang.String', 'java.util.Map').implementation = function (url, additionalHttpHeaders) {
console.log("[*] Original URL (with headers): " + url);
console.log("[*] Additional headers: " + JSON.stringify(additionalHttpHeaders));

//var newUrl = "http://www.baidu.com"
console.log("[*] Modified URL (with headers): " + newUrl);

var result = this.loadUrl(newUrl, additionalHttpHeaders);
return result;
};
});

成功在bp上抓到包
最终脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646

function hook_dlopen(so_name) {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
if (path.indexOf(so_name) !== -1) {
this.match = true;
}
}
},
onLeave: function (retval) {
if (this.match) {
console.log(so_name, "加载成功");
var base = Module.findBaseAddress("libDexHelper.so");
patch_func_nop(base.add(282068));
patch_func_nop(base.add(322656));
patch_func_nop(base.add(323320));
patch_func_nop(base.add(208136));
patch_func_nop(base.add(290200));
patch_func_nop(base.add(288908));
patch_func_nop(base.add(330520));
//===============> libDexHelper.so 0x76f08dddd4 282068 44dd4
//===============> libDexHelper.so 0x76f08e7c60 322656 4ec60
//===============> libDexHelper.so 0x76f08e7ef8 323320 4eef8
//===============> libDexHelper.so 0x76f08cbd08 208136 32d08
//===============> libDexHelper.so 0x76f08dfd98 290200 46d98
//===============> libDexHelper.so 0x76f08dfd98 290200 46d98
//===============> libDexHelper.so 0x76f08df88c 288908 4688c
//===============> libDexHelper.so 0x76f08e9b18 330520 50b18

}
}
});
}

function patch_func_nop(addr) {
Memory.patchCode(addr, 8, function (code) {
code.writeByteArray([0xE0, 0x03, 0x00, 0xAA]);
code.writeByteArray([0xC0, 0x03, 0x5F, 0xD6]);
console.log("patch code at " + addr);
});
}

hook_dlopen("libDexHelper.so");

function hajimi() {
var clone = Module.findExportByName('libc.so', 'clone');
Interceptor.attach(clone, {
onEnter: function (args) {
if (args[3] != 0) {
var addr = args[3].add(96).readPointer();
var so_name = Process.findModuleByAddress(addr).name;
var so_base = Module.getBaseAddress(so_name);
var offset = (addr - so_base);
console.log("===============>", so_name, addr, offset, offset.toString(16));
}
},
onLeave: function (retval) {}
});
}

//hajimi(); // 这一部分不需要每次都执行,只在需要时调用

/*
* This script combines, fixes & extends a long list of other scripts, most notably including:
*
* - https://codeshare.frida.re/@akabe1/frida-multiple-unpinning/
* - https://codeshare.frida.re/@avltree9798/universal-android-ssl-pinning-bypass/
* - https://pastebin.com/TVJD63uM
*/

setTimeout(function () {
Java.perform(function () {
console.log("---");
console.log("Unpinning Android app...");

/// -- Generic hook to protect against SSLPeerUnverifiedException -- ///

// In some cases, with unusual cert pinning approaches, or heavy obfuscation, we can't
// match the real method & package names. This is a problem! Fortunately, we can still
// always match built-in types, so here we spot all failures that use the built-in cert
// error type (notably this includes OkHttp), and after the first failure, we dynamically
// generate & inject a patch to completely disable the method that threw the error.
try {
const UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException');
UnverifiedCertError.$init.implementation = function (str) {
console.log(' --> Unexpected SSL verification failure, adding dynamic patch...');

try {
const stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace();
const exceptionStackIndex = stackTrace.findIndex(stack =>
stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException"
);
const callingFunctionStack = stackTrace[exceptionStackIndex + 1];

const className = callingFunctionStack.getClassName();
const methodName = callingFunctionStack.getMethodName();

console.log(` Thrown by ${className}->${methodName}`);

const callingClass = Java.use(className);
const callingMethod = callingClass[methodName];

if (callingMethod.implementation) return; // Already patched by Frida - skip it

console.log(' Attempting to patch automatically...');
const returnTypeName = callingMethod.returnType.type;

callingMethod.implementation = function () {
console.log(` --> Bypassing ${className}->${methodName} (automatic exception patch)`);

// This is not a perfect fix! Most unknown cases like this are really just
// checkCert(cert) methods though, so doing nothing is perfect, and if we
// do need an actual return value then this is probably the best we can do,
// and at least we're logging the method name so you can patch it manually:

if (returnTypeName === 'void') {
return;
} else {
return null;
}
};

console.log(` [+] ${className}->${methodName} (automatic exception patch)`);
} catch (e) {
console.log(' [ ] Failed to automatically patch failure');
}

return this.$init(str);
};
console.log('[+] SSLPeerUnverifiedException auto-patcher');
} catch (err) {
console.log('[ ] SSLPeerUnverifiedException auto-patcher');
}

/// -- Specific targeted hooks: -- ///

// HttpsURLConnection
try {
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
HttpsURLConnection.setDefaultHostnameVerifier.implementation = function (hostnameVerifier) {
console.log(' --> Bypassing HttpsURLConnection (setDefaultHostnameVerifier)');
return; // Do nothing, i.e. don't change the hostname verifier
};
console.log('[+] HttpsURLConnection (setDefaultHostnameVerifier)');
} catch (err) {
console.log('[ ] HttpsURLConnection (setDefaultHostnameVerifier)');
}
try {
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
HttpsURLConnection.setSSLSocketFactory.implementation = function (SSLSocketFactory) {
console.log(' --> Bypassing HttpsURLConnection (setSSLSocketFactory)');
return; // Do nothing, i.e. don't change the SSL socket factory
};
console.log('[+] HttpsURLConnection (setSSLSocketFactory)');
} catch (err) {
console.log('[ ] HttpsURLConnection (setSSLSocketFactory)');
}
try {
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
HttpsURLConnection.setHostnameVerifier.implementation = function (hostnameVerifier) {
console.log(' --> Bypassing HttpsURLConnection (setHostnameVerifier)');
return; // Do nothing, i.e. don't change the hostname verifier
};
console.log('[+] HttpsURLConnection (setHostnameVerifier)');
} catch (err) {
console.log('[ ] HttpsURLConnection (setHostnameVerifier)');
}

// SSLContext
try {
const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
const SSLContext = Java.use('javax.net.ssl.SSLContext');

const TrustManager = Java.registerClass({
// Implement a custom TrustManager
name: 'dev.asd.test.TrustManager',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function (chain, authType) { },
checkServerTrusted: function (chain, authType) { },
getAcceptedIssuers: function () { return []; }
}
});

// Prepare the TrustManager array to pass to SSLContext.init()
const TrustManagers = [TrustManager.$new()];

// Get a handle on the init() on the SSLContext class
const SSLContext_init = SSLContext.init.overload(
'[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
);

// Override the init method, specifying the custom TrustManager
SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
console.log(' --> Bypassing Trustmanager (Android < 7) request');
SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
};
console.log('[+] SSLContext');
} catch (err) {
console.log('[ ] SSLContext');
}

// TrustManagerImpl (Android > 7)
try {
const array_list = Java.use("java.util.ArrayList");
const TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');

// This step is notably what defeats the most common case: network security config
TrustManagerImpl.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) {
console.log(' --> Bypassing TrustManagerImpl checkTrusted ');
return array_list.$new();
}

TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
console.log(' --> Bypassing TrustManagerImpl verifyChain: ' + host);
return untrustedChain;
};
console.log('[+] TrustManagerImpl');
} catch (err) {
console.log('[ ] TrustManagerImpl');
}

// OkHTTPv3 (quadruple bypass)
try {
// Bypass OkHTTPv3 {1}
const okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');
okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
console.log(' --> Bypassing OkHTTPv3 (list): ' + a);
return;
};
console.log('[+] OkHTTPv3 (list)');
} catch (err) {
console.log('[ ] OkHTTPv3 (list)');
}
try {
// Bypass OkHTTPv3 {2}
// This method of CertificatePinner.check could be found in some old Android app
const okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');
okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {
console.log(' --> Bypassing OkHTTPv3 (cert): ' + a);
return;
};
console.log('[+] OkHTTPv3 (cert)');
} catch (err) {
console.log('[ ] OkHTTPv3 (cert)');
}
try {
// Bypass OkHTTPv3 {3}
const okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');
okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (a, b) {
console.log(' --> Bypassing OkHTTPv3 (cert array): ' + a);
return;
};
console.log('[+] OkHTTPv3 (cert array)');
} catch (err) {
console.log('[ ] OkHTTPv3 (cert array)');
}
try {
// Bypass OkHTTPv3 {4}
const okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');
okhttp3_Activity_4['check$okhttp'].implementation = function (a, b) {
console.log(' --> Bypassing OkHTTPv3 ($okhttp): ' + a);
return;
};
console.log('[+] OkHTTPv3 ($okhttp)');
} catch (err) {
console.log('[ ] OkHTTPv3 ($okhttp)');
}

// Trustkit (triple bypass)
try {
// Bypass Trustkit {1}
const trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
console.log(' --> Bypassing Trustkit OkHostnameVerifier(SSLSession): ' + a);
return true;
};
console.log('[+] Trustkit OkHostnameVerifier(SSLSession)');
} catch (err) {
console.log('[ ] Trustkit OkHostnameVerifier(SSLSession)');
}
try {
// Bypass Trustkit {2}
const trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
console.log(' --> Bypassing Trustkit OkHostnameVerifier(cert): ' + a);
return true;
};
console.log('[+] Trustkit OkHostnameVerifier(cert)');
} catch (err) {
console.log('[ ] Trustkit OkHostnameVerifier(cert)');
}
try {
// Bypass Trustkit {3}
const trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
trustkit_PinningTrustManager.checkServerTrusted.implementation = function () {
console.log(' --> Bypassing Trustkit PinningTrustManager');
};
console.log('[+] Trustkit PinningTrustManager');
} catch (err) {
console.log('[ ] Trustkit PinningTrustManager');
}

// Appcelerator Titanium
try {
const appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
appcelerator_PinningTrustManager.checkServerTrusted.implementation = function () {
console.log(' --> Bypassing Appcelerator PinningTrustManager');
};
console.log('[+] Appcelerator PinningTrustManager');
} catch (err) {
console.log('[ ] Appcelerator PinningTrustManager');
}

// OpenSSLSocketImpl Conscrypt
try {
const OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, JavaObject, authMethod) {
console.log(' --> Bypassing OpenSSLSocketImpl Conscrypt');
};
console.log('[+] OpenSSLSocketImpl Conscrypt');
} catch (err) {
console.log('[ ] OpenSSLSocketImpl Conscrypt');
}

// OpenSSLEngineSocketImpl Conscrypt
try {
const OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function (a, b) {
console.log(' --> Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);
};
console.log('[+] OpenSSLEngineSocketImpl Conscrypt');
} catch (err) {
console.log('[ ] OpenSSLEngineSocketImpl Conscrypt');
}

// OpenSSLSocketImpl Apache Harmony
try {
const OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function (asn1DerEncodedCertificateChain, authMethod) {
console.log(' --> Bypassing OpenSSLSocketImpl Apache Harmony');
};
console.log('[+] OpenSSLSocketImpl Apache Harmony');
} catch (err) {
console.log('[ ] OpenSSLSocketImpl Apache Harmony');
}

// PhoneGap sslCertificateChecker (https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin)
try {
const phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {
console.log(' --> Bypassing PhoneGap sslCertificateChecker: ' + a);
return true;
};
console.log('[+] PhoneGap sslCertificateChecker');
} catch (err) {
console.log('[ ] PhoneGap sslCertificateChecker');
}

// IBM MobileFirst pinTrustedCertificatePublicKey (double bypass)
try {
// Bypass IBM MobileFirst {1}
const WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');
WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function (cert) {
console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string): ' + cert);
return;
};
console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string)');
} catch (err) {
console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string)');
}
try {
// Bypass IBM MobileFirst {2}
const WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');
WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function (cert) {
console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string array): ' + cert);
return;
};
console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string array)');
} catch (err) {
console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string array)');
}

// IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass)
try {
// Bypass IBM WorkLight {1}
const worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function (a, b) {
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket): ' + a);
return;
};
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)');
} catch (err) {
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)');
}
try {
// Bypass IBM WorkLight {2}
const worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (cert): ' + a);
return;
};
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)');
} catch (err) {
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)');
}
try {
// Bypass IBM WorkLight {3}
const worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function (a, b) {
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (string string): ' + a);
return;
};
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)');
} catch (err) {
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)');
}
try {
// Bypass IBM WorkLight {4}
const worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession): ' + a);
return true;
};
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)');
} catch (err) {
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)');
}

// Conscrypt CertPinManager
try {
const conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
console.log(' --> Bypassing Conscrypt CertPinManager: ' + a);
return true;
};
console.log('[+] Conscrypt CertPinManager');
} catch (err) {
console.log('[ ] Conscrypt CertPinManager');
}

// CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager
try {
const cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
console.log(' --> Bypassing CWAC-Netsecurity CertPinManager: ' + a);
return true;
};
console.log('[+] CWAC-Netsecurity CertPinManager');
} catch (err) {
console.log('[ ] CWAC-Netsecurity CertPinManager');
}

// Worklight Androidgap WLCertificatePinningPlugin
try {
const androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');
androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {
console.log(' --> Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);
return true;
};
console.log('[+] Worklight Androidgap WLCertificatePinningPlugin');
} catch (err) {
console.log('[ ] Worklight Androidgap WLCertificatePinningPlugin');
}

// Netty FingerprintTrustManagerFactory
try {
const netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function (type, chain) {
console.log(' --> Bypassing Netty FingerprintTrustManagerFactory');
};
console.log('[+] Netty FingerprintTrustManagerFactory');
} catch (err) {
console.log('[ ] Netty FingerprintTrustManagerFactory');
}

// Squareup CertificatePinner [OkHTTP<v3] (double bypass)
try {
// Bypass Squareup CertificatePinner {1}
const Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');
Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {
console.log(' --> Bypassing Squareup CertificatePinner (cert): ' + a);
return;
};
console.log('[+] Squareup CertificatePinner (cert)');
} catch (err) {
console.log('[ ] Squareup CertificatePinner (cert)');
}
try {
// Bypass Squareup CertificatePinner {2}
const Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');
Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
console.log(' --> Bypassing Squareup CertificatePinner (list): ' + a);
return;
};
console.log('[+] Squareup CertificatePinner (list)');
} catch (err) {
console.log('[ ] Squareup CertificatePinner (list)');
}

// Squareup OkHostnameVerifier [OkHTTP v3] (double bypass)
try {
// Bypass Squareup OkHostnameVerifier {1}
const Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
console.log(' --> Bypassing Squareup OkHostnameVerifier (cert): ' + a);
return true;
};
console.log('[+] Squareup OkHostnameVerifier (cert)');
} catch (err) {
console.log('[ ] Squareup OkHostnameVerifier (cert)');
}
try {
// Bypass Squareup OkHostnameVerifier {2}
const Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
console.log(' --> Bypassing Squareup OkHostnameVerifier (SSLSession): ' + a);
return true;
};
console.log('[+] Squareup OkHostnameVerifier (SSLSession)');
} catch (err) {
console.log('[ ] Squareup OkHostnameVerifier (SSLSession)');
}

// Android WebViewClient (double bypass)
try {
// Bypass WebViewClient {1} (deprecated from Android 6)
const AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');
AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
console.log(' --> Bypassing Android WebViewClient (SslErrorHandler)');
};
console.log('[+] Android WebViewClient (SslErrorHandler)');
} catch (err) {
console.log('[ ] Android WebViewClient (SslErrorHandler)');
}
try {
// Bypass WebViewClient {2}
const AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');
AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function (obj1, obj2, obj3) {
console.log(' --> Bypassing Android WebViewClient (WebResourceError)');
};
console.log('[+] Android WebViewClient (WebResourceError)');
} catch (err) {
console.log('[ ] Android WebViewClient (WebResourceError)');
}

// Apache Cordova WebViewClient
try {
const CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');
CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
console.log(' --> Bypassing Apache Cordova WebViewClient');
obj3.proceed();
};
} catch (err) {
console.log('[ ] Apache Cordova WebViewClient');
}

// Boye AbstractVerifier
try {
const boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');
boye_AbstractVerifier.verify.implementation = function (host, ssl) {
console.log(' --> Bypassing Boye AbstractVerifier: ' + host);
};
} catch (err) {
console.log('[ ] Boye AbstractVerifier');
}

// Appmattus
try {
const appmatus_Activity = Java.use('com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyInterceptor');
appmatus_Activity['intercept'].implementation = function (a) {
console.log(' --> Bypassing Appmattus (Transparency)');
return a.proceed(a.request());
};
console.log('[+] Appmattus (CertificateTransparencyInterceptor)');
} catch (err) {
console.log('[ ] Appmattus (CertificateTransparencyInterceptor)');
}

try {
const CertificateTransparencyTrustManager = Java.use(
'com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyTrustManager'
);
CertificateTransparencyTrustManager['checkServerTrusted'].overload(
'[Ljava.security.cert.X509Certificate;',
'java.lang.String'
).implementation = function (x509CertificateArr, str) {
console.log(' --> Bypassing Appmattus (CertificateTransparencyTrustManager)');
};
CertificateTransparencyTrustManager['checkServerTrusted'].overload(
'[Ljava.security.cert.X509Certificate;',
'java.lang.String',
'java.lang.String'
).implementation = function (x509CertificateArr, str, str2) {
console.log(' --> Bypassing Appmattus (CertificateTransparencyTrustManager)');
return Java.use('java.util.ArrayList').$new();
};
console.log('[+] Appmattus (CertificateTransparencyTrustManager)');
} catch (err) {
console.log('[ ] Appmattus (CertificateTransparencyTrustManager)');
}

console.log("Unpinning setup completed");
console.log("---");
});

}, 0);

Java.perform(function () {
// 获取 WebView 类
var WebView = Java.use('android.webkit.WebView');

// Hook loadUrl 方法
WebView.loadUrl.overload('java.lang.String').implementation = function (url) {
// 在加载 URL 之前打印原始 URL
console.log("[*] Original URL: " + url);

// 这里可以添加修改 URL 的逻辑
// 例如,将所有的 http 链接替换为 https 链接
// var newUrl = url.replace('http://', 'https://');
//var newUrl = "http://www.baidu.com"

// 打印修改后的 URL
console.log("[*] Modified URL: " + newUrl);

// 调用原始的 loadUrl 方法加载修改后的 URL
var result = this.loadUrl(newUrl);

return result;
};

// 如果需要 Hook 带有额外参数的 loadUrl 方法,可以添加以下代码
WebView.loadUrl.overload('java.lang.String', 'java.util.Map').implementation = function (url, additionalHttpHeaders) {
console.log("[*] Original URL (with headers): " + url);
console.log("[*] Additional headers: " + JSON.stringify(additionalHttpHeaders));

//var newUrl = "http://www.baidu.com"
console.log("[*] Modified URL (with headers): " + newUrl);

var result = this.loadUrl(newUrl, additionalHttpHeaders);
return result;
};
});