当前位置: 首页>后端>正文

Frida安卓基础

| 基于Kali Linux
| htop 查看当前活跃进程
| jnettop 实时查看系统网络负载工具
| 源码阅读:https://cs.android.com
| 源码阅读:http://aospxref.com
| 源码阅读:http://androidxref.com
| 源码阅读:https://www.androidos.net.cn/sourcecode

Frida安卓基础,第1张
目录

1. 刷机

Android 源码编译和刷机ROOT

2. Shell 常用命令

  • cat 查看文本文件内容: cat 1.txt
  • touch 创建空文件 : touch a.txt
  • echo > 覆盖写操作: echo "afra55" > a.txt
  • echo >> 扩展写操作
  • grep 过滤符合条件的输出: cat a.txt | grep afra
  • ps -e 打印全部进程,查看手机的全部进程
  • ps 打印当前进程
  • netstat 查看对应APP进程的IP、端口、协议等网络信息: netstat -alpe grep org.myapp
  • lsof 查看对应进程打开的文件: lsof -p 21212 -l
  • top 查看当前活跃进程,查看手机当前运行的进程

3. adb 常用命令

描述 命令
查看当前处于前台的Activity adb shell dumpsys activity top
打印当前焦点窗口 adb shell dumpsys window | grep mCurrentFocus
打印包信息,四大组件MIME权限等 adb shell dumpsys 包名
查看APPP的数据库信息 adb shell dumpsys dbinfo 包名
截图保存到手机 adb shell screencap -p 路径
截图保存到电脑 adb exec-out screencap -p > screen.png
录制屏幕 adb shell screenrecord /sdcard/filename.mp4
在焦点输入框内输入文字,无法输入中文 adb shell input test 文字
列出所有按照的APK包名 adb shell pm list packages
安装手机里的APK文件,uninstall 包名用于卸载 adb shell pm install 安装包路径
启动APP的Activity, -D是DEBUG模式 adb shell am start-activity -D -N 包名/类名
启动主Activity adb shell monkey -p 包名 -c android.intent.category.LAUNCHER 1
查看手机系统架构 adb shell getprop ro.product.cpu.abi
查看手机型号 adb shell getprop ro.product.model
查看电池信息 adb shell dumpsys battery
查看屏幕分辨率 adb shell wm size
查看屏幕密度 adb shell wm density
查看android_id adb shell settings get secure android_id
adb获取蓝牙MAC地址 adb shell settings get secure bluetooth_address
adb获取IMEI adb shell "service call iphonesubinfo 1 | toybox cut -d \"'\" -f2 | toybox grep -Eo '[0-9]' | toybox xargs | toybox sed 's/\ //g'"
清除应用数据&缓存 adb shell pm clear 包名
获取设备IP地址 adb shell ip route | awk '{print }'
启用设备的网络 adb 功能 adb tcpip 5555
网络连接设备 adb connect DEVICE_IP:5555
截图 adb shell screencap -p /sdcard/screenshot.png
查看应用安装路径, 该路径下的apk可以pull下来使用 adb shell pm path 包名
强制停止应用 adb shell am force-stop 包名
模拟按键输入,见附表一 adb shell input keyevent 按键代码
向上滑动手势解锁 adb shell input swipe 300 1000 300 500
发送广播,见附表二 adb shell am broadcast -a <action> [-d ] [-t <mime_type>] [-c <category>]
查看实时资源占用情况,见附表四 adb shell top

附表一:按键代码

keycode 含义
3 HOME 键
4 返回键
5 打开拨号应用
6 挂断电话
24 增加音量
25 降低音量
26 电源键
27 拍照(需要在相机应用里)
64 打开浏览器
82 菜单键
85 播放/暂停
86 停止播放
87 播放下一首
88 播放上一首
122 移动光标到行首或列表顶部
123 移动光标到行末或列表底部
126 恢复播放
127 暂停播放
164 静音
176 打开系统设置
187 切换应用
207 打开联系人
208 打开日历
209 打开音乐
210 打开计算器
220 降低屏幕亮度
221 提高屏幕亮度
223 系统休眠
224 点亮屏幕
231 打开语音助手
276 如果没有 wakelock 则让系统休眠

