【Android 抓包对抗】代理检查绕过

android,对抗,代理,检查,绕过 · 浏览次数 : 335

小编点评

**代码简介** 该代码包含一个 Java 类 `OkHttpUtil`,其中包含了一个 `verify` 方法用于验证 SSL 证书是否合法。 **代码分析** 1. **`TrustAllManager` 类** * 该类注册了 `X509TrustManager` 类,并指定了 `checkClientTrusted` 和 `checkServerTrusted` 方法用于处理客户端和服务器证书。 2. **`MyHostnameVerify` 类** * 该类注册了 `HostnameVerifier` 类,并指定了 `verify` 方法用于验证证书中域名匹配的字符串。 3. **`ConnectivityManager` 类** * 该类用于获取网络连接信息,并设置一个回调函数来处理网络状态变化。 4. **`NetworkInfo` 类** * 该类用于表示网络连接的具体信息,包括是否已连接、协议等。 5. **`OkHttpUtil` 类** * 该类包含一个 `verify` 方法,用于验证 SSL 证书是否合法。该方法使用 `CertificatePinner` 类对证书进行验证。 6. **`main` 方法** * 该方法是一个主方法,负责加载类,初始化 `OkHttpUtil`,并设置网络连接回调。 * 在 `main` 方法中,使用 `try` 和 `catch` 块处理网络请求。 * 如果验证失败,打印错误信息并进行处理。 * 如果验证成功,打印流量日志信息并进行处理。 **注意** * 代码中没有显示 SSL 端口配置,假设证书在端口 443 上有效。 * `OkHttpUtil.verify` 方法使用 `CertificatePinner` 类对证书进行验证,证书的校验参数可能取决于 SSL 协议和证书类型。

正文

1. 安装apk,点进去发现一点就挂

2. apk 拖入到jadx中观察,发现多出检查,一旦满足条件就会退出

....
        if (((ConnectivityManager) getSystemService("connectivity")).getNetworkInfo(17).isConnected()) {
            stop();
        }
....
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                String name = networkInterfaces.nextElement().getName();
                if (name.equals("tun0") || name.equals("ppp0")) {
                    stop();
                }
            }
......
                        ConnectivityManager connectivityManager = (ConnectivityManager) OkHttpUtil.activityContext.getSystemService("connectivity");
                        if (Build.VERSION.SDK_INT >= 23 && connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork()).hasTransport(4)) {
                            System.exit(-1);
                        }
......

3. 编写frida绕过检查,防止app一进入就挂了

        var can_hook = false
        var ConnectivityManager = Java.use("android.net.ConnectivityManager");
        ConnectivityManager.getNetworkInfo.overload('int').implementation = function(){
            console.log("call getNetworkInfo function !!!")
            if(arguments[0] == 17){
                can_hook = true
            }
            var ret = this.getNetworkInfo(arguments[0])
            return ret
        }
 
        var NetworkInfo = Java.use("android.net.NetworkInfo")
        NetworkInfo.isConnected.implementation = function(){
            var ret = this.isConnected()
            if(can_hook){
                ret = false
                can_hook = false
                console.log("call isConnected function !!!")
            }
            return ret
        }

        var NetworkCapabilities = Java.use("android.net.NetworkCapabilities")
        NetworkCapabilities.hasTransport.implementation = function(){
            var ret = this.hasTransport(arguments[0])
            if(arguments[0] == 4){
                console.log("call hasTransport function !!!")
                ret = false
            }
            return ret
        }
 
        NetworkCapabilities.transportNameOf.overload('int').implementation = function(){
            console.log("call transportNameOf function !!!")
            var ret = this.transportNameOf(arguments[0])
            if(ret.indexOf("VPN") >= 0){
                ret = "WIFI"
            }
            return ret;
        }

        var NetworkInterface = Java.use("java.net.NetworkInterface")
        NetworkInterface.getAll.implementation = function(){
            var nis = this.getAll()
            console.log("call getAll function !!!")
            nis.forEach(function(ni){
                if (ni.name.value.indexOf("tun0")>=0 || ni.name.value.indexOf("ppp0")>=0 ){
                    ni.name.value = "xxxx"
                    ni.displayName.value = "xxxx"
                }
            })
            return nis
        }

成功让app可以进入,但是还是抓不到包

观察到和上一篇有一点出入的地方,设置了不让代理

builder.proxy(Proxy.NO_PROXY);

这里有两种解法,
一是hook 这个proxy方法
参考: https://www.freebuf.com/articles/terminal/249920.html
二是手机开启VPN,转发流量到charls上,这个方法的好处是更底层的流量代理,socket也找处理不误

