二进制文件中protobuf结构分析
字数 1750 2025-08-30 06:50:35

Protocol Buffers (Protobuf) 结构分析与逆向工程指南

1. Protobuf 简介

Protocol Buffers (Protobuf) 是 Google 开发的一种数据序列化协议,具有以下特点:

  • 类似于 XML 但更高效
  • 用于结构化数据序列化
  • 适用于数据存储和通信协议
  • 跨平台和异构系统 RPC 调用
  • 序列化/反序列化效率高
  • 体积比 XML 和 JSON 小得多,适合网络传输

2. Protobuf 开发环境搭建

2.1 安装 Protobuf 编译器

# 下载 Protobuf
git clone https://github.com/protocolbuffers/protobuf

# 编译安装
cd protobuf
./configure && make
sudo make install

2.2 安装 C 语言支持库

# 下载 protobuf-c
git clone https://github.com/protobuf-c/protobuf-c

# 编译安装
cd protobuf-c
./configure && make
sudo make install

3. Protobuf 基本使用示例

3.1 定义 .proto 文件

syntax = "proto3";
package example;

message Person {
    string name = 1;
    int32 id = 2;
    string email = 3;
}

3.2 生成 C 语言代码

protoc --c_out=. message.proto

这将生成两个文件:

  • message.pb-c.c - 实现文件
  • message.pb-c.h - 头文件

3.3 关键数据结构分析

3.3.1 ProtobufCMessage 基础结构

struct ProtobufCMessage {
    const ProtobufCMessageDescriptor *descriptor;  // 消息描述符
    unsigned n_unknown_fields;                     // 未知字段数量
    ProtobufCMessageUnknownField *unknown_fields;  // 未知字段
};

3.3.2 字段描述符 ProtobufCFieldDescriptor

struct ProtobufCFieldDescriptor {
    const char *name;            // 字段名称
    uint32_t id;                // 字段标签号
    ProtobufCLabel label;        // 字段标签类型
    ProtobufCType type;          // 字段数据类型
    unsigned quantifier_offset;  // 量词偏移
    unsigned offset;             // 字段偏移
    // ... 其他成员
};

3.3.3 消息描述符 ProtobufCMessageDescriptor

const ProtobufCMessageDescriptor example__person__descriptor = {
    PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
    "example.Person",           // 完整消息名称
    "Person",                   // 简短消息名称
    "Example__Person",          // C结构体名称
    "example",                  // 包名
    sizeof(Example__Person),    // 消息大小
    3,                         // 字段数量
    example__person__field_descriptors, // 字段描述符数组
    // ... 其他成员
};

3.4 字段类型和标签枚举

3.4.1 ProtobufCType 字段类型

typedef enum {
    PROTOBUF_C_TYPE_INT32,      // int32
    PROTOBUF_C_TYPE_SINT32,     // signed int32
    PROTOBUF_C_TYPE_SFIXED32,   // signed int32 (4 bytes)
    PROTOBUF_C_TYPE_INT64,      // int64
    PROTOBUF_C_TYPE_SINT64,     // signed int64
    PROTOBUF_C_TYPE_SFIXED64,   // signed int64 (8 bytes)
    PROTOBUF_C_TYPE_UINT32,     // unsigned int32
    PROTOBUF_C_TYPE_FIXED32,    // unsigned int32 (4 bytes)
    PROTOBUF_C_TYPE_UINT64,     // unsigned int64
    PROTOBUF_C_TYPE_FIXED64,    // unsigned int64 (8 bytes)
    PROTOBUF_C_TYPE_FLOAT,      // float
    PROTOBUF_C_TYPE_DOUBLE,     // double
    PROTOBUF_C_TYPE_BOOL,       // boolean
    PROTOBUF_C_TYPE_ENUM,       // enumerated type
    PROTOBUF_C_TYPE_STRING,     // UTF-8 or ASCII string
    PROTOBUF_C_TYPE_BYTES,      // arbitrary byte sequence
    PROTOBUF_C_TYPE_MESSAGE,    // nested message
} ProtobufCType;

3.4.2 ProtobufCLabel 字段标签

typedef enum {
    PROTOBUF_C_LABEL_REQUIRED,  // 必须字段
    PROTOBUF_C_LABEL_OPTIONAL,  // 可选字段
    PROTOBUF_C_LABEL_REPEATED,  // 可重复字段
    PROTOBUF_C_LABEL_NONE,      // 无标签(proto3)
} ProtobufCLabel;

3.5 二进制数据表示

struct ProtobufCBinaryData {
    size_t len;     // 数据长度
    uint8_t *data;  // 数据指针
};

4. Protobuf 逆向工程方法

4.1 逆向分析流程

  1. 定位 ProtobufCMessageDescriptor 结构体
  2. 分析字段描述符数组 ProtobufCFieldDescriptor
  3. 提取每个字段的:
    • name: 字段名称
    • id: 字段标签号
    • label: 字段标签类型
    • type: 字段数据类型
  4. 根据偏移量确定字段在结构体中的位置

4.2 IDA 逆向分析技巧

  1. 识别 ProtobufCMessageDescriptor 结构体特征:

    • 包含 magic number
    • 包含消息名称字符串
    • 包含字段数量和字段描述符数组指针
  2. 字段描述符分析:

    • name 字段: 指向字段名称字符串
    • id 字段: 字段标签号
    • label 字段: 对应 ProtobufCLabel 枚举
    • type 字段: 对应 ProtobufCType 枚举
    • offset 字段: 字段在结构体中的偏移量
  3. 结构体布局:

    • 前 0x18 字节为 ProtobufCMessage 基础结构
    • 后续为自定义字段

