Frida应用基础及APP https证书验证破解

栏目: 服务器 · 发布时间: 6年前

内容简介:Frida是适用于开发人员、逆向工程师和安全研究人员的轻量级Hook工具,它允许将JavaScript代码或库注入Windows、macOS、GNU / Linux、iOS、Android和QNX上的本机应用程序。此外, Frida还提供了一些基于Frida API构建的简单工具。Frida的四大特点:

一、Frida简介

1. 基础介绍

Frida是适用于开发人员、逆向工程师和安全研究人员的轻量级Hook工具,它允许将JavaScript代码或库注入Windows、macOS、GNU / Linux、iOS、Android和QNX上的本机应用程序。此外, Frida还提供了一些基于Frida API构建的简单工具。

Frida应用基础及APP https证书验证破解

Frida的四大特点:

  • 可编写脚本:将脚本注入黑盒进程,无须源代码即可劫持任何功能函数,监视加密API或跟踪私有应用程序代码;然后编辑,点击保存,即可查看结果,不需要进行编译或重新启动程序。
  • 可移植的:适用于Window、macOS、GNU / Linux、iOS、Android和QNX。从npm安装绑定的Node.js,从PyPI获取 Python 包,或通过其Swift绑定、.NET绑定、Qt / Qml绑定或C API使用Frida。
  • 免费的:Frida是并且将永远是免费软件(免费自由)。
  • 经过实战检验:现在安全人员正在使用Frida对大规模移动应用进行快速、深入的分析。 Frida拥有全面的测试套件,并经过多年的严格测试,涵盖了广泛的用例。

Frida访问地址:https://github.com/frida/frida。

2. 与其他Hook工具的对比

(1) Xposed的优缺点

  • 优点:在编写 Java 层hook插件的时候非常好用,这一点完全优越于FridaSubstrateCydia,因为它也是Android项目,可以直接编写Java代码调用各类api进行操作,而且可以安装到手机上直接使用。
  • 缺点:配置安装环境繁琐,兼容性差,在Hook底层的时候就很无助了。

(2) Frida的优缺点

  • 优点:配置环境简单,操作也很便捷,对于破解者来说开发阶段非常好用。支持Java层和Native层的hook操作,只是在Native层hook如果是非基本类型的话操作有点麻烦。
  • 缺点:因为它只适合破解者在开发阶段使用,因此它无法像Xposed那样用于实践。比如写一个微信外挂,用Frida写肯定不行,因为它无法在手机端运行。

(3) SubstrateCydia的优缺点

  • 优点:和Xposed类似可以运行在手机端。支持Java层和Native层的hook操作,但是Java层hook不怎么常用,用得比较多的是Native层的hook操作,因为它也是Android工程,可以调用系统api,操作更为方便。
  • 缺点:和Xposed一样安装配置环境烦琐,兼容性差。

以上3个 工具 可以说是现在用得最多的hook工具了,总结一句话就是,写Java层hook还是Xposed方便,写Native层hook适合用SubstrateCydia,而对于处在开发阶段的破解者来说,则还是Frida最靠谱。

二、Frida Hook示例

1. 连接Android设备

(1)需要一台已经root的Android设备(可以使用Android模拟器),支持4.2~6.0版本。

(2)需要使用来自Android SDK中的adb工具连接Android设备。

(3)在 https://github.com/frida/frida/releases 中下载相应的frida-server应用,示例使用夜神Android模拟器4.4版本,下载的frida服务端是frida-server-12.2.16-android-x86.xz。

(4)启动夜神Android模拟器4.4版本,运行adb devices命令,即可成功连接Android设备,如图2.1所示。

Frida应用基础及APP https证书验证破解

图2.1连接 Android 设备

(5)运行如下命令,将frida-server复制到Android设备上,提升权限并运行。

$ adb push frida-server /data/local/tmp/  
$ adb shell "chmod 777 /data/local/tmp/frida-server" 
$ adb shell "/data/local/tmp/frida-server &" 

(6)运行adb shell ps命令,查看frida-server已成功运行,如图2.2所示。

Frida应用基础及APP https证书验证破解

图2.2 Frida-Server 成功运行

