建行生活2.x版本SSL pinning bypass

建行生活2.x版本SSL pinning bypass

注入frida-gadget.so

使用了新版本的梆梆企业版加固,对frida的限制严格,调试了很长时间后找到了一种注入frida-gadget.so的方法:在壳执行前加载一个so文件,以hook pthread_create,禁止壳创建反调试、环境检测线程,并加载frida-gadget.so(有缺陷,程序启动后,不能连接firda进行Hook,会被检测到并结束进程,没有定位到检测代码,所以在程序启动时就连接frida进行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
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
typedef int (*JNI_OnLoadFunc)(JavaVM *vm, void *reserved);
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
shadowhook_init(SHADOWHOOK_MODE_UNIQUE, (bool)1);
if (stub_dlopen == NULL)
{
int err_num = shadowhook_get_errno();
const char *err_msg = shadowhook_to_errmsg(err_num);
LOG("hook dlopen error %d - %s", err_num, err_msg);
}
else
{
LOG("hook dlopen success!");
}

libdexhelper_handle = dlopen("libDexHelper1.so", RTLD_NOW);
if (libdexhelper_handle == NULL)
{
LOG(" [!] Could not dlopen file! (%s)\n", dlerror());
return -1;
}
LOG(" [+] Library Loaded!\n");
JNI_OnLoadFunc onLoadFunc = (int (*)(JavaVM * vm, void *reserved)) dlsym(libdexhelper_handle, "JNI_OnLoad");
if (onLoadFunc == NULL)
{
LOG(" [!] No JNI_OnLoad found!\n");
return -1;
}
LOG(" [+] Found JNI_OnLoad: %p\n", onLoadFunc);
libdexhelper_base = (unsigned long)onLoadFunc - 0x00026468;
LOG("libdexhelper_base: %lx", libdexhelper_base);


void * libSdkHelper_Sin_handle = dlopen("libSdkHelper_Sin1.so", RTLD_NOW);
if (libSdkHelper_Sin_handle == NULL)
{
LOG(" [!] Could not dlopen libSdkHelper_Sin1.so ! (%s)\n", dlerror());
return -1;
}
LOG(" [+] Library Loaded: libSdkHelper_Sin1.so \n");
JNI_OnLoadFunc sdkhelper_onLoadFunc = (int (*)(JavaVM * vm, void *reserved)) dlsym(libSdkHelper_Sin_handle, "JNI_OnLoad");
if (sdkhelper_onLoadFunc == NULL)
{
LOG(" [!] No JNI_OnLoad found!\n");
return -1;
}
LOG(" [+] Found JNI_OnLoad: %p\n", sdkhelper_onLoadFunc);
libSdkHelper_Sin_base = (unsigned long)sdkhelper_onLoadFunc - 0x00012C30;
LOG("libSdkHelper_Sin_base: %lx", libSdkHelper_Sin_base);


pthread_create_stub = shadowhook_hook_sym_name("libc.so", "pthread_create", (void *)proxy_pthread_create, (void **)&orig_pthread_create);
if(pthread_create_stub == NULL)
{
int err_num = shadowhook_get_errno();
const char *err_msg = shadowhook_to_errmsg(err_num);
LOG("hook pthread_create error %d - %s", err_num, err_msg);
}
else{
LOG("hook pthread_create success!");
}

// patch libdexheler1.so
unsigned char * address_of_kill = (unsigned char *)dlsym(libdexhelper_handle, "pDD13E0C66A8F8BF92E99643C59C3B809");
LOG("pDD13E0C66A8F8BF92E99643C59C3B809 address_of_kill: %p", address_of_kill);
address_of_kill[8] = 0x00;
address_of_kill[9] = 0x00;
address_of_kill[10] = 0xa0;
address_of_kill[11] = 0xe3;
LOG("pDD13E0C66A8F8BF92E99643C59C3B809 patched");
LOG("start patch 0x005B6E8...");
unsigned char * address_of_5B6E8 = address_of_kill-0x5ed4;
LOG("address_of_5B6E8 : %p", address_of_5B6E8);
address_of_5B6E8[0] = 0xbd;
address_of_5B6E8[1] = 0xe8;
address_of_5B6E8[2] = 0xf0;
address_of_5B6E8[3] = 0x8f;
LOG("function 5B6E8 patched");

// load frida
LOG(" [!] dlopen libfrida...\n");
void * libfrida_handle = dlopen("libmiui_sec.so", RTLD_NOW);
if (libfrida_handle == NULL)
{
LOG(" [!] Could not dlopen libfrida! (%s)\n", dlerror());
return -1;
}
for (int x = 10; x > 0; --x) {
LOG("wait for frida: %d", x);
usleep(990000);
}


LOG(" [+] Calling JNI_OnLoad\n");
onLoadFunc(vm, NULL);
LOG("JNI_OnLoad succeeded!");
return SYSTEST_JNI_VERSION;
}

frida 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
var OkHostnameVerifier = Java.use('com.nantian.nthttptool.okhttp3.internal.tls.OkHostnameVerifier');
OkHostnameVerifier.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
console.log(' --> Bypassing Trustkit OkHostnameVerifier(SSLSession): ' + a);
return true;
};
OkHostnameVerifier.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
console.log(' --> Bypassing Trustkit OkHostnameVerifier(cert): ' + a);
return true;
};

var CertificatePinner = Java.use("com.nantian.nthttptool.okhttp3.CertificatePinner");
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function (arg_0, arg_1) {
console.log("CertificatePinner->check (argType: java.lang.String): " + arg_0);
console.log("CertificatePinner->check (argType: java.util.List): " + arg_1);
return;
}


var WebViewClient = Java.use("android.webkit.WebViewClient");

WebViewClient.onReceivedSslError.implementation = function (webView, sslErrorHandler, sslError) {
console.log("WebViewClient onReceivedSslError invoke");
sslErrorHandler.proceed();
return;
};

var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var SSLContext = Java.use('javax.net.ssl.SSLContext');

var TrustManager = Java.registerClass({
name: 'com.sensepost.test.TrustManager',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function (chain, authType) {
},
checkServerTrusted: function (chain, authType) {
},
getAcceptedIssuers: function () {
return [];
}
}
});

var TrustManagers = [TrustManager.$new()];
var SSLContext_init = SSLContext.init.overload(
'[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
);
SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
console.log('[!] Successfully intercepted trustmanager request');
SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
};

持久化

依旧使用sandhook框架,使用lief添加依赖库的方式注入so,so中动态加载dex。

hook代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@HookReflectClass("com.nantian.nthttptool.okhttp3.internal.tls.OkHostnameVerifier")
public class Hook_OkHostnameVerifier {
public static String TAG = "zhighest_hook";


@HookMethod("verify")
@MethodReflectParams({"java.lang.String", "javax.net.ssl.SSLSession"})
public static Object verify_Hook1(Object thiz, String s, javax.net.ssl.SSLSession session) throws Throwable {
Log.d(TAG, "Bypassing com.nantian.nthttptool.okhttp3.internal.tls.OkHostnameVerifier.verify1()...");
return true;
}

@HookMethod("verify")
@MethodReflectParams({"java.lang.String", "java.security.cert.X509Certificate"})
public static Object verify_Hook1(Object thiz, String s, java.security.cert.X509Certificate certificate) throws Throwable {
Log.d(TAG, "Bypassing com.nantian.nthttptool.okhttp3.internal.tls.OkHostnameVerifier.verify2()...");
return true;
}


}