4.3 还原 .proto 文件

通过逆向分析可以还原出原始 .proto 文件定义,例如:

syntax = "proto3";
package example;

message Person {
    string name = 1;
    int32 id = 2;
    string email = 3;
}

5. 实战案例分析

5.1 [CISCN 2023 初赛]StrangeTalkBot

分析过程:

  1. 定位到 ProtobufCMessageDescriptor 结构体

  2. 分析字段描述符数组:

    • 第一个字段 actionid:
      • id: 1
      • label: PROTOBUF_C_LABEL_REQUIRED (0)
      • type: PROTOBUF_C_TYPE_SINT64 (4)
      • offset: 0x18
  3. 还原 .proto 文件

漏洞利用:

  • UAF (Use-After-Free) 漏洞
  • 利用思路:
    1. 泄漏 libc 和堆地址
    2. 修改指针申请到 free_hook
    3. 构造 ORW 链
    4. 触发漏洞

5.2 [CISCN 2024]protoverflow

分析过程:

  1. 识别 C++ 版本的 Protobuf 结构
  2. 手撕 IDA 还原 .proto 文件
  3. 发现栈溢出漏洞

利用方法:

  1. 构造恶意 Protobuf 数据
  2. 触发栈溢出控制流劫持

6. 工具推荐

  1. pbtk - Protobuf 逆向工具
  2. 半自动化 IDAPython 脚本 - 用于快速提取 Protobuf 结构
  3. protoc - 官方编译器,用于验证还原的 .proto 文件

7. 总结

Protobuf 逆向工程关键点:

  1. 理解 Protobuf 的核心数据结构
  2. 掌握 IDA 中识别 Protobuf 结构的方法
  3. 能够从二进制中还原 .proto 文件定义
  4. 了解不同语言实现(C/C++/Python)的差异
  5. 熟悉常见漏洞模式和利用方法

通过系统分析 Protobuf 的结构和逆向方法,可以有效应对相关二进制分析挑战。

Protocol Buffers (Protobuf) 结构分析与逆向工程指南 1. Protobuf 简介 Protocol Buffers (Protobuf) 是 Google 开发的一种数据序列化协议,具有以下特点: 类似于 XML 但更高效 用于结构化数据序列化 适用于数据存储和通信协议 跨平台和异构系统 RPC 调用 序列化/反序列化效率高 体积比 XML 和 JSON 小得多,适合网络传输 2. Protobuf 开发环境搭建 2.1 安装 Protobuf 编译器 2.2 安装 C 语言支持库 3. Protobuf 基本使用示例 3.1 定义 .proto 文件 3.2 生成 C 语言代码 这将生成两个文件: message.pb-c.c - 实现文件 message.pb-c.h - 头文件 3.3 关键数据结构分析 3.3.1 ProtobufCMessage 基础结构 3.3.2 字段描述符 ProtobufCFieldDescriptor 3.3.3 消息描述符 ProtobufCMessageDescriptor 3.4 字段类型和标签枚举 3.4.1 ProtobufCType 字段类型 3.4.2 ProtobufCLabel 字段标签 3.5 二进制数据表示 4. Protobuf 逆向工程方法 4.1 逆向分析流程 定位 ProtobufCMessageDescriptor 结构体 分析字段描述符数组 ProtobufCFieldDescriptor 提取每个字段的: name: 字段名称 id: 字段标签号 label: 字段标签类型 type: 字段数据类型 根据偏移量确定字段在结构体中的位置 4.2 IDA 逆向分析技巧 识别 ProtobufCMessageDescriptor 结构体特征: 包含 magic number 包含消息名称字符串 包含字段数量和字段描述符数组指针 字段描述符分析: name 字段: 指向字段名称字符串 id 字段: 字段标签号 label 字段: 对应 ProtobufCLabel 枚举 type 字段: 对应 ProtobufCType 枚举 offset 字段: 字段在结构体中的偏移量 结构体布局: 前 0x18 字节为 ProtobufCMessage 基础结构 后续为自定义字段 4.3 还原 .proto 文件 通过逆向分析可以还原出原始 .proto 文件定义,例如: 5. 实战案例分析 5.1 [ CISCN 2023 初赛 ]StrangeTalkBot 分析过程: 定位到 ProtobufCMessageDescriptor 结构体 分析字段描述符数组: 第一个字段 actionid: id: 1 label: PROTOBUF_ C_ LABEL_ REQUIRED (0) type: PROTOBUF_ C_ TYPE_ SINT64 (4) offset: 0x18 还原 .proto 文件 漏洞利用: UAF (Use-After-Free) 漏洞 利用思路: 泄漏 libc 和堆地址 修改指针申请到 free_ hook 构造 ORW 链 触发漏洞 5.2 [ CISCN 2024 ]protoverflow 分析过程: 识别 C++ 版本的 Protobuf 结构 手撕 IDA 还原 .proto 文件 发现栈溢出漏洞 利用方法: 构造恶意 Protobuf 数据 触发栈溢出控制流劫持 6. 工具推荐 pbtk - Protobuf 逆向工具 半自动化 IDAPython 脚本 - 用于快速提取 Protobuf 结构 protoc - 官方编译器,用于验证还原的 .proto 文件 7. 总结 Protobuf 逆向工程关键点: 理解 Protobuf 的核心数据结构 掌握 IDA 中识别 Protobuf 结构的方法 能够从二进制中还原 .proto 文件定义 了解不同语言实现(C/C++/Python)的差异 熟悉常见漏洞模式和利用方法 通过系统分析 Protobuf 的结构和逆向方法,可以有效应对相关二进制分析挑战。