操作方法:
1. 手机下载一个VPN软件,比如Brook
2. 点进去,选择socks5 然后填入charls监听的IP 和监听socks 的端口比如默认的8889
3. PC上操作charles, proxy -> Proxy Settings 点击enbale SOCKS proxy
这样操作APP时,就可以在Charles上看到流量了

4. 但还是看不到流量数据,这是因为代码中有一些检查,通过观察堆栈日志,需要追加以下代码,绕过日志中的报错检查

        var MainActivity = Java.use("com.dta.dtawallpaper.MainActivity$4");
        MainActivity["onFailure"].implementation = function (call, iOException) {
            console.log("***************************")
            console.log(Java.use("android.util.Log").getStackTraceString(iOException));
            this.onFailure(call, iOException);
        };

        var CertificatePinner = Java.use("okhttp3.CertificatePinner");
        CertificatePinner["check$okhttp"].implementation = function (hostname, cleanedPeerCertificatesFn) {
        
        };

        var OkHttpUtil = Java.use("com.dta.dtawallpaper.util.OkHttpUtil$1");
        OkHttpUtil["verify"].implementation = function (str, sSLSession) {
            return true
        };

5. 整体代码为

function main(){
    Java.perform(function (){
 
        //TrustAllManager
        var TrustAllManagerClass = Java.registerClass({
            name: "TrustAllManager",
            implements:[Java.use("javax.net.ssl.X509TrustManager")],
            methods: {
                checkClientTrusted(chain, authType) {
                    console.log("checkClientTrusted Called!!")
                },
                checkServerTrusted(chain, authType) {
                    console.log("checkServerTrusted Called!!")
                },
                getAcceptedIssuers() {
                  return [];
                },
              }
        })
        var trustAllManagerHandle = TrustAllManagerClass.$new()
 
        var sslContext = Java.use("javax.net.ssl.SSLContext").getInstance("TLS")
        var trustManagers = Java.array("Ljavax.net.ssl.X509TrustManager;",[trustAllManagerHandle])
        sslContext.init(null,trustManagers,null)
        var sslSocketFactory = sslContext.getSocketFactory()
 
        Java.use("okhttp3.OkHttpClient$Builder").sslSocketFactory.overload('javax.net.ssl.SSLSocketFactory', 'javax.net.ssl.X509TrustManager').implementation = function(arg0, arg1){
            console.log("sslSocketFactory Called!!")
            return this.sslSocketFactory(sslSocketFactory,trustAllManagerHandle)
        }
 
 
        //HostnameVerify
        var MyHostnameVerify = Java.registerClass({
            name: "MyHostnameVerify",
            implements:[Java.use("javax.net.ssl.HostnameVerifier")],
            methods: {
                verify(hostname, session){
                    console.log(hostname)
                    return true
                }
            }
        })
        var myHostnameVerifyHandle = MyHostnameVerify.$new()
 
        Java.use("okhttp3.OkHttpClient$Builder").build.implementation = function(){
            this.hostnameVerifier(myHostnameVerifyHandle)
            console.log(this.hostnameVerifier)
            return this.build()
        }

        var can_hook = false
        var ConnectivityManager = Java.use("android.net.ConnectivityManager");
        ConnectivityManager.getNetworkInfo.overload('int').implementation = function(){
            console.log("call getNetworkInfo function !!!")
            if(arguments[0] == 17){
                can_hook = true
            }
            var ret = this.getNetworkInfo(arguments[0])
            return ret
        }
 
        var NetworkInfo = Java.use("android.net.NetworkInfo")
        NetworkInfo.isConnected.implementation = function(){
            var ret = this.isConnected()
            if(can_hook){
                ret = false
                can_hook = false
                console.log("call isConnected function !!!")
            }
            return ret
        }

        var NetworkCapabilities = Java.use("android.net.NetworkCapabilities")
        NetworkCapabilities.hasTransport.implementation = function(){
            var ret = this.hasTransport(arguments[0])
            if(arguments[0] == 4){
                console.log("call hasTransport function !!!")
                ret = false
            }
            return ret
        }
 
        NetworkCapabilities.transportNameOf.overload('int').implementation = function(){
            console.log("call transportNameOf function !!!")
            var ret = this.transportNameOf(arguments[0])
            if(ret.indexOf("VPN") >= 0){
                ret = "WIFI"
            }
            return ret;
        }

        var NetworkInterface = Java.use("java.net.NetworkInterface")
        NetworkInterface.getAll.implementation = function(){
            var nis = this.getAll()
            console.log("call getAll function !!!")
            nis.forEach(function(ni){
                if (ni.name.value.indexOf("tun0")>=0 || ni.name.value.indexOf("ppp0")>=0 ){
                    ni.name.value = "xxxx"
                    ni.displayName.value = "xxxx"
                }
            })
            return nis
        }

        var MainActivity = Java.use("com.dta.dtawallpaper.MainActivity$4");
        MainActivity["onFailure"].implementation = function (call, iOException) {
            console.log("***************************")
            console.log(Java.use("android.util.Log").getStackTraceString(iOException));
            this.onFailure(call, iOException);
        };

        var CertificatePinner = Java.use("okhttp3.CertificatePinner");
        CertificatePinner["check$okhttp"].implementation = function (hostname, cleanedPeerCertificatesFn) {
        
        };

        var OkHttpUtil = Java.use("com.dta.dtawallpaper.util.OkHttpUtil$1");
        OkHttpUtil["verify"].implementation = function (str, sSLSession) {
            return true
        };
    });

}
 
