APP反抓包 - 客户端证书验证进阶(代码混淆)

发布于:2024-05-14 ⋅ 阅读:(183) ⋅ 点赞:(0)

1.关于混淆

  • 在安卓开发中,对于第三方的包是可以进行混淆的,例如:OKHttp3.Http.Cert.check 被混淆后可以是a.f.c.b 形式。
  • 在安卓开发中,系统包是无法混淆的,例如:java.security.KeyStore不会被混淆。

由于这种的情况的存在,再次审示我们之前的通用脚本,就会发现他是不通用的,例如:

  • 客户端证书校验的frida脚本【不通用,被混淆后无法用】

    Java.use('okhttp3.CertificatePinner');  
    Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
    
  • 服务端证书校验的frida脚本【通用】

    Java.use("java.security.KeyStore");
    

那如果遇到有存在混淆的app,内部又加入了客户端证书校验,原来的绕过方式就都不能用来,怎么解决呢?

  • Hook系统底层必走的核心方法,获取调用栈
  • 根据调用栈向上寻找 客户端证书校验 代码位置,找其他被混淆后的 类名和方法名
  • 用frida Hook脚本的方式绕过

如下图:未混淆时,客户端证书校验的三个位置:

在这里插入图片描述

如下图:app混淆后,代码会变成这样:

在这里插入图片描述

2.客户端校验和系统方法

客户端校验的顺序分别是:

  • 第1步:调用证书校验
    在这里插入图片描述

  • 第2步:主机校验
    在这里插入图片描述

  • 第3步:pinner公钥校验,这个校验过程本质上是调用CertificatePinner类中的check方法。
    在这里插入图片描述

**注意:**内部按照顺序对这3个过程进行校验,只要有一个无法通过,后续的校验就不会再触发执行。

上述三个校验的触发位置是在:okhttp3.internal.connection.RealConnection类中的connectTls方法,例如:

在这里插入图片描述

2.1 调用栈

我是怎么确定触发校验的位置就是这里的?

最简单的方式就是对我们已开发完成的安卓程序(NetDemo)案例进行Hook,根据他们的调用栈来证明,例如:

Log.e("调用栈", Log.getStackTraceString(new Throwable()));

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.2 Hook系统位置

在上述调用栈中发现在证书校验时,底层会走 com.android.org.conscrypt.NativeSsldoHandshake方法。

所以,可以Hook他,根据调用栈向上找到证书校验的位置(其他验证也在旁边)。

Java.perform(function () {
   
    var NativeSsl = Java.use('com.android.org.conscrypt.NativeSsl');
    NativeSsl.doHandshake.overload('java.io.FileDescriptor', 'int').implementation = function (a, b) {
   
        console.log("参数:", a, b);
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
        return this.doHandshake(a, b);
    };
});

// frida -UF -l 1.hook_check.js

在这里插入图片描述

对比未混淆和混淆的代码,可以找到相应的证书监测的位置:

在这里插入图片描述

3.滴答清单(案例)

以滴答清单(v6.3.3.0)为例,来展开代码混淆处理的过程。

3.1 现象

打开app,进入注册界面,点击【发送验证码】

  • 未设置代理,可以发送成功
  • 已设置代理,请求发送失败

在这里插入图片描述

那么,内部应该可能是做了客户端校验。

但是,使用justrustme 和 frida 脚本依然不好使,哪就有可能是内部进行了代码混淆。

3.2 寻找connectTls

因为触发客户端校验的位置是在:okhttp3.internal.connection.RealConnection类中的connectTls方法中,所以,我们可以先寻找到这个位置,看他被混淆成了啥?

在这里插入图片描述

可以通过hook系统方法 + 输入调用栈,定位 RealConnection类的connectTls方法

Java.perform(function () {
   
    var NativeSsl = Java.use('com.android.org.conscrypt.NativeSsl');
    NativeSsl.doHandshake.overload('java.io.FileDescriptor', 'int').implementation = function (a, b) {
   
        console.log("参数:", a, b);
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
        return this.doHandshake(a, b);
    };
});

// frida -UF -l 1.hook_check.js

在这里插入图片描述

在这里插入图片描述

3.3 pinner校验

3.3.1 寻找位置

pinner校验比较常见,在这里也比较简单:

aVar2.f28365k.a(aVar2.f28355a.f28521d, a11.f28513c);

- 在安卓开发中,这个a方法其实就是 CertificatePinner类中的check方法
- 并且 aVar2.f28365k 返回的就是CertificatePinner类

在这里插入图片描述

在这里插入图片描述

所以,我们参考之前hook的check方法,来编写hook脚本,对此方法进行hook,例如:

在这里插入图片描述

Java.perform(function () {
   
    var pinner = Java.use('rk.f');
    pinner.a.overload('java.lang.String', 'java.util.List').implementation 

网站公告

今日签到

点亮在社区的每一天
去签到