首页
社区
课程
招聘
[原创]写一个简单的trace
发表于: 2025-8-30 20:25 6363

[原创]写一个简单的trace

2025-8-30 20:25
6363

Small Trace 工具发布 - 一个基于 QDBI 与 Frida 的简易追踪工具

随着软件逆向与安全研究的发展,越来越多的开发者和研究人员开始关注代码追踪。尽管市面上已有不少工具,但大多数都未开源,或者无法提供定制化的追踪功能。在此背景下,我决定利用几天时间开发一款简单的代码追踪工具。借助前辈们的工作,结合 QDBI 与 Frida 的 Gum 模块,我构建了 Small Trace。这款工具虽然简单,但能有效地帮助用户观察内存读写、函数调用等关键操作。

看着周围越来越多的人在使用代码追踪工具,我也开始使用前辈们开发的许多追踪工具,然而这些工具都没有开源,且许多定制打印功能无法满足我的需求。因此,我决定自行动手,花了几天时间写了一个简单的追踪工具。这个工具的主要目的是进行内存读写、函数调用等的简单打印,可以帮助开发者在调试过程中快速定位问题。

Small Trace目前使用了QDBI与Frida的Gum模块实现,未来计划加入基于ptrace的追踪功能,进一步提升工具的灵活性与功能。

Small Trace可以打印内存读取、函数调用等信息,帮助开发者更好地理解程序的运行流程。例如,在追踪一个内存读取操作时,可能会得到如下的输出:

如上所示,工具能够打印内存读取时的数据值、数据地址,以及调用的具体函数信息,包括函数调用的内容。这对于分析内存相关问题、定位加密解密逻辑尤为有用。

获取文件
你将得到两个文件:libqdbi.soCalvinTrace.js

加载动态库
你需要让目标程序加载我们的动态库 libqdbi.so。你可以使用任何方法加载此库,但我推荐使用如下方法:

这样,你就可以开始进行内存跟踪了,轻松查看加密解密操作的位置,方便定位问题。

这里一定要调用一次 ,或者 让程序自己跑,跑到 你 hook 的地方。

如何获取 保存的日志呢?

日志当然会自动的保存在 /data/data/包名/qdbi_log.txt 咯

现在 实战我写的小demo

目标代码

一个简单的 base64 解码

编译后 打开 apk 发现so的名称为 libcheckqdbi.so

我要trace的方法 为 Java_io_calvin_checkqdbi_MainActivity_checkQDBI

现在我要 先将 trace so push 到 手机 data/local/tmp 目录下 赋予权限

然后填写数据到frida 脚本

这次使用 符号 进行 hook

填写好后 测试

你可以用adb 看到日志

表示程序 正常 hook

这时候只需要主动调用 这个方法Java_io_calvin_checkqdbi_MainActivity_checkQDBI 就行了

马上在日志里就会显示

那么在apk的私有目录里就会有我记录下的日志

可以辅助我在ida 分析时 观测到内存的数据 至少 可以推断大概的内容 这里base64解出来的内容 就是 hello this is test !!!!

Small Trace 工具虽简单,却能帮助开发者在调试过程中获取关于内存读写、函数调用的关键数据。通过结合 QDBI 和 Frida,我们可以快速实现对内存操作的追踪。未来,我还计划加入基于 ptrace 的跟踪功能,使得这个工具更加灵活与强大。希望这个工具能为从事逆向分析与调试的朋友们提供一些帮助。

项目的地址 : 20cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6z5K9g2c8A6j5h3&6q4M7W2S2A6L8X3M7$3y4U0k6Q4x3V1k6e0L8h3q4D9L8q4)9J5k6q4c8J5j5h3y4W2

如果你对 签名校验 环境检测 以及移动安全 有兴趣 可以加我一起交流学习 我打算建一个学习交流群

memory read at 0xb4000070d9505f40, instruction address = 0x70d68f75d8, data size = 8, data value = 8b858ed670000000
 00000070d9505f00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |                |
 00000070d9505f10  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |                |
 00000070d9505f20  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |                |
 00000070d9505f30  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |                |
