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 方式是启动前就Hook:objection -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
调试。
- 安装 objection:pip3 install objection
- 下载
wallbreaker
到自己的插件目录:git clone https://github/hluwa/Wallbreaker ~/.objection/plugins/Wallbreaker - 启动 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条)