【攻防世界】bad_python
收获
熟悉 python 逆向中反编译工具 uncompyle6 的使用方法
了解 .pyc 文件头的结构
通过自己手动生成对应 python 版本的 .pyc 文件来修复文件头
思路
解压得到一个 .pyc 的 Python 反编译文件
用本机 uncompyle6 反编译失败,提示 KeyError: ‘3.10.4’,本机用的 Python 版本是 3.10.4,应该是 Python 版本不对
根据文件名“pyre.cpython-36.pyc”,应该是提示该文件由 python 3.6 编译而来
拖到 win10 虚拟机,安装 Python 3.6.0
用虚拟机的 uncompyle6 反编译:pip install uncompyle6
编译失败,提示:
assert iscode(co), f"""{co} does not smell like code"""
AssertionError: None does not smell like code
用记事本打开,内容是乱码,用 exeinfo pe 查看,发现并未识别成 .pyc 文件
用 WinHex 查看文件头很奇怪,应该是文件头被修改
按照网上给的 pyc 文件头:03 F3 0D 0A,修改之后发现没什么用
pyc 文件头占文件最开始的 16字节,只需修改第一行即可
并且 pyc 文件头好像并不固定,比如文件头包含:python 的版本、文件修改时间等信息
尝试自己生成一个由 python 3.6.0 版本编译的 .pyc 文件,再将正常的文件头拷过来,恢复损坏的文件
随意创建一个 python 文件,使用 python -m py_compile C:\Users\wyy\Desktop\My_test.py
生成 .pyc
成功后,会在 .py 文件夹下生成一个 __pycache__
文件夹
查看自己生成的 pyc 文件的文件头,正常
用正常的文件头数据替换掉损坏文件的第一行,再次编译,编译成功
将代码复制出来:
from ctypes import *
from Crypto.Util.number import bytes_to_long
from Crypto.Util.number import long_to_bytes
def encrypt(v, k):
v0 = c_uint32(v[0])
v1 = c_uint32(v[1])
sum1 = c_uint32(0)
delta = 195935983
for i in range(32):
v0.value += (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[(sum1.value & 3)]
sum1.value += delta
v1.value += (v0.value << 4 ^ v0.value >> 7) + v0.value ^ sum1.value + k[(sum1.value >> 9 & 3)]
return (
v0.value, v1.value)
if __name__ == '__main__':
flag = input('please input your flag:')
k = [255, 187, 51, 68]
if len(flag) != 32:
print('wrong!')
exit(-1)
a = []
for i in range(0, 32, 8):
v1 = bytes_to_long(bytes(flag[i:i + 4], 'ascii'))
v2 = bytes_to_long(bytes(flag[i + 4:i + 8], 'ascii'))
a += encrypt([v1, v2], k)
enc = [
4006073346, 2582197823, 2235293281, 558171287, 2425328816, 1715140098, 986348143, 1948615354]
for i in range(8):
if enc[i] != a[i]:
print('wrong!')
exit(-1)
print('flag is flag{%s}' % flag)
逻辑就是将 flag 每 4 字节进行 bytes_to_long()
的转换
然后每相邻的两个 4 字节的 bytes_to_long()
结果为一组进行加密处理
加密过程比较类似于 tea 算法,对循环过程进行逆向解密即可
脚本
from ctypes import *
from Crypto.Util.number import bytes_to_long
from Crypto.Util.number import long_to_bytes
def decrypt(v, k):
v0 = c_uint32(v[0])
v1 = c_uint32(v[1])
sum1 = c_uint32(0)
delta = 195935983
sum1.value = delta * 32
for i in range(32):
v1.value -= (v0.value << 4 ^ v0.value >> 7) + v0.value ^ sum1.value + k[(sum1.value >> 9 & 3)]
sum1.value -= delta
v0.value -= (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[(sum1.value & 3)]
return v0.value, v1.value
enc = [4006073346, 2582197823,
2235293281, 558171287,
2425328816, 1715140098,
986348143, 1948615354]
k = [255, 187, 51, 68]
b = []
for i in range(0, 8, 2):
b += decrypt([enc[i], enc[i + 1]], k)
print(b)
# [1416114547, 1597076319, 1096762721, 1937334096, 2037671984, 1851744082, 863397202, 1936023344]
flag = b''
for i in range(0, 8):
v = long_to_bytes(b[i])
print(v, end=' ')
flag += v
print()
print(flag)
# b'Th1s_1s_A_Easy_Pyth0n__R3veRse_0'
结果
Th1s_1s_A_Easy_Pyth0n__R3veRse_0