|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "AndroidFRIDA脚本系列" |
| 4 | +date: 2025-03-11 |
| 5 | +toc: true |
| 6 | +author: Bin4xin |
| 7 | +categories: |
| 8 | +- blog |
| 9 | +tags: |
| 10 | +- Android |
| 11 | +- FRIDA |
| 12 | +--- |
| 13 | + |
| 14 | +* [FRIDA 脚本系列(一)入门篇:在安卓`8.1`上 dump 蓝牙接口和实例](#frida%E8%84%9A%E6%9C%AC%E7%B3%BB%E5%88%97%E4%B8%80%E5%85%A5%E9%97%A8%E7%AF%87%E5%9C%A8%E5%AE%89%E5%8D%9381%E4%B8%8Adump%E8%93%9D%E7%89%99%E6%8E%A5%E5%8F%A3%E5%92%8C%E5%AE%9E%E4%BE%8B) |
| 15 | + * [0x01.FRIDA 是啥?为啥这么火?](#0x01frida%E6%98%AF%E5%95%A5%E4%B8%BA%E5%95%A5%E8%BF%99%E4%B9%88%E7%81%AB) |
| 16 | + * [0x02.FRIDA 脚本的概念](#0x02frida%E8%84%9A%E6%9C%AC%E7%9A%84%E6%A6%82%E5%BF%B5) |
| 17 | + * [0x03. 简单脚本一:枚举所有的类](#0x03%E7%AE%80%E5%8D%95%E8%84%9A%E6%9C%AC%E4%B8%80%E6%9E%9A%E4%B8%BE%E6%89%80%E6%9C%89%E7%9A%84%E7%B1%BB) |
| 18 | + * [0x04. 简单脚本二:定位目标类并打印类的实例](#0x04%E7%AE%80%E5%8D%95%E8%84%9A%E6%9C%AC%E4%BA%8C%E5%AE%9A%E4%BD%8D%E7%9B%AE%E6%A0%87%E7%B1%BB%E5%B9%B6%E6%89%93%E5%8D%B0%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B) |
| 19 | + * [0x05. 简单脚本三:枚举所有方法并定位方法](#0x05%E7%AE%80%E5%8D%95%E8%84%9A%E6%9C%AC%E4%B8%89%E6%9E%9A%E4%B8%BE%E6%89%80%E6%9C%89%E6%96%B9%E6%B3%95%E5%B9%B6%E5%AE%9A%E4%BD%8D%E6%96%B9%E6%B3%95) |
| 20 | + * [0x06. 综合案例:在安卓`8.1`上 dump 蓝牙接口和实例:](#0x06%E7%BB%BC%E5%90%88%E6%A1%88%E4%BE%8B%E5%9C%A8%E5%AE%89%E5%8D%9381%E4%B8%8Adump%E8%93%9D%E7%89%99%E6%8E%A5%E5%8F%A3%E5%92%8C%E5%AE%9E%E4%BE%8B) |
| 21 | + |
| 22 | +FRIDA 脚本系列(一)入门篇:在安卓`8.1`上 dump 蓝牙接口和实例 |
| 23 | +--------------------------------------- |
| 24 | + |
| 25 | +### 0x01.FRIDA 是啥?为啥这么火? |
| 26 | + |
| 27 | +`frida`目前非常火爆,该框架从`Java`层 hook 到`Native`层 hook 无所不能,虽然持久化还是要依靠`Xposed`和`hookzz`等开发框架,但是`frida`的动态和灵活对逆向以及自动化逆向的帮助非常巨大。 |
| 28 | + |
| 29 | +`frida`是啥呢,github 目录 [Awesome Frida](https://github.com/dweinstein/awesome-frida) 这样介绍`frida`的: |
| 30 | + |
| 31 | +> Frida is Greasemonkey for native apps, or, put in more technical terms, it’s a dynamic code instrumentation toolkit. It lets you inject snippets of JavaScript into native apps that run on Windows, Mac, Linux, iOS and Android. Frida is an open source software. |
| 32 | +
|
| 33 | +`frida`是平台原生`app`的`Greasemonkey`,说的专业一点,就是一种动态插桩工具,可以插入一些代码到原生`app`的内存空间去,(动态地监视和修改其行为),这些原生平台可以是`Win`、`Mac`、`Linux`、`Android`或者`iOS`。而且`frida`还是开源的。 |
| 34 | + |
| 35 | +`Greasemonkey`可能大家不明白,它其实就是`firefox`的一套插件体系,使用它编写的脚本可以直接改变`firefox`对网页的编排方式,实现想要的任何功能。而且这套插件还是外挂的,非常灵活机动。 |
| 36 | + |
| 37 | +`frida`也是一样的道理。那它为什么这么火爆呢? |
| 38 | + |
| 39 | +动静态修改内存实现作弊一直是刚需,比如金山游侠,本质上`frida`做的跟它是一件事情。原则上是可以用`frida`把金山游侠,包括`CheatEngine`等 “外挂” 做出来的。 |
| 40 | + |
| 41 | +当然,现在已经不是直接修改内存就可以高枕无忧的年代了。大家也不要这样做,做外挂可是违法行为。 |
| 42 | + |
| 43 | +在逆向的工作上也是一样的道理,使用`frida`可以 “看到” 平时看不到的东西。出于编译型语言的特性,机器码在 CPU 和内存上执行的过程中,其内部数据的交互和跳转,对用户来讲是看不见的。当然如果手上有源码,甚至哪怕有带调试符号的可执行文件包,也可以使用`gbd`、`lldb`等调试器连上去看。 |
| 44 | + |
| 45 | +那如果没有呢?如果是纯黑盒呢?又要对`app`进行逆向和动态调试、甚至自动化分析以及规模化收集信息的话,我们需要的是细粒度的流程控制和代码级的可定制体系,以及不断对调试进行动态纠正和可编程调试的框架,这就是`frida`。 |
| 46 | + |
| 47 | +`frida`使用的是`python`、`JavaScript`等 “胶水语言” 也是它火爆的一个原因,可以迅速将逆向过程自动化,以及整合到现有的架构和体系中去,为你们发布 “威胁情报”、“数据平台” 甚至 “AI 风控” 等产品打好基础。 |
| 48 | + |
| 49 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/01.png) |
| 50 | + |
| 51 | +官宣屁屁踢甚至将其`敏捷开发`和`迅速适配到现有架构`的能力作为其核心卖点。 |
| 52 | + |
| 53 | +### 0x02.FRIDA 脚本的概念 |
| 54 | + |
| 55 | +`FRIDA脚本`就是利用`FRIDA`动态插桩框架,使用`FRIDA`导出的`API`和方法,对内存空间里的对象方法进行监视、修改或者替换的一段代码。`FRIDA`的`API`是使用`JavaScript`实现的,所以我们可以充分利用`JS`的匿名函数的优势、以及大量的`hook`和回调函数的 API。 |
| 56 | + |
| 57 | +我们来举个最直观的例子:`hello-world.js` |
| 58 | + |
| 59 | +``` |
| 60 | +setTimeout(function(){ |
| 61 | + Java.perform(function(){ |
| 62 | + console.log("hello world!"); |
| 63 | + }); |
| 64 | +}); |
| 65 | +
|
| 66 | +``` |
| 67 | + |
| 68 | +这基本上就是一个`FRIDA`版本的 "Hello World!",我们把一个匿名函数作为参数传给了`setTimeout()`函数,然而函数体中的`Java.perform()`这个函数本身又接受了一个匿名函数作为参数,该匿名函数中最终会调用`console.log()`函数来打印一个 “Hello world!” 字符串。我们需要调用`setTimeout()`方法因为该方法将我们的函数注册到`JavaScript`运行时中去,然后需要调用`Java.perform()`方法将函数注册到`Frida`的`Java`运行时中去,用来执行函数中的操作,当然这里只是打了一条`log`。 |
| 69 | + |
| 70 | +然后我们在手机上将`frida-server`运行起来,在电脑上进行操作: |
| 71 | + |
| 72 | +`$ frida -U -l hello-world.js android.process.media` |
| 73 | + |
| 74 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/001.png) |
| 75 | + |
| 76 | +然后可以看到`console.log()`执行成功,字符串打印了出来。 |
| 77 | + |
| 78 | +### 0x03. 简单脚本一:枚举所有的类 |
| 79 | + |
| 80 | +我们现在来给这个`HelloWorld.js`稍微加一点功能,比如说枚举所有已经加载的类,这就用到了`Java`对象的`enumerateLoadedClasses`方法。代码如下: |
| 81 | + |
| 82 | +``` |
| 83 | +setTimeout(function (){ |
| 84 | + Java.perform(function (){ |
| 85 | + console.log("\n[*] enumerating classes..."); |
| 86 | + Java.enumerateLoadedClasses({ |
| 87 | + onMatch: function(_className){ |
| 88 | + console.log("[*] found instance of '"+_className+"'"); |
| 89 | + }, |
| 90 | + onComplete: function(){ |
| 91 | + console.log("[*] class enuemration complete"); |
| 92 | + } |
| 93 | + }); |
| 94 | + }); |
| 95 | +}); |
| 96 | +
|
| 97 | +``` |
| 98 | + |
| 99 | +首先还是确保手机上的`frida-server`正在运行中,然后在电脑上操作: |
| 100 | + |
| 101 | +``` |
| 102 | +$ frida -U -l enumerate_classes.js android.process.media |
| 103 | +
|
| 104 | +
|
| 105 | +``` |
| 106 | + |
| 107 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/002.png) |
| 108 | + |
| 109 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/003.png) |
| 110 | + |
| 111 | +### 0x04. 简单脚本二:定位目标类并打印类的实例 |
| 112 | + |
| 113 | +现在我们已经找到目标进程中所有已经加载的类,比如说现在我们的目标是要查看其蓝牙相关的类,我们可以把代码修改成这样: |
| 114 | + |
| 115 | +``` |
| 116 | +Java.enumerateLoadedClasses({ |
| 117 | + onMatch: function(instance){ |
| 118 | + if (instance.split(".")[1] == "bluetooth"){ |
| 119 | + console.log("[->]\t"+instance); |
| 120 | + } |
| 121 | + }, |
| 122 | + onComplete: function() { |
| 123 | + console.log("[*] class enuemration complete"); |
| 124 | + } |
| 125 | + }); |
| 126 | +
|
| 127 | +``` |
| 128 | + |
| 129 | +我们来看下效果: |
| 130 | + |
| 131 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/005.png) |
| 132 | + |
| 133 | +可以找到上述这么多蓝牙相关的类。当然也可以使用字符串包含的方法,使用`JavaScript`字符串的`indexOf()`、`search()`或者`match()`方法,这个留给读者自己完成。 |
| 134 | + |
| 135 | +定位到我们想要研究的类之后,就可以打印类的实例了,查看 [`FRIDA的API手册`](https://www.frida.re/docs/javascript-api/#java)可以得知,此时应该使用`Java.choose()`函数,来选定某一个实例。 |
| 136 | + |
| 137 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/004.png) |
| 138 | + |
| 139 | +我们增加下列几行选定`android.bluetooth.BluetoothDevice`类的实例的代码。 |
| 140 | + |
| 141 | +``` |
| 142 | +Java.choose("android.bluetooth.BluetoothDevice",{ |
| 143 | + onMatch: function (instance){ |
| 144 | + console.log("[*] "+" android.bluetooth.BluetoothDevice instance found"+" :=> '"+instance+"'"); |
| 145 | + bluetoothDeviceInfo(instance); |
| 146 | + }, |
| 147 | + onComplete: function() { console.log("[*] -----");} |
| 148 | +}); |
| 149 | +
|
| 150 | +``` |
| 151 | + |
| 152 | +在手机打开蓝牙,并且连接上我的漫步者蓝牙耳机,开始播放内容之后: |
| 153 | + |
| 154 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/006.jpeg) |
| 155 | + |
| 156 | +在电脑上运行脚本: |
| 157 | + |
| 158 | +``` |
| 159 | +$ frida -U -l enumerate_classes_bluetooth_choose.js com.android.bluetooth |
| 160 | +
|
| 161 | +
|
| 162 | +``` |
| 163 | + |
| 164 | +可以看到正确检测到了我的蓝牙设备: |
| 165 | + |
| 166 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/007.png) |
| 167 | + |
| 168 | +### 0x05. 简单脚本三:枚举所有方法并定位方法 |
| 169 | + |
| 170 | +上文已经将类以及实例枚举出来,接下来我们来枚举所有方法,主要使用了`Java.use()`函数。 |
| 171 | + |
| 172 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/008.png) |
| 173 | + |
| 174 | +`Java.use()`与`Java.choose()`最大的区别,就是在于前者会新建一个对象,后者会选择内存中已有的实例。 |
| 175 | + |
| 176 | +对代码的增加如下: |
| 177 | + |
| 178 | +``` |
| 179 | +function enumMethods(targetClass) |
| 180 | +{ |
| 181 | + var hook = Java.use(targetClass); |
| 182 | + var ownMethods = hook.class.getDeclaredMethods(); |
| 183 | + hook.$dispose; |
| 184 | +
|
| 185 | + return ownMethods; |
| 186 | +} |
| 187 | +
|
| 188 | +... |
| 189 | +... |
| 190 | +
|
| 191 | + var a = enumMethods("android.bluetooth.BluetoothDevice") |
| 192 | + a.forEach(function(s) { |
| 193 | + console.log(s); |
| 194 | + }); |
| 195 | +
|
| 196 | +``` |
| 197 | + |
| 198 | +保持上一小节环境的情况下,在电脑上进行操作: |
| 199 | + |
| 200 | +``` |
| 201 | +$ frida -U -l enumerate_classes_bluetooth_choose_allmethod.js com.android.bluetooth |
| 202 | +
|
| 203 | +``` |
| 204 | + |
| 205 | +最终效果如下,类的所有方法均被打印了出来。 |
| 206 | + |
| 207 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/009.png) |
| 208 | + |
| 209 | +接下来如何 “滥用” 这些方法,拦截、修改参数、修改结果、等等,皆可悉听尊便,具体流程请参考 |
| 210 | + |
| 211 | +### 0x06. 综合案例:在安卓`8.1`上 dump 蓝牙接口和实例: |
| 212 | + |
| 213 | +一个比较好的综合案例,就是作为�上文案例的`dump`蓝牙信息的 “加强版”——['BlueCrawl'](https://github.com/IOActive/BlueCrawl)。 |
| 214 | + |
| 215 | +``` |
| 216 | +VERSION="1.0.0" |
| 217 | +setTimeout(function(){ |
| 218 | + Java.perform(function(){ |
| 219 | +
|
| 220 | + Java.enumerateLoadedClasses({ |
| 221 | + onMatch: function(instance){ |
| 222 | + if (instance.split(".")[1] == "bluetooth"){ |
| 223 | + console.log("[->]\t"+lightBlueCursor()+instance+closeCursor()); |
| 224 | + } |
| 225 | + }, |
| 226 | + onComplete: function() {} |
| 227 | + }); |
| 228 | +
|
| 229 | + Java.choose("android.bluetooth.BluetoothGattServer",{ |
| 230 | + onMatch: function (instance){ |
| 231 | + ... |
| 232 | + onComplete: function() { console.log("[*] -----");} |
| 233 | + }); |
| 234 | +
|
| 235 | + Java.choose("android.bluetooth.BluetoothGattService",{ |
| 236 | + onMatch: function (instance){ |
| 237 | + ... |
| 238 | + onComplete: function() { console.log("[*] -----");} |
| 239 | + }); |
| 240 | +
|
| 241 | + Java.choose("android.bluetooth.BluetoothSocket",{ |
| 242 | + onMatch: function (instance){ |
| 243 | + ... |
| 244 | + onComplete: function() { console.log("[*] -----");} |
| 245 | + }); |
| 246 | +
|
| 247 | + Java.choose("android.bluetooth.BluetoothServerSocket",{ |
| 248 | + onMatch: function (instance){ |
| 249 | + ... |
| 250 | + onComplete: function() { console.log("[*] -----");} |
| 251 | + }); |
| 252 | +
|
| 253 | + Java.choose("android.bluetooth.BluetoothDevice",{ |
| 254 | + onMatch: function (instance){ |
| 255 | + ... |
| 256 | + onComplete: function() { console.log("[*] -----");} |
| 257 | + }); |
| 258 | + }); |
| 259 | +},0); |
| 260 | +
|
| 261 | +``` |
| 262 | + |
| 263 | +该脚本首先枚举了很多蓝牙相关的类,然后`choose`了很多类,包括蓝牙接口信息以及蓝牙服务接口对象等,还加载了内存中已经分配好的蓝牙设备对象,也就是上文我们已经演示的信息。我们可以用这个脚本来 “查看”`App`加载了哪些蓝牙的接口,`App`是否正在查找蓝牙设备、或者是否窃取蓝牙设备信息等。 |
| 264 | + |
| 265 | +在电脑上运行命令: |
| 266 | + |
| 267 | +``` |
| 268 | +$ frida -U -l bluecrawl-1.0.0.js com.android.bluetooth |
| 269 | +``` |
| 270 | + |
| 271 | +[](/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/pic/010.png) |
| 272 | + |
| 273 | +可以看到该脚本在安卓 8.1 上运行良好,我们的接口和设备均被打印了出来。 |
| 274 | + |
| 275 | +## REF |
| 276 | + |
| 277 | +- [简悦 SimpRead](http://ksria.com/simpread/) |
| 278 | +- [AndroidSecurityStudy](https://github.com/r0ysue/AndroidSecurityStudy/blob/master/FRIDA/B01/README.md) |
0 commit comments