python反编译
出题
https://www.nssctf.cn/problem/2038
参考链接:https://www.nssctf.cn/note/set/1517
背景
pyc⽂件格式
magic number + 源代码⽂件信息 + PyCodeObject
4 个字节的 magic number
12 个字节的源代码⽂件信息(不同版本的 Python 包含的⻓度和信息都不⼀样)
序列化之后的 PyCodeObject

Python 是⼀种解释型语⾔,它不像编译型语⾔那样将源代码直接编译成机器码执⾏。Python 的解释器
会在运⾏代码之前先将源代码编译成字节码,然后将字节码解释执⾏。pyc ⽂件就是这个过程中⽣成的
字节码⽂件。
当 Python 解释器⾸次执⾏⼀个 .py ⽂件时,它会在同⼀⽬录下⽣成⼀个对应的 pyc ⽂件,以便于下次
加载该⽂件时可以更快地执⾏。如果源⽂件在修改之后被重新加载,解释器会重新⽣成pyc ⽂件以更新
缓存的字节码
⼀般需要反编译的附件查壳都会有如下红⾊标志

工具
本地
uncompyle6 现仅适⽤于 Python 2.4 到 3.8 版本,3.8 及以上版本使⽤ pycdc ,3.8左右版本两者都可
以试试
uncompyle6安装要python版本对应(不能太⾼),我⽤anaconda创建虚拟环境
uncompyle: uncompyle6
⽂件名.pyc > ⽂件名.py
pycdc: ./pycdc.exe ⽂件名
https://github.com/extremecoders-re/decompyle-builds/releases/tag/build-14-Nov-2023-
5936412
下载地址如上
在线
贴两个⽐较好⽤的在线⽹站
https://www.toolkk.com/tools/pyc-decomplie#google_vignette
目标
1.exe⽂件变成pyc⽂件
⾸先,先将 pyinstxtractor.py ⼯具与我们要反编译的 .exe ⽂件放⼊同⼀个⼯作⽬录下:
在上述⽬录打开终端: python pyinstxtractor.py ⽂件名.exe
有些附件不清楚格式可以到kali下file命令查看或者⽤IDA打开发现如下字样,也暗示要反编译

说明版本是python3.7的

运⾏完成后,在此⽂件夹下我们会发现多了⼀个 ⽂件名.exe_extracted 的⽂件夹

⽬录⾥有两个没有后缀的⽂件,这就是反编译的重点
总体上还是找那些没有后缀的⽂件
为src⽂件添加.pyc的后缀,并⽤winhex打开src和struct⽂件

注意,直接将src添加.pyc后缀后所编译的py⽂件是缺少Magic Number的,所以我们要⽤struct⽂件的
⽂件头来修复src⽂件的⽂件头
由于src⽂件直接是以E3开头的,所以我们这⾥直接将struct⽂件E3前⾯的11字节复制到src⽂件的⽂件头
就可以了;如果不是直接以E3开头,就⽐较两个⽂件E3前⾯的字节,将src⽂件E3前⾯的字节改为struct
⽂件E3前⾯的字节即可(这⾥只是针对这道题,其他题⽂件头通常都不⼀样)
2.pyc⽂件变成py⽂件
开启虚拟环境: uncompyle6 ⽂件名.pyc > ⽂件名.py
前提python版本要⼀样
magic修复
适合已知python版本的题⽬
放到winhex⾥可以发现E3前⾯全是0,正常的pyc⽂件E3前⾯包含Magic Number和时间戳
1.Python3.3以下的版本中,只有Magic Number和四位时间戳
2.Python3.3到Python3.7(不包含3.7)版本中,只有Magic Number和⼋位时间戳 + ⼤⼩信息
3.Python3.7及以上版本的编译后⼆进制⽂件中,头部除了四字节Magic Number,还有四个字节的空位
和⼋个字节的时间戳 + ⼤⼩信息,时间戳填充0即可

pyc版本号参考
补全的时候是⼩端序,记得颠倒过来,只改前四个字节就可以,⽐如3.7版本先42再0A
这⾥抄⼀下⽹上的magic number
1 | |
可以看已有版本的magic number

import importlib
importlib.util.MAGIC_NUMBER.hex()
出题
⽣成pyc: python -m ⽂件名
即使有报错也能⽣成

如果是另外python版本可以⽤下⾯这种

⽣成exe: pyinstaller -F tmp.py

更新: 2024-05-09 20:56:20
原文: https://www.yuque.com/chaye-apqbl/vsc85q/svmmqlvdm0b8tzyu