(7)运行adb shell netstat命令,检查frida-server监听端口,默认为27042,如图2.3所示。

Frida应用基础及APP https证书验证破解

图2.3 端口监听成功

(8)运行adb forward tcp:27042 tcp:27042命令,把Android设备端口转发到PC端。

(9)运行frida-ps –R命令,即可查询Android设备当前运行进程,至此连接Android设备成功(见图2.4)。另外,也可以直接通过USB将Android设备与PC端连接,运行frida-ps –U即可测试是否连接成功。

Frida应用基础及APP https证书验证破解

图2.4  Android 设备连接成功检测

2. HTTPS单向认证强校验Hook示例

本次示例通过在本地搭建Tomcat + SSL自签名证书环境,使用一个开源的Android HTTPS双向认证项目:

https://github.com/Frank-Zhu/AndroidHttpsDemo ,对其中部分代码进行修改后重新编译,构建本次测试的 APP应用。

(1) 基本原理

想要绕过证书锁定抓明文包就需要先知道APP是如何进行锁定操作的,然后再针对其操作进行注入解锁。

Android客户端关于证书处理的逻辑按照安全等级分类,如表2.1所示。

Frida应用基础及APP https证书验证破解

表2.1 Android客户端证书处理的安全等级分类

Apache http client 因为从api23起被Android抛弃,因此使用率较低。目前更多使用的是HttpURLConnection类或第三方库OKhttp3.0进行HTTPS通信。其中OKhttp3.0的部分运用与HttpURLConnection相同,客户端都可以通过实现X509TrustManager接口的checkServerTrusted方法,将服务器证书与APP预埋证书做对比,来完成强校验。此外,也可以再通过实现HostnameVerifier接口的verify方法,校验服务器证书中的一般名称(CN)是否与域名相符。通过使用上述方法,完成客户端对服务端的证书强校验。

(2) 应用分析

由于这次是自编译的文件,就不通过APK反编译等方法查看代码了,直接看主要通信类HttpClientSslHelper的源码。

public class HttpClientSslHelper { 
    public static boolean isServerTrusted1 = true;  //强校验关键参数 
    private static SSLContext sslContext = null; 
    public static OkHttpClient getSslOkHttpClient(Context context) { 
        OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
        builder.sslSocketFactory(getSslContextByCustomTrustManager(context).getSocketFactory()) 
                .hostnameVerifier(new HostnameVerifier() { 
                    @Override  //实现自定义的HostnameVerifier 对象的verify校验方法 
                    public boolean verify(String hostname, SSLSession session) { 
                        Log.d("HttpClientSslHelper", "hostname = " + hostname); 
                        if ("192.168.96.1".equals(hostname)) { 
                            //根据isServerTrusted1的值进行校验,若为True,则校验成功,执行后续连接 
                            return isServerTrusted1; 
                        } else { 
                            //由于是实验环境,if语句总为真,不会执行else语句 
                            HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier(); 
                            return hv.verify("localhost", session); 
                        } 
                    } 
                }); 
        return builder.build(); 
    } 
 
    public static SSLContext getSslContextByCustomTrustManager(Context context) { 
        if (sslContext == null) { 
            try { 
                CertificateFactory cf = CertificateFactory.getInstance("X.509","BC"); 
                InputStream caInput = new BufferedInputStream(context.getResources().getAssets().open("server.cer")); 
                final Certificate ca; 
                try { 
                    ca = cf.generateCertificate(caInput); 
                } finally { 
                    caInput.close(); 
                } 
                sslContext = SSLContext.getInstance("TLS"); 
                //自定义X509TrustManager接口的checkClientTrusted、checkServerTrusted和getAcceptedIssuers方法 
                sslContext.init(null, new X509TrustManager[]{new X509TrustManager() { 
                    public void checkClientTrusted(X509Certificate[] chain, 
                                                   String authType) throws CertificateException { 
                        Log.d("HttpClientSslHelper", "checkClientTrusted --> authType = " + authType); 
                        //校验客户端证书 
                    } 
 
                    public void checkServerTrusted(X509Certificate[] chain, 
                                                   String authType) throws CertificateException { 
                        Log.d("HttpClientSslHelper", "checkServerTrusted --> authType = " + authType); 
                        //校验服务器证书 
                        for (X509Certificate cert : chain) { 
                            cert.checkValidity(); 
                            try { 
                                 //关键点,用APP中内置的服务端证书server.cer来校验网络连接中服务器颁发的证书 
                                cert.verify(ca.getPublicKey()); 
                            } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException | SignatureException e) { 
                                e.printStackTrace(); 
                                //校验失败,则更改isServerTrusted1值为false 
                                isServerTrusted1 = false; 
                            } 
                        } 
                    } 
 
                    public X509Certificate[] getAcceptedIssuers() { 
                        return new X509Certificate[0]; 
                    } 
                }}, null); 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } 
        } 
        return sslContext; 
    } 
} 