附表二:常见广播意图
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED

action 触发时机
android.net.conn.CONNECTIVITY_CHANGE 网络连接发生变化
android.intent.action.SCREEN_ON 屏幕点亮
android.intent.action.SCREEN_OFF 屏幕熄灭
android.intent.action.BATTERY_LOW 电量低,会弹出电量低提示框
android.intent.action.BATTERY_OKAY 电量恢复了
android.intent.action.BOOT_COMPLETED 设备启动完毕
android.intent.action.DEVICE_STORAGE_LOW 存储空间过低
android.intent.action.DEVICE_STORAGE_OK 存储空间恢复
android.intent.action.PACKAGE_ADDED 安装了新的应用
android.net.wifi.STATE_CHANGE WiFi 连接状态发生变化
android.net.wifi.WIFI_STATE_CHANGED WiFi 状态变为启用/关闭/正在启动/正在关闭/未知
android.intent.action.BATTERY_CHANGED 电池电量发生变化
android.intent.action.INPUT_METHOD_CHANGED 系统输入法发生变化
android.intent.action.ACTION_POWER_CONNECTED 外部电源连接
android.intent.action.ACTION_POWER_DISCONNECTED 外部电源断开连接
android.intent.action.DREAMING_STARTED 系统开始休眠
android.intent.action.DREAMING_STOPPED 系统停止休眠
android.intent.action.WALLPAPER_CHANGED 壁纸发生变化
android.intent.action.HEADSET_PLUG 插入耳机
android.intent.action.MEDIA_UNMOUNTED 卸载外部介质
android.intent.action.MEDIA_MOUNTED 挂载外部介质
android.os.action.POWER_SAVE_MODE_CHANGED 省电模式开启

附表三:系统属性

属性名 含义
ro.build.version.sdk SDK 版本
ro.build.version.release Android 系统版本
ro.build.version.security_patch Android 安全补丁程序级别
ro.product.model 型号
ro.product.brand 品牌
ro.product.name 设备名
ro.product.board 处理器型号
ro.product.cpu.abilist CPU 支持的 abi 列表
persist.sys.isUsbOtgEnabled 是否支持 OTG
dalvik.vm.heapsize 每个应用程序的内存上限
ro.sf.lcd_density 屏幕密度

附表四:实时资源占用情况表描述

列名 含义
PID 进程 ID
PR 优先级
CPU% 当前瞬间占用 CPU 百分比
S 进程状态(R=运行,S=睡眠,T=跟踪/停止,Z=僵尸进程)
#THR 线程数
VSS Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PCY 调度策略优先级,SP_BACKGROUND/SPFOREGROUND
UID 进程所有者的用户 ID
NAME 进程名

3. Frida 环境

3.1 安装 Frida

https://github.com/frida/frida

# frida --version
15.2.2

3.2 查看手机系统架构

# adb shell getprop ro.product.cpu.abi
arm64-v8a

3.3 下载与安装的Frida版本对应 frida-server

下载测试机系统架构对应的 frida-server
https://github.com/frida/frida/releases

frida-server-15.2.2-android-arm64.xz

3.4 讲 frida-server 推送到手机

# 7z x frida-server-15.2.2-android-arm64.tar.xz
# adb push  frida-server-15.2.2-android-arm64 /data/local/tmp/
# adb shell
# su
# cd /data/local/tmp
# chmod 777 frida-server-15.2.2-android-arm64

3.5 启动 frida-server

# adb shell
# su
# cd /data/local/tmp
# ./frida-server-15.2.2-android-arm64

4 Frida 脚本智能提示

基于Node和NPM环境。
安装 nodejs: https://nodejs.org/en/download/package-manager
推荐使用三方包管理器安装:https://github.com/nodesource/distributions#installation-instructions

4.1 使用Frida示例项目

# git clone https://github.com/oleavr/frida-agent-example
# cd frida-agent-example
# npm install

使用vscode等IDE打开此工程,在agent文件夹下编写JavaScript,会有智能提示。

