app反爬测试之apk逆向分析-frida

这篇具有很好参考价值的文章主要介绍了app反爬测试之apk逆向分析-frida。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

目前为止,很多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 请求,获取到证书却没有后续了,要么就是一些无关的请求,找不到想要的接口

比如如下图:

安卓app逆向分析,ssl,https,网络协议

针对这种,如果是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了,我就没必要整这些了。

如果是 App 的开发者或者把 apk 逆向出来了,那么可以直接通过修改 AndroidManifest.xml 文件,在 apk 里面添加证书的信任规则即可,详情可以参考 破解https的SSL Pinning · app抓包利器:Charles,这种思路属于第一种信任证书的解决方案。

强制信任证书

其实就是将证书设置为系统证书,只需要将抓包软件的证书设置为系统区域即可。但这个前提是手机必须要 ROOT,而且需要计算证书 Hash Code 并对证书进行重命名,具体可以参考 https://crifan.github.io/app_capture_package_tool_charles/website/how_capture_app/complex_https/https_ssl_pinning, 把ssl代理证书强制的放到安卓机的/system/etc/security/cacerts/目录下,这个目录就是安卓机系统信任的目录。

具体步骤:

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

2.修改证书名称


系统证书目录:/system/etc/security/cacerts/

其中的每个证书的命名规则如下:
<Certificate_Hash>.
文件名是一个Hash值,而后缀是一个数字。

文件名可以用下面的命令计算出来:
openssl x509 -subject_hash_old -in <Certificate_File>

后缀名的数字是为了防止文件名冲突的,比如如果两个证书算出的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.进行抓包

2021-11-09补充:

安卓10版本有更高的保护机制,即使root了也没法把证书导入到系统证书目录里,解决方法: https://blog.csdn.net/fjh1997/article/details/106756012 

httpcannary

这个是安卓端的抓包工具,网上吹得很火,根据我(我手机是安卓10)亲自操作,发现其实没有用,也不知道是不是我的姿势错误,或者我手机安卓系统版本太高了失效

VirtualApp

用这个可以免root操作,然后正常抓包,但是这个方法我没有实际操作过,网上的资料不多,自行查找

Xposed + JustTrustMe

Xposed 是一款 Android 端的 Hook 工具,利用它我们可以 Hook App 里面的关键方法的执行逻辑,绕过 HTTPS 的证书校验过程。JustTrustMe 是基于 Xposed 一个插件,它可以将 HTTPS 证书校验的部分进行 Hook,改写其中的证书校验逻辑,这种思路是属于第二种绕过 HTTPS 证书校验的解决方案。

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

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

具体可以参考 Frida CodeShare。

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等的地方下载

VPN抓包

免root,在安卓机上安装packet capture,然后抓包,我试了下,我的手机(我手机是安卓10)没用

魔改JustTrustMe

在JustTrustMe插件上增加一个可以运行时根据实际情况调整ssl检测的功能,对hook增加动态适配,这个方法我没试过,我在看雪论坛里找到一个 JustTrustMePlus,点我下载

反编译app包

用apktools修改配置文件里的ssl证书检测部分,可利用jadx等工具分析源码,然后重新打包,再抓包分析,这个方法是可行的,详细的步骤自行百度吧,后续有时间的话,我单独发一篇对app的脱壳重新打包

AndServer处理

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

  

以上的方法就是我所知道的方法,各位朋友自行操作

接下来进入正题,frida hook

什么是frida

官网:Frida • A world-class dynamic instrumentation toolkit | Observe and reprogram running programs on Windows, macOS, GNU/Linux, iOS, watchOS, tvOS, Android, FreeBSD, and QNX

Frida是个轻量级别的hook框架, 是Python API,用JavaScript调试来逻辑

Frida的核心是用C编写的,并将Google的V8引擎注入到目标进程中,在这些进程中,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:\Users\Administrator 开头的都是在pc机上操作的,需要在安卓机目录里操作的我都有说明,不要搞混了

