从一道CTF题学习python字节码到源码逆向
概述:
该题来源为2022爱春秋冬季赛ezpython,难度不是很大刚好适合我这样的萌新入门
题目:
3 0 LOAD_CONST 1 (204)
3 LOAD_CONST 2 (141)
6 LOAD_CONST 3 (44)
9 LOAD_CONST 4 (236)
12 LOAD_CONST 5 (111)
15 LOAD_CONST 6 (140)
18 LOAD_CONST 6 (140)
21 LOAD_CONST 7 (76)
24 LOAD_CONST 3 (44)
27 LOAD_CONST 8 (172)
30 LOAD_CONST 9 (7)
33 LOAD_CONST 9 (7)
36 LOAD_CONST 10 (39)
39 LOAD_CONST 11 (165)
42 LOAD_CONST 12 (70)
45 LOAD_CONST 9 (7)
48 LOAD_CONST 10 (39)
51 LOAD_CONST 13 (166)
54 LOAD_CONST 11 (165)
57 LOAD_CONST 14 (134)
60 LOAD_CONST 14 (134)
63 LOAD_CONST 6 (140)
66 LOAD_CONST 1 (204)
69 LOAD_CONST 11 (165)
72 LOAD_CONST 9 (7)
75 LOAD_CONST 10 (39)
78 LOAD_CONST 15 (230)
81 LOAD_CONST 6 (140)
84 LOAD_CONST 11 (165)
87 LOAD_CONST 12 (70)
90 LOAD_CONST 3 (44)
93 LOAD_CONST 8 (172)
96 LOAD_CONST 16 (102)
99 LOAD_CONST 17 (6)
102 LOAD_CONST 6 (140)
105 LOAD_CONST 1 (204)
108 LOAD_CONST 15 (230)
111 LOAD_CONST 15 (230)
114 LOAD_CONST 7 (76)
117 LOAD_CONST 18 (198)
120 LOAD_CONST 19 (38)
123 LOAD_CONST 20 (175)
126 BUILD_LIST 42
129 STORE_FAST 0 (flag) 4 132 SETUP_LOOP 54 (to 189)
135 LOAD_GLOBAL 0 (range)
138 LOAD_CONST 21 (42)
141 CALL_FUNCTION 1
144 GET_ITER
>> 145 FOR_ITER 40 (to 188)
148 STORE_FAST 1 (i) 5 151 LOAD_FAST 0 (flag)
154 LOAD_FAST 1 (i)
157 BINARY_SUBSCR //读取列表中的值
158 LOAD_CONST 22 (5)
161 BINARY_RSHIFT
162 LOAD_FAST 0 (flag)
165 LOAD_FAST 1 (i)
168 BINARY_SUBSCR
169 LOAD_CONST 23 (3)
172 BINARY_LSHIFT
173 BINARY_OR
174 LOAD_CONST 24 (255)
177 BINARY_AND
178 LOAD_FAST 0 (flag)
181 LOAD_FAST 1 (i)
184 STORE_SUBSCR
185 JUMP_ABSOLUTE 145
>> 188 POP_BLOCK
>> 189 LOAD_CONST 0 (None)
192 RETURN_VALUE
分析:
先了解python的字节码结构,如下:
源码行号 | 指令在函数中的偏移 | 指令符号 | 指令参数 | 实际参数值
第一个为源码行号,从上述题目中我们可以了解到,本题只有5行源码,但是只给了从第3行开始的字节码
第二个指令在函数中的偏移和第四个指令参数对于做题来说不是太过重要,我们在做题的时候主要还是看指令符号和实际参数值
在第3行的字节码指令符号中,有LOAD_CONST ,BUILD_LIST ,STORE_FAST 三种类型
LOAD_CONST 加载常量,通常为整数值
BUILD_LIST 创建一个列表
STORE_FAST 一般用于保存值到局部变量
理解了上述指令符号含义后,我们来看题目中第3行的字节码,先看第一个

分析后知道加载了一个常量,数值为204,以此向后分析发现,大部分一样,至此我们知道加载了如下常数
204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175
然后我们来这里