由上可知,将HttpClientSslHelper类的getSslContextByCustomTrustManager方法重写,重新实现checkServerTrusted方法,让其不修改isServerTrusted1的值,即可绕过证书强校验。

(3) 开始Hook

重新实现checkServerTrusted方法

构造完整脚本如下:

import frida, sys 
  
def on_message(message, data): 
    if message['type'] == 'send': 
        print("[*] {0}".format(message['payload'])) 
    else: 
        print(message) 
  
jscode = """ 
Java.perform(function () { 
    var HttpClientSslHelper = Java.use('com.frankzhu.androidhttpsdemo.HttpClientSslHelper'); 
    var Log = Java.use('android.util.Log'); 
    HttpClientSslHelper.getSslContextByCustomTrustManager.implementation = function () { 
        var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); 
        var SSLContext = Java.use('javax.net.ssl.SSLContext'); 
        var TrustManager = Java.registerClass({ 
            name: 'com.frankzhu.androidhttpsdemo.test', 
            implements: [X509TrustManager], 
            methods: { 
                checkClientTrusted: function (chain, authType) { 
                }, 
                checkServerTrusted: function (chain, authType) { 
                    Log.d("Frida Hook checkServerTrusted()", "Success!!!"); 
                    send("Frida Hook checkServerTrusted() Success!!!"); 
                }, 
                getAcceptedIssuers: function () { 
                    return []; 
                } 
            } 
        }); 
        // Prepare the TrustManagers array to pass to HttpClientSslHelper.sslContext.init() 
        var TrustManagers = [TrustManager.$new()]; 
        send("Custom, Empty TrustManager ready"); 
        // Override the init method, specifying our new TrustManager 
        var sslContext = SSLContext.getInstance("TLS"); 
        sslContext.init(null, TrustManagers, null); 
        //return的值类型必须与原来的相同,否则会出现Error: Implementation for getSslContextByCustomTrustManager expected return value compatible with 'javax.net.ssl.SSLContext',同时导致应用崩溃 
        //源码里有private static SSLContext sslContext = null;如果想通过this.sslContext使用该变量,一定要注意Hook的时机,要在sslContext变为对象后再Hook,这样就不会出现应用异常崩溃 
        return sslContext; 
    } 
}); 
""" 
  
process = frida.get_remote_device().attach('com.frankzhu.androidhttpsdemo') 
script = process.create_script(jscode) 
script.on('message', on_message) 
script.load() 
sys.stdin.read() 

测试步骤:

  • 使用Burpsuite,设置PC端和Android端的代理;
  • 打开测试APP,运行上述Python脚本;
  • 点击APP网络测试按钮,发送网络请求(一定要在第一次点击按钮前,运行Python脚本)。

未用Frida Hook的结果如图2.5、图2.6所示。

Frida应用基础及APP https证书验证破解

图2.5  连接报错

Frida应用基础及APP https证书验证破解

图2.6  HTTPS 抓包失败

使用Frida Hook后的结果如图2.7~图2.9所示。

Frida应用基础及APP https证书验证破解

图2.7  脚本运行成功

Frida应用基础及APP https证书验证破解

图2.8  运行日志

Frida应用基础及APP https证书验证破解

图2.9   HTTPS 证书验证破解成功


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Data Mining

Web Data Mining

Bing Liu / Springer / 2006-12-28 / USD 59.95

Web mining aims to discover useful information and knowledge from the Web hyperlink structure, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is n......一起来看看 《Web Data Mining》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具