【python】【protobuf】逆向还原protobuf结构

文章目录

  • 一、前言
  • 二、示例
  • 三、python demo

一、前言

在很多场景,都有一个需求:
得到了一个编码后的protobuf数据(比如竞品调研的的数据包),需要逆向还原其proto结构文件。
有3种方案去做这件事情:

  1. 从编码入手,人工肉眼分析。
  • 费时费力
  • 容易出错(在一些嵌套结构,或者有优化编码的地方)
  • 但,对理解 protobuf 编码原理非常有帮助
  1. 借助 protoc.exe
  • protoc.exe --decode_raw < f1.bin
  • 缺点:没有给出数据类型
# protoc.exe --decode_raw <f1.bin
1 {
  1 {
    1: "\004\032\224\354~m\350-?\266(qJ\264.0\031v\204I\364v,\001\341P\341\300\326\013!\351\014"
    2 {
      1892: "\000"
    }
  }
  2: "\001d\2457\370\332\362\335\345e0\231\212(\007\2275d\330\025\327\000pk\254\361\213\020.N<\010"
}
  1. 借助在线工具先把protobuf的基本结构识别出来,然后结合对数据的理解进行修正。
  • 为什么需要修正?
    因为有些字段刚好符合 protobuf 的编码规则,被错误识别为结构
  • 对比 protoc --decode_raw 功能,优势是:
    结构更加清晰
    会提供Field 的数据类型

二、示例

