对app的反爬测试之apk逆向分析-frida绕过sslpinning检测

对app的反爬测试之apk逆向分析-frida绕过sslpinning检测

2023年6月30日发(作者:)

对app的反爬测试之apk逆向分析-frida绕过sslpinning检测前⾔:

受⼈所托,需要对他们的产品进⾏反爬测试,所以就有了以下内容。

不过,我知道,针对这⽅⾯的⽂章太多了,是真的多,⽽且好早就有了,但是⽬前为⽌,很多app的防护基本也还是⽤的ssl pinning检测证书。因为,⽬前的app要嘛不⽤ssl,要嘛⽤就是⼀般的ssl,基本就是在⼿机上装个相关软件 的代理即可,⽽且这个代理基本就是fiddler,charlels,burpsuite,mitmproxy(Python环境下的)四个抓包软件⾃带的ssl证书,然后即可抓到ssl(https)的请求以上这些,基本可以解决⼤部分的app(其实很多使⽤ssl的⽹站也是这样处理)

但是因为很多app为了防⽌数据被分析爬取,会做ssl pinning验证

>

ssl painning

SSL Pinning是⼀种防⽌中间⼈攻击(MITM)的技术,主要机制是在客户端发起请求–>收到服务器发来的证书进⾏校验,如果收到的证书不被客户端信任,就直接断开连接不继续求情。所以在遇到对关键请求开启SSL Pinning的APP时,我们抓包就只能看到APP上提⽰⽆法连接⽹络或者请求失败之类的提⽰;⽽在抓包⼯具上⾯,要么就只能看到⼀排 CONNECT 请求,获取到证书却没有后续了,要么就是⼀些⽆关的请求,找不到想要的接⼝

⽐如如下图:

针对这种,如果是web⽹站,我们都知道,在本地装下抓包软件⾃带的ssl证书就⾏了,但是app的话,如此操作之后还是不⾏,⽽且app还会提⽰没⽹(⽐如:⽹络连接失败,⽹络有问题等等的),反正意思就是没⽹的意思,这种就是因为app⾃⾝做了ssl pinning验证处理,验证下当前的ssl证书是否是合法允许的,如果不是就会验证失败

其实使⽤ssl pinning⽬前已经成为了趋势,那么我们的⽬前对象刚好就有这个怎么办呢?

⽬前根据我的经验,最有效的有三个⽅法:

1.使⽤低版本的安卓机抓包2.使⽤ios端⼿机抓包3.使⽤frida绕过证书处理

>

使⽤低版本的安卓机抓包

因为app的话,⽬前主流的都是⽤的前后端分离开发,所以越到后期,app更新新版后,越会有不同版本的后端接⼝存在,⽽且新版接⼝和⽼版接⼝其实返回的数据差异性很⼩,并且有个关键点就是,为了兼容性,会依旧留下旧版接⼝,因为每个⽤户使⽤的⼿机不⼀样,安卓或者ios版本不同,系统版本也就会不同,且⽼款⼿机因为内存太⼩,不会更新新版的app包,种种情况下来,结果就是会留下旧版接⼝,⽽且这个旧版接⼝安全性⽐新版低很多,所以可以⽤低版本的饿安卓机来抓包,就正常的抓包流程即可,不出意外的话,可能还⽤的普通的http请求。为什么⾼版本的安卓就抓不到包呢,因为⾼版本的(安卓7以上)开始,安卓⾃带了⼀些安全机制,本质上就是只信任系统证书,不再信任⽤户⾃⼰安装的证书了,我们装的ssl代理证书就是⾃⼰装的,所以就会验证不通过了

>

使⽤ios端⼿机抓包

这个情况真的很多,因为,苹果端的appstore管理得很严,不能加些⾃⼰独特的东西,但是加ssl是可以的,但是很多app并没有加我就不知道了,这个情况就很简单,需要⼀台iphone,其他都是正常抓包操作,然后安装证书,把证书信任下就⾏了,详细的操作就不说了,⽹上很多教程

>

使⽤frida绕过证书处理

这个⽅法就是本篇⽂章的重点了,这个放到后⾯再说 >

其他⽅法其实也有其他的⽅法,这些⽅法并不是通⽤的,可能运⽓好可以⽤,运⽓不好就没⽤:

