Frida 脱壳、自动化、fridaUiTools、objection、Wallbreaker

r0ysue 系列文章:https:githubr0ysueAndroidSecurityStudy Awesome Frida (库、项目、工具):https:githubdwei

r0ysue 系列文章:https://github/r0ysue/AndroidSecurityStudy
Awesome Frida (库、项目、工具):https://github/dweinstein/awesome-frida

学习 Frida 的实际高频场景,比如:

  • 动态查看 安卓应用程序 在当前内存中的状态
  • 指哪儿就能 hook 哪儿
  • 比如 脱壳,
  • 还有使用 Frida 来自动化获取参数、返回值等数据,
  • 主动调用 API 获取签名结果 sign 等。

 
 

1、Frida 脱壳、自动化

实用 FRIDA 进阶:脱壳、自动化、高频问题:https://www.anquanke/post/id/197670

Frida 脱壳

  • 一代整体型壳:采用 Dex 整体加密,动态加载运行的机制;
  • 二代函数抽取型壳:粒度更细,将方法单独抽取出来,加密保存,解密执行。二代函数抽取壳目前是可以从根本上进行还原的,dump出所有的运行时的方法体,填充到dump下来的dex中去的,这也是 fart 的核心原理;
  • 三代 VMP、Dex2C壳:独立虚拟机解释执行、语义等价语法迁移,强度最高。Dex2C 目前是没有办法还原的,只能跟踪进行分析;VMP虚拟机解释执行保护的是映射表,只要心思细、功夫深,是可以将映射表还原的;

推荐的几个内存中搜索和dump出dex的Frida工具,在一些场景中可以满足大家的需求。

方法 1:文件头搜dex

地址:https://github/r0ysue/frida_dump

命令:frida -U --no-pause -f com.xxxxxx.xxxxxx  -l dump_dex.js

其核心逻辑原理:magic.indexOf("dex") == 0,只要文件头中含有魔数dex,就把它dump下来。

if (dex_maps[base] == undefined) {
    dex_maps[base] = size;
    var magic = ptr(base).readCString();
    if (magic.indexOf("dex") == 0) {
        var process_name = get_self_process_name();
        if (process_name != "-1") {
            var dex_path = "/data/data/" + process_name + "/files/" + base.toString(16) + "_" + size.toString(16) + ".dex";
            console.log("[find dex]:", dex_path);
            var fd = new File(dex_path, "wb");
            if (fd && fd != null) {
                var dex_buffer = ptr(base).readByteArray(size);
                fd.write(dex_buffer);
                fd.flush();
                fd.close();
                console.log("[dump dex]:", dex_path);

            }
        }
    }
}

方法 2:objection 的 DexClassLoader

安卓只能使用继承自 BaseDexClassLoader 的两种 ClassLoader,一种是 PathClassLoader,用于加载系统中已经安装的apk;一种就是 DexClassLoader,加载未安装的 jar包 或 apk。可以用 objcetion 直接在堆上暴力搜索所有的 dalvik.system.DexClassLoader 实例,命令:android heap search instances dalvik.system.DexClassLoader  效果见下图:

连热补丁都被搜出来了,在某些一代壳上效果不错。

方法 3:暴力搜内存:DEXDump

地址:https://github/hluwa/FRIDA-DEXDump
对于完整的dex,采用暴力搜索dex035即可找到。而对于抹头的dex,通过匹配一些特征来找到,然后自动修复文件头。命令:python main.py 

打开 dump下来的dex,非常完整,可以用jadx直接解析。用010打开可以看到完整的文件头——dexn035,其实现代码也是简单粗暴,直接搜索:64 65 78 0a 30 33 35 00:

Memory.scanSync(range.base, range.size, "64 65 78 0a 30 33 35 00").forEach(function (match) {
var range = Process.findRangeByAddress(match.address);

if (range != null && range.size < match.address.toInt32() + 0x24 - range.base.toInt32()) {
    return;
}

var dex_size = match.address.add("0x20").readInt();

if (range != null) {

    if (range.file && range.file.path
        && (range.file.path.startsWith("/data/app/")
            || range.file.path.startsWith("/data/dalvik-cache/")
            || range.file.path.startsWith("/system/"))) {
        return;
    }

    if (match.address.toInt32() + dex_size > range.base.toInt32() + range.size) {
        return;
    }
}

还有一部分想要特征匹配的功能还在实现中:

// @TODO improve fuzz
if (
    range.size >= 0x60
    && range.base.readCString(4) != "dexn"
    && range.base.add(0x20).readInt() <= range.size //file_size
    // && range.base.add(0x24).readInt() == 112 //header_size
    && range.base.add(0x34).readInt() < range.size
    && range.base.add(0x3C).readInt() == 112 //string_id_off
) {
    result.push({
        "addr": range.base,
        "size": range.base.add(0x20).readInt()
    });
}

方法 4:暴力搜内存:objection

既然直接使用 Frida 的 API 可以暴力搜索内存,那么 objection 也可以暴力搜内存。

命令:memory search "64 65 78 0a 30 33 35 00"

搜出来的offset是:0x79efc00000,大小是c4 41 83 00,也就是0x8341c4,转化成十进制就是8602052,最后dump下来的内容与FRIDA-DEXDump脱下来的一模一样,拖到jdax里可以直接解析。

Frida 自动化

在 Frida 出现之前,没有任何一款工具,可以在语言级别支持直接在电脑上调用app中的方法。像Xposed是纯Java,根本就没有电脑上运行的版本;各种Native框架也是一样,都是由C/C++/asm实现,根本与电脑毫无关系。而Frida主要是一款在电脑上操作的工具,其本身就决定了其“高并发”、“多联通”、“自动化”等特性:

“高并发”:同时操作多台手机,同时调用多个手机上的多个app中的算法;
“多联通”:电脑与手机互联互通,手机上处理不了的在电脑上处理、反之亦然;
“自动化”:手机电脑互相协同,实现横跨桌面、移动平台协同自动化利器。

连接多台设备

Frida用于自动化的场景中,必然是不可能在终端敲frida-tools里的那些命令行工具的,有人说可以将这些命令按顺序写成脚本,那为啥不直接写成python脚本呢?枉费大胡子叔叔(Frida的作者oleavr的头像)为我们写好了Python bindings,我们只需要直接调用即可享受。

Python bindings在安装好frida-tools的时候已经默认安装在我们的电脑上了,可以直接使用。

连接多台设备非常简单,如果是USB口直接连接的,只要确保adb已经连接上,如果是网络调试的,也要用adb connect连接上,并且都开启frida server,键入adb devices或者frida-ls-devices命令时多台设备的id都会出现,最终可以使用frida.get_device(id)的API来选择设备,如下图所示。

互联互通

互联互通是指把app中捕获的内容传输到电脑上,电脑上处理结束后再发回给app继续处理。看似很简单的一个功能,目前却仅有Frida可以实现。

比如说我们有这样一个app,其中最核心的地方在于判断用户是否为admin,如果是,则直接返回错误,禁止登陆。如果不是,则把用户和密码上传到服务器上进行验证登录操作,其核心代码逻辑如下:

public class MainActivity extends AppCompatActivity {

    EditText username_et;
    EditText password_et;
    TextView message_tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        password_et = (EditText) this.findViewById(R.id.editText2);
        username_et = (EditText) this.findViewById(R.id.editText);
        message_tv = ((TextView) findViewById(R.id.textView));

        this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (username_et.getText().toString()pareTo("admin") == 0) {
                    message_tv.setText("You cannot login as admin");
                    return;
                }
                //我们hook的目标就在这里
                message_tv.setText("Sending to the server :" + Base64.encodeToString((username_et.getText().toString() + ":" + password_et.getText().toString()).getBytes(), Base64.DEFAULT));

            }
        });

    }
}