4.2 使用 npm 包 frida-gum

在系统里装上这个这个npm包(https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/frida-gum),可以在任意工程获得frida的代码提示、补全和API查看。
npm i -g @types/frida-gum

5 Frida 注入命令

5.1 USB 注入

查看进程
# frida-ps -U
注入脚本:
# frida -U 进程名 -l 脚本路径.js
或直接对当前顶层应用注入脚本:
# frida -UF -l 脚本路径.js
加上 -f 参数则将启动App的权利交由Frida来控制,即使目标App已经启动,在使用Frida注入程序时还是会重新启动App.
# frida -U -f 进程名 -l hook.js
--no-pause 是 Frida 的一个参数,用于在启动时禁止自动暂停目标进程。默认情况下,Frida 会在注入到目标进程后自动暂停该进程,以便用户可以执行进一步的操作,比如在运行时修改内存或进行调试。使用 --no-pause 参数可以禁止这种自动暂停行为,使目标进程继续正常运行。这在某些场景下可能很有用,例如当你只需要监视应用程序的行为而无需进行交互式的调试时。
# frida -U -f 进程名 -l hook.js --no-pause

5.2 网络模式注入

5.2.1 安装 Termux

可以在手机上执行linux命令
https://github.com/termux/termux-app#installation

5.2.2 frida-server 使用网络模式进行监听

在手机上执行命令,打开 Termux:

# su
# cd /data/local/tmp/
# ./frida-server-15.2.2-android-arm64 -l 0.0.0.0:8888

或者直接在电脑上执行也行,网络模式一般用来分析那些禁止USB链接的应用。
查看 frida-service 监听的端口:
# netstat -tulp | grep frida

tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN      14541/frida-server-15.2.2-android-arm64

5.2.3 Frida网络注入

# frida -H 192.168.0.107:8888 -l test.js FridaTest
使用参数 -H 传入测试机的IP和端口,即可进行网络设备注入。

6 Frida脚本基础

test.js

function main(){
    Java.perform(function(){
        console.log("任何对APP的JAVA层的操作,都要写在这个匿名函数里面")

        // 获取对应类的JavaScript对象
        var Example = Java.use('com.example.Example') 

         // new 了一个 Java Stirng 字符串
        var JavaString = Java.use('java.lang.String').$new('122')

        // Hook 重载 类Example 的方法,在该方法调用的时候,会触发匿名函数,可不加overload,fraida报错信息会提示是否应该加上参数信息
        Example.方法名.overload('java.lang.String', 'java.lang.String').implementation = function(str, str2){

            // 传入参数,获取结果,可以自行修改传入参数
            var result = this.方法名(JavaString, JavaString.$new('123'))
            console.log('str, str2, result: ', str, str2, result)
            
            // 打印调用堆栈信息
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
            return result  // 返回结果,可以自行修改返回结果
        }


        // 主动调用类 Example 的静态方法
        var subResult = Example.静态方法名(JavaString.$new("6"), JavaString.$new("7"))

        // 主动调用 Example 的内部方法和变量
        Java.choose('com.example.Example', {
            onMatch:function(instance){
                console.log("变量值", instance.变量名.value)

                // 调用内部方法
                instance.方法名()
            },onComplete:function(){
                console.log("动态调用成功")
            }
        })

        console.log(subResult)
    })
}
setImmediate(main) // 注入后立即执行 main函数
// setTimeout(main, 100) // 注入后,100ms后再执行 main函数

7 RPC 及Python自动化

https://github.com/frida/frida-python

在 js 脚本末尾添加 rpc.exports 用于导出函数,注意导出函数名必须小写:

rpc.exports = {
    callmain:main,
    getfun:getNumber
}

上面导出了2个函数,使得外部可以调用。
loader.py

import frida, sys, time

def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)

# 获得USB句柄,
devices = frida.get_usb_device()

# 可以添加多个网络设备
# devices = frida.get_usb_device().add_remote_device('192.168.0.107:8888')

# spawn 方式注入
# pid = devices.spawn(["进程名"])
# devices.resume(pid) # 唤起进程
# time.sleep(1) 
# process = devices.attach(pid)