*00000070d9505f40  8B 85 8E D6 70 00 00 00 F0 E1 CD AC 71 00 00 B4 |    p       q   |
 00000070d9505f50  70 5F 50 D9 70 00 00 B4 B8 7B 8F D6 70 00 00 00 |p_P p    {  p   |
 00000070d9505f60  38 C0 ED DD 70 00 00 00 F0 E1 CD AC 71 00 00 B4 |8   p       q   |
 00000070d9505f70  00 60 50 D9 70 00 00 B4 2A 00 00 00 00 00 00 00 | `P p   *       |
0x00000070d68f75dc  0x255dc         blr x8  ;X30=0x70d68f7bb8 -> 0x70d68f75e0
  CALL -> [/apex/com.android.art/lib64/libart.so] art::(anonymous namespace)::CheckJNI::NewStringUTF(_JNIEnv*, char const*) (.llvm.17249515741404199542) + 0x435ed4 (size=1808) (target=0x70eba35ed4)
0x00000070eba35ed4  0x435ed4            sub sp, sp, #224
0x00000070eba35ed8  0x435ed8            stp x29, x30, [sp, #128]
memory read at 0xb4000070d9505f40, instruction address = 0x70d68f75d8, data size = 8, data value = 8b858ed670000000
 00000070d9505f00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |                |
 00000070d9505f10  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |                |
 00000070d9505f20  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |                |
 00000070d9505f30  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |                |
*00000070d9505f40  8B 85 8E D6 70 00 00 00 F0 E1 CD AC 71 00 00 B4 |    p       q   |
 00000070d9505f50  70 5F 50 D9 70 00 00 B4 B8 7B 8F D6 70 00 00 00 |p_P p    {  p   |
 00000070d9505f60  38 C0 ED DD 70 00 00 00 F0 E1 CD AC 71 00 00 B4 |8   p       q   |
 00000070d9505f70  00 60 50 D9 70 00 00 B4 2A 00 00 00 00 00 00 00 | `P p   *       |
0x00000070d68f75dc  0x255dc         blr x8  ;X30=0x70d68f7bb8 -> 0x70d68f75e0
  CALL -> [/apex/com.android.art/lib64/libart.so] art::(anonymous namespace)::CheckJNI::NewStringUTF(_JNIEnv*, char const*) (.llvm.17249515741404199542) + 0x435ed4 (size=1808) (target=0x70eba35ed4)
0x00000070eba35ed4  0x435ed4            sub sp, sp, #224
0x00000070eba35ed8  0x435ed8            stp x29, x30, [sp, #128]
adb shell
su
setenforce 0
adb shell
su
setenforce 0
var TraceSoPath = "/data/local/tmp/libqdbi.so"// 用于存放目标SO的路径
var SO_name = "libcheckqdbi.so";      // 目标SO的名称
var Symbol = "Java_io_calvin_checkqdbi_MainActivity_checkQDBI";       // 符号名
var so_offset = 0;     // SO中的偏移量
var Trace_Mode = 0;    // 跟踪模式 (0 - 符号追踪, 1 - 偏移量追踪)
var args = 2;         // 目标函数的参数数量
var TraceSoPath = "/data/local/tmp/libqdbi.so"// 用于存放目标SO的路径
var SO_name = "libcheckqdbi.so";      // 目标SO的名称
var Symbol = "Java_io_calvin_checkqdbi_MainActivity_checkQDBI";       // 符号名
var so_offset = 0;     // SO中的偏移量
var Trace_Mode = 0;    // 跟踪模式 (0 - 符号追踪, 1 - 偏移量追踪)
var args = 2;         // 目标函数的参数数量
frida -U -f XXX.XXX.XXX -l CalvinTrace.js
frida -U -f XXX.XXX.XXX -l CalvinTrace.js
// Base64 解码函数
std::string base64_decode(const std::string &encoded) {
    const std::string base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
    int in_len = encoded.size();
    int i = 0;
    int j = 0;
    int in_ = 0;
    unsigned char char_array_4[4], char_array_3[3];
    std::string ret;
 
    while (in_len-- && (encoded[in_] != '=') && is_base64(encoded[in_])) {
        char_array_4[i++] = encoded[in_]; in_++;
        if (i == 4) {
            for (i = 0; i < 4; i++) {
                char_array_4[i] = base64_chars.find(char_array_4[i]);
            }
            char_array_3[0] = (char_array_4[0] << 2) | (char_array_4[1] >> 4);
            char_array_3[1] = (char_array_4[1] << 4) | (char_array_4[2] >> 2);
            char_array_3[2] = (char_array_4[2] << 6) | char_array_4[3];
            for (i = 0; (i < 3); i++) {
                ret += char_array_3[i];
            }
            i = 0;
        }
    }
 
    if (i) {
        for (int j = i; j < 4; j++) {
            char_array_4[j] = 0;
        }
        for (int j = 0; j < 4; j++) {
            char_array_4[j] = base64_chars.find(char_array_4[j]);
        }
        char_array_3[0] = (char_array_4[0] << 2) | (char_array_4[1] >> 4);
        char_array_3[1] = (char_array_4[1] << 4) | (char_array_4[2] >> 2);
        char_array_3[2] = (char_array_4[2] << 6) | char_array_4[3];
        for (int j = 0; (j < i - 1); j++) {
            ret += char_array_3[j];
        }
    }
 
    return ret;
}
 
 
extern "C"
JNIEXPORT jstring JNICALL
Java_io_calvin_checkqdbi_MainActivity_checkQDBI(JNIEnv *env, jobject thiz) {
    // 假设你有一个 Base64 编码的字符串
    std::string encoded_string = "aGVsbG8gdGhpcyBpcyB0ZXN0ICEhISE="; // "hello this is test!" 的 Base64 编码
 
    // 使用 base64_decode 函数解码
    std::string decoded_string = base64_decode(encoded_string);
 
    // 返回解码后的字符串
    return env->NewStringUTF(decoded_string.c_str());
}
// Base64 解码函数
std::string base64_decode(const std::string &encoded) {
    const std::string base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
    int in_len = encoded.size();
    int i = 0;
    int j = 0;
    int in_ = 0;
    unsigned char char_array_4[4], char_array_3[3];
    std::string ret;
 
    while (in_len-- && (encoded[in_] != '=') && is_base64(encoded[in_])) {
        char_array_4[i++] = encoded[in_]; in_++;
        if (i == 4) {
            for (i = 0; i < 4; i++) {
                char_array_4[i] = base64_chars.find(char_array_4[i]);
            }
            char_array_3[0] = (char_array_4[0] << 2) | (char_array_4[1] >> 4);
            char_array_3[1] = (char_array_4[1] << 4) | (char_array_4[2] >> 2);
            char_array_3[2] = (char_array_4[2] << 6) | char_array_4[3];
            for (i = 0; (i < 3); i++) {
                ret += char_array_3[i];
            }
            i = 0;
        }
    }
 
    if (i) {
        for (int j = i; j < 4; j++) {
            char_array_4[j] = 0;
        }
        for (int j = 0; j < 4; j++) {
            char_array_4[j] = base64_chars.find(char_array_4[j]);

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 2025-8-30 20:27 被逆天而行编辑 ,原因:
收藏
免费 154
支持
分享
最新回复 (97)
雪    币: 8273
活跃值: (4833)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享,
2025-8-31 01:36
0
雪    币: 3071
活跃值: (3974)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习一下
2025-8-31 02:39
0
雪    币: 3304
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
学习一下
2025-8-31 06:29
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2025-8-31 08:27
0
雪    币: 204
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
66
2025-8-31 13:34
0
雪    币: 980
活跃值: (3105)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
1
2025-8-31 14:45
0
雪    币: 0
活跃值: (1230)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
 666
2025-8-31 15:28
0
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
1
2025-8-31 15:33
0
雪    币: 206
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
回复看内容
2025-8-31 18:14
0
雪    币: 104
活跃值: (7270)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
tql
2025-8-31 20:45
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
tql
2025-9-1 08:22
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
111
2025-9-1 09:01
0
雪    币: 419
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
大佬牛逼
2025-9-1 09:53
0
雪    币: 557
活跃值: (4394)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
膜拜大佬
2025-9-1 09:55
0
雪    币: 5050
活跃值: (5144)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
666
2025-9-1 10:50
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
666
2025-9-1 14:14
0
雪    币: 2377
活跃值: (2966)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
666
2025-9-1 16:14
0
雪    币: 1292
活跃值: (2267)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
我来看看 
2025-9-1 16:19
0
雪    币: 1501
活跃值: (3713)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
20
11
2025-9-1 17:12
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
感谢分享
2025-9-2 01:38
0
雪    币: 1818
活跃值: (1185)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
66
2025-9-2 09:14
0
雪    币: 42
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
23
6666
2025-9-2 10:27
0
雪    币: 268
活跃值: (1328)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
6
2025-9-2 14:39
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
25
6
2025-9-2 16:29
0
游客
登录 | 注册 方可回帖
返回