首页 > 编程语言 >从一道CTF题学习python字节码到源码逆向

从一道CTF题学习python字节码到源码逆向

时间:2022-12-25 18:11:56浏览次数:60  
标签:LOAD 39 CONST 140 python 码到 flag 源码 165

概述:

该题来源为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)

标签:LOAD,39,CONST,140,python,码到,flag,源码,165
From: https://www.cnblogs.com/nLesxw/p/python_bytecode.html

相关文章

  • python中pandas操作excel数据
    python自动化办公领域,pandas处理excel表格非常优秀,今天初次使用pandas,测试一下。#coding:utf-8importpandasaspdfile_path=r"G:\41个设备.xlsx"data=pd.read_excel......
  • 推荐-centos7安装高版本python3.10
    前言如果在centos7上编译安装python3.7以上版本,ssl功能会出问题,因为python3.7以后需要更高版本的openssl支持,这样的话,就需要提前编译安装高版本的openssl,比如1.1.1系列,这......
  • 不用描述符,不算懂 Python
    在日常的编码中,我们应该使用Python的描述符,来使代码更具有单一职责原则,也就是SRP(SingleResponsibilityPrinciple)原则,如果你还没有用过描述符,那快来看看怎么用吧,不然就......
  • Python学习笔记--SQL数据
    SQL本人受到Java的影响,数据库的话,就不按照教程走了,我就直接使用的是Navicat软件的数据库啦!SQL支持注释:两种单行注释(--和#),和一种多行注释(/**/)基础的使用语法:使......
  • python中socket使用UDP协议简单实现服务端与客户端通信
    UDP为不可靠传输,也就是发送方不关心对方是否收到消息,一般用于聊天软件。但现在的聊天软件虽然使用的是UDP协议,但已从代码层面上解决了丢失信息的问题。下面使用python代码......
  • Python中使用zip函数的七重境界
    1.引言Python中有一些内置函数,可以使我们的代码非常优雅。​​zip​​函数就是其中之一,但是zip函数的使用对于初学者来说不是很直观,有时容易出错。因此本文将从7个层次来......
  • 【pygame游戏】用Python实现一个蔡徐坤大战篮球的小游戏,可还行?【附源码】
    准备工作开发环境Python版本:3.7.8相关模块:requests模块;tqdm模块;pyfreeproxy模块;pyechats模块;以及一些python自带的模块。效果预览开始界面 游戏规则wasd控制人物......
  • python之路55 cookie与session 操作 把模块变成字符串进行导入
    django中间件三个了解的方法1.process_view 路由匹配成功之后执行视图函数/类之前自动触发(顺序同process_request)2.process_exception 视图函数/类执行报错自动触发(......
  • python-数据库
    python使用内置SQLite3模块,支持SQLite3数据库的访问和相关的数据库操作。python3操作SQLite3数据库的基本流程如下:1)导入相关库或模块(SQLite3)2)使用connect()连接数据库并......
  • 基于OpenVINO的端到端DL网络-Tesseract5+VS2017+win10源码编译攻略
    一,记录我目前在win10X64和VS2017的环境下成功编译Tesseract5.0的方式;二,记录在VS2017C++工程中调用Tesseract4.0的方法;三,记录编译和调用Tesseract4.0过程中踩到的坑和相......