buu-[GWCTF 2019]pyre题解
前置知识点
是什么
和java类似python也是一门半解释半执行的语言,.py后缀的python源码可以理解为全解释的解释型代码,而python编译器可以将.py后缀的代码(也就是日常所说的python代码)编译成字节码,然后再执行代码内容。也就是说转换为字节码是每次运行py文件必不可少的步骤,因此,如果直接运行字节码无疑会提高编译运行速度,在python中的.pyc就是保存字节码的文件。
- .py文件:直接写的python代码
- .pyc文件:python代码转换为字节码后的文件
怎么做
而对于逆向而言,使用一个库就可以进行对pyc代码的逆向了,经过学习,选择uncompyle进行逆向,使用pip或conda指令安装皆可。注意:uncompyle库是跨版本的,因此python2和3的使用没有差异,python2.7使用的是uncompyle2,python3.x使用的是uncompyle6,指令安装会自带安装对应版本。常用指令如下
- 以python3举例对应
uncompyle6 安装
pip install uncompyle- liunx下
git clone https://github.com/rocky/python-uncompyle6然后进入下载的目录python setup.py install - conda镜像库暂时没有
uncompyle所以conda install不行
反编译(忘了指令也可以
uncompyle6 --help)uncompyle6 原文件路径.pyc > 保存的文件路径.py
指令记忆
- compyle:v.编译,其中含有com-聚集-编译成字节码所以更集成,-py- python专属,-le 编译了速度快了乐了,com-py-le
- un-:反,un-compyle,反编译
正式解题
得到反编译代码
使用uncompyle6 原文件路径.pyc > 保存的文件路径.py得到反编译代码(手动加了注释)
关于
\x \u是什么参考:https://blog.csdn.net/huangjin0507/article/details/79863057
总结就是
\u是一种编码格式,转换的话就使用 字符串的成员方法decode()\u \d \o分别是十六 十 八进制,转换的话使用字符转换,可参考 一道进制转换题解
# uncompyle6 version 3.7.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: encode.py
# Compiled at: 2019-08-19 21:01:57
print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):
num = ((input1[i] + i) % 128 + 128) % 128
code += num
for i in range(l - 1):
code[i] = code[i] ^ code[(i + 1)]
print code
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
# okay decompiling attachment.pyc*解读加密过程(位运算)
解读关键的两部分加密过程:
code的l-1位置不会被修改,而且正向过程中赋值code[i]时不修改code[i+1],且要保证code[i+1]是原始值- 然后根据运算规则逆向一下式子:
异或:Z ^ Q
- 满足交换律和结合律
- a^a = 0
- a^0 = a
- 同理 a^a^b = b
- 因此
code[i] = code[i] ^ code[(i + 1)]正向运行结果 - 逆向的
code[i] = code[i] ^ code[(i + 1)]等价于code[i] = code[i] ^ code[(i + 1)] ^ code[(i + 1)] - 即
code[i] = code[i]。因此,只要倒着枚举,使用code[i] = code[i] ^ code[(i + 1)]就可以算出每一个code[i]了原来的值了(请使用代码思维理解,此处难理解)
for i in range(l - 1):
code[i] = code[i] ^ code[(i + 1)]- 根据模运算规则简化一下式子(需要用到同余的知识不赘述了参考:https://blog.csdn.net/weixin_43207025/article/details/90609975)
for i in range(l):
num = ((input1[i] + i) % 128 + 128) % 128
code += num逆向反加密代码
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
flag = ''
for i in range(len(code)-2, -1, -1):
code[i]=chr(ord(code[i])^ord(code[i+1]))
for i in range(len(code)):
flag+=chr((ord(code[i])-i)%128)
print(flag)运行得到结果GWHT{Just_Re_1s_Ha66y!}如图