这里介绍第三种方案,借助在线工具 + 修正。

  1. 拿到了一段数据
Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000000   0A 4D 0A 29 0A 21 04 1A  94 EC 7E 6D E8 2D 3F B6    M ) !  旍~m???
00000010   28 71 4A B4 2E 30 19 76  84 49 F4 76 2C 01 E1 50   (qJ?0 v処魐, 酨
00000020   E1 C0 D6 0B 21 E9 0C 12  04 A2 76 01 00 12 20 01   崂?!?       
00000030   64 A5 37 F8 DA F2 DD E5  65 30 99 8A 28 07 97 35   d?蜉錯0檴( ?
00000040   64 D8 15 D7 00 70 6B AC  F1 8B 10 2E 4E 3C 08      d??pk?.N< 
  1. 利用在线工具解析基本结构

Online Protobuf Decoder : https://protogen.marcgravell.com/decode

在这里插入图片描述
看到这个图,基本结构就可以还原出来了:

syntax = "proto2";

message Field1_1_2 {
	optional bytes f1 = 1892;
}

message Field1_1  {
	optional bytes f1 = 1;
	optional Field1_1_2 f2 = 2;
}

message Field1 {
	optional Field1_1 f1 = 1;
	optional bytes f2 = 2;
}

message Sample {
	optional Field1 f1 = 1;
}

这个结构,解析上面的数据是成功的
但是,可以注意一下,下面部分的定义不太常见,id比较特殊

message SampleField1_1_2 {
optional bytes f1 = 1892;
}

拿到了第二段数据,发现解码失败。

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000000   0A 78 0A 29 0A 21 04 3B  FC AF 46 BE E6 05 9B 88    x ) ! ;F炬 泩
00000010   D4 62 A6 96 AC 82 C7 EC  9D ED 96 BB BE 98 C9 18   詁瑐庆 頄痪樕 
00000020   BB 7C 75 15 BB C8 38 12  04 00 00 50 00 0A 29 0A   粅u 蝗8    P  ) 
00000030   21 04 09 AD 0C C5 B6 D8  E2 31 12 D9 86 7C 93 89   !  ?哦剽1 賳|搲
00000040   5D EB 4E 7C A8 87 E4 0F  F2 7C E2 31 5B 99 B3 CD   ]|▏?騶?[櫝?
00000050   B4 58 12 04 7C 2B 0D 00  12 20 4C 4C 90 8B 75 9A   碭  |+    LL 媢?
00000060   CD 3D 5C EC AD B7 6D 70  14 16 90 91 D2 09 DA A3   ?\飙穖p   懸 冢
00000070   F2 D6 53 FB 0A B4 46 E6  03 F2                     蛑S?碏??

再利用在线工具校验一下结构:
在这里插入图片描述
这时候发现跟第一次的结构确实有差异,差异在于:
在这里插入图片描述
对比可以发现,第二次的结构可以兼容第一次,而且解析出来的数据明显更合理,于是可以得到修正后的结构:

syntax = "proto2";

message Field1_1  {
	optional bytes f1 = 1;
	optional bytes f2 = 2;
}

message Field1 {
	optional Field1_1 f1 = 1;
	optional bytes f2 = 2;
}

message Sample {
	optional Field1 f1 = 1;
}

这样就完成了一次protobuf结构的还原与修订过程。

三、python demo

  1. 把以下结构保存为 sample.proto 文件:
syntax = "proto2";

message Field1_1  {
	optional bytes f1 = 1;
	optional bytes f2 = 2;
}

message Field1 {
	optional Field1_1 f1 = 1;
	optional bytes f2 = 2;
}

message Sample {
	optional Field1 f1 = 1;
}
  1. 利用 protoc.exe 编译 sample.proto, 得到 sample_pb2.py
protoc.exe --I=. --python_out=. sample.proto
  1. 引用
import sample_pb2

# f1.bin
chunk1 = file_chunk_keys_pb2.FileChunkKeys()
with open("f1.bin", "rb") as f:    
    chunk1.ParseFromString(f.read())
    
    print("#Field 1-1")
    for i in range(len(chunk1.f1.f1)):
        item1_1 = chunk1.f1.f1[i]
        print("chunk.f1.f1[", i, "]", ".f1 =", item1_1.f1.hex(' '))
        print("chunk.f1.f1[", i, "]", ".f2 =", item1_1.f2.hex(' '))

    print("")
    print("#Field 1-2")
    print("chunk.f1.f2 =", chunk1.f1.f2.hex(' '))

# f4.bin
chunk2 = file_chunk_keys_pb2.FileChunkKeys()
with open("f4.bin", "rb") as f:    
    chunk2.ParseFromString(f.read())
    
    print("#Field 1-1")
    for i in range(len(chunk2.f1.f1)):
        item1_1 = chunk2.f1.f1[i]
        print("chunk.f1.f1[", i, "]", ".f1 =", item1_1.f1.hex(' '))
        print("chunk.f1.f1[", i, "]", ".f2 =", item1_1.f2.hex(' '))

    print("")
    print("#Field 1-2")
    print("chunk.f1.f2 =", chunk2.f1.f2.hex(' '))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/5205.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux常用文件管理命令

Linux常用文件管理命令 目录Linux常用文件管理命令前言常用命令练习题创建文件夹题目代码复制题目代码移动题目代码删除题目代码系列操作题目代码前言 本文将讲解我们在使用Linux操作系统时经常需要使用的命令&#xff0c;也可以当成是一篇笔记的记录&#xff0c;当然光看这些…

Ubuntu安装交叉编译器gcc

1.创建文件并把压缩包复制到文件夹下 2.解压到文件夹下 先找到放置的目录 也可以直接找到文件夹右键-在终端打开 通过-C选项指定解压后的目标目录 tar -jxvf gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux.tar.bz2 -C /opt 注意:输入文件名时可以Tab键自动补齐 输入…

计算机网络中端到端与点到点的区别

计算机网络中端到端与点到点的区别 数据传输的可靠性是通过数据链路层和网络层的点对点和传输层的端对端保证的。端到端与点到点是针对网络中传输的两端设备间的关系而言的。 在一个网络系统的不同分层中&#xff0c;可能用到端到端传输&#xff0c;也可能用到点到点传输。如…

限流、熔断、服务降级

在分布式系统中&#xff0c;如果某个服务节点发生故障或者网络发生异常&#xff0c;都有可能导致调用方被阻塞等待&#xff0c;如果超时时间设置很长&#xff0c;调用方资源很可能被耗尽。这又导致了调用方的上游系统发生资源耗尽的情况&#xff0c;最终导致系统雪崩。 举例&a…

[Vulfocus解题系列]Spring WebFlow 远程代码执行漏洞(CVE-2017-4971)

简介 Spring WebFlow 是一个适用于开发基于流程的应用程序的框架&#xff08;如购物逻辑&#xff09;&#xff0c;可以将流程的定义和实现流程行为的类和视图分离开来。在其 2.4.x 版本中&#xff0c;如果我们控制了数据绑定时的field&#xff0c;将导致一个SpEL表达式注入漏洞…

科大奥瑞物理实验——声速的测量

实验名称&#xff1a;声速的测量 1. 实验目的&#xff1a; &#xff08;1&#xff09;了解超声波的发射和接收方法。 &#xff08;2&#xff09;加深对振动合成、波动干涉等理论知识的理解。 &#xff08;3&#xff09;掌握用驻波法和相位法测声速。 2. 实验器材&#xff1a…

如何挖掘用户需求的真正动机?关键是4大因素

需求分析实质是挖掘用户内心真正的目标&#xff0c;并转化为产品需求的过程。而用户需求是用户基于自身角度提出的表层需求&#xff0c;这些需求往往有用户期望的产品功能指向。而在产品功能指向的背后&#xff0c;暗藏着潜在的用户动机&#xff0c;这是用户真正希望解决的核心…

【尚硅谷】Java数据结构与算法笔记13 - 图

文章目录一、图的基本介绍1.1 为什么要有图1.2 图的举例说明1.3 图的常用概念二、图的表示方式2.1 邻接矩阵2.2 邻接表三、图的快速入门案例四、图的遍历4.1 深度优先遍历 DFS4.1.1 基本思想4.1.2 算法步骤4.1.3 图示4.2 广度优先遍历 BFS4.2.1 基本思想4.2.2 算法步骤4.2.3 图…

【机器学习】P8 过拟合与欠拟合、正则化与正则化后的损失函数和梯度下降

过拟合与欠拟合、正则化与正则化后的损失函数和梯度下降过拟合与欠拟合过拟合与欠拟合直观理解线性回归中 过拟合与欠拟合逻辑回归中 过拟合与欠拟合过拟合与欠拟合的解决办法过拟合解决方案欠拟合解决方案包含正则化的损失函数正则化线性回归损失函数正则化逻辑回归损失函数包…

java爬虫利器Jsoup的使用

对于长期使用java做编程的程序猿应该知道&#xff0c;java支持的爬虫框架还是有很多的&#xff0c;如&#xff1a;ebMagic、Spider、Jsoup等。今天我们就用Jsoup来实现一个小小的爬虫程序&#xff0c;Jsoup作为kava的HTML解析器&#xff0c;可以直接对某个URL地址、HTML文本内容…

焦虑真的好吗 过度的焦虑存在哪些影响

日常常见的焦虑情绪真的好吗&#xff1f;焦虑是我们七情中的一种正常情绪表现&#xff0c;我们生活当中很多因素都可能会导致我们产生焦虑的情绪表现&#xff0c;如一场考试、一次挑战、一个活动等等。这种焦虑情绪的产生并不是一件坏事&#xff0c;相反&#xff0c;焦虑情绪的…

ROS学习笔记(零):ROS与机器人概述

ROS学习笔记&#xff08;零&#xff09;&#xff1a;ROS与机器人概述ROSROS的起源ROS的特点ROS架构设计机器人机器人的定义机器人的组成执行机构驱动系统传感系统控制系统ROS ROS的起源 ROS&#xff08;Robot Operating System&#xff09;是一个广泛使用的机器人操作系统&…

Python图片相册批处理器的设计与实现批量添加图片水印、批量命名等功能

课题研究使用Python语言开发一个包含批量添加图片水印、批量命名等功能的图片批处理程序&#xff0c;功能模块大概包含以下模块&#xff1a; &#xff08;1&#xff09;首页模块&#xff1a;首页是整个软件的初始页面&#xff0c;包含用户登录、注册、关于本软件等功能&#xf…

红日(vulnstack)5 内网渗透ATTCK实战

环境配置 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;l8r7 攻击机&#xff1a;kali2022.03 192.168.135.128(NET模式) win7 192.168.138.136 (仅主机模式) 192.168.135.150 (NET模式) win2008 192.168.138.138 (仅主机模式) web渗透 1.nmap探测目标靶机开…

Qt学习笔记之SQLITE数据库

1. SQLite数据库介绍 SQLite&#xff0c;是一款轻型的数据库&#xff0c;是遵守ACID的关系型数据库管理系统&#xff0c;它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的&#xff0c;而且已经在很多嵌入式产品中使用了它&#xff0c;…

SpringBoot(1)基础入门

SpringBoot基础入门SpringBoot项目创建方式Idea创建SpringBoot官网创建基于阿里云创建项目手工搭建SpringBoot启动parentstarter引导类内嵌tomcat基础配置属性配置配置文件分类yaml文件yaml数据读取整合第三方技术整合JUnit整合MyBatis整合Mybatis-Plus整合DruidSpringBoot是由…

运动健康路线导入,助力用户轻松导航

华为HMS Core运动健康服务支持通过REST API&#xff0c;以GPX文件格式写入用户路线数据&#xff0c;支持导入轨迹&#xff08;Track&#xff09;或路程&#xff08;Route&#xff09;类型的数据&#xff0c;实现用户路线数据在华为运动健康App中的展示效果。 假若与华为运动健…

​selenium+python做web端自动化测试框架与实例详解教程​

下面有详细的代码介绍&#xff0c;如果不是很明白的话&#xff0c;可以看看这套视频&#xff0c;在哔站学习人数超过数万人&#xff01; 在华为工作了10年的大佬出的Web自动化测试教程&#xff0c;华为现用技术教程&#xff01;_哔哩哔哩_bilibili在华为工作了10年的大佬出的W…

分享NVIDIA GTC干货_用软件引领车辆电子架构

随着软件定义功能变得更多&#xff0c;车辆电气/电子架构正在从分布式计算演变为集中式计算。通过将这台集中式超级计算机与人工智能融合在一起&#xff0c;开发模块化软件并创建数据中心基础设施。 电子架构 EEA(Electrical and Electronic Architecture) 首先介绍下EEA&am…

Ansys Zemax | 如何建模离轴抛物面镜

离轴抛物面反射镜是光学工业中一种重要的设计类型。本文演示了如何根据制造商给出的规格设计一个离轴抛物面反射镜&#xff0c;并演示如何使用主光线求解将像面中心与主光线路径对齐。(联系我们获取文章附件) 简介 离轴抛物面反射镜的优点是光束通过反射到达像面途中将不会受…