protobuf初探
发表于:2023-11-15 |
字数统计: 787 | 阅读时长: 4分钟 | 阅读量:

protobuf安装

1
python3 -m pip install protobuf

protobuf-c安装

1
2
3
4
5
6
7
git clone https://github.com/protobuf-c/protobuf-c.git
sudo apt install autoconf, automake, libtool,libprotobuf-dev,libprotoc-dev,protobuf-compiler
./autogen.sh
./configure --prefix=/usr/local/protobuf-c --libdir=/usr/lib
make -j8 && make install
sudo cp -r /usr/local/protobuf-c/include/protobuf-c /usr/include
sudo ln -s /usr/local/protobuf-c/bin/protoc-gen-c /usr/local/bin/protoc-c

protobuf关键结构逆向

首先编写一个devicemsg.proto

1
2
3
4
5
6
syntax = "proto2";

message devicemsg{
int64 choice = 1;
sint64 money = 2;
}

执行命令,生成devicemsg.pb-c.h/c

1
protoc-c --c_out=. devicemsg.proto

发现.c文件中存在下列函数

1
2
3
4
5
6
7
8
9
Devicemsg *
devicemsg__unpack(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (Devicemsg *)
protobuf_c_message_unpack(&devicemsg__descriptor,
allocator, len, data);
}

&devicemsg__descriptor就是我们需要着重分析的结构体

查看结构体定义

  • magic,一般为0x28AAEEF9
  • n_fields, 关系到原始的message结构内有几条记录
  • fields, 这个指向message内所有记录类型组成的一个数组,可以借此逆向分析message结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
struct ProtobufCMessageDescriptor {
/** Magic value checked to ensure that the API is used correctly. */
uint32_t magic;

/** The qualified name (e.g., "namespace.Type"). */
const char *name;
/** The unqualified name as given in the .proto file (e.g., "Type"). */
const char *short_name;
/** Identifier used in generated C code. */
const char *c_name;
/** The dot-separated namespace. */
const char *package_name;

/**
* Size in bytes of the C structure representing an instance of this
* type of message.
*/
size_t sizeof_message;

/** Number of elements in `fields`. */
unsigned n_fields;
/** Field descriptors, sorted by tag number. */
const ProtobufCFieldDescriptor *fields;
/** Used for looking up fields by name. */
const unsigned *fields_sorted_by_name;

/** Number of elements in `field_ranges`. */
unsigned n_field_ranges;
/** Used for looking up fields by id. */
const ProtobufCIntRange *field_ranges;

/** Message initialisation function. */
ProtobufCMessageInit message_init;

/** Reserved for future use. */
void *reserved1;
/** Reserved for future use. */
void *reserved2;
/** Reserved for future use. */
void *reserved3;
};
  • name,变量名
  • id, 在message结构体中的顺序
  • label, 前面标记的required等,这里是proto2的语法
  • type, 数据类型,string还是int64等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
struct ProtobufCFieldDescriptor {
/** Name of the field as given in the .proto file. */
const char *name;

/** Tag value of the field as given in the .proto file. */
uint32_t id;

/** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */
ProtobufCLabel label;

/** The type of the field. */
ProtobufCType type;

/**
* The offset in bytes of the message's C structure's quantifier field
* (the `has_MEMBER` field for optional members or the `n_MEMBER` field
* for repeated members or the case enum for oneofs).
*/
unsigned quantifier_offset;

/**
* The offset in bytes into the message's C structure for the member
* itself.
*/
unsigned offset;

/**
* A type-specific descriptor.
*
* If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the
* corresponding `ProtobufCEnumDescriptor`.
*
* If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to
* the corresponding `ProtobufCMessageDescriptor`.
*
* Otherwise this field is NULL.
*/
const void *descriptor; /* for MESSAGE and ENUM types */

/** The default value for this field, if defined. May be NULL. */
const void *default_value;

/**
* A flag word. Zero or more of the bits defined in the
* `ProtobufCFieldFlag` enum may be set.
*/
uint32_t flags;

/** Reserved for future use. */
unsigned reserved_flags;
/** Reserved for future use. */
void *reserved2;
/** Reserved for future use. */
void *reserved3;
};

type枚举如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;

生成python模块

1
2
3
4
5
6
7
8
protoc --python_out=. devicemsg.proto
#######################################
msg = bank_pb2.devicemsg()
msg.choice = 1
msg.money = 0x3F
io.sendafter(
b"4.show me flag\n", msg.SerializeToString()
)

参考链接

pwn题中的protobuf逆向 - Jmp·Cliff - 博客园 (cnblogs.com)

Loora1N’s Blog | 鹭雨 |

[原创] 2021第五空间 pb WP-CTF对抗-看雪-安全社区|安全招聘|kanxue.com

Linux protobuf以及protobuf-c的安装与使用说明_protobuf c-CSDN博客

关于protobuf的解题步骤 | 196082’s blog (gitee.io)

上一篇:
年终回忆-2023
下一篇:
cgi调试