最近整理网盘时发现了三年前尝试用Python写的玩具编程语言。想看下当年的"黑历史"代码,但是他被我拿pyinstaller进行了打包于是对他进行了反编译
逆向工具准备
pyinstxtractor
PyInstaller的反编译工具,能将打包的exe还原成pyc
pycdc
支持Python 3.10的高版本反编译器(注:3.9以下推荐使用uncompyle6)
环境准备
- Python 3.10(需与打包环境版本一致)
- C++编译环境
完整逆向流程
第一步:提取exe中的pyc文件
# 下载提取工具
curl -L https://github.com/extremecoders-re/pyinstxtractor/raw/master/pyinstxtractor.py -o pyinstxtractor.py
# 执行提取(注意使用打包时的Python版本!)
python3.10 pyinstxtractor.py ipili.exe
提取成功后会出现ipili.exe_extracted目录,其中:
PYZ-00.pyz_extracted存放依赖库
主脚本通常是打包前的文件名(如main.pyc)
查找技巧:
- 按文件大小排序,主脚本通常>10KB
- 查看
struct文件中的入口路径 - 用文本编辑器打开疑似文件,搜索
__main__等特征
第二步:编译pycdc反编译器
# 安装编译依赖
sudo apt install build-essential cmake clang # Ubuntu/Debian
brew install cmake llvm # MacOS
# 编译过程
git clone --recursive https://github.com/zrax/pycdc.git
cd pycdc
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j8
编译完成后得到:
pycdc:字节码→Python源码pycdas:字节码反汇编器
第三步:执行反编译
# 转换主文件
./pycdc ../ipili.exe_extracted/main.pyc > recovered_main.py
# 处理依赖库
for f in PYZ-00.pyz_extracted/*.pyc; do
./pycdc $f > ../recovered_$(basename $f).py
done
踩坑记录
代码段缺失问题
尚未解决
经验总结
- 版本对应原则:打包与反编译环境需严格一致
- 持续归档:现在代码已经玩上异地备份了,具体的后面可能会写篇文章
逆向成果
写的太烂了,推荐别看
# main.py
import random as ran
import tool
print('an interpretive programming language based on Python 1.0 (64bit) Can run with Windows system.')
def codech(command):
names = []
datas = []
if len(command) == 0:
print('未输入命令')
return None
if None in command:
print(tool.khcl(command))
return None
if None in command:
exit()
return None
if None in command:
we = tool.khcl(command)
input(we)
return None
if None in command:
if_text = command.split(' ')
if_bl1 = if_text[1]
if_bl2 = if_text[3]
if_tj = if_text[2]
if if_tj == '==':
if if_bl1 == if_bl2:
print('true')
return None
if None != if_bl2:
print('false')
return None
return None
if None == '!=':
if if_bl1 != if_bl2:
print('true')
return None
if None == if_bl2:
print('false')
return None
return None
if None == '<':
if if_bl1 < if_bl2:
print('true')
return None
if None > if_bl2:
print('false')
return None
return None
if None == '>':
if if_bl1 > if_bl2:
print('true')
return None
if None < if_bl2:
print('false')
return None
None('运算符错误')
return None
return None
if None in command:
lang = tool.khcl(command)
main(lang)
return None
if None in command:
var_qwe = tool.khcl(command)
var_name_and_data = var_qwe.split(',')
var_name = var_name_and_data[0]
var_data = var_name_and_data[1]
names.append(var_name)
datas.append(var_data)
return None
if None in command:
tool.main(command)
return None
if None in command:
var_qqwe = tool.khcl(command)
var_qname_and_data = var_qqwe.split(',')
var_qname = int(var_qname_and_data[0])
var_qdata = int(var_qname_and_data[1])
stop = ran.randint(var_qname, var_qdata)
print(stop)
return None
# WARNING: Decompyle incomplete
def codeus(command):
names = []
datas = []
if len(command) == 0:
print('未输入命令')
return None
if None in command:
print(tool.khcl(command))
return None
if None in command:
exit()
return None
if None in command:
we = tool.khcl(command)
input(we)
return None
if None in command:
if_text = command.split('')
if_bl1 = if_text[1]
if_bl2 = if_text[3]
if_tj = if_text[2]
if if_tj == '==':
if if_bl1 == if_bl2:
print('true')
return None
if None != if_bl2:
print('false')
return None
return None
if None == '!=':
if if_bl1 != if_bl2:
print('true')
return None
if None == if_bl2:
print('false')
return None
return None
if None == '<':
if if_bl1 < if_bl2:
print('true')
return None
if None > if_bl2:
print('false')
return None
return None
if None == '>':
if if_bl1 > if_bl2:
print('true')
return None
if None < if_bl2:
print('false')
return None
None('Operator error')
return None
return None
if None in command:
lang = tool.khcl(command)
main(lang)
return None
if None in command:
var_qwe = tool.khcl(command)
var_name_and_data = var_qwe.split(',')
var_name = var_name_and_data[0]
var_data = var_name_and_data[1]
names.append(var_name)
datas.append(var_data)
return None
if None in command:
var_qqwe = tool.khcl(command)
var_qname_and_data = var_qqwe.split(',')
var_qname = int(var_qname_and_data[0])
var_qdata = int(var_qname_and_data[1])
stop = ran.randint(var_qname, var_qdata)
print(stop)
return None
if None in command:
css = tool.khcl(command)
cs1 = css[0]
file = open(cs1)
text = file.read()
print(text)
return None
if None in command:
csdata = command.split(' ')
csdata1 = csdata[1].split(',')
cs1 = int(csdata1[1])
i = 0
if i == cs1:
print(csdata1[0])
i = i + 1
if not i == cs1:
return None
return None
if None in command:
tool.main(command)
return None
None('Function call error')
return None
def main(langs):
if langs == 'zh-cn':
command = input('>>>')
codech(command)
continue
if langs == 'en-us':
command = input('>>>')
codeus(command)
continue
main('zh-cn')
#tool.py
import platform
import wgetss
def khcl(com):
text = str.split(com, '(')
text2 = text[1]
text3 = str.split(text2, ')')
return text3[0]
def download(com):
text = khcl(com)
text1 = str.split(text, ',')
url = text1[0]
date = text1[1]
wgetss.download(url, date)
def pycode(comm):
zhcode = khcl(comm)
print(zhcode)
if '(' in zhcode and ')' in zhcode:
exec(zhcode)
return None
None('未输入命令')
def main(code):
if 'osname' in code:
osname = platform.system()
print(osname)
return None
if None in code:
print(platform.processor())
return None
if None in code:
pycode(code)
return None
if None in code:
download(code)
return None
5433

被折叠的 条评论
为什么被折叠?



