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!}
如图