Frida基础笔记

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

[TOC]

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 常用命令

  • adb shell dumpsys activity top 查看当前处于前台的Activity
  • adb shell dumpsys window | grep mCurrentFocus 打印当前焦点窗口
  • adb shell dumpsys 包名 打印包信息,四大组件MIME权限等
  • adb shell dumpsys dbinfo 包名 查看APPP的数据库信息
  • adb shell screencap -p 路径 截图保存到对应路径
  • adb shell input test 文字 在焦点输入框内输入文字,无法输入中文
  • adb shell pm list packages 列出所有按照的APK包名
  • adb shell pm install 安装包路径 安装手机里的APK文件,uninstall 包名用于卸载
  • adb shell am start-activity -D -N 包名/类名 以DEBUG模式启动APP的Activity, 不加-D则正常启动
  • adb shell getprop ro.product.cpu.abi 查看手机系统架构
  • adb shell settings get secure bluetooth_address adb获取蓝牙MAC地址
  • adb shell "service call iphonesubinfo 1 | toybox cut -d \"'\" -f2 | toybox grep -Eo '[0-9]' | toybox xargs | toybox sed 's/\ //g'" adb获取IMEI

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环境。

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

使用VSCode在frida-agent-example子目录下编写JS脚本就会有智能提示。

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 打印相应类的具体内容

需要使用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 

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

你可能感兴趣的:(Frida基础笔记)