>> 安卓模拟器

⽤安卓模拟器,模拟低版本安卓然后抓包

>> 对证书信任,修改APP设置

看这个app是否是⾃有app,如果是⾃有的,⾕歌有debug模式,该模式下让app默认可以信任⽤户域的证书(trust-anchors),如果是⾮⾃有,⽤xposed+JustTrustMe即可,但是使⽤Xposed框架需要root,⽹上那些微信魔改⼩功能,什么⾃动抢红包,防消息撤回之类的就是⽤的xposed框架改的,⽤JustTrustMe来信任⽤户安装的证书⽬前市⾯上有VitualXposed、太极等虚拟的框架,不⽤root也可以操作,太极这个软件挺好的,有太极-阴(免root)和太极-阳(需要root),两个版本都可以⽤,但是针对有些app的话,太极-阴没戏,只能太极-阳,但是既然我都已经root了,我就没必要整这些了。

>> 强制信任证书

具体步骤:

s导出.pem证书,选择.prm类型 保存在pc上

2.修改证书名称系统证书⽬录:/system/etc/security/cacerts/

其中的每个证书的命名规则如下:.⽂件名是⼀个Hash值,⽽后缀是⼀个数字。

⽂件名可以⽤下⾯的命令计算出来:openssl x509 -subject_hash_old -in

后缀名的数字是为了防⽌⽂件名冲突的,⽐如如果两个证书算出的Hash值是⼀样的话,那么⼀个证书的后缀名数字可以设置成0,⽽另⼀个证书的后缀名数字可以设置成1

3. ⽤adb命令把证书推到⼿机上adb push xxxxxxx.0 /sdcard/

4.复制到系统⽬录并修改权限(安卓8.1.0 Magisk Root)

mount -o rw,remount /system 【不修改 没法写⼊】mount -o rw,remount /

mv /sdcard/xxxxxxx.0 /etc/security/cacerts/ 移动⽂件到系统chown root:root /etc/security/cacerts/fc365f9d.0 修改⽤户组chmod 644 /system/etc/security/cacerts/xxxxxxx.0 修改权限

5. 重启⼿机验证即可这时你就发现证书已经在系统级别⾥了

6.进⾏抓包

补充:

这个是安卓端的抓包⼯具,⽹上吹得很⽕,根据我(我⼿机是安卓10)亲⾃操作,发现其实没有⽤,也不知道是不是我的姿势错误,或者我⼿机安卓系统版本太⾼了失效

⽤这个可以免root操作,然后正常抓包,但是这个⽅法我没有实际操作过,⽹上的资料不多,⾃⾏查找

Xposed 是⼀款 Android 端的 Hook ⼯具,利⽤它我们可以 Hook App ⾥⾯的关键⽅法的执⾏逻辑,绕过 HTTPS 的证书校验过程。JustTrustMe 是基于 Xposed ⼀个插件,它可以将 HTTPS 证书校验的部分进⾏ Hook,改写其中的证书校验逻辑,这种思路是属于第⼆种绕过 HTTPS 证书校验的解决⽅案。

当然基于 Xposed 的类似插件也有很多,如 SSLKiller、sslunpining 等等,可以⾃⾏搜索。

不过 Xposed 的安装必须要 ROOT,如果不想 ROOT 的话,可以使⽤后⽂介绍的 VirtualXposed。

Xposed 的使⽤需要 ROOT,如果不想 ROOT 的话,可以直接使⽤⼀款基于 VirtualApp 开发的 VirtualXposed ⼯具,它提供了⼀个虚拟环境,内置了 Xposed。我们只需要将想要的软件安装到 VirtualXposed ⾥⾯就能使⽤ Xposed 的功能了,然后配合 JustTrustMe 插件也能解决 SSL Pining 的问题,这种思路是属于第⼆种绕过 HTTPS 证书校验的解决⽅案。

>> 特殊改写

其实本质上是对⼀些关键的校验⽅法进⾏了 Hook 和改写,去除了⼀些校验逻辑。但是对于⼀些代码混淆后的 App 来说,其校验 HTTPS 证书的⽅法名直接变了,那么JustTrustMe 这样的插件就⽆法 Hook 这些⽅法,因此也就⽆效了。

