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

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中目的端口是不是没有配置导致的,在这里我踩了一点坑

posted @ 2023-03-09 18:58  明月照江江  阅读(1478)  评论(0编辑  收藏  举报