运行起来的效果如下图:

目标就是在电脑上“得到”输入框输入的内容,并且修改其输入的内容,并且“传输”给安卓机器,使其通过验证。也就是说,我们的目标是哪怕输入admin的账户名和密码,也可以绕过本地校验,进行服务器验证登陆的操作。

所以最终的hook代码的逻辑就是,截取输入,传输给电脑,暂停执行,得到电脑传回的数据之后,继续执行,用js来写就这么写:

Java.perform(function () {
    var tv_class = Java.use("android.widget.TextView");
    tv_class.setText.overload("java.lang.CharSequence").implementation = function (x) {
        var string_to_send = x.toString();
        var string_to_recv;
        send(string_to_send); // 将数据发送给kali主机的python代码
        recv(function (received_json_object) {
            string_to_recv = received_json_object.my_data
            console.log("string_to_recv: " + string_to_recv);
        }).wait(); //收到数据之后,再执行下去
        return this.setText(string_to_recv);
    }
});

在电脑上的处理流程是,将接受到的JSON数据解析,提取出其中的密码部分保持不变,然后将用户名替换成admin,这样就实现了将admin和password发送给服务器的结果。我们的代码如下:

import time
import frida

def my_message_handler(message, payload):
    print message
    print payload
    if message["type"] == "send":
        print message["payload"]
        data = message["payload"].split(":")[1].strip()
        print 'message:', message
        data = data.decode("base64") # 解码
        user, pw = data.split(":") # 提取用户名和密码
        data = ("admin" + ":" + pw).encode("base64") # 组成新的组合并编码
        print "encoded data:", data
        script.post({"my_data": data})  # 将JSON对象发送回去
        print "Modified data sent"