环境准备

安装frida

没有python的安装python,然后安装frida:

1

2

3

pip  install frida

pip install frida-tools

安装过程很慢,这个只能耐心等待,然后如果你是macbook的话,如果你遇到安装出错,可以看看我这篇文章的解决方法 macos 安装frida的坑

然后frida是mac,linux,windows都可以安装使用的,这个根据你自己的条件选择了

安装adb

这个就很简单,去 安卓开发网  然后下载这个工具:

安卓app逆向分析,ssl,https,网络协议

  

安卓app逆向分析,ssl,https,网络协议

 如果你下载太慢可以在我这里下载:点我

下载完毕后,解压,然后放到你想放的路径,然后配置下环境变量即可,此电脑(我的电脑)- 属性-高级系统设置-环境变量-系统变量的path,新增即可

安卓app逆向分析,ssl,https,网络协议

然后,打开终端:

安卓app逆向分析,ssl,https,网络协议

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

安卓app逆向分析,ssl,https,网络协议

以上配置是windows平台,如果是其他平台的话,自行查找,这里就不展示了

找一个安卓机(已root)

根据现在的行情,要找到一个已root的手机,问题不大也不小,但是很多时候没有必要,所以我这里就选择用安卓模拟器来辅助操作了

安装夜神模拟器,夜神默认是安卓5,你可以自行选择安卓版本,在夜神里设置已root即可

安卓app逆向分析,ssl,https,网络协议

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

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

安卓app逆向分析,ssl,https,网络协议

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

安卓app逆向分析,ssl,https,网络协议

打开调试

安卓app逆向分析,ssl,https,网络协议

adb连接安卓机(模拟器)

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

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

安卓app逆向分析,ssl,https,网络协议

进入后,找nox.vbox文件

安卓app逆向分析,ssl,https,网络协议

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

安卓app逆向分析,ssl,https,网络协议

用 adb connect 127.0.0.1:端口   连接

安卓app逆向分析,ssl,https,网络协议

我这里已经连接上了,所以提示已连接

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

安卓app逆向分析,ssl,https,网络协议

安装frida-server

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

1

adb shell getprop ro.product.cpu.abi

安卓app逆向分析,ssl,https,网络协议

然后去这里下载对应架构的frida-server :  点我

我这里是x86,安卓,所以选下面我选中那个下载,你的安卓机是什么你就选哪个就行了

安卓app逆向分析,ssl,https,网络协议

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

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

解压,然后用adb 传到安卓机上

1

adb push (本机的frida-sever文件所在目录) (安卓机目录)

  

安卓app逆向分析,ssl,https,网络协议

这里提示太长了,看不出来,可以用adb shell 去那个目录下看下是否有frida-server即可:

安卓app逆向分析,ssl,https,网络协议

修改frida-server的权限:

1

chmod 700 frida-server

  

安卓app逆向分析,ssl,https,网络协议

下载一个frida hook 的js文件

这个文件,有好几个版本,我选用了两个版本,放到下面,你们自己选择吧

版本1:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

setTimeout(function(){

    Java.perform(function (){

        console.log("");

        console.log("[.] Cert Pinning Bypass/Re-Pinning");

        var CertificateFactory = Java.use("java.security.cert.CertificateFactory");

        var FileInputStream = Java.use("java.io.FileInputStream");

        var BufferedInputStream = Java.use("java.io.BufferedInputStream");

        var X509Certificate = Java.use("java.security.cert.X509Certificate");

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

        var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");

        var SSLContext = Java.use("javax.net.ssl.SSLContext");

        // Load CAs from an InputStream

        console.log("[+] Loading our CA...")

        cf = CertificateFactory.getInstance("X.509");

         

        try {

            var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");

        }

        catch(err) {

            console.log("[o] " + err);

        }

        var bufferedInputStream = BufferedInputStream.$new(fileInputStream);

        var ca = cf.generateCertificate(bufferedInputStream);

        bufferedInputStream.close();

        var certInfo = Java.cast(ca, X509Certificate);

        console.log("[o] Our CA Info: " + certInfo.getSubjectDN());

        // Create a KeyStore containing our trusted CAs

        console.log("[+] Creating a KeyStore for our CA...");

        var keyStoreType = KeyStore.getDefaultType();

        var keyStore = KeyStore.getInstance(keyStoreType);

        keyStore.load(nullnull);

        keyStore.setCertificateEntry("ca", ca);

         

        // Create a TrustManager that trusts the CAs in our KeyStore

        console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");

        var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();

        var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);

        tmf.init(keyStore);

        console.log("[+] Our TrustManager is ready...");

        console.log("[+] Hijacking SSLContext methods now...")

        console.log("[-] Waiting for the app to invoke SSLContext.init()...")

        SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;""[Ljavax.net.ssl.TrustManager;""java.security.SecureRandom").implementation = function(a,b,c) {

            console.log("[o] App invoked javax.net.ssl.SSLContext.init...");

            SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;""[Ljavax.net.ssl.TrustManager;""java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);

            console.log("[+] SSLContext initialized with our custom TrustManager!");

        }

    });

},0);

  

版本2:

1

2

3

4

5

6

7

8

9

10

Java.perform(function() {

    var array_list = Java.use("java.util.ArrayList");

    var ApiClient = Java.use('com.android.org.conscrypt.TrustManagerImpl');

    ApiClient.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) {

        // console.log('Bypassing SSL Pinning');

        var k = array_list.$new();

        return k;

        }

}, 0);

  

然后你自己复制以上的任何一个版本的代码,然后在本地新建一个js文件,粘贴进去就行了

安卓app逆向分析,ssl,https,网络协议
安卓app逆向分析,ssl,https,网络协议

或者这个:

安卓app逆向分析,ssl,https,网络协议

这里补充一个完全版:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

Java.perform(function() {

/*

hook list:

1.SSLcontext

2.okhttp

3.webview

4.XUtils

5.httpclientandroidlib

6.JSSE

7.network\_security\_config (android 7.0+)

8.Apache Http client (support partly)

9.OpenSSLSocketImpl

10.TrustKit

11.Cronet

*/

    // 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 = Java.use('javax.net.ssl.X509TrustManager');

    var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier');

    var SSLContext = Java.use('javax.net.ssl.SSLContext');

    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: https://gist.github.com/oleavr/3ca67a173ff7d207c6b8c3b0ca65a9d8

    // Java.registerClass() is only supported on ART for now(201803). 所以android 4.4以下不兼容,4.4要切换成ART使用.

    /*

06-07 16:15:38.541 27021-27073/mi.sslpinningdemo W/System.err: java.lang.IllegalArgumentException: Required method checkServerTrusted(X509Certificate[], String, String, String) missing

06-07 16:15:38.542 27021-27073/mi.sslpinningdemo W/System.err:     at android.net.http.X509TrustManagerExtensions.<init>(X509TrustManagerExtensions.java:73)

        at mi.ssl.MiPinningTrustManger.<init>(MiPinningTrustManger.java:61)

06-07 16:15:38.543 27021-27073/mi.sslpinningdemo W/System.err:     at mi.sslpinningdemo.OkHttpUtil.getSecPinningClient(OkHttpUtil.java:112)

        at mi.sslpinningdemo.OkHttpUtil.get(OkHttpUtil.java:62)

        at mi.sslpinningdemo.MainActivity$1$1.run(MainActivity.java:36)

*/

    var X509Certificate = Java.use("java.security.cert.X509Certificate");

    var TrustManager;

    try {

        TrustManager = Java.registerClass({

            name: 'org.wooyun.TrustManager',

            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.message);

    }

    // Prepare the TrustManagers array to pass to SSLContext.init()

    var TrustManagers = [TrustManager.$new()];

    try {

        // Prepare a Empty SSLFactory

        var TLS_SSLContext = SSLContext.getInstance("TLS");

        TLS_SSLContext.init(null, TrustManagers, null);

        var EmptySSLFactory = TLS_SSLContext.getSocketFactory();

    catch (e) {

        quiet_send(e.message);

    }

    send('Custom, Empty TrustManager ready');

    // Get a handle on the init() on the SSLContext class

    var SSLContext_init = SSLContext.init.overload(

        '[Ljavax.net.ssl.KeyManager;''[Ljavax.net.ssl.TrustManager;''java.security.SecureRandom');

    // Override the init method, specifying our new TrustManager

    SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {

        quiet_send('Overriding SSLContext.init() with the custom TrustManager');

        SSLContext_init.call(thisnull, 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 = Java.use('okhttp3.CertificatePinner');

        quiet_send('OkHTTP 3.x Found');

        CertificatePinner.check.overload('java.lang.String''java.util.List').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 (err.message.indexOf('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 = Java.use('appcelerator.https.PinningTrustManager');

        send('Appcelerator Titanium Found');

        PinningTrustManager.checkServerTrusted.implementation = function() {

            quiet_send('Appcelerator checkServerTrusted() called. Not throwing an exception.');

        }

    catch (err) {

        // If we dont have a ClassNotFoundException exception, raise the

        // problem encountered.

        if (err.message.indexOf('ClassNotFoundException') === 0) {

            throw new Error(err);

        }

    }

    /*** okhttp unpinning ***/

    try {

        var OkHttpClient = Java.use("com.squareup.okhttp.OkHttpClient");

        OkHttpClient.setCertificatePinner.implementation = function(certificatePinner) {

            // do nothing

            quiet_send("OkHttpClient.setCertificatePinner Called!");

            return this;

        };

        // Invalidate the certificate pinnet checks (if "setCertificatePinner" was called before the previous invalidation)

        var CertificatePinner = Java.use("com.squareup.okhttp.CertificatePinner");

        CertificatePinner.check.overload('java.lang.String''[Ljava.security.cert.Certificate;').implementation = function(p0, p1) {

            // do nothing

            quiet_send("okhttp Called! [Certificate]");

            return;

        };

        CertificatePinner.check.overload('java.lang.String''java.util.List').implementation = function(p0, p1) {

            // do nothing

            quiet_send("okhttp Called! [List]");

            return;

        };

    catch (e) {

        quiet_send("com.squareup.okhttp not found");

    }

    /*** WebView Hooks ***/

    /* frameworks/base/core/java/android/webkit/WebViewClient.java */

    /* public void onReceivedSslError(Webview, SslErrorHandler, SslError) */

    var WebViewClient = Java.use("android.webkit.WebViewClient");

    WebViewClient.onReceivedSslError.implementation = function(webView, sslErrorHandler, sslError) {

        quiet_send("WebViewClient onReceivedSslError invoke");

        //执行proceed方法

        sslErrorHandler.proceed();

        return;

    };

    WebViewClient.onReceivedError.overload('android.webkit.WebView''int''java.lang.String''java.lang.String').implementation = function(a, b, c, d) {

        quiet_send("WebViewClient onReceivedError invoked");

        return;

    };

    WebViewClient.onReceivedError.overload('android.webkit.WebView''android.webkit.WebResourceRequest''android.webkit.WebResourceError').implementation = function() {

        quiet_send("WebViewClient onReceivedError invoked");

        return;

    };

    /*** JSSE Hooks ***/

    /* libcore/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java */

    /* public final TrustManager[] getTrustManager() */

    /* TrustManagerFactory.getTrustManagers maybe cause X509TrustManagerExtensions error  */

    // var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");

    // TrustManagerFactory.getTrustManagers.implementation = function(){

    //     quiet_send("TrustManagerFactory getTrustManagers invoked");

    //     return TrustManagers;

    // }

    var HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");

    /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */

    /* public void setDefaultHostnameVerifier(HostnameVerifier) */

    HttpsURLConnection.setDefaultHostnameVerifier.implementation = function(hostnameVerifier) {

        quiet_send("HttpsURLConnection.setDefaultHostnameVerifier invoked");

        return null;

    };

    /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */

    /* public void setSSLSocketFactory(SSLSocketFactory) */

    HttpsURLConnection.setSSLSocketFactory.implementation = function(SSLSocketFactory) {

        quiet_send("HttpsURLConnection.setSSLSocketFactory invoked");

        return null;

    };

    /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */

    /* public void setHostnameVerifier(HostnameVerifier) */

    HttpsURLConnection.setHostnameVerifier.implementation = function(hostnameVerifier) {

        quiet_send("HttpsURLConnection.setHostnameVerifier invoked");

        return null;

    };

    /*** Xutils3.x hooks ***/

    //Implement a new HostnameVerifier

    var TrustHostnameVerifier;

    try {

        TrustHostnameVerifier = Java.registerClass({

            name: 'org.wooyun.TrustHostnameVerifier',

            implements: [HostnameVerifier],

            method: {

                verify: function(hostname, session) {

                    return true;

                }

            }

        });

    catch (e) {

        //java.lang.ClassNotFoundException: Didn't find class "org.wooyun.TrustHostnameVerifier"

        quiet_send("registerClass from hostnameVerifier >>>>>>>> " + e.message);

    }

    try {

        var RequestParams = Java.use('org.xutils.http.RequestParams');

        RequestParams.setSslSocketFactory.implementation = function(sslSocketFactory) {

            sslSocketFactory = EmptySSLFactory;

            return null;

        }

        RequestParams.setHostnameVerifier.implementation = function(hostnameVerifier) {

            hostnameVerifier = TrustHostnameVerifier.$new();

            return null;

        }

    } catch (e) {

        quiet_send("Xutils hooks not Found");

    }

    /*** httpclientandroidlib Hooks ***/

    try {

        var AbstractVerifier = Java.use("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier");

        AbstractVerifier.verify.overload('java.lang.String', '[Ljava.lang.String', '[Ljava.lang.String', 'boolean').implementation = function() {

            quiet_send("httpclientandroidlib Hooks");

            return null;

        }

    } catch (e) {

        quiet_send("httpclientandroidlib Hooks not found");

    }

    /***

android 7.0+ network_security_config TrustManagerImpl hook

apache httpclient partly

***/

    var TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl");

    // try {

    //     var Arrays = Java.use("java.util.Arrays");

    //     //apache http client pinning maybe baypass

    //     //https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#471

    //     TrustManagerImpl.checkTrusted.implementation = function (chain, authType, session, parameters, authType) {

    //         quiet_send("TrustManagerImpl checkTrusted called");

    //         //Generics currently result in java.lang.Object

    //         return Arrays.asList(chain);

    //     }

    //

    // } catch (e) {

    //     quiet_send("TrustManagerImpl checkTrusted nout found");

    // }

    try {

        // Android 7+ TrustManagerImpl

        TrustManagerImpl.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {

            quiet_send("TrustManagerImpl verifyChain called");

            // Skip all the logic and just return the chain again :P

            //https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2017/november/bypassing-androids-network-security-configuration/

            // https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#L650

            return untrustedChain;

        }

    } catch (e) {

        quiet_send("TrustManagerImpl verifyChain nout found below 7.0");

    }

    // OpenSSLSocketImpl

    try {

        var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');

        OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, authMethod) {

            quiet_send('OpenSSLSocketImpl.verifyCertificateChain');

        }

        quiet_send('OpenSSLSocketImpl pinning')

    } catch (err) {

        quiet_send('OpenSSLSocketImpl pinner not found');

    }

    // Trustkit

    try {

        var Activity = Java.use("com.datatheorem.android.trustkit.pinning.OkHostnameVerifier");

        Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(str) {

            quiet_send('Trustkit.verify1: ' + str);

            return true;

        };

        Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(str) {

            quiet_send('Trustkit.verify2: ' + 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 = Java.use("org.chromium.net.CronetEngine$Builder");

        //https://developer.android.com/guide/topics/connectivity/cronet/reference/org/chromium/net/CronetEngine.Builder.html#enablePublicKeyPinningBypassForLocalTrustAnchors(boolean)

        netBuilder.enablePublicKeyPinningBypassForLocalTrustAnchors.implementation = function(arg) {

            //weibo not invoke

            console.log("Enables or disables public key pinning bypass for local trust anchors = " + arg);

            //true to enable the bypass, false to disable.

            var ret = netBuilder.enablePublicKeyPinningBypassForLocalTrustAnchors.call(thistrue);

            return ret;

        };

        netBuilder.addPublicKeyPins.implementation = function(hostName, pinsSha256, includeSubdomains, expirationDate) {

            console.log("cronet addPublicKeyPins hostName = " + hostName);

            //var ret = netBuilder.addPublicKeyPins.call(this,hostName, pinsSha256,includeSubdomains, expirationDate);

            //this 是调用 addPublicKeyPins 前的对象吗? Yes,CronetEngine.Builder

            return this;

        };

    catch (err) {

        console.log('[-] Cronet pinner not found')

    }

});

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

  • SSLcontext(ART only)
  • okhttp
  • webview
  • XUtils(ART only)
  • httpclientandroidlib
  • JSSE
  • network_security_config (android 7.0+)
  • Apache Http client (support partly)
  • OpenSSLSocketImpl
  • TrustKit
  • Cronet 

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

安卓机配置代理

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

安卓app逆向分析,ssl,https,网络协议

长按wiredssid

安卓app逆向分析,ssl,https,网络协议
安卓app逆向分析,ssl,https,网络协议

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

安卓机上安装ssl证书

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

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

安卓app逆向分析,ssl,https,网络协议

也可以用adb 像传frida-server一样,用adb push把证书push到安卓机上,然后在安卓机的设置-安全里本地导入证书:

安卓app逆向分析,ssl,https,网络协议

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

开始hook

hook的本质意思就是钩子,在开发里面通俗的说就是可以在任意流程里插一手,然后做些手脚,比如打开一个app,在启动到完全打开app,显示app的首页,这个过程就可以hook一下,比如把本来要打开首页的,改成打开第二页数据,当然这只是举个例子

启动frida-server:

1

/data/local/tmp/frida-server

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

1

/data/local/tmp/fsx86 -0.0.0.0:6666  (6666就是自定义端口)

  

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

安卓app逆向分析,ssl,https,网络协议

映射端口

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

1

2

adb forward tcp:27042 tcp:27042

adb forward tcp:27043 tcp:27043

  

找到需要hook的app包名

这个包名不是app的名字,是安装之后存在目录里的文件夹名,一般是com.xxxx.xxx之类的,但是有少部分奇葩的报名并不是com开头

查看当前所有的包名:

1

frida-ps -U

安卓app逆向分析,ssl,https,网络协议

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

安卓app逆向分析,ssl,https,网络协议

以上查看app包,显示出来太多了,你根本不知道哪个才是我们需要的包名,可以使用下面的命令查看

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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 <USER_ID>:根据用户id查询用户的空间的所有包,USER_ID代表当前连接设备的顺序,从零开始

  

如果还找不到,可以先在安卓机上启动了目标app后,再用命令查看:

1

adb shell "dumpsys window | grep mCurrentFocus"

  

安卓app逆向分析,ssl,https,网络协议

hook操作

1

frida -U -f (app包名) -l  (js目录)  --no-pause

  

安卓app逆向分析,ssl,https,网络协议
安卓app逆向分析,ssl,https,网络协议

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

运行完这条命令,安卓机会自动打开目标app,

app打开界面我就不展示了

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

安卓app逆向分析,ssl,https,网络协议

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

ok,绕过ssl  pinning成功!!!

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

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

补充:

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

检测模拟器的办法:

  • 1.检测模拟器上特有的文件
  • 2.检测qemu pipes驱动程序
  • 3.检测手机号是否是155552155开头的
  • 4.检测设备ID是否是15个0
  • 5.检测IMSI ID是否是31026+10个0
  • 6.检测运营商是否是“Android”
  • 7.代码里用getInstance()方法调用任意一个方法,返回true就是模拟器
  • 8.检测IMEI或者入网许可证

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

免root使用frida

其实不root也可以使用frida,这里我就不展开了,给一个大神写的链接,里面还有其他方法的hook,感兴趣自己看吧,点我

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

JEB 

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

JEB:JEB Decompiler by PNF Software

JADX

与 JEB 类似,JADX 也是一款安卓反编译软件,可以将 apk 反编译得到 jar 文件,得到 Java 代码,从而进一步分析逻辑。
JADX:GitHub - skylot/jadx: Dex to Java decompiler

  

dex2jar、jd-gui

  

这两者通常会配合使用来进行反编译,同样也可以实现 apk 文件的反编译,但其用起来个人感觉不如 JEB、JADX 方便。

脱壳

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

FRIDA-DEXDump:GitHub - hluwa/frida-dexdump: A frida tool to dump dex in memory to support security engineers analyzing malware.
Dumpdex:GitHub - WrBug/dumpDex: 💯一款Android脱壳工具,需要xposed支持, 易开发已集成该项目。

反汇编

一些 apk 里面的加密可能直接写入 so 格式的动态链接库里面,要想破解其中的逻辑,就需要用到反汇编的一些知识了,这里可以借助于 IDA 这个软件来进行分析。
IDA:Hex Rays – State-of-the-art binary code analysis solutions

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

模拟

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

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

adb

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

触动精灵、按键精灵

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

触动精灵:触动精灵官网 - 更好用的手机自动化辅助工具

Appium

类似 Selenium,Appium 是手机上的一款移动端的自动化测试工具,也能做到可见即可爬的操作。

 Appium:Redirecting

AirTest

同样是一款移动端的自动化测试工具,是网易公司开发的,相比 Appium 来说使用更方便。

AirTest:http://airtest.netease.com/

Appium/AirTest + mitmdump

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

mitmdump:https://mitmproxy.readthedocs.io/文章来源地址https://www.toymoban.com/news/detail-606502.html

到了这里,关于app反爬测试之apk逆向分析-frida的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android Spider App逆向 Frida - 夜神模拟器安装配置 基本使用

    Frida 是一款基于 Python + JavaScript 的 Hook 与调试框架,实现app逆向的强大工具; 模拟器下载安装教程:https://blog.csdn.net/EXIxiaozhou/article/details/127767808 提示:以下是本篇文章正文内容,下面案例可供参考 Frida是一款易用的跨平 Hook 工具, Java 层到 Native 层的 Hook 无所不能,是一种

    2024年01月24日
    浏览(49)
  • [安卓逆向]apktool实现APK反编译、重打包、签名

    apktool 主要用于逆向apk文件。它可以将资源解码,并在修改后可以重新构建它们。 APKtool官网: https://ibotpeaches.github.io/Apktool/ APKtool下载: https://bitbucket.org/iBotPeaches/apktool/downloads/ APKtool源码: https://github.com/iBotPeaches/Apktool 将 apktool_2.6.1.jar 放到一个文件夹下(如:D:apktool),然

    2024年02月03日
    浏览(50)
  • 安卓逆向学习及APK抓包(二)--Google Pixel一代手机的ROOT刷入面具

    在手机选择上,优先选择谷歌系列手机,Nexus和Pixel系列,刚好手头有Pixel一代,就直接root了,大家感兴趣可以某宝几百块钱入手一台。Pixel手机花了本人一天,中间踩坑无数,终于还是root成功,感触颇深,所以先记录一下Pixel手机的root之旅。 安卓逆向学习及APK抓包(一)【Ka

    2024年02月11日
    浏览(63)
  • uni-app离线打包安卓apk

    记录一下打包apk的过程: 参考:uni-app离线打包官网地址 2-1.遇见问题 1. 加载.idea和.gradle失败, 解决: File → Project Structure 重新构建: File → Sync Project with Gradle Files 安卓结构: Project → Android 登录开发者中心选择需要打包的应用→各平台信息→查看或新增安卓打包信息 这里

    2024年04月17日
    浏览(79)
  • Web逆向、软件逆向、安卓逆向、APP逆向,关于网络安全这些你必须懂

    逆向工程是网络安全行业里面一项很重要的技术。 逆向是一个相对正向而言的解释,相对正向来说,对一个程序来讲,正向就是开发的过程,从0到1。 就是在一个软件诞生的整个生命周期中的一个过程, 也就是按照需求通过编码把需求实现,产生一个程序,当然这个程序可

    2024年02月07日
    浏览(43)
  • 【0-1】从0.1开始学Android逆向-APK基本结构概要分析

    最近在进行Android的逆向,在这里整理知识点和分享Android逆向知识。如果文章中有任何勘误,诚挚的邀请师傅们批评改正! 逆向工程(Reverse Engineering)是一种分析和解剖已有产品、系统或软件的过程,以了解其内部工作原理、设计、功能或源代码。逆向工程可以应用于多个领

    2024年02月08日
    浏览(39)
  • cocos creator 3.x打包构建原生安卓APK流程(打包release版本,修改APP图标)

    本文介绍cocos creator 3.x如何打包构建原生安卓APK,一开始是按照官网构建示例操作的,发现存在各种SDK版本问题,因为对原生Android没什么研究只能瞎琢磨,最后勉强算是打包出来了…写个文章记录下流程,免得后续又忘记…如果有不对的地方,欢迎在评论区指正,有疑问也可

    2024年02月10日
    浏览(69)
  • 【Android安全】安装mitmproxy Https抓包证书 | 安卓SSL抓包

    macbook上 mitmproxy 抓取安卓手机https流量 重点是安装mitmproxy Https抓包证书 手机需要root,macbook上需要安装好mitmproxy 需要完成下文1-3: https://github.com/doug-leith/cydia (接入有线网并开启无线热点) 启用 IP 转发: sudo sysctl -w net.inet.ip.forwarding=1 保存文件: https://github.com/doug-leith/cy

    2024年01月22日
    浏览(45)
  • APP攻防--安卓逆向&JEB动态调试&LSPosed模块&算法提取&Hook技术

    安装java环境变量(最好jdk11) 安装adb环境变量 设置adb环境变量最好以Android命名 启动开发者模式 设置--关于平板电脑--版本号(单机五次) 开启USB调试 设置--系统--高级--开发者选项--USB调试 开启USB调试目的是为了后续让JEB能够获取模拟器上的进程 安装激活JEB 软件安装包和破解参

    2024年02月05日
    浏览(66)
  • 如何给苹果ipa和安卓apk应用APP包体修改手机屏幕上logo图标iocn?

    虽然修改应用文件图标是一个简单的事情,但是还是有很多小可爱是不明白的,你要是想要明白的话,那我就让你今天明白明白,我们今天采用的非常规打包方式,常规打包方式科技一下教程铺天盖地,既然小弟我出马,肯定要让这个马出去的快一点, 我们得先了解一下安装

    2024年02月07日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包