这里建立一个列表,长度为42,你也可以通过数前面加载的常量发现,刚好是42个常量,然后保存值到变量flag中,那这里保存的值是什么呢?其实就是位于该指令符号前面的所有的值。
综上我们就得到python源码的第3行源码
flag = [204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175]
接着分析第4行字节码:

这里的指令符号有:
SETUP_LOOP,用于开始循环,括号里的189表示循环退出点(字节码结构中的第二个指令在函数中偏移)
LOAD_GLOBAL,用来加载全局变量,包括指定函数名,类名,模块名等全局符号
LOAD_CONST ,(请看上文)
CALL_FUNCTION,用来表示前面加载全局变量的参数个数
GET_ITER,FOR_ITER ,获取参数,开始迭代。这两个不需要过多理解,属于for-in结构特有的,它们通常同时出现。
STORE_FAST,(请看上文)
综上分析:开始循环,加载了一个全局函数range,加载了一个常量42,range函数的参数为1,执行循环的变量i,得到源码如下:
for i in range(42):
继续分析第5行字节码:

这里出现了前面没出现过的字节码有:
BINARY_SUBSCR ,读取迭代器中某个下标的值
BINARY_RSHIFT,进行右移运算
BINARY_LSHIFT ,左移运算
BINARY_OR,或运算
BINARY_AND ,与运算
STORE_SUBSCR ,修改迭代器中某个下标的值
JUMP_ABSOLUTE ,回到循环起点
RETURN_VALUE ,函数结束标志
POP_BLOCK,特有的,不用特别理解,对转换回源码不重要,通常和LOAD_CONST 0 (None)一起出现。
整体理解:先读取了flag[i]的值,然后加载一个常数5进行右移,得到如下:
flag[i] >> 5
然后继续读取flag[i]的值,加载一个常数3进行左移,得到如下:
flag[i] << 3
然后进行或运算,得到如下:
(flag[i] >> 5) | (flag[i] << 3)
加载一个常数255,接着进行与运算,得到如下:
(flag[i] >> 5) | (flag[i] << 3) & 255
最后存入flag[i],得到如下:
flag[i] = (flag[i] >> 5) | (flag[i] << 3) & 255
注意字节码从上到下的顺序和源码运算的优先级顺序。
最终从全部的字节码翻译过来的源码如下:
flag = [204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175]
for i in range(42):
flag[i] = (flag[i] >> 5) | (flag[i] << 3) & 255
最终解题脚本如下:
flag = [204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175] for i in range(42):
flag[i] = (flag[i] >> 5) | (flag[i] << 3) & 255 str_flag = ''
for i in flag:
str_flag += chr(i)
print(str_flag)
得到flag:flag{ddbae889-2895-44df-897d-2ae30df77b61}
参考链接:
死磕python字节码-手工还原python源码 - 知乎 (zhihu.com)
python 字节码死磕 - 大步向前blue - 博客园 (cnblogs.com)
从一道CTF题学习python字节码到源码逆向的更多相关文章
- 很值得学习的java 画图板源码
很值得学习的java 画图板源码下载地址:http://download.csdn.net/source/2371150 package minidrawpad; import java.awt.*; ...
- Python逆向(四)—— Python内置模块dis.py源码详解
一.前言 上一节我们对Python编译及反汇编做了讲解,大家知道dis模块可以将编译好的pyc文件中提取出来的PyCodeObject反汇编为可以阅读字节码形式.本节我们对dis模块中的源码进行详细的 ...
- iOS学习——布局利器Masonry框架源码深度剖析
iOS开发过程中很大一部分内容就是界面布局和跳转,iOS的布局方式也经历了 显式坐标定位方式 --> autoresizingMask --> iOS 6.0推出的自动布局(Auto La ...
- python重试库retryiny源码剖析
上篇博文介绍了常见需要进行请求重试的场景,本篇博文试着剖析有名的python第三方库retrying源码. 在剖析其源码之前,有必要讲一下retrying的用法,方便理解. 安装: pip insta ...
- django python mange.py runserver 源码
django python mange.py runserver 源码 入 口 mange.py文件 execute_from_command_line函数 输入参数为['manage.py', 'r ...
- Spring学习之——手写Spring源码V2.0(实现IOC、D、MVC、AOP)
前言 在上一篇<Spring学习之——手写Spring源码(V1.0)>中,我实现了一个Mini版本的Spring框架,在这几天,博主又看了不少关于Spring源码解析的视频,受益匪浅,也 ...
- 3-51单片机WIFI学习(开发板8266底层源码介绍)
上一篇链接 http://www.cnblogs.com/yangfengwu/p/8743502.html 直接上源码:注意源码有两部分,第一部分是一开始的时候写在模块内部的,另一部分是存在手机内 ...
- android源码-安卓源码-Android源码下载-安卓游戏源码
android源码 高仿精仿金山手机卫士应用源码V1.2 高仿精仿金山手机卫士应用源码,该应用的级别实现了金山卫士的级别功能了,可以说跟现实中我们使用的金山卫士应用的功能几乎差不 人气:9286 ...
- Flink源码分析 - 源码构建
原文地址:https://mp.weixin.qq.com/s?__biz=MzU2Njg5Nzk0NQ==&mid=2247483692&idx=1&sn=18cddc1ee ...
- Elasticsearch源码分析 - 源码构建
原文地址:https://mp.weixin.qq.com/s?__biz=MzU2Njg5Nzk0NQ==&mid=2247483694&idx=1&sn=bd03afe5a ...
随机推荐
- Java Style的C++容器流式处理类
很久没有上博客园了,最近一段时间,因为工作的关系时间上比较闲,利用闲暇时间重新翻了一下丢弃很久的C++语言.C++从98.11.14.17目前已经也走到了20版本,发生了很多变化,也引入了很多新的语言 ...
- 2022牛客OI赛前集训营-提高组(第一场) 奇怪的函数 根号很好用
奇怪的函数 考虑暴力,每次查询\(O(n)\)扫所有操作,修改\(O(1)\) 这启发我们平衡复杂度,考虑分块. 观察题目性质,可以发现,经过若干次操作后得到的结果一定是一个关于\(x\)的分段函数, ...
- Stanford CoreNLP无法生成实例对象
在服务器上运行Stanford,今日无法启动"StanfordCoreNLP"了,就是运行下面代码一直在运行,不结束,不报错. from stanfordcorenlp impor ...
- 在vue页面引入echarts,图表的数据来自数据库 springboot+mybatis+vue+elementui+echarts实现图表的制作
文章目录 1.实现的效果 2.前端代码 3.后端controller代码 4.servie层代码 5.serviceImpl层代码 6.mapper层代码 7.xml中的sql语句 8.遇到的问题 8 ...
- vue2 解决跨域
vue2.x 解决跨域 通过devServer将接口代理到本地在开发的时候,需要请求同局域网内的接口,发现直接使用http://对方的ip地址/接口路径,会出现类似下图的跨域报错 找到并打开vue.c ...
- Microsoft Office for Mac最新版本安装教程,亲测可用!!!
办公必备的Office工具,它为需要使用 Office 工具的用户和企业设计,让他们可以利用功能强大的 Outlook 来处理电子邮件.日历和通讯录事宜.你所熟知和信赖的 Office 经过更新后,可 ...
- 图文详解丨iOS App上架全流程及审核避坑指南
App Store作为苹果官方的应用商店,审核严格周期长一直让用户头疼不已,很多app都"死"在了审核这一关,那我们就要放弃iOS用户了吗?当然不是!本期我们从iOS app上架流 ...
- 【Java复健指南09】项目练习全解--房屋出租系统
一个基于文本界面的综合练习,主要用于串联和回忆知识点,比较简单 各个界面的设计样式 主菜单 =============房屋出租系统菜单============ 1 新 增 房 源 2 查 找 房 屋 ...
- Oracle数据库的导出和导入
本次数据库的导入导出操作是导出公司环境的Oracle数据库,再导入本地数据库,采用impdp和expdp命令进行导入导出操作. 一.导出52数据库 1.用system用户登录到数据库,查看是否有创建d ...
- 嵌入式学习-c语言篇01:搭建C语言环境
使用NotePad++和gcc编译器来搭建c语言环境 NotePad++:C语言编码器 gcc:C语言编译器 这两个软甲可以去官网下载 下载好进入该文件夹,如图: 添加环境变量:直接cmd,运行gcc ...