返回更新列表
新发布Aug 21, 2026

pbtk v1.1.3

用于逆向工程和模糊测试基于Protobuf的应用程序的工具集

分享

pbtk - 逆向工程 Protobuf 应用

Protobuf 是一种序列化格式,由 Google 开发,并越来越多地应用于 Android、Web、桌面及其他应用程序中。它包含一套用于声明数据结构的语言,该语言随后会被编译成代码或其他类型的结构,具体取决于目标实现。

pbtk(Protobuf 工具包)是一套完整的脚本集,可通过统一的图形界面访问,提供两大主要功能:

  • 从程序中提取 Protobuf 结构,将其转换回可读的 .proto 文件,支持多种实现:

    • 所有主流的 Java 运行时(base、Lite、Nano、Micro、J2ME),完全支持 Proguard,(2026:此功能仍工作良好,但主要适用于旧版 APK)
    • 包含嵌入式反射元数据的二进制文件(通常是 C++,有时是 Java 及大多数其他绑定),(2026:此功能仍工作良好)
    • 使用 JsProtoUrl 运行时的 Web 应用程序。(2026:此功能需要更新)
  • 编辑、重放和模糊测试发送到 Protobuf 网络端点的数据,通过一个便捷的图形界面,允许你实时编辑 Protobuf 消息的字段并查看结果。

pbtk 编辑器 GUI

安装

PBTK 需要 Python ≥ 3.5、PySide 6、Python-Protobuf 3,以及一些可执行程序(chromium、jad、dex2jar...)来运行提取器脚本。

Ubuntu 用户可以通过 snap 安装:

$ sudo snap install pbtk
$ pbtk

Archlinux 用户可以直接通过 软件包 安装:

$ yay -S pbtk-git
$ pbtk

在大多数其他发行版上,您需要直接运行:

# 对于 Ubuntu/Debian 测试衍生版:
$ sudo apt install python3-pip git openjdk-8-jre python3-qtpy-pyside6

# 然后使用 UV:
$ sudo snap install --classic astral-uv
$ uv tool install pbtk
$ pbtk

# 或者使用 pipx:
$ sudo apt install pipx
$ pipx install pbtk
$ pbtk

Windows 也支持(需要相同的模块)。一旦您运行 GUI,它会根据您尝试执行的操作警告您缺少什么。

命令行使用(通过包管理器安装)

GUI 可以通过主脚本启动:

pbtk

以下脚本也可以独立使用,无需 GUI:

pbtk-jar-extract [-h] input_file [output_dir]
pbtk-from-binary [-h] input_file [output_dir]
pbtk-web-extract [-h] input_url [output_dir] # 需要更新以在 2026 年正常工作

当从 snap 安装时,具体命令有所不同:

pbtk.jar-extract [-h] input_file [output_dir]
pbtk.from-binary [-h] input_file [output_dir]
pbtk.web-extract [-h] input_url [output_dir]

命令行使用(本地)

GUI 可以通过主脚本启动:

uv sync # 下载依赖到 .venv 文件夹
source .venv/bin/activate # 将本地脚本置于当前 shell 会话的 $PATH 中
uv tool install -e . # 让本地脚本始终位于 $PATH 中
pbtk

以下脚本也可以独立使用,无需 GUI:

pbtk-jar-extract [-h] input_file [output_dir]
pbtk-from-binary [-h] input_file [output_dir]
pbtk-web-extract [-h] input_url [output_dir] # 需要更新以在 2026 年正常工作

典型工作流程

假设您正在逆向工程一个 Android 应用程序。您使用喜爱的反编译器探索了一下应用程序,发现它使用 Protobuf 作为 POST 数据通过 HTTPS 以典型方式传输。

您打开 PBTK,会看到一个友好的欢迎界面:

欢迎界面

第一步是将您的 .proto 文件转换为文本格式。如果您针对的是 Android 应用,只需放入 APK 并等待即可神奇地完成!(除非是非常特殊的实现)

完成界面

完成后,您跳转到 ~/.pbtk/protos/<您的 APK 名称>(通过命令行或欢迎界面底部的按钮打开文件浏览器,任您选择)。应用程序的所有 .proto 文件都在这里。

回到您的反编译器,您遇到了构造发送到您感兴趣 HTTPS 端点的数据的类。它通过调用一个由生成代码构成的类来序列化 Protobuf 消息。

您的反编译器

后一个类应该与您的 .protos 目录中的某个内容完全匹配(即 com.foo.bar.a.b 将匹配 com/foo/bar/a/b.proto)。无论哪种方式,通过 grep 其名称,您应该能够引用它。

