Android
CTF 竞赛工具示例
本示例推荐使用 Android 4.4 x86 模拟器镜像,基于 SECCON Quals CTF 2015 的 APK1 题目实现(APK 下载)。
保存为 ctf.py 后执行 python ctf.py
:
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode = """
Java.perform(() => {
// 定义要挂钩的类
const MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');
// 挂钩按钮点击事件
const onClick = MainActivity.onClick;
onClick.implementation = function (v) {
// 显示函数调用通知
send('onClick 被触发');
// 先执行原始 onClick 处理逻辑
onClick.call(this, v);
// 修改关键字段值
this.m.value = 0; // 注意必须使用 .value 访问字段
this.n.value = 1;
this.cnt.value = 999;
// 输出日志提示获取flag
console.log('操作完成:' + JSON.stringify(this.cnt));
};
});
"""
process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors')
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] 正在运行CTF破解工具')
script.load()
sys.stdin.read()
重要说明:必须使用
this.m.value = 0
而非this.m = 0
来修改字段值。若类中存在同名方法m()
,则需改用this._m.value = 0
。在访问对象属性时,通常需要通过.value
获取实际值。
Java 桥接功能示例
Frida 的 Java 桥接功能可实现以下操作:
Java.perform(() => {
// 创建并初始化 String 对象
const JavaString = Java.use('java.lang.String');
const exampleString1 = JavaString.$new('Java 环境中的示例字符串');
console.log('[+] 字符串内容: ' + exampleString1);
console.log('[+] 字符串长度: ' + exampleString1.length());
// 获取默认字符集并转换字符串
const Charset = Java.use('java.nio.charset.Charset');
const charset = Charset.defaultCharset();
// 将 JS 字符串转为字节数组
const charArray = '待转换的JavaScript字符串'.split('').map(c => c.charCodeAt(0));
// 通过重载构造器创建 String 对象
const exampleString2 = JavaString.$new.overload('[B', 'java.nio.charset.Charset')
.call(JavaString, charArray, charset);
console.log('[+] 转换结果: ' + exampleString2);
// 挂钩 StringBuilder 构造器
const StringBuilder = Java.use('java.lang.StringBuilder');
const ctor = StringBuilder.$init.overload('java.lang.String');
ctor.implementation = function (arg) {
const result = ctor.call(this, arg);
const partial = arg ? arg.toString().slice(0, 10) : '';
console.log('新建 StringBuilder: "' + partial + '"');
return result;
};
// 挂钩 toString 方法
StringBuilder.toString.implementation = function () {
const result = this.toString();
console.log('StringBuilder 内容预览: ' + result.slice(0, 10));
return result;
};
});
堆栈追踪示例
Java.perform(() => {
const Cipher = Java.use('javax.crypto.Cipher');
const Exception = Java.use('java.lang.Exception');
const Log = Java.use('android.util.Log');
// 挂钩 Cipher.init() 方法
Cipher.init.overload('int', 'java.security.Key').implementation = function (opmode, key) {
const result = this.init(opmode, key);
console.log('加密模式:', opmode, '密钥:', key);
// 打印当前调用堆栈
console.log(Log.getStackTraceString(Exception.$new()));
return result;
};
});
关键术语说明:
Java.perform - Frida 的 Java 环境执行上下文
implementation - 方法挂钩的实现体
overload - 处理 Java 方法重载
$new - 实例化 Java 对象
getStackTraceString - 获取异常堆栈信息
原文链接:Android | Frida • A world-class dynamic instrumentation toolkit
翻译来源:DeepSeek