device = frida.get_usb_device()
pid = device.spawn(["com.roysue.demo04"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)
with open("s4.js") as f:
    script = session.create_script(f.read())
script.on("message", my_message_handler)  # 注册消息处理函数
script.load()
raw_input()

同样很多手机上无法处理的数据,也可以编码后发送到电脑上进行处理,比如处理GBK编码的中文字符集数据,再比如对dump下来的内存或so进行二次解析还原等,这些在js几乎是无法处理的(或难度非常大),但是到了电脑上就易如反掌,用python导入几个库就可以。

在一些(网络)接口的模糊测试的场景中,一些字典和畸形数据的构造也会在电脑上完成,app端最多作为执行端接受和发送这些数据,这时候也需要使用到Frida互联互通动态修改的功能。

远程调用(RPC)

在脚本里定义一个导出函数,并用 rpc.exports 的字典进行声明:

function callSecretFun() { //定义导出函数
    Java.perform(function () {
        //to-do 做自己想做的事情 
        //比如这里是找到隐藏函数并且调用
        Java.choose("com.roysue.demo02.MainActivity", {
            onMatch: function (instance) {
                console.log("Found instance: " + instance);
                console.log("Result of secret func: " + instance.secret());
            },
            onComplete: function () { }
        });
    });
}
rpc.exports = {
    //把callSecretFun函数导出为callsecretfunction符号,导出名不可以有大写字母或者下划线
    callsecretfunction: callSecretFun 
};

在电脑上就可以直接在py代码里调用这个方法:

import time
import frida

def my_message_handler(message, payload):
    print message
    print payload

device = frida.get_usb_device()
pid = device.spawn(["com.roysue.demo02"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)
with open("s3.js") as f:
    script = session.create_script(f.read())
script.on("message", my_message_handler)
script.load()

command = ""
while 1 == 1:
    command = raw_input("Enter command:n1: Exitn2: Call secret functionnchoice:")
    if command == "1":
        break
    elif command == "2": #在这里调用
        script.exports.callsecretfunction()

最终效果就是按一下2,function callSecretFun()就会被执行一次,并且结果会显示在电脑上的py脚本里,以供后续继续处理,非常方便。也可以使用 python 的 flask 框架暴露出去

Frida 技巧

反调试基本思路

几个最基本的思路

更改 frida-server 的文件名。例如改成 fs1287amd64

更改 frida-server 的监听端口,比如 frida-server 的默认端口是27042,有的反调试会检测这个默认端口,可以把端口改成非标准端口。
比如将 frida-server 启动在 6666 端口:
        ./fs1287amd64 -l 0.0.0.0:6666
然后,使用 frida-tools 工具和 objection 分别连接的方法如下:
        frida-ps -H 192.168.1.102:6666
        objection -N -h 192.168.1.102 -p 6666 -g com.android.settings explore

连接非标准端口。因为 python bindings 只认 adb,所以要通过 adb 命令将手机的 6666 端口映射到电脑的27042端口: adb forward tcp:27042 tcp:6666adb forward tcp:27042 tcp:6666

通过 Frida 内存特征对 maps 中 elf 文件进行扫描匹配特征的反调试方法,支持 frida-gadget 和frida-server。:https://github/qtfreet00/AntiFrida

其核心代码如下:

void *check_loop(void *) {
    int fd;
    char path[256];
    char perm[5];
    unsigned long offset;
    unsigned int base;
    long end;
    char buffer[BUFFER_LEN];
    int loop = 0;
    unsigned int length = 11;
    //"frida:rpc"的内存布局特征
    unsigned char frida_rpc[] =
            {

                    0xfe, 0xba, 0xfb, 0x4a, 0x9a, 0xca, 0x7f, 0xfb,
                    0xdb, 0xea, 0xfe, 0xdc
            };

    for (unsigned char &m : frida_rpc) {
        unsigned char c = m;
        c = ~c;
        c ^= 0xb1;
        c = (c >> 0x6) | (c << 0x2);
        c ^= 0x4a;
        c = (c >> 0x6) | (c << 0x2);
        m = c;
    }
    //开始检测frida反调试循环
    LOGI("start check frida loop");
    while (loop < 10) {
        fd = wrap_openat(AT_FDCWD, "/proc/self/maps", O_RDONLY, 0);
        if (fd > 0) {
            while ((read_line(fd, buffer, BUFFER_LEN)) > 0) {

                // 匹配frida-server和frida-gadget的内存特征
                if (sscanf(buffer, "%x-%lx %4s %lx %*s %*s %s", &base, &end, perm, &offset, path) !=
                    5) {
                    continue;
                }
                if (perm[0] != 'r') continue;
                if (perm[3] != 'p') continue; 
                if (0 != offset) continue;
                if (strlen(path) == 0) continue;
                if ('[' == path[0]) continue;
                if (end - base <= 1000000) continue;
                if (wrap_endsWith(path, ".oat")) continue;
                if (elf_check_header(base) != 1) continue;
                if (find_mem_string(base, end, frida_rpc, length) == 1) {
                    //发现其内存特征
                    LOGI("frida found in memory!");
#ifndef DEBUG
                    //杀掉自己的进程
                    wrap_kill(wrap_getpid(),SIGKILL);
#endif
                    //退出
                    break;
                }
            }
        } else {
            LOGI("open maps error");
        }
        wrap_close(fd);
        //休息三秒,进入下一个检查循环,也就是这个反调试一共会运作30秒,30秒后结束
        loop++;
        sleep(3);
    }
    return nullptr;
}


void anti_frida_loop() {
    pthread_t t;
    //创建一个线程,执行反调试工作
    if (pthread_create(&t, nullptr, check_loop, (void *) nullptr) != 0) {
        exit(-1);
    };
    pthread_detach(t);
}

想过这种反调试,得找到反调试在哪个so的哪里,nop 掉创建 check_loop 线程的地方,或者 nop掉 kill 自己进程的地方,都可以。也可以直接kill掉反调试进程。

场景:frida命令注入后,app调不起来,这时候用ps -e命令查看多一个反调试进程,直接kill掉那个进程后,app就起来了,这个app是使用的一个大厂的加固服务,这个进程就是壳的一部分。

打印 byte[] [B

ByteString.of 是用来把 byte[]数组转成hex字符串的函数, 安卓系统自带ByteString,app里面没有也没关系,可以去系统里面拿,这里给个小案例:

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
var j = Java.use("xxxxxxx.businessm.j");
j.x.implementation = function() {
    var result = this.x();
    console.log("j.x:", ByteString.of(result).hex());
    return result;
};

j.a.overload('[B').implementation = function(bArr) {
    this.a(bArr);
    console.log("j.a:", ByteString.of(bArr).hex());
};

hook 管理子进程

经常有人会问,像那种 com.xxx.xxx:push、com.xxx.xxx:service、com.xxx.xxx:notification、com.xxx.xxx:search这样的进程如何hook,或者说如何在其创建伊始进行hook,因为这样的进程一般都是由主进程fork()出来的。

这种的就要用到Frida最新的Child gating机制,可以参考《FRIDA脚本系列(四)更新篇:几个主要机制的大更新》,官方的完整代码在这里。可以在进程创建之初对该进程进行控制和hook,已经很多人用了,效果很好,达成目标。

hook 混淆方法名

有些方法名上了很强的混淆,如何处理?其实很简单,可以看上面ZenTracer的源码,hook类的所有子类,hook类的所有方法,并且hook方法的所有重载,《FRIDA脚本系列(二)成长篇:动静态结合逆向WhatsApp》。

中文参数问题

hook 某些方法的时候,发现传进来的参数竟然是中文的,如何打印出来?如果是utf8还好,Frida的CLI也是直接支持utf8的,如果是GBK字符集的,目前没有找到在js里进行打印的方法,可以send()到电脑上进行打印。

hook 主动注册

使用 Frida 来 hook JNI 的一些函数,打印出主动调用的执行路径。下面是 hook Google play Market 的例子:frida -U --no-pause -f com.android.vending -l hook_RegisterNatives.js

源码地址:https://github/lasting-yang/frida_hook_libart

追踪 JNI API

地址:https://github/chame1eon/jnitrace

延迟 hook

在带壳hook的时候,善用两 个frida提供的延时 hook 机制:

  • frida --no-pause 是进程直接执行,有时候会 hook 不到,如果把 --no-pause 拿掉,进入 CLI 之后延迟几秒再使用 %resume 恢复执行,就会 hook 到;
  • js 中的 setTimeout(func, delay[, ...parameters]) 函数,会延时delay毫秒来调用func,有时候不加延时会hook不到,加个几百到几千毫秒的延时就会hook到。

2、Frida GUI 工具

Frida 是一个功能强大的 Hook 工具,提供了 java 和 so层 的Hook,在使用 Frida 逆向分析的过程中,大部分时间是花在写代码和操作Adb命令行的上面,这就导致工作效率比较低。其实可以把这些操作都自动化运行,从而高效的进行逆向分析工作,下面是整合的一些资源和脚本。

fridaUiTools

菜鸟学飞之frida整合怪:https://bbs.kanxue/thread-268219.htm
github:https://github/dqzg12300/fridaUiTools

fridaUiTools 是一个界面化整理脚本的工具。参考项目 ZenTracer。支持:win、mac、linux。功能缝合怪是把一些常用的 frida 的 hook 脚本简单统一输出方式后,整合进来。并且把常用的功能做成界面调用的。

一些参考:

  • ZenTracer:https://github/hluwa/ZenTracer
  • r0capture:https://github/r0ysue/r0capture
  • jnitrace:https://github/chame1eon/jnitrace
  • JNI-Frida-Hook:https://github/Areizen/JNI-Frida-Hook
  • DroidSSLUnpinning:https://github/WooyunDota/DroidSSLUnpinning
  • frida_hook_libart:https://github/lasting-yang/frida_hook_libart
  • frida_dump:https://github/lasting-yang/frida_dump
  • frida-dexdump:https://github/hluwa/frida-dexdump
  • fart:https://github/search?q=fart&type=repositories
  • stalker、sktrace:https://bbs.kanxue/thread-264680.htm
  • Wallbreaker:https://bbs.kanxue/thread-277929.htm

jshook (支持安卓手机)

JsHook 可以在 Android 手机上用 js 实现 Hook:https://jshook/

github:https://github/JsHookApp

Frida GUI 工具

frida tool ui:https://zhuanlan.zhihu/p/603913742

Frida 工具 Web 界面版

Awesome-Frida-UI(Frida工具Web界面版):https://www.52pojie/thread-982162-1-1.html

github:https://github/viva-frida/awesome-frida-ui

3、Objection

frida 提供了各种 API ,通过代码调用 API 可以实现具体的功能,例如:禁用证书绑定、拦截函数等。但是每次操作都需要写代码毕竟不方便,于是就有大佬将各种常见常用的功能整合进一个工具,然后在命令行通过命令就可以使用,这个工具就是 objection一个基于 frida 的命令行 hook 工具功能强大,命令众多,而且不用写一行代码,便可实现诸如内存搜索、类和模块搜索、方法hook,打印参数、返回值、调用栈等,还支持 RPC 调用逆向必备、内存漫游神器。

objection 目前只支持 Java层的 hook,但是 objection 有提供插件接口,可以自己写 frida 脚本去定义接口,比如葫芦娃大佬的脱壳插件,实名推荐: https://github/hluwa/FRIDA-DEXDump

安装 objection

github:https://github/sensepost/objection
pypi:https://pypi/project/objection/

安装命令:pip3 install objection
查看帮助:objection --help

双进程保护可以防止程序被动态攻击。简单的双进程保护就是从原进程再fork一个空进程出来,让逆向分析的时候附加到空进程中导致hook不上。双进程进程保护主要功能:

  • 1、保护父进程,ptrace所有线程,防止被附加、调试、暂停;
  • 2、保护子进程,防止被暂停、异常退出;

绕过 ROOT检测、双进程保护:https://wwwblogs/ranbox/p/18461031

objection 当用 spwan 方式时,就会触发 双进程防护,需要修改 objection 源码

def get_session(self) -> frida.core.Session: 函数修改。

         ###################################################################
        debug_print('Resuming PID test {pid}'.format(pid=self.spawned_pid))
        self.device.resume(self.spawned_pid)
        self.session = self.device.attach(self.spawned_pid)
        ###################################################################

inject 函数修改的部分 ( 不需要添加代码,直接注释掉 )

效果:( 没修改之前直接报错,修改后可以正常进入 objection )

objection 帮助

帮助:
        示例:objection --help
        示例:objection api --help
        示例:objection explore --help

用法:objection [OPTIONS] COMMAND [ARGS]...
Options:
  -N, --network            通过网络进行连接。(默认是通过USB进行连接)
  -h, --host TEXT          通过网络连接时的IP [默认: 127.0.0.1]
  -p, --port INTEGER       通过网络连接时的端口[默认: 27042]
  -ah, --api-host TEXT     http的api使用的IP[default: 127.0.0.1]
  -ap, --api-port INTEGER  http的api使用的端口[default: 8888]
  -g, --gadget TEXT        通过Process(进程名)(或Frida的Gadget名)进行连接。[默认: Gadget]
  -S, --serial TEXT        要连接设备的序列号,当有多个设备时,可以指定序列号连接指定的设备
  -d, --debug              启用带有详细输出的调试模式。(包括堆栈跟踪中的代理源映射)
  --help                   帮助

Commands:
  api          用无头模式开启 objection API 服务
  device-type  获取附加设备的信息。
  explore      开启 objection exploration REPL.
  patchapk     用 frida-gadget.so 给apk打补丁(Patch)。
  patchipa     用 FridaGadget dylib 给 IPA 打补丁(Patch)
  run          执行单个 objection command
  signapk      使用 objection key 对 apk 进行 Zipalign 和 sign
  version      打印版本信息

命令行参数:https://github/sensepost/objection/blob/master/objection/console/cli.py
运行批量 hook 命令:objection -g com.android.settings explore -c "hook_cmd.txt"
加载插件:objection -g com.xxx.xxx explore -P ~/objection/objection_plugins

Frida 分为 "客户端、服务端"

  • 客户端:客户端(控制端) 编写的 Python 代码,用于连接远程设备,提交要注入的 JS 代码到服务端,接受服务端发来的消息。
  • 服务器:服务端(被控制端) 接收 JS 代码并注入到目标进程,操作内存数据,给客户端发送消息。

frida 帮助

通常情况下 adb forward <local> <remote> 主要用于将连接到本地计算机的 设备(adb 是 Android Debug bridge 简称,所以通常是安卓系统的设备)上的端口 转发到 本地计算机,或者将 本地计算机的端口 转发到 连接的设备上。无法直接将端口转发到远程设备。如果想要将端口通过 adb 转发到远程主机,可以结合ssh隧道来实现。步骤如下:
在本地机器上建立到远程主机的ssh隧道:ssh -L local_port:localhost:remote_port user@remote_host
示例:将本地的8080端口转发到远程主机的8080端口 ssh -L 8080:localhost:8080 user@remote_ip_address
然后使用adb将设备上的端口转发到本地:adb forward tcp:local_port device_port
示例:转发本地的8080端到远程的5000端口 adb forward tcp:8080 5000

frida --help
用法: frida [options] target

位置 参数:
  args                  额外参数 和/或 目标

选项:
  -h, --help            帮助
  -D ID, --device ID    连接到指定ID的设备。(使用 adb devices 命令查看 device id)
  -U, --usb         表示连接到USB设备,需要adb devices 可以看到设备
  -R, --remote      连接到远程的机器,但是不能填写远程的IP地址和端口
                    所以需要使用adb forward转发的方式映射到本机的27042端口,
                    且server端必须允许外界连接: fs_server -l 9600      
       -R 不带 ip:port 时,表示只能通过本地端口转发的形式连接到远程 fs-server             
       -R 加上 ip:port 时等价于-H 参数。
            frida -R 192.168.9.5:9600 -F  等价于 frida -H 192.168.9.5:9600 -F
            frida -R -F                   等价于 frida -H 192.168.9.5:27042 -F

  -H HOST, --host HOST    连接远程的 frida-server。示例:frida -H 192.168.9.5:9600 -F
  --certificate CERTIFICATE    使用TLS方式连接HOST时使用的证书
  --origin ORIGIN       连接到远程服务器,"origin"头设置为 ORIGIN
  --token TOKEN         使用token与HOST进行token认证
  --keepalive-interval INTERVAL  设置存活间隔(以秒为单位),0为禁用(默认为-1为基于传输自动选择)                       
  --p2p                    与目标建立点对点连接
  --stun-server ADDRESS    设置STUN服务器地址与 --p2p 一起使用
  --relay address,username,password,turn-{udp,tcp,tls}   添加中继与-p2p一起使用
  -f TARGET, --file TARGET       重新运行应用程序并附加
  -F, --attach-frontmost         附加到最前端的应用程序上
  -n NAME, --attach-name NAME    附加到指定的名字上                        
  -N IDENTIFIER, --attach-identifier IDENTIFIER   附加到指定的标识符上
  -p PID, --attach-pid PID       附加到指定的pid上
  -W PATTERN, --await PATTERN    等待模式,等待刷出匹配模式
  --stdio {inherit,pipe}         当 spawning 时,stdio 的行为(默认“inherit”)
  --aux option                   在spawning时,设置辅选项,例如 uid=(int)42 (支持类型: string, bool, int)
  --realm {native,emulated}      realm to attach in
  --runtime {qjs,v8}             运行时使用的 script 引擎
  --debug                        启用Node.js兼容的脚本调试器
  --squelch-crash                如果启用,将不会将崩溃报告转储到控制台
  -O FILE, --options-file FILE   包含附加命令行选项的文本文件
  --version                      程序的版本号
  -l SCRIPT, --load SCRIPT       加载的脚本                        
  -P PARAMETERS_JSON, --parameters PARAMETERS_JSON   JSON格式的参数,与Gadget相同                        
  -C USER_CMODULE, --cmodule USER_CMODULE        加载的模块
  --toolchain {any,internal,external}            从源代码编译时使用的CModule工具链
  -c CODESHARE_URI, --codeshare CODESHARE_URI    加载的CODESHARE_URI
  -e CODE, --eval CODE  对CODE求值
  -q                               安静模式,没有任何提示输出
  -t TIMEOUT, --timeout TIMEOUT    在静默模式终止前需要等待几秒钟                        
  --pause                          让主线程在spawning程序后暂停
  -o LOGFILE, --output LOGFILE     输出到日志文件
  --eternalize          在退出之前将脚本永久化
  --exit-on-error       在SCRIPT中遇到任何异常后以代码1退出
  --kill-on-exit        在Frida退出时杀死生成的程序
  --auto-perform        用Java.perform 包装输入的代码
  --auto-reload         启用自动加载所提供的脚本和c模块(默认为开启,将来会需要)
  --no-auto-reload      禁用自动加载所提供的脚本和c模块

端口转发

        adb forward tcp:27042 tcp:27042

启动 frida,并加载 js 脚本

        frida -U -l js_okhttp.js     -F com.cdsb.newsreader
        frida -U -l okhttp_poker.js  -F com.huanqiu.news
        frida -U -l frida_hook_js.js -f com.huanqiu.news

启动 objection

objection 默认是通过 USB 进行通信,也可以指定 --network 通过网络通信。

objection -g 包名 explore      // 注入进程,如果进程没有启动,会以spwan方式启动进程

objection -g "com.ss.android.ugc.aweme" explore   // "包名(com.xxx.xxx)"是 spawn 方式
objection -g "抖音" explore                                      // "app名" 是 attach 方式

objection -N -h 192.168.1.3 -p 9999 -g 包名 explore    // 指定ip和端口的连接

spawn 方式是启动前就Hookobjection -N -h 192.168.1.3 -p 9999 -g com.xxx.xxx explore --startup-command "android hooking watch class_method '包名.类名.方法'  --dump-args --dump-return --dump-backtrace"

示例:

  • 执行命令:objection -g com.hd.zhibo explore --startup-command "android hooking watch class_method android.app.AlertDialog.onCreate --dump-args --dump-backtrace --dump-return"
  • 输出结果顺序:调用的函数、堆栈、参数、返回值

查看 objection 日志

cat .objection/objection.log         查看日志
cat objection.log |grep -i http    筛选日志

进入 objection 后的 所有命令

进入 objection 后的几个基本操作:

  • 键入命令之后,回车执行;
  • help: 不知道当前命令的效果是什么,在当前命令前加 help 比如:help env、help frida,回车之后会出现当前命令的解释信息;
  • 空格、tab: 不知道输入什么的时就就按tab或者空格会有命令提示和说明,上下键可以查看都有哪些命令,按空格可以选中命令,按 enter 键是执行该命令。
  • jobs: 作业系统,可以查看和杀死正在 运行的 hook 任务。

详细的功能需要合理运用 "空格、tab、help"

!         # 执行操作系统命令
android    # 安卓专用命令
    clipboard
        monitor   # 监控安卓剪切板
    deoptimize    # 反优化。强制VM执行解释器中的所有内容
    heap          # 监控 Android 堆的命令
        evaluate  # 在 Java 类中执行 JavaScript 脚本。
        execute   # 在 Java 类中执行 方法。android heap execute 实例ID 实例方法
        print
            fields   # 打印 instance 的所有 fields
            methods  # 打印 instance 的所有 methods
        search
            instances  # 在当前Android heap上搜索类的实例。
    hooking
        generate  生成 Frida hooks 代码
            class    生成 class 的通用 hook 代码
            simple    每个类方法的简单hook 代码
        get
            current_activity  # 获取当前显示的(foregrounded 意思 前景) activity
        list
            activities      # 列出已经注册的 Activities
            class_loaders   # 列出已经注册的 class loaders
            class_methods   # 列出 class 中的可用的方法
            classes         # 列出当前已经载入的所有类
            receivers       # 列出已经注册的 BroadcastReceivers
            services        # 列出已经注册的 Services
        search
            classes 关键字  # 搜索与名称匹配的Java类
            methods 关键字  # 搜索与名称匹配的Java方法
        set
            return_value  # 设置一个方法的返回值。只支持布尔返回
        watch
            class         # 监视类中所有方法的调用
            class_method  # 监视对特定类方法的调用
    intent
        launch_activity  # 使用Intent启动一个Activity类
        launch_service   # 使用Intent启动一个Service类
    keystore
        clear  # 清除 Android KeyStore(密钥库)
        list   # 列出 Android KeyStore 中的条目
        watch  # 监视 Android KeyStore 的使用
    proxy  
        set    # 为应用程序设置代理
    root
        disable   # 试图禁用 root 检测
        simulate  # 试图模拟 root 的环境
    shell_exec    # 执行shell命令
    sslpinning
        disable  # 在各种 Java libraries/classes 尝试禁用 SSL pinning
    ui
        FLAG_SECURE  # 控制当前Activity的FLAG_SECURE
        screenshot   # 在当前 Activity 进行截图
cd          # 改变当前工作目录
commands    
    clear   # 清除当前会话命令的历史记录
    history # 列出当前会话命令历史记录
    save    # 将在此会话中运行的所有惟一命令保存到一个文件中
env       # 打印环境信息
evaluate  # JavaScrip 交互环境,可以在agent中动态执行JavaScript代码。
exit    # 退出
file    # 远程文件系统(即device)相关操作
    cat     # 打印文件内容
    download  # 下载一个文件
    http    
        start   # 在当前工作目录下,启动HTTP服务器
        status  # 获取 HTTP服务器的状态
        stop    # 停止正在运行的HTTP服务器
    upload      # 上传一个文件
frida    # 获取关于 frida 环境的信息
import   # 从完整路径导入 frida 脚本并运行
ios     执行指定的 ios 命令
    bundles
    cookies
    heap
    hooking
    info
    jailbreak
    keychain
    monitor
    nsurlcredentialstorage
    nsuserdefaults
    pasteboard
    plist
    sslpinning
    ui
jobs
    kill  # 结束一个任务。不会卸载加载的脚本
    list  # 列出当前所有的任务
ls        # 列出当前工作目录下的文件
memory
    dump  # dump(转储)进程中内存的数据
        all 文件名           # Dump 当前进程的整个内存
        from_base 起始地址 字节数 文件 # 将(x)个字节的内存从基址转储到文件
    list  # 列出当前进程的内存相关信息
        exports  # 列出模块的导出 (so库中的方法)
        modules  # 列出当前进程中已加载的 模块(so库)
    search  # 在应用程序的内存中搜索。
            示例:
            memory search "41 41 41 41"
            memory search "41 ?? de ad"
            memory search "deadbeef" --string
    write   # 将原始字节写入内存地址。小心使用!
ping    # ping agent
plugin   
    load  # 载入插接。使用帮助 help plugin load
pwd          # 打印当前工作目录
reconnect    # 重新连接 device
rm           # 从远程文件系统(即device)上删除文件
sqlite       # sqlite 数据库命令
    connect  # 连接到SQLite数据库文件
ui
    alert    # 显示警报消息,可以指定要显示的消息。(目前iOS崩溃)

示例:探索 安卓内置应用 "设置",来演示 objection 基本用法。

  • 手机上启动 frida-server 后,点击 "设置" 图标进入程序,然后查看 "设置" 应用的包名
  • 使用 objection 注入 "设置" 应用:objection -g com.android.settings explore

env   # 环境信息
ls    # 查看当前目中的文件
jobs list          # 查看 hook 的任务有多少个
jobs kill jobid    # 把正在 hook 的任务关闭
android sslpinning disable   # 禁用 SSL,过 ssl 证书认证
android root disable         # 禁用 root

objection基本操作与实战:https://bbs.kanxue/thread-277929.htm

memory 操作

memory list modules              # 枚举内存中所有模块(即so库)
memory list exports 文件名.so    # 枚举模块中所有导出函数
示例:memory list exports libssl.so    查看库的导出函数
memory dump all from_base    提取整个(或部分)内存
memory dump from_base 0xc935628c 100 memory.dex    
memory search "64 65 78 0a 30 33 35 00"     # 暴力搜内存
memory search "aiyou,bucuoo" --string     # 搜索整个内存
memory search "aiyou,bucuoo" --string --offsets-only    # 仅看偏移地址

# 列举加载的 modules,也就是so文件
        memory list modules
        memory list modules --json result.txt

# 列举 so 文件的导出方法
        memory list exports xxx.so

# dump所有内存
        memory dump all /tmp/dump

# dump内存指定地址和大小
        memory dump from_base 0x130b4060 1024 /tmp/dump

# 在内存搜索
        memory search "64 65 78 0a 30 33 35 00"
        memory search "99999999999" --string
        memory search "66 72 ?? ?? 61"

# 修改内存
        memory write 0x130b4060 "99999999999" --string

activity / services / receivers 组件相关

# 列出应用程序具有的组件
        android hooking list activities
        android hooking list services
        android hooking list receivers

# 获取当前activity
        android hooking get current_activity

# 启动某个activity
        android intent launch_activity com.xxx.xxx.Activity

# 启动某个service
        android intent launch_service xxxx

class / method 相关

# 列举所有加载的类
        android hooking list classes

# 查找已加载的类中带有关键词的类
        android hooking search classes xxx

# 查看xx类有哪些方法
        android hooking list class_methods com.xx.xx

# 在内存中所有已加载的类的方法中搜索包含特定关键词的方法
        android hooking search methods xxx

# 查找所有类的实例
        android heap search instances xxx

# 主动调用指定实例的函数
        android heap execute instance_ID function

# hook指定类的所有方法, 会打印该类下的所有调用
        android hooking watch class com.xxx.xxx            

# hook指定方法, 如果有重载会hook所有重载
        android hooking watch class_method com.xxx.xxx.methodName

# 以上命令支持下面参数
# --dump-args : 打印参数
# --dump-backtrace : 打印调用栈
# --dump-return : 打印返回值
# eg:
android hooking watch class_method com.xxx.xxx.methodName --dump-args --dump-backtrace --dump-return
android hooking set return_value com.xxx.xxx.methodName false    # 设置返回值(只支持bool类型)


# 生成某个类的hook js代码
        android hooking generate  simple  com.xxx.xxx

任务管理

# 列举出当前任务
        jobs list

# 关闭任务
        jobs kill [job_id]

文件操作

# 文件基本操作
        ls
        file download
        file upload
        file cat

# 文件服务器,在当前目录下启动一个http server
        file http start/stop/status

抓包

#关闭ssl校验
        android sslpinning disable

其他操作

# 打印出应用程序文件、缓存和其他目录的位置
        env

# 对APP隐藏root
        android root disable 

# 执行命令
        android shell_exec ls 

# 截屏
        android ui screenshot /sdcard/1.png

# 导入外部 js 脚本
        import 1.js 

日志

objection日志文件位于:

        ~/.objection/objection.log

命令历史文件位于:

~/.objection/objection_history
删除 ~/.objection目录后,在下次 objection 启动时会重新创建。

参考:https://github/sensepost/objection/wiki/Using-objection

自动生成 hook 代码

示例:android hooking generate simple com.android.settings.DisplaySettings

Java.perform(function() {
    var clazz = Java.use('com.android.settings.DisplaySettings');
    clazz.getPreferenceScreenResId.implementation = function() {

        //

        return clazz.getPreferenceScreenResId.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.android.settings.DisplaySettings');
    clazz.getLogTag.implementation = function() {

        //

        return clazz.getLogTag.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.android.settings.DisplaySettings');
    clazz.getHelpResource.implementation = function() {

        //

        return clazz.getHelpResource.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.android.settings.DisplaySettings');
    clazz.onCreate.implementation = function() {

        //

        return clazz.onCreate.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.android.settings.DisplaySettings');
    clazz.createPreferenceControllers.implementation = function() {

        //

        return clazz.createPreferenceControllers.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.android.settings.DisplaySettings');
    clazz.access$000.implementation = function() {

        //

        return clazz.access$000.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.android.settings.DisplaySettings');
    clazz.buildPreferenceControllers.implementation = function() {

        //

        return clazz.buildPreferenceControllers.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.android.settings.DisplaySettings');
    clazz.getMetricsCategory.implementation = function() {

        //

        return clazz.getMetricsCategory.apply(this, arguments);
    }
});

生成的代码大部分要素都有了,只需要简单补充即可使用。

hook 方法的所有重载

objection 的 help 中指出,在 hook 给出的单个方法的时候,会 hook 它的所有重载

用 File 类看下效果:android hooking watch class_method java.io.File.$init --dump-args --dump-backtrace --dump-return

可以看到 objection 自动 hook 了 File 构造器的所有重载,一共是6个。在设置界面随意进出几个子设置界面,可以看到命中很多次该方法的不同重载,每次参数的值也都不同,

objection rpc

objection rpc:https://github/sensepost/objection/wiki/API

$ curl -s "http://127.0.0.1:8888/rpc/invoke/androidHookingListActivities"
["com.reddit.frontpage.StartActivity","com.reddit.frontpage.IntroductionActivity", ... snip ...]

- RPC调用执行脚本:`url -X POST -H "Content-Type: text/javascript" http://127.0.0.1:8888/script/runonce -d "@script.js"`

$ cat script.js
{
    send(Frida.version);
}

[{"payload":"12.8.0","type":"send"}]

内存漫游

简单使用

  • 启动 Frida-server,并转发端口 ( adb forward tcp:27042 tcp:27042 )
  • 附加需要调试的 app,进入交互界面 ( objection -g [packageName] explore )

使用逍遥模拟器时需要先进入模拟器所在目录,然后使用目录中 adb.exe 命令进行连接:adb.exe connect 127.0.0.1:21503

以下只是写了一部分指令和功能, 详细的功能需要合理运用 空格 和 help

Memory 指令
    memory list modules               //枚举当前进程模块
    memory list exports [lib_name]    //查看指定模块的导出函数
    memory list exports libart.so --json /tmp/libart.json //将结果保存到json文件中
    memory search --string --offsets-only                  //搜索内存

android heap 指令
    //堆内存中搜索指定类的实例, 可以获取该类的实例id
    search instances search instances com.xx.xx.class
     
    //直接调用指定实例下的方法
    android heap execute [ins_id] [func_name]
     
    //自定义frida脚本, 执行实例的方法
    android heap execute [ins_id]

android 指令
    android root disable   //尝试关闭app的root检测
    android root simulate  //尝试模拟root环境
    
    android ui screenshot [image.png]    //截图
    android ui FLAG_SECURE false         //设置FLAG_SECURE权限

内存漫游
    android hooking list classes    //列出内存中所有的类
     
    //在内存中所有已加载的类中搜索包含特定关键词的类
    android hooking search classes [search_name] 
     
    //在内存中所有已加载的方法中搜索包含特定关键词的方法
    android hooking search methods [search_name] 
     
    //直接生成hook代码
    android hooking generate simple [class_name]

hook 方式
    /*
        hook指定方法, 如果有重载会hook所有重载,如果有疑问可以看
        --dump-args : 打印参数
        --dump-backtrace : 打印调用栈
        --dump-return : 打印返回值
    */     
    //hook指定类, 会打印该类下的所有调用
    android hooking watch class com.xxx.xxx
     
    //设置返回值(只支持bool类型)
    android hooking set return_value com.xxx.xxx.methodName false

Spawn 方式 Hook
    objection -g packageName explore --startup-command '[obejection_command]'

activity 和 service 操作
    android hooking list activities                   //枚举activity
    android intent launch_activity [activity_class]   //启动activity
    android hooking list services                     //枚举services
    android intent launch_service [services_class]    //启动services

任务管理器
    jobs list            // 查看任务列表
    jobs kill [task_id]  // 关闭任务

关闭 app 的 ssl 校验
    android sslpinning disable

监控系统剪贴板
    // 获取Android剪贴板服务上的句柄并每5秒轮询一次用于数据。 
    // 如果发现新数据,与之前的调查不同,则该数据将被转储到屏幕上。
    help android  clipboard

执行命令行
    help android shell_exec [command]
	

android hooking list classes                  # 列出内存中所有的类
android hooking list class_methods 包名.类名  # 列出类的所有方法
android hooking list services          # 查看可供开启的服务
android hooking list activities        # 列出所有可用 activities
android hooking search classes 关键字  # 在内存中已加载的类中搜索包含特定关键词的类
android hooking search methods 关键字  # 在内存中已加载的类的方法中搜索包含特定关键词的类
android hooking generate simple 类名  # 生成 指定类 的 hook 代码

android intent launch_service 完整Service名  # 启动 指定 服务
android intent launch_activity 包名.类名     # 启动 指定的 activities

// hook类的所有方法。监视执行某个操作的时候调用了哪些方法
android hooking watch class 包名.类名

// 默认会Hook方法的所有重载
android hooking watch class_method 包名.类名.方法 

// 如果只需hook其中一个重载函数 指定参数类型 多个参数用逗号分隔
android hooking watch class_method 包名.类名.方法 "参数1,参数2"

android heap search instances 包名.类名 --fresh   # 搜索堆中的实例
android heap execute 地址(hashcode的地址) 方法名  # 调用实例的方法

file download [file] [outfile]    # 从远程文件系统中下载文件

列出内存中所有的类、搜索类

命令:android hooking list classes

命令:android hooking search classes 关键字

命令:android hooking search methods 关键字

列出指定类的所有方法

命令:android hooking list class_methods 包名.类名

示例:android hooking list class_methods com.android.settings.DisplaySettings

查看内存中加载的库:memory list modules

运行命令 memory list modules

查看库的导出函数:memory list exports libssl.so

运行命令 memory list exports libssl.so 列出 libssl.so 库的导出函数

将结果保存到 json文件中

当结果太多,终端无法全部显示时,可以将结果导出到文件中然后使用其他软件查看

使用 json 格式保存的 libart.so 的导出函数
# memory list exports libart.so --json /root/libart.json  
Writing exports as json to /root/libart.json...
Wrote exports to: /root/libart.json

提取整个(或部分)内存:memory dump all from_base

这部分内容与下文脱壳部分有重叠,在脱壳部分介绍用法。

搜索整个内存:memory search --string --offsets-only

这部分也与脱壳部分有重叠,在脱壳部分详细介绍用法。

内存堆(heap)上的搜索执行

在堆 (heap)上搜索实例

查看AOSP源码关于设置里显示系统设置的部分,发现存在着 DisplaySettings类,可以在堆上搜索是否存在着该类的实例。

首先在手机上点击进入 "显示" 设置,然后运行命令:android heap search instances com.android.settings.DisplaySettings

并得到相应的实例地址:

调用实例的方法

查看源码得知 com.android.settings.DisplaySettings类 有一个 getPreferenceScreenResId()方法,这样就可以直接调用该实例的 getPreferenceScreenResId()方法,

后文也会介绍在objection中直接打印类的所有方法的命令

用 excute 命令:android heap execute 0x2526 getPreferenceScreenResId

Handle 0x2526 is to class com.android.settings.DisplaySettings
Executing method: getPreferenceScreenResId()
2132082764

可见结果被直接打印了出来。

在实例上执行 js 代码

也可以在找到的实例上直接编写 js 脚本,输入android heap evaluate 0x2526 命令后,会进入一个迷你编辑器环境,

  • 输入 console.log("evaluate result:"+clazz.getPreferenceScreenResId()) 这串脚本,
  • 按ESC退出编辑器,然后按回车,即会开始执行这串脚本,输出结果。
# android heap evaluate 0x2526                                          
(The handle at `0x2526` will be available as the `clazz` variable.)

console.log("evaluate result:"+clazz.getPreferenceScreenResId()) 

JavaScript capture complete. Evaluating...
Handle 0x2526 is to class com.android.settings.DisplaySettings
evaluate result:2132082764

这个功能其实非常厉害,可以即时编写、出结果、即时调试自己的代码,不用再:编写→注入→操作→看结果→再调整,而是直接出结果。

启动 activity 或 service

直接启动 activity

直接上代码,想要进入显示设置,可以在任意界面直接运行以下代码进入显示设置:

# android intent launch_activity com.android.settings.DisplaySettings                      
(agent) Starting activity com.android.settings.DisplaySettings...
(agent) Activity successfully asked to start.

查看当前可用的 activity

可以使用 android hooking list 命令来查看当前可用的 activities,然后使用上述命令进行调起。

# android hooking list activities

com.android.settings.ActivityPicker
com.android.settings.AirplaneModeVoiceActivity
com.android.settings.AllowBindAppWidgetActivity
com.android.settings.AppWidgetPickActivity
com.android.settings.BandMode
com.android.settings.ConfirmDeviceCredentialActivity
com.android.settings.CredentialStorage
com.android.settings.CryptKeeper$FadeToBlack
com.android.settings.CryptKeeperConfirm$Blank
com.android.settings.DeviceAdminAdd
com.android.settings.DeviceAdminSettings
com.android.settings.DisplaySettings
com.android.settings.EncryptionInterstitial
com.android.settings.FallbackHome
com.android.settings.HelpTrampoline
com.android.settings.LanguageSettings
com.android.settings.MonitoringCertInfoActivity
com.android.settings.RadioInfo
com.android.settings.RegulatoryInfoDisplayActivity
com.android.settings.RemoteBugreportActivity
com.android.settings.RunningServices
com.android.settings.SetFullBackupPassword
com.android.settings.SetProfileOwner
com.android.settings.Settings
com.android.settings.Settings
com.android.settings.Settings$AccessibilityDaltonizerSettingsActivity
com.android.settings.Settings$AccessibilitySettingsActivity
com.android.settings.Settings$AccountDashboardActivity
com.android.settings.Settings$AccountSyncSettingsActivity
com.android.settings.Settings$AdvancedAppsActivity

直接启动 service

也可以先使用 android hooking list services 查看可供开启的服务,

然后使用 android intent launch_service com.android.settings.bluetooth.BluetoothPairingService 命令来开启服务。

插件:Wallbreaker

葫芦娃 github:https://github/hluwa?tab=repositories

Wallbreaker 是基于 frida 的一个工具,可以从内存里面进行 Java 的逆向工程,用于实时分析 Java 内存堆,并提供一些命令从内存中搜索对象或类,并精美地可视化目标的真实结构。

使用方法:参看 github:https://github/hluwa/Wallbreaker

插件编写 : objection pluging:https://github/sensepost/objection/wiki/Plugins

快速分析 Java 类/对象结构

From:https://bbs.pediy/thread-260110.htm

Wallbreaker 取自 wikipedia 上对《三体》"破壁者"的翻译。

wallbreaker 是一个超级懒人(我)为了减少编写重复性垃圾代码而产生的一个工具,主要作用是将内存中 Java 类或对象的结构数据进行可视化。

就像介个亚子:

应用场景

如何使用

目前我是比较喜欢以 objection 插件的形式来使用,本来我也想自己写交互式控制台,但我觉得 objection 已经写得挺好,直接上车就好了,所以暂时不打算自己实现了。
开发的时候就使用 ipython 或者写 testcase 调试。

  1. 安装 objection:pip3 install objection
  2. 下载 wallbreaker 到自己的插件目录:git clone https://github/hluwa/Wallbreaker ~/.objection/plugins/Wallbreaker
  3. 启动 frida-server,使用 -P 参数带着插件启动 objection:objection -g com.app.name explore -P ~/.objection/plugins

然后就可以愉快的使用 wallbreaker 的几个命令了:

  • 搜索 plugin wallbreaker classsearch <type-pattern>
        根据给的 pattern 对所有类名进行匹配,列出匹配到的所有类名。[return all matched class]
  • 搜索 实例对象:plugin wallbreaker objectsearch <instance-class-name>
        根据类名搜索内存中已经被创建的实例,列出 handle 和 toString() 的结果。 [return all matched object-handle and toString]
  • ClassDump,输出类的结构:plugin wallbreaker classdump <class-name> [--fullname]
        输出类的结构, 若加了 --fullname 参数,打印的数据中类名会带着完整的包名。
            [
               pretty print class structure: fields declare, static field value, methods declare.
                  set --fullname to display package name of type name.
            ]
  • ObjectDump:plugin wallbreaker objectdump <object-handle> [--fullname] [--as-class class-name]
        在 ClassDump 的基础上,输出指定对象中的每个字段的数据。
            [
               pretty print object structure: fields declare and value, methods declare.
                  set --fullname to display package name of type name;
                  set --as-class to cast instance type(super class, not interface).
               if instance is a collection or map, dump all entries.
            ]

DEMO:https://asciinema/a/XZf8yLWJylCKJfcaYzcKlNbIy

Wallbreaker 的使用

objection 基本使用 + Wallbreaker:https://www.52pojie/forum.php?mod=viewthread&tid=1626964

加载并使用 Wallbreaker插件:objection -g com.android.phone explore -P ~/.objection/plugins

搜索类:plugin wallbreaker classsearch <pattern>
        根据给的 pattern 对所有类名进行匹配,列出匹配到的所有类名。

搜索对象:plugin wallbreaker objectsearch <classname>
        根据类名搜索内存中已经被创建的实例,列出 handle 和 toString() 的结果。

ClassDump:plugin wallbreaker classdump <classname> [--fullname]
        输出类的结构, 若加了 --fullname 参数,打印的数据中类名会带着完整的包名。

ObjectDump:plugin wallbreaker objectdump <handle> [--fullname]
        在 ClassDump 的基础上,输出指定对象中的每个字段的数据。

4、其他 hook 工具

类似 objection 的 hook 工具

ZenTracer

前面的 objection 已经足够强大,优点是 hook 准确、粒度细。这里再推荐个批量 hook 查看调用轨迹的工具 ZenTracer:https://github/hluwa/ZenTracer 可以更大范围地 hook。

hooker

这项目黄了,现在非常适合用来学习,想 hook 找其他框架吧。

github:https://github/CreditTone/hooker

frida 杀器 hooker windows 版本:https://www.52pojie/thread-1773012-1-1.html

hooker是一个基于frida实现的逆向工具包。为逆向开发人员提供统一化的脚本包管理方式、通杀脚本、自动化生成hook脚本、内存漫游探测activity和service、firda版JustTrustMe、disable ssl pinning

  • hooker和frida、objection有什么不同
  • hooker环境部署
    • 1. git clone项目
    • 2. 安装依赖
    • 3. 手机连接adb
    • 4. 手机开发环境部署
    • 5. 指定fridaserver端口的手机开发环境部署
    • 6. 部署之后手机的增强功能
  • 快速开始
    • 1. 查看可调试进程
    • 2. attach一个应用
    • 3. 应用工作目录
  • 应用工作目录的命令
    • 1. hooking
    • 2. attach
    • 3. spawn
    • 4. objection
    • 5. xinitdeploy
    • 6. kill
    • 7. disable_sslpinning
  • 应用工作目录的通杀脚本
    • 1. url.js
    • 2. activity_events.js
    • 3. click.js
    • 4. android_ui.js
    • 5. keystore_dump.js
    • 6. edit_text.js
    • 7. text_view.js
    • 8. ssl_log.js
    • 9. object_store.js
    • 10. hook_RN.js
    • 11. just_trust_me.js
    • 12. just_trust_me_okhttp_hook_finder.js
  • hooker调试命令行
    • a-打印Activity栈
    • b-打印Service栈
    • c-扫描指定Object
    • d-展开Object[]、List或Map
    • v-以View方式查看对象
    • e-检测类在内存中是否存在
    • s-正则表达式扫描类
    • j-生成指定类的hook脚本
    • k-生成字符串hook脚本
  • hooker高级应用
    • radar.dex
    • 脚本的内置函数
      • 1. loadDexfile(dexfile)
      • 2. checkLoadDex(className,dexfile)
      • 3. loadXinitDexfile(dexfile)
      • 4. loadXRadarDexfile()
      • 5. fastTojson(javaObject)
      • 6. getPrettyString(javaObject)
      • 7. getField(javaObject, fieldName)
      • 8. storeObjectAndLog(javaObject)
    • 原生ui自动化
      • 1. startActivity(activityName)
      • 2. contextStartActivity(activityName)
      • 3. contextStartActivity(activityName)
      • 4. home()
      • 5. back()
      • 6. finishCurrentActivity()
      • 7. clickByText(text)
      • 8. clickById(id)
      • 9. hover(x,y,upStepLength)
      • 10. viewTree()
    • 远程frida支持

发布者:admin,转转请注明出处:http://www.yc00.com/web/1754950070a5219815.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

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

关注微信