太好了:下一步是进入第2步,选择您想要输入的 .proto 文件,并填写一些关于端点的信息。

端点创建表单

您还可以提供一些发送到该端点的原始 Protobuf 数据样本(通过 mitmproxy 或 Wireshark 捕获),并以十六进制编码的形式粘贴。

第3步是关于点击按钮并观察结果的有趣部分!您会看到一个树状视图,代表 Protobuf 结构中的每个字段(重复字段末尾有 "+",必需字段没有复选框)。

端点创建表单

只需将鼠标悬停在字段上即可获得焦点。如果字段是整数类型,可以使用鼠标滚轮增加/减少它。悬停时也会显示枚举信息。

就这些!您可以据此确定每个字段的含义。如果您从混淆代码中提取了 .proto 文件,可以通过点击字段名称,根据您观察到的含义重命名字段。

逆向愉快!👌 🎉

本地数据存储

PBTK 将提取的 .proto 信息存储在 ~/.pbtk/protos/(Windows 上为 %APPDATA%\pbtk\protos)。

您可以通过常规文件浏览器和文本编辑器直接在此目录中移动、移出、重命名、编辑或删除数据,这是预期的方式,不会干扰 PBTK 的运行。

基于 HTTP 的端点以 JSON 对象的形式存储在 ~/.pbtk/endpoints/ 中。这些对象是请求/响应信息对的数组,如下所示:

[{
    "request": {
        "transport": "pburl",
        "proto": "www.google.com/VectorTown.proto",
        "url": "https://www.google.com/VectorTown",
        "pb_param": "pb",
        "samples": [{
            "pb": "!....",
            "hl": "fr"
        }]
    },
    "response": {
        "format": "other"
    }
}]

源代码结构

PBTK 内部使用两种可插拔模块:提取器(extractors)和传输器(transports)。

  • 提取器 支持从目标 Protobuf 实现或平台中提取 .proto 结构。

提取器定义在 src/pbtk/extractors/*.py 中。它们以带有装饰器的方法形式定义,如下所示:

@register_extractor(name = 'my_extractor',
                    desc = 'Extract Protobuf structures from Foobar code (*.foo, *.bar)',
                    depends={'binaries': ['foobar-decompiler']})
def my_extractor(path):
    # 加载 `path` 输入文件的内容并执行你的操作...
    
    # 然后,使用生成器生成提取的 .proto 文件:
    for i in do_your_extraction_work():
        yield proto_name + '.proto', proto_contents
    
    # 也可以生成其他类型的信息,例如端点信息或要显示的进度。
  • 传输器 支持一种反序列化、重新序列化和通过网络发送 Protobuf 数据的方式。例如,最常用的传输器是通过 HTTP 发送原始 POST 数据。

传输器定义在 src/pbtk/utils/transports.py 中。它们以带有装饰器的类形式定义,如下所示:

@register_transport(
    name = 'my_transport',
    desc = 'Protobuf as raw POST data',
    ui_data_form = 'hex strings'
)
class MyTransport():
    def __init__(self, pb_param, url):
        self.url = url
    
    def serialize_sample(self, sample):
        # 我们从用户那里获取了一个输入数据样本。
        # 验证它是否以“ui_data_form”参数描述的格式有效,否则抛出异常或返回 False。
        # 可选地在返回之前修改此数据。
        bytes.fromhex(sample)
        return sample
    
    def load_sample(self, sample, pb_msg):
        # 将输入数据解析为提供的 Protobuf 对象。
        pb_msg.ParseFromString(bytes.fromhex(sample))
    
    def perform_request(self, pb_data, tab_data):
        # 使用提供的 URL 和 Protobuf 对象执行请求,并可选择性地使用其他传输特定的辅助数据。
        return post(url, pb_data.SerializeToString(), headers=USER_AGENT)

后续改进

以下功能可能会在未来的版本中出现:

  • 完成自动模糊测试部分。
  • 支持从 Java 代码中提取扩展。
  • 支持 JSPB(主要 JavaScript)运行时。
  • 如果您希望支持其他平台,只需提交一个 issue,我会关注。

我尽力为大多数模块编写了易于阅读和注释完善的代码(除了那些基本上自说明的部分,比如连接 GUI 信号),以便您能够贡献代码。

许可协议

pbtk 根据 GNU GPL 许可证发布(我,以此声明等)。

项目名称的大小写没有正式规定,规则只是遵循您的心意 ❤

分类