# attach 方式进程注入
process = devices.attach('进程名')

# 加载脚本代码
with open('test.js') as f:
    jscode = f.read()
script = process.create_script(jscode)

# 注册信息打印函数
script.on('message', on_message)
script.load()

command = ""
while 1==1:
    command = input("\nEnter:\n1:exit\n2:call\n3:get\nchoice:")
    if command == "1":
        break
    elif command == "2":
        script.exports.callmain() # 调用脚本方法
    elif command == "3":
        script.exports.getfun()

执行该Python即可。

8 Objection 安装

Objection 可以快速搜索内存,搜索,Hook方法,打印参数返回值调用栈,不写一行脚本就能进行APP分析。
https://github.com/sensepost/objection

9 Objection 常用命令

注入后,把要HOOK的功能都触发一次。

9.1 注入

# objection -g 包名 explore

9.2 列出内存所有的类

# android hooking list classes

9.3 搜索包含关键词的类

# android hooking search classes 关键词

9.4 搜索包含关键词的方法

# android hooking search methods 关键词

9.5 查看指定类的所有方法

# android hooking list class_methods 完整类名

9.6 列出注入进程的所有 Activity

# android hooking list activities

9.7 列出注入进程的所有 services

# android hooking list services

9.8 HOOK 指定方法

# android hooking watch class_method 方法名 --dump-args --dump-backtrace --dump-return

9.9 查看当前正在HOOK的作业信息

# jobs list

9.10 移除HOOK

# jobs kill 作业ID

9.11 启动Activity

# android intent launch_activity Activity名

9.12 搜索实例类似 Java.use

# android heap search instance 类名

9.13 执行无参实例方法

# android heap execute 实例Handle 方法名

9.14 执行有参实例方法

# android heap evaluate 实例Handle
clazz.方法名(参数...)

9.15 执行静态方法

TODO

9.16 使用插件Wallbreaker打印相应类的具体内容

需要使用Objection的插件 https://github.com/hluwa/wallbreaker,这个插件可以打印类的具体内容,比如静态成员实例成员的值,及所有函数。>
下载&安装:

# git clone https://github.com/hluwa/wallbreaker ~/.objection/plugins/Wallbreaker

注入时使用-P加载插件即可:

# objection  -g 包名 explore -P ~/.objection/plugins/

或者在注入后,再进行加载使用 :

# plugin load /root/.objection/plugins/Wallbreaker/
# plugin wallbreaker objectsearch java.util.HashMap
# plugin wallbreaker objectdump <object-handle>

示例,打印系统主要API接口:

# objection -g com.android.settings explore  
# plugin load /root/.objection/plugins/Wallbreaker/
# plugin wallbreaker classdump android.os.Build

9.17 ZenTracer

有界面的HOOK工具,更方便便捷。
https://github.com/hluwa/ZenTracer

10 Objection 网络模式

开启测试机的 frida-server 网络模式监听,详见5.2。
使用 -N 参数进行网络模式连接:
# objection -N -h 192.168.0.107 -p 8888 -g 包名 explore

11 脱壳

11.1 FRIDA-DEXDump

这个工具可以从内存中搜索和dump符合条件的dex文件,当然VMP壳时脱不了的,只能脱1代壳。

11.1.1 安装插件

https://github.com/hluwa/frida-dexdump#frida-dexdump
这里作为Objection插件来使用:

# pip3 install frida-dexdump

11.1.2 脱壳&重打包

推荐使用 -d 模式,开启深度搜索模式。

# frida-dexdump -U -f 包名 -d

# frida-dexdump -FU -d

等待一段时间,完成脱壳,记得脱壳前先玩玩APP。

classes.dex
classes02.dex  
classes03.dex  
classes04.dex  
classes05.dex