setImmediate(main)

成功看到流量日志
image

PS: 如果遇到一些问题 可以看一下是不是 SSL Proxying Settings中目的端口是不是没有配置导致的,在这里我踩了一点坑

与【Android 抓包对抗】代理检查绕过相似的内容:

【Android 抓包对抗】代理检查绕过

1. 安装apk,点进去发现一点就挂 2. apk 拖入到jadx中观察,发现多出检查,一旦满足条件就会退出 .... if (((ConnectivityManager) getSystemService("connectivity")).getNetworkInfo(17).isConnecte

【Android 抓包对抗】客户端证书和域名校验绕过

1. 按照之前的方式(https://www.cnblogs.com/gradyblog/p/17197707.html)进行抓包发现证书校验失败 SSL handshake with client failed: An unknown issue occurred processing the c

《吐血整理》高级系列教程-吃透Fiddler抓包教程(35)-Fiddler如何抓取微信小程序的包-下篇

1.简介 通过前边和宏哥的学习,我们了解到Android 7.0 之后增加了对第三方证书的限制,抓包工具(charles、fiddler等)提供的证书都无法通过校验,也就无法抓取HTTPS请求了,对测试工作影响很大。 最近更新的微信 7.0 也增加了第三方证书校验,导致无法正常抓包。 2.解决思路

《吐血整理》高级系列教程-吃透Fiddler抓包教程(32)-Fiddler如何抓取IOS系统中Flutter应用程序的包

1.简介 上一篇讲解了安卓手机可以通过VPN代理来抓取Flutter应用程序的包,iOS(iphone)同样使用上一篇中VPN方法(原理与android是一致的),同样需要使用到VPN,在iOS也有许多与drony功能类似的软件,大家可以自己选择自己喜欢的使用,宏哥这里使用的是Shadowrocke

《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(6)-Charles安卓手机抓包大揭秘

1.简介 Charles和Fiddler一样不但能截获各种浏览器发出的 HTTP 请求,也可以截获各种智能手机发出的HTTP/ HTTPS 请求。 Charles也能截获 Android 和 Windows Phone 等设备发出的 HTTP/HTTPS 请求。 今天宏哥讲解和分享Charles如何

使用 shell 脚本自动申请进京证 (六环外) —— debug 过程

写好的自动办理六环外进京证脚本跑不通,总是返回办理业务人数较多 (500) 错误,Charles / VNET 抓包、android 交叉编译 jq、升级 curl…都不起作用,最终还是神奇的 adb shell 帮了大忙,最后定位到根因,居然是用 shell 字符串长度作为数据长度导致的,这错误犯的有点低级……

《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(16)-Charles其他骚操作之大结局

1.简介 今天就说一些Charles的其他操作、以及抓包跨域的问题和常见的问题如何解决。到此Charles这一系列的文章也要和大家说再见了,其他什么小程序、Android7.0等等的问题可以查看宏哥的Fiddler系列文章,只不过是将Fiddler换成Charles而已。 2.模拟403/404 其

Unity 利用Cache实现边下边玩

现在手机游戏的常规更新方案都是在启动时下载所有资源更新,游戏质量高的、用户粘性大的有底气,先安装2个G,启动再更新2个G,文件小了玩家还觉得品质不行不想玩。 最近在做微信、抖音小游戏,使用他们提供的资源缓存方案,现在要转成Android APP, 也想用这种边下边玩的机制把首包做小。 其实很简单,直

一个 .NET 开源的地图组件库 - Mapsui

前言 今天大姚给大家分享一个.NET开源(MIT License)、免费、同时支持多平台框架(MAUI、WPF、Avalonia、Uno、Blazor、WinUI、Eto、.NET Android 和 .NET iOS)地图组件库:Mapsui。 项目源代码 支持的UI框架的NuGet包 创建Bla

【Android 逆向】VM Kali 中 charles 抓android https 协议

1. 虚拟机调成桥接模式(不用选择 复制物理网络链接状态) 2. 虚拟机中 打开 Charles 4. 选择 Proxy ->SSL Proxying Settings 1. 选择SSL Proxying 菜单 2. 勾选Enable SSL Proxying 3. 在include 中选择Add