>> 强制全局代理

⼿机root后,使⽤proxy Droid 实现强制全局代理,让ssl代理证书⽣效,proxy Droid可以在UpToDown,ApkHere等的地⽅下载

抓包免root,在安卓机上安装packet capture,然后抓包,我试了下,我的⼿机(我⼿机是安卓10)没⽤ >> 魔改JustTrustMe在JustTrustMe插件上增加⼀个可以运⾏时根据实际情况调整ssl检测的功能,对hook增加动态适配,这个⽅法我没试过,我在看雪论坛⾥找到⼀个 JustTrustMePlus,

>> 反编译app包⽤apktools修改配置⽂件⾥的ssl证书检测部分,可利⽤jadx等⼯具分析源码,然后重新打包,再抓包分析,这个⽅法是可⾏的,详细的步骤⾃⾏百度吧,后续有时间的话,我单独发⼀篇对app的脱壳重新打包

处理这个⼯具的原理就是把⼀个安卓机在本地作为⼀台服务器,然后找到数据接⼝,这个⽅法没有亲测过,更多的适⽤于获取app的sign/token时去获取接⼝

以上的⽅法就是我所知道的⽅法,各位朋友⾃⾏操作

接下来进⼊正题,frida hook

什么是frida

Frida是个轻量级别的hook框架, 是Python API,⽤JavaScript调试来逻辑Frida的核⼼是⽤C编写的,并将注⼊到⽬标进程中,在这些进程中,JS可以完全访问内存,挂钩函数甚⾄调⽤进程内的本机函数来执⾏。使⽤Python和JS可以使⽤⽆风险的API进⾏快速开发。Frida可以帮助您轻松捕获JS中的错误并为您提供异常⽽不是崩溃。

frida是平台原⽣app的Greasemonkey,说的专业⼀点,就是⼀种动态插桩⼯具,可以插⼊⼀些代码到原⽣app的内存空间去,(动态地监视和修改其⾏为),这些原⽣平台可以是Win、Mac、Linux、Android或者iOS。⽽且frida还是开源的。Greasemonkey可能⼤家不明⽩,它其实就是firefox的⼀套插件体系,使⽤它编写的脚本可以直接改变firefox对⽹页的编排⽅式,实现想要的任何功能。⽽且这套插件还是外挂的,⾮常灵活机动。

frida框架主要分为两部分:1)⼀部分是运⾏在系统上的交互⼯具frida CLI。2)另⼀部分是运⾏在⽬标机器上的代码注⼊⼯具 frida-server

注:以下相关操作,终端⾥凡是 C:UsersAdministrator 开头的都是在pc机上操作的,需要在安卓机⽬录⾥操作的我都有说明,不要搞混了

环境准备

>

安装frida没有python的安装python,然后安装frida:pip install fridapip install frida-tools 安装过程很慢,这个只能耐⼼等待,然后如果你是macbook的话,如果你遇到安装出错,可以看看我这篇⽂章的解决⽅法

然后frida是mac,linux,windows都可以安装使⽤的,这个根据你⾃⼰的条件选择了>

安装adb这个就很简单,去 然后下载这个⼯具:

如果你下载太慢可以在我这⾥下载:下载完毕后,解压,然后放到你想放的路径,然后配置下环境变量即可,此电脑(我的电脑)- 属性-⾼级系统设置-环境变量-系统变量的path,新增即可

然后,打开终端:

敲adb,回车,如果有以下提⽰,说明你adb安装成功

以上配置是windows平台,如果是其他平台的话,⾃⾏查找,这⾥就不展⽰了

>

找⼀个安卓机(已root)根据现在的⾏情,要找到⼀个已root的⼿机,问题不⼤也不⼩,但是很多时候没有必要,所以我这⾥就选择⽤安卓模拟器来辅助操作了安装夜神模拟器,夜神默认是安卓5,你可以⾃⾏选择安卓版本,在夜神⾥设置已root即可

>

打开开发者选项⾥的USB调试

设置⾥⾯,关于本机,然后狂点系统版本号,开启开发者模式:

返回,会多⼀个开发者选项:

打开调试

>

adb连接安卓机(模拟器)

在安装了frida和adb的真机操作系统下,打开终端,⽤ adb connect IP 连接安卓机:

夜神的ip是127.0.0.1:62001,这⾥注意,如果你创建了多个安卓系统的话,那么你待连接的安卓机不⼀定是62001,可能是其他的,可以在安装⽬录⾥⾯找

进⼊后,找⽂件

⽤⽂本编辑器打开,搜索5555就能看到是哪个端⼝了,为什么必须是5555端⼝呢,因为5555就是模拟器挂载在我们windows真机上的端⼝

⽤ adb connect 127.0.0.1:端⼝ 连接

我这⾥已经连接上了,所以提⽰已连接

连接之后可以⽤ adb devices查看已连接的机器:

>

安装frida-serverfrida-server这个需要安装在安卓机上,但是安卓机我们都知道有很多个版本,对应架构才⾏,要查看当前安卓机的架构:adb shell getprop  

然后去这⾥下载对应架构的frida-server :

我这⾥是x86,安卓,所以选下⾯我选中那个下载,你的安卓机是什么你就选哪个就⾏了

然后下载很慢,我这⾥也提供了,

但是,⼀定注意,pip安装的frida版本⼀定要跟去frida官⽹下载的frida-server版本对应上,不然连不上

解压,然后⽤adb 传到安卓机上adb push (本机的frida-sever⽂件所在⽬录) (安卓机⽬录)  

这⾥提⽰太长了,看不出来,可以⽤adb shell 去那个⽬录下看下是否有frida-server即可:

修改frida-server的权限:chmod 700 frida-server  

>

下载⼀个frida hook 的js⽂件

这个⽂件,有好⼏个版本,我选⽤了两个版本,放到下⾯,你们⾃⼰选择吧

版本1:

setTimeout(function(){ m(function (){ (""); ("[.] Cert Pinning Bypass/Re-Pinning"); var CertificateFactory = ("icateFactory"); var FileInputStream = ("putStream"); var BufferedInputStream = ("edInputStream"); var X509Certificate = (".X509Certificate"); var KeyStore = ("re"); var TrustManagerFactory = ("anagerFactory"); var SSLContext = ("text"); // Load CAs from an InputStream ("[+] Loading ") cf = tance("X.509");

try { var fileInputStream = FileInputStream.$new("/data/local/tmp/"); } catch(err) { ("[o] " + err); } var bufferedInputStream = BufferedInputStream.$new(fileInputStream); var ca = teCertificate(bufferedInputStream); (); var certInfo = (ca, X509Certificate); ("[o] Our CA Info: " + jectDN()); // Create a KeyStore containing our trusted CAs ("[+] Creating a KeyStore for "); var keyStoreType = aultType(); var keyStore = tance(keyStoreType); (null, null); tificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore ("[+] Creating a TrustManager that trusts the CA in "); var tmfAlgorithm = aultAlgorithm(); var tmf = tance(tmfAlgorithm); (keyStore); ("[+] Our TrustManager "); ("[+] Hijacking SSLContext ") ("[-] Waiting for the app to invoke ()...") ad("[ager;", "[anager;", "Random").implementation = function(a,b,c) { ("[o] App invoked ..."); ad("[ager;", "[anager;", "Random").call(this, a, stManagers(), c); ("[+] SSLContext initialized with our custom TrustManager!"); } });},0);  版本2:m(function() { var array_list = ("ist"); var ApiClient = ('anagerImpl'); entation = function(a1, a2, a3, a4, a5, a6) { // ('Bypassing SSL Pinning'); var k = array_list.$new(); return k;

}}, 0);  然后你⾃⼰复制以上的任何⼀个版本的代码,然后在本地新建⼀个js⽂件,粘贴进去就⾏了

或者这个:

这⾥补充⼀个完全版:

m(function() {/*hook list:k_security_config (android 7.0+) Http client (support partly)*/ // Attempts to bypass SSL pinning implementations in a number of // ways. These include implementing a new TrustManager that will // accept any SSL certificate, overriding OkHTTP v3 check() // method etc. var X509TrustManager = ('.X509TrustManager'); var HostnameVerifier = ('meVerifier'); var SSLContext = ('text'); var quiet_output = false; // Helper method to honor the quiet flag. function quiet_send(data) { if (quiet_output) { return; } send(data) } // Implement a new TrustManager // ref: /oleavr/3ca67a173ff7d207c6b8c3b0ca65a9d8 // erClass() is only supported on ART for now(201803). 所以android 4.4以下不兼容,4.4要切换成ART使⽤. /*06-07 16:15:38.541 27021-27073/ningdemo W/: lArgumentException: Required method checkServerTrusted(X509Certificate[], String, String, String) missing06-07 16:15:38.542 27021-27073/ningdemo W/: at .X509TrustManagerExtensions.(:73) at ingTrustManger.(:61)06-07 16:15:38.543 27021-27073/ningdemo W/: at PinningClient(:112) at (:62) at tivity$1$(:36)*/ var X509Certificate = (".X509Certificate"); var TrustManager; try { TrustManager = erClass({ name: 'anager', implements: [X509TrustManager], methods: { checkClientTrusted: function(chain, authType) {}, checkServerTrusted: function(chain, authType) {}, getAcceptedIssuers: function() { // var certs = [X509Certificate.$new()]; // return certs; return []; } } }); } catch (e) { quiet_send("registerClass from X509TrustManager >>>>>>>> " + e); } // Prepare the TrustManagers array to pass to () var TrustManagers = [TrustManager.$new()]; try { // Prepare a Empty SSLFactory var TLS_SSLContext = tance("TLS"); TLS_(null, TrustManagers, null); var EmptySSLFactory = TLS_ketFactory(); } catch (e) { quiet_send(e); } send('Custom, Empty TrustManager ready'); // Get a handle on the init() on the SSLContext class var SSLContext_init = ad( '[ager;', '[anager;', 'Random'); // Override the init method, specifying our new TrustManager SSLContext_entation = function(keyManager, trustManager, secureRandom) { quiet_send('Overriding () with the custom TrustManager'); SSLContext_(this, null, TrustManagers, null); }; /*** okhttp3.x unpinning ***/ // Wrap the logic in a try/catch as not all applications will have // okhttp as part of the app. try { var CertificatePinner = ('icatePinner'); quiet_send('OkHTTP 3.x Found'); ad('', '').implementation = function() { quiet_send('OkHTTP 3.x check() called. Not throwing an exception.'); } } catch (err) { // If we dont have a ClassNotFoundException exception, raise the // problem encountered. if (f('ClassNotFoundException') === 0) { throw new Error(err); } } // Appcelerator Titanium PinningTrustManager // Wrap the logic in a try/catch as not all applications will have // appcelerator as part of the app. try { var PinningTrustManager = ('gTrustManager'); send('Appcelerator Titanium Found'); entation = function() { quiet_send('Appcelerator checkServerTrusted() called. Not throwing an exception.'); } } catch (err) { // If we dont have a ClassNotFoundException exception, raise the // problem encountered. if (f('ClassNotFoundException') === 0) { throw new Error(err); } } /*** okhttp unpinning ***/ try { var OkHttpClient = ("Client"); entation = function(certificatePinner) { // do nothing quiet_send("tificatePinner Called!"); return this; }; // Invalidate the certificate pinnet checks (if "setCertificatePinner" was called before the previous invalidation) var CertificatePinner = ("icatePinner"); ad('', '[icate;').implementation = function(p0, p1) { // do nothing quiet_send("okhttp Called! [Certificate]"); return; }; ad('', '').implementation = function(p0, p1) { // do nothing quiet_send("okhttp Called! [List]"); return; }; } catch (e) { quiet_send(" not found"); } /*** WebView Hooks ***/ /* frameworks/base/core/java/android/webkit/ */ /* public void onReceivedSslError(Webview, SslErrorHandler, SslError) */ var WebViewClient = ("wClient"); entation = function(webView, sslErrorHandler, sslError) { quiet_send("WebViewClient onReceivedSslError invoke"); //执⾏proceed⽅法 d(); return; }; ad('w', 'int', '', '').implementation = function(a, b, c, d) { quiet_send("WebViewClient onReceivedError invoked"); return; }; ad('w', 'ourceRequest', 'ourceError').implementation = function() { quiet_send("WebViewClient onReceivedError invoked"); return; }; /*** JSSE Hooks ***/ /* libcore/luni/src/main/java/javax/net/ssl/ */ /* public final TrustManager[] getTrustManager() */ /* stManagers maybe cause X509TrustManagerExtensions error */ // var TrustManagerFactory = ("anagerFactory"); // entation = function(){ // quiet_send("TrustManagerFactory getTrustManagers invoked"); // return TrustManagers; // } var HttpsURLConnection = ("RLConnection"); /* libcore/luni/src/main/java/javax/net/ssl/ */ /* public void setDefaultHostnameVerifier(HostnameVerifier) */ entation = function(hostnameVerifier) { quiet_send("aultHostnameVerifier invoked"); return null; }; /* libcore/luni/src/main/java/javax/net/ssl/ */ /* public void setSSLSocketFactory(SSLSocketFactory) */ entation = function(SSLSocketFactory) { quiet_send("SocketFactory invoked"); return null; }; /* libcore/luni/src/main/java/javax/net/ssl/ */ /* public void setHostnameVerifier(HostnameVerifier) */ entation = function(hostnameVerifier) { quiet_send("tnameVerifier invoked"); return null; }; /*** Xutils3.x hooks ***/ //Implement a new HostnameVerifier var TrustHostnameVerifier; try { TrustHostnameVerifier = erClass({ name: 'ostnameVerifier', implements: [HostnameVerifier], method: { verify: function(hostname, session) { return true; } } }); } catch (e) { //otFoundException: Didn't find class "ostnameVerifier" quiet_send("registerClass from hostnameVerifier >>>>>>>> " + e); } try { var RequestParams = ('tParams'); entation = function(sslSocketFactory) { sslSocketFactory = EmptySSLFactory; return null; } entation = function(hostnameVerifier) { hostnameVerifier = TrustHostnameVerifier.$new(); return null; } } catch (e) { quiet_send("Xutils hooks not Found"); } /*** httpclientandroidlib Hooks ***/ try { var AbstractVerifier = ("ctVerifier"); ad('', '[', '[', 'boolean').implementation = function() { quiet_send("httpclientandroidlib Hooks"); return null; } } catch (e) { quiet_send("httpclientandroidlib Hooks not found"); } /***android 7.0+ network_security_config TrustManagerImpl hookapache httpclient partly***/ var TrustManagerImpl = ("anagerImpl"); // try { // var Arrays = (""); // //apache http client pinning maybe baypass // ///google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/#471 // entation = function (chain, authType, session, parameters, authType) { // quiet_send("TrustManagerImpl checkTrusted called"); // //Generics currently result in // return (chain); // } // // } catch (e) { // quiet_send("TrustManagerImpl checkTrusted nout found"); // } try { // Android 7+ TrustManagerImpl entation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) { quiet_send("TrustManagerImpl verifyChain called"); // Skip all the logic and just return the chain again :P ///uk/about-us/newsroom-and-events/blogs/2017/november/bypassing-androids-network-security-configuration/ // /google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/#L650 return untrustedChain; } } catch (e) { quiet_send("TrustManagerImpl verifyChain nout found below 7.0"); } // OpenSSLSocketImpl try { var OpenSSLSocketImpl = ('LSocketImpl'); entation = function(certRefs, authMethod) { quiet_send('CertificateChain'); } quiet_send('OpenSSLSocketImpl pinning') } catch (err) { quiet_send('OpenSSLSocketImpl pinner not found'); } // Trustkit try { var Activity = ("nameVerifier"); ad('', 'sion').implementation = function(str) { quiet_send('1: ' + str); return true; }; ad('', '.X509Certificate').implementation = function(str) { quiet_send('2: ' + str); return true; }; quiet_send('Trustkit pinning') } catch (err) { quiet_send('Trustkit pinner not found') } try { //cronet pinner hook //weibo don't invoke var netBuilder = ("Engine$Builder"); ///guide/topics/connectivity/cronet/reference/org/chromium/net/#enablePublicKeyPinningBypassForLocalTrustAnchors(boolean) entation = function(arg) { //weibo not invoke ("Enables or disables public key pinning bypass for local trust anchors = " + arg); //true to enable the bypass, false to disable. var ret = (this, true); return ret; }; entation = function(hostName, pinsSha256, includeSubdomains, expirationDate) { ("cronet addPublicKeyPins hostName = " + hostName); //var ret = (this,hostName, pinsSha256,includeSubdomains, expirationDate); //this 是调⽤ addPublicKeyPins 前的对象吗? Yes,r return this; }; } catch (err) { ('[-] Cronet pinner not found') }});

上⾯这个完全版本包含了如下功能,如果你想⼀步到位的话,就可以⽤这个完全版

SSLcontext(ART only)okhttpwebviewXUtils(ART only)httpclientandroidlibJSSEnetwork_security_config (android 7.0+)Apache Http client (support partly)OpenSSLSocketImplTrustKitCronet

任意⼀个都可以,不要三个都⽤,都⽤也没⽤,根据实际情况选⽤

>

安卓机配置代理

配置代理到开启了抓包⼯具的IP上:

长按wiredssid

补充⼀句,当配置完代理后,pc端电脑上⼀定要打开对应的抓包软件,不然安卓机会没⽹

>

安卓机上安装ssl证书

根据你选⽤的抓包⼯具,fiddler,charles,burpsuite,安装证书即可,你可以访问局域⽹下带的ip来下载,然后安装:

配置了代理再执⾏此步骤,不然打不开下载证书的局域⽹址

也可以⽤adb 像传frida-server⼀样,⽤adb push把证书push到安卓机上,然后在安卓机的设置-安全⾥本地导⼊证书:

⽤adb push 之后,还是把代理配置上,不然后⾯操作也⽆法继续,不管怎么操作,反正必须要ssl证书安装上即可

开始hook

hook的本质意思就是钩⼦,在开发⾥⾯通俗的说就是可以在任意流程⾥插⼀⼿,然后做些⼿脚,⽐如打开⼀个app,在启动到完全打开app,显⽰app的⾸页,这个过程就可以hook⼀下,⽐如把本来要打开⾸页的,改成打开第⼆页数据,当然这只是举个例⼦

>

启动frida-server:/data/local/tmp/frida-server

补充下,有的⾼级点的app会检测本地是否启动了frida-server的程序,以及监听是否开启了27042端⼝,所以,如果有反调试的话,建议将frida-server改个⾃定义的名字,⽐如fsx86之类的,反正就是别让app检测到,然后启动:

/data/local/tmp/fsx86 -l 0.0.0.0:6666 (6666就是⾃定义端⼝)  

这⾥要⽤绝对路径来启动,我也不知道为啥,启动,如下,warning是个警告,⽆所谓,说明启动成功了,只要没报错就⾏了

>

映射端⼝

在pc端电脑,装adb的机器上使⽤如下命令映射端⼝

adb forward tcp:27042 tcp:27042adb forward tcp:27043 tcp:27043

  

>

找到需要hook的app包名

这个包名不是app的名字,是安装之后存在⽬录⾥的⽂件夹名,⼀般是之类的,但是有少部分奇葩的报名并不是com开头查看当前所有的包名:frida-ps -U

注意要安卓机⾥先启动了firda-server,然后adb连上了安卓机,才可以调⽤frida命令, 如果不启动的话,运⾏frida这样,Failed,失败的意思

以上查看app包,显⽰出来太多了,你根本不知道哪个才是我们需要的包名,可以使⽤下⾯的命令查看adb shell pm list packages:打印设备上的所有软件包adb shell pm list packages -f:输出包和包相关联的⽂件adb shell pm list packages -d:只输出禁⽤的包由于本机禁⽤没有,输出为空adb shell pm list packages -e:只输出启⽤的包adb shell pm list packages -s:只输出系统的包adb shell pm list packages -3:只输出第三⽅的包adb shell pm list packages -i:只输出包和安装信息(安装来源)adb shell pm list packages -u:只输出包和未安装包信息(安装来源)adb shell pm list packages --user :根据⽤户id查询⽤户的空间的所有包,USER_ID代表当前连接设备的顺序,从零开始  如果还找不到,可以先在安卓机上启动了⽬标app后,再⽤命令查看:adb shell "dumpsys window | grep mCurrentFocus"  

>

hook操作frida -U -f (app包名) -l (js⽬录) --no-pause  

注意了,这段js是放在安装了frida和adb的电脑上,不是放在安卓机上

运⾏完这条命令,安卓机会⾃动打开⽬标app,

app打开界⾯我就不展⽰了

如果打开的就是我们预期的那个app,那就是对的,如果打开错了,请重新获取app包名,打开之后就可以⽤抓包⼯具进⾏抓包了,ssl的⼀样的可以抓:

上⾯看到的https的还是会隧道,但是紧接着就有数据出现,说明还是抓到了数据包了

ok,绕过ssl pinning成功

其实如果你觉得需要做些改动的话,可以写个python脚本来调⽤,js代码就作为⽂件内容读取就⾏了,然后进⾏hook操作

最后得出的结论就是,我朋友他们的产品,其实反爬做得挺好,上⾯的截图也可以看到,其实还是有些数据拿不到的

补充:如果你⽤的模拟器在安装了app之后打不开,说明app有检测是否是模拟器或者对安卓版本做了检测,版本太低直接不给使⽤,那么你就只能⽤真机操作了,adb连接真机操作区别不⼤,详细的⾃⾏百度

>

检测模拟器的办法:

1.检测模拟器上特有的⽂件2.检测qemu pipes驱动程序3.检测⼿机号是否是155552155开头的4.检测设备ID是否是15个05.检测IMSI ID是否是31026+10个06.检测运营商是否是“Android”7.代码⾥⽤getInstance()⽅法调⽤任意⼀个⽅法,返回true就是模拟器8.检测IMEI或者⼊⽹许可证

以上都是我以前搜集的数据,但是,根据现在的时代发展,可能模拟器也早就更新迭代了,把⼀些特征给抹除或者改的跟真机⼀样了,所以有些⽅法并不是有⽤了,这个就只有⾃⾏选择了

>

免root使⽤frida

其实不root也可以使⽤frida,这⾥我就不展开了,给⼀个⼤神写的链接,⾥⾯还有其他⽅法的hook,感兴趣⾃⼰看吧,

>

针对很安全性很强的app——逆向

>> JEB

JEB 是⼀款适⽤于 Android 应⽤程序和本机机器代码的反汇编器和反编译器软件。利⽤它我们可以直接将安卓的 apk 反编译得到 Smali 代码、jar ⽂件,获取到 Java 代码。有了Java 代码,我们就能分析其中的加密逻辑了。

、jd-gui

这两者通常会配合使⽤来进⾏反编译,同样也可以实现 apk ⽂件的反编译,但其⽤起来个⼈感觉不如 JEB、JADX ⽅便。

>> 脱壳

⼀些 apk 可能进⾏了加固处理,所以在反编译之前需要进⾏脱壳处理。⼀般来说可以先借助于⼀些查壳⼯具查壳,如果有壳的话可以借助于 Dumpdex、FRIDA-DEXDump 等⼯具进⾏脱壳。

>> 反汇编

以上的⼀些逆向操作需要较深的功底和安全知识,在很多情况下,如果逆向成功了,⼀些加密算法还是能够被找出来的,找出来了加密逻辑之后,我们⽤程序模拟就⽅便了。

>> 模拟

逆向对于多数有保护 App 是有⼀定作⽤的,但有的时候 App 还增加了风控检测,⼀旦 App 检测到运⾏环境或访问频率等信息出现异常,那么 App 或服务器就可能产⽣防护,直接停⽌执⾏或者服务器返回假数据等都是有可能的。

对于这种情形,有时候我们就需要回归本源,真实模拟⼀些 App 的⼿⼯操作了。

最常规的 adb 命令可以实现⼀些⼿机⾃动化操作,但功能有限。

>> 触动精灵、按键精灵

有很多商家提供了⼿机 App 的⼀些⾃动化脚本和驱动,如触动精灵、按键精灵等,利⽤它们的⼀些服务我们可以⾃动化地完成⼀些 App 的操作。

类似 Selenium,Appium 是⼿机上的⼀款移动端的⾃动化测试⼯具,也能做到可见即可爬的操作。

同样是⼀款移动端的⾃动化测试⼯具,是⽹易公司开发的,相⽐ Appium 来说使⽤更⽅便。

mitmdump 其实是⼀款抓包软件,与 mitmproxy 是⼀套⼯具。这款软件配合⾃动化的⼀些操作就可以⽤ Python 实现实时抓包处理了。

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1688094277a80092.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信