可以使用gerp定位关键类所在的dex:
grep -ril "关键词" ./*.dex

11.1.3 使用 apktool 重打包

https://github.com/iBotPeaches/Apktool/tree/docs

还是MT管理器方便,推荐使用

反编译APK但不反编译 dex, 加-s命令即可:

# apktool d 包名 -s

将反编译后的dex删除。
把脱壳后的class重命名并放入反编译后的文件里:

classes.dex
classes2.dex  
classes3.dex  
classes4.dex  
classes5.dex

重要的一点时,脱壳后的Applicaiton入口变了,需要找到脱壳后的Application,

# grep -ril "Application" ./*.dex
# grep -ril "android.app.Application" ./*.dex
# grep -ril "onCreate()" ./*.dex

找到关键 dex,反编译后查找 extends Application 即可找到真正的Applicaiton。
在清单文件中替换 application 节点的name即可。
重新编译:

# apktool b 反编译的文件夹

重新编译的APK在反编译目录下的dist文件夹。
创建签名文件:

# keytool -genkey -alias 别名 -keyalg RSA -validity 2000 -keystore test.jks

进行签名:

jarsigner -verbose -keystore 签名文件 -signedjar 签名后的.apk 等待签名的.apk 别名

11.2 FRIDA-FART

https://github.com/hanbinglengyue/FART

这个工具用于脱二代抽取型加固壳。

12 Charles 抓包 (ROOT环境)

12.1 下载并安装

https://www.charlesproxy.com/download/

12.2 手机安装证书

手机配置代理后打开网页chls.pro/ssl,下载并安装用户证书。

12.3 将用户证书变成系统证书

# adb shell
# su
# cd /data/misc/user/0/cacerts-added/  
# mount -o remount,rw /system
# cp * /etc/security/cacerts 
# chmod 777 /etc/security/cacerts/* 
# mount -o remount,ro /system
# reboot

12.4 配置SOCKS5

移除手动配置的代理,安装应用Postern并配置 SOCKS5协议,打开Charles的 SOCKS 协议,端口号要和 HTTP协议不一样。

13 HOOK关键词OkHttp抓包

13.1 OkHttp未被混淆

清空 Objection 日志:
# rm ~/.objection/objection.log
注入APP:
# objection -g 包名 explore
获取APP已经加载的所有类:
# android hooking list classes
退出确保日志已经存储:
# exit
复制日志文件到其他目录:
# cp ~/.objection/objection.log ./
过滤网络相关的类, 并保存到文件中, 可以先扫描再使用符号重定向:
# cat objection.log | grep -i HttpURLConnection > HttpURLConnection.txt
# cat objection.log | grep -i okhttp > okhttp.txt
# cat objection.log | grep -i okhttp3 > okhttp3.txt
使用VIM再每行行首添加Hook命令:
# :%s/^/android hooking watch class /
保存并退出:
# :wq
注入并批量执行HOOK命令:
# objection -g 包名 explore -c "./okhttp.txt"
查看相关函数, 退出 Objection,然后再对该函数进行HOOK:
# android hooking watch class_method 函数名 --dump-args --dump-backtrace --dump-return
就能找到调用的具体位置, 再对调用函数进行HOOK。

13.2 OkHttp 被混淆了

https://github.com/siyujie/okhttpLogger-Frida
该项目使用了OkHttp3框架的特征去验证OkHtt3是否被使用了,而不是直接搜所关键词。
下载项目。
okhttpfind.dex 拷贝到 /data/local/tmp/ 目录下,并提升权限。

# adb push okhttpfind.dex /data/local/tmp/
# su
# chmod 777 /data/local/tmp/okhttpfind.dex 

执行命令启动frida -U -l okhttp_poker.js -f com.example.demo --no-pause 可追加 -o [output filepath]保存到文件。
或者打开应用到前台执行注入命令:frida -U -l okhttp_poker.js -F --no-pause
执行find()方法。
如果提示方法未找到,则修改脚本直接执行 find()
Find Complete 里的内容覆盖到脚本里的对应参数。
再次注入执行hold()方法,就会输出所有的请求信息。

13.3 Frida 动态注入 Dex

通过如下API即可动态加载DEX到内存中,使用我们自己的类和方法:

 Java.openClassFile("/data/local/tmp/HttpLoggingInter").load()

示例:OkHttp3 提供了日志打印库:

 implementation("com.squareup.okhttp3:logging-interceptor")

但分析的APP使用了OkHttp3,而且没有加日志打印库的时候,可以进行dex动态注入,自己写一个dex,来加载APP里没有的类库。
一般OkHttp3是这样加载日志打印拦截器的:

   HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
   interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
   new OkHttpClient.Builder()
                .addNetworkInterceptor(interceptor)
                .build();

写一个空Android项目,添加该类库,并运行起来。
app/build/intermediates/apk/debug 找到生成的APK,并解压缩。
通过下面的命令找到类库所在的dex文件。
# grep -ril "HttpLoggingInterceptor" ./*.dex
将其推送至/data/local/tmp目录下:
adb push HttpLoggingInterceptor.dex /data/local/tmp/
编写Frida脚本:

function main(){
    Java.perform(function(){

        // 加载我们的dex文件
        Java.openClassFile("/data/local/tmp/HttpLoggingInterceptor.dex").load();
        var HttpLoggingInterceptor = Java.use("okhttp3.logging.HttpLoggingInterceptor");
        var HttpLoggingInterceptorObj = HttpLoggingInterceptor.$new();
        var Level = Java.use("okhttp3.logging.HttpLoggingInterceptor$Level");
        // 设置枚举值BODY,另OkHttp3打印所有日志
        HttpLoggingInterceptorObj.setLevel(Level.BODY.value);
        var Builder = Java.use("okhttp3.OkHttpClient$Builder");
        Builder.build.implementation = function(){
            this.networkInterceptors().add(HttpLoggingInterceptorObj);
            console.log("add network interceptor");
            return this.build();
        };
        console.log("hook okhttp3 log");
    })
}
setImmediate(main) 

执行命令使用Spawned模式, 从APP启动的时候,就开始HOOK注入:
# frida -U -f 进程名 -l 脚本.js --no-pause
这时APP进行网络请求时,即可看到所有信息。

14. HOOK 应用证书文件

保存证书到 sdcar里:

function hook_KeyStore_load() {
    Java.perform(function () {
        var myArray=new Array(1024);
        var i = 0
        for (i = 0; i < myArray.length; i++) {
            myArray[i]= 0x0;
         }
        var buffer = Java.array('byte',myArray);
        var StringClass = Java.use("java.lang.String");

        var KeyStore = Java.use("java.security.KeyStore");
        KeyStore.load.overload('java.security.KeyStore$LoadStoreParameter').implementation = function (arg0) {
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));

            console.log("KeyStore.load1:", arg0);
            this.load(arg0);
        };
        KeyStore.load.overload('java.io.InputStream', '[C').implementation = function (arg0, arg1) {
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));

            console.log("KeyStore.load2: filename = ", arg0,',password = ', arg1 StringClass.$new(arg1) : null);
            if (arg0){
                var filename  = "/sdcard/Download/"+ String(arg0)
                var file =  Java.use("java.io.File").$new(filename);
                var out = Java.use("java.io.FileOutputStream").$new(file);
                var r;
                while( (r = arg0.read(buffer)) > 0){
                    out.write(buffer,0,r)
                }
                console.log('save_path = ',filename,", cert save success!")
                out.close()
            }
            this.load(arg0, arg1);
        };
        
        console.log("hook_KeyStore_load...");
    });
}
function main(){
    hook_KeyStore_load()
}
setImmediate(main);

导出证书后,可使用 KeyStore Explorer 工具转换证书格式,以便导入到 Charles中。
如果API使用了非标准HTTPS端口,还要手动配置该端口为HTTP数据包。

15 安卓应用层明文协议抓包通杀脚本 r0capture

https://github.com/r0ysue/r0capture

16. Java类追踪脚本 r0tracer

  • 根据黑白名单批量追踪类的所有方法
  • 在命中方法后打印出该类或对象的所有域值、参数、调用栈和返回值
  • 极简的文本保存日志机制、易于搜索关键参数
  • 针对加壳应用找不到类时可以切换Classloader

https://www.xamrdz.com/backend/3vd1923439.html

相关文章: