资讯专栏INFORMATION COLUMN

将 exe 文件反编译成 Python 脚本

xbynet / 1174人阅读

摘要:打包成单文件所使用的命令为打包成文件夹所使用的命令为不管是哪种打包方式都会留下一个文件。这样我们只需将脚本文件和脚本文件放置到同一文件夹下,运行我们的脚本。可以看到已经完美的反编译出其中的脚本好了,相信大家已经明白了反编译的原理。

近期阅读了一篇很感兴趣的文章,为免后续文章被删无法再阅读,现自己写一下哈~

原文章:爆强!将 exe 文件反编译成 Python 脚本!

这篇文章跟自己的另一篇文章,正好形成技术上的互逆过程,也同时欢迎阅读指正

python代码文件封装为可执行exe文件_py_IA&IM的博客-CSDN博客1.安装依赖库pip install pywin32pipinstall pyinstaller(安装失败可换为:pipinstall pyinstaller --no-use-pep517)或可通过python第三方库网站下载后安装。验证pyinstaller安装成功:2.python文件生成可执行exe文件windows+R键 -> cmd -> 控制台界面切入python文件所在的目录执行命令:pyinstaller -F python文件名.py,生成..https://blog.csdn.net/qq_40794377/article/details/108425780

————————————————————————————————————————————————————————————

最近遇到了一个问题,自己打包好的exe文件还在,但是Python源文件不知什么时候被误删了。现在想改动一下功能,重写Python脚本工程量也太大了,怎么办?

今天我将教大家如何反编译exe文件,即将自己或别人写好的exe,还原成Python源码。

以最近写Python一键自动整理归类文件为例进行演示,运行所需的代码和文件都会在文末提供给大家。

打包成单文件所使用的命令为:

pyinstaller -Fw --icon=h.ico auto_organize_gui.py --add-data="h.ico;/"

打包成文件夹所使用的命令为:

pyinstaller -w --icon=h.ico auto_organize_gui.py --add-data="h.ico;."

不管是哪种打包方式都会留下一个exe文件。

首先我们需要从exe文件中抽取出其中的pyc文件:

抽取exe中的pyc文件

抽取pyinstaller打包的exe中的pyc文件,提取pyc文件有两种方法:

  1. 通过 pyinstxtractor.py 脚本提取pyc文件

  2. 通过 pyi-archive_viewer 工具提取pyc文件

脚本提取pyc文件

pyinstxtractor.py 脚本可以在github项目 python-exe-unpacker 中下载,地址:

https://github.com/countercept/Python-exe-unpacker

下载该项目后把其中的pyinstxtractor.py脚本文件复制到与exe同级的目录。

然后进入exe所在目录的cmd执行:

Python pyinstxtractor.py auto_organize_gui.exe

执行后便得到exe文件名加上_extracted后缀的文件夹:

对两种打包方式产生的exe提取出的文件结构稍有区别:

工具提取pyc文件

pyi-archive_viewer是PyInstaller自己提供的工具,它可以直接提取打包结果exe中的pyc文件。

详细介绍可参考官方文档:ttps://pyinstaller.readthedocs.io/en/stable/advanced-topics.html#using-pyi-archive-viewer

执行pyi-archive_viewer [filename]即可查看 exe 内部的文件结构:

pyi-archive_viewer auto_organize.exe

操作命令:

U: go Up one levelO : open embedded archive nameX : extract nameQ: quit

然后可以提取出指定需要提取的文件:

要提取其他被导入的pyc文件,则需要先打开PYZ-00.pyz

很显然,使用PyInstaller的pyi-archive_viewer 工具操作起来比较麻烦,一次只能提取一个文件,遇到子模块还需执行一次打开操作。

所以后面我也只使用pyinstxtractor.py 脚本来提取pyc文件。

反编译pyc文件为py脚本

有很多对pyc文件进行解密的网站,例如:

  • https://tool.lu/pyc/

不过我们直接使用 uncompyle6 库进行解码,使用pip可以直接安装:

pip install uncompyle6

uncompyle6可以反编译.pyc后缀结尾的文件,两种命令形式:

  1. uncompyle6 xxx.pyc>xxx.py

  2. uncompyle6 -o xxx.py xxx.pyc

以前面编码过程中生成的缓存为例进行演示:

uncompyle6 auto_organize.cpython-37.pyc>auto_organize.py

执行后便直接将.pyc文件反编译成Python脚本了:

从编译结果看注释也被保留了下来:

对于不是pyc后缀结尾的文件,使用uncompyle6反编译时会报出 must point to a Python source that can be compiled, or Python bytecode (.pyc, .pyo) 的错误。

所以我们需要先对提取出的内容人工修改后缀:

运行入口pyc文件反编译

对于从pyinstaller提取出来的pyc文件并不能直接反编译,入口运行类共16字节的 magic 和 时间戳被去掉了。

如果直接进行反编译,例如执行 uncompyle6 auto_organize_gui.exe_extracted/auto_organize_gui.pyc

会报出如下错误:ImportError: Unknown magic number 227 in auto_organize_gui.exe_extracted/auto_organize_gui.pyc

使用支持16进制编辑的文本编辑器查看一探究竟,这里我使用UltraEdit32

分别打开正常情况下编译出的pyc和从pyinstaller提取出来的pyc文件进行对比:

可以看到前16个字节都被去掉了,其中前四个字节是magic,这四个字节会随着系统和Python版本发生变化,必须一致。后四个字节包括时间戳和一些其他的信息,都可以随意填写。

我们先通过UltraEdit32向pyinstaller提取的文件添加头信息:

选择开头插入16个字节后,只需要替换前4个字节为当前环境下的magic:

然后执行:

uncompyle6 auto_organize_gui.exe_extracted/auto_organize_gui.pyc>auto_organize_gui.py

执行后可以看到文件已经顺利的被反编译:

依赖性pyc文件反编译

考虑再反编译导入的其他依赖文件:

先用UltraEdit32打开查看一下:

可以看到对于非入口运行的pyc文件是从12字节开始缺4个字节。

这里我们选择第13个字节再插入四个字节即可:

然后再执行:

uncompyle6 auto_organize_gui.exe_extracted/PYZ-00.pyz_extracted/auto_organize.pyc > auto_organize.py

然后成功的反编译出依赖的文件:

代码与原文件几乎完全一致:

批量反编译

如果一个exe需要被反编译的Python脚本只有3个以内的文件,我们都完全可以人工来操作。

但是假如一个exe涉及几十个甚至上百个Python脚本需要反编译的时候,人工操作未免工作量过于巨大,我们考虑将以上过程用Python实现,从而达到批量反编译的效果。

提取exe中的pyc

import osimport sysimport pyinstxtractorexe_file = r"D:/PycharmProjects/gui_project/dist/auto_organize_gui.exe"sys.argv = ["pyinstxtractor", exe_file]pyinstxtractor.main()# 恢复当前目录位置os.chdir("..")
[*] Processing D:/PycharmProjects/gui_project/dist/auto_organize_gui.exe[*] Pyinstaller version: 2.1+[*] Python version: 37[*] Length of package: 9491710 bytes[*] Found 984 files in CArchive[*] Beginning extraction...please standby[*] Found 157 files in PYZ archive[*] Successfully extracted pyinstaller archive: D:/PycharmProjects/gui_project/dist/auto_organize_gui.exeYou can now use a Python decompiler on the pyc files within the extracted directory

预处理pyc文件修护校验头

def find_main(pyc_dir):    for pyc_file in os.listdir(pyc_dir):        if not pyc_file.startswith("pyi-") and pyc_file.endswith("manifest"):            main_file = pyc_file.replace(".exe.manifest", "")            result = f"{pyc_dir}/{main_file}"            if os.path.exists(result):                return main_filepyc_dir = os.path.basename(exe_file)+"_extracted"main_file = find_main(pyc_dir)main_file

读取从pyz目录抽取的pyc文件的前4个字节作基准:

pyz_dir = f"{pyc_dir}/PYZ-00.pyz_extracted"for pyc_file in os.listdir(pyz_dir):    if pyc_file.endswith(".pyc"):        file = f"{pyz_dir}/{pyc_file}"        breakwith open(file, "rb") as f:    head = f.read(4)list(map(hex, head))
["0x42", "0xd", "0xd", "0xa"]

校准入口类:

import shutilif os.path.exists("pycfile_tmp"):    shutil.rmtree("pycfile_tmp")os.mkdir("pycfile_tmp")main_file_result = f"pycfile_tmp/{main_file}.pyc"with open(f"{pyc_dir}/{main_file}", "rb") as read, open(main_file_result, "wb") as write:    write.write(head)    write.write(b"/0"*12)    write.write(read.read())

校准子类:

pyz_dir = f"{pyc_dir}/PYZ-00.pyz_extracted"for pyc_file in os.listdir(pyz_dir):    pyc_file_src = f"{pyz_dir}/{pyc_file}"    pyc_file_dest = f"pycfile_tmp/{pyc_file}"    print(pyc_file_src, pyc_file_dest)    with open(pyc_file_src, "rb") as read, open(pyc_file_dest, "wb") as write:        write.write(read.read(12))        write.write(b"/0"*4)        write.write(read.read())

开始反编译

from uncompyle6.bin import uncompileif not os.path.exists("py_result"):    os.mkdir("py_result")for pyc_file in os.listdir("pycfile_tmp"):    sys.argv = ["uncompyle6", "-o",                f"py_result/{pyc_file[:-1]}", f"pycfile_tmp/{pyc_file}"]    uncompile.main_bin()

完整代码下载见文末。

这样我们只需将Python脚本、exe文件和pyinstxtractor.py脚本文件 放置到同一文件夹下,运行我们的Python脚本。即可反编译exe。

可以看到已经完美的反编译出exe其中的Python脚本:

好了,相信大家已经明白了反编译的原理。那么既然是攻防,如何防止自己打包的exe被反编译呢?

如何防止exe被反编译呢

只需在打包命令后面加上--key命令即可,例如文章开头的命令可以更换为:

pyinstaller -Fw --icon=h.ico auto_organize_gui.py --add-data="h.ico;/" --key 123456

123456是你用来加密的密钥,可以随意更换。

该加密参数依赖tinyaes,可以通过以下命令安装:

pip install tinyaes

打包后再次执行反编译:

exe_file = r"D:/PycharmProjects/gui_project/dist/auto_organize_gui.exe"uncompyle_exe(exe_file, True)

结果只有入口脚本反编译成功,被依赖的脚本均被加密,无法直接被反编译:

可以看到抽取的中间结果变成了.pyc.encrypted格式,无法直接被反编译:

可以看到,常规手段就无法直接反编译了。

这个时候还想反编译就需要底层的逆向分析研究了,或者pyinstaller的源码完整研究一遍,了解其加密处理的机制,看看有没有破解的可能。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/122199.html

相关文章

  • 全网首份Python打包工具Pyinstaller实战指南,如丝滑般体验

    摘要:最好是客户双击,完事儿。目前已经兼容,以及和。一共会有个对象,分别是。,就是我们的工作目录,存放我们的数据。编译打包最后,我们执行就好了。打包的可执行文件会在里,中是一些打包时候需要的文件。输出中最后有字样,就算成功了。 showImg(https://img-blog.csdnimg.cn/20190303211533768.png?x-oss-process=image/water...

    caikeal 评论0 收藏0
  • 4 个快速的 Python 编译器 for 2018

    摘要:但是由于程序并没有那么快,开发人员多年来创建了几个的编译器,包括和。在下面的细分中,所有的编译器都针对进行基准测试。编译器是系列的一部分,旨在作为的现代替代品。不仅仅是的编译器,它是的超集,支持与的互操作性。 简评:Python 和其他的解释型语言一样经常被吐槽性能不行,所以开发人员为了提升性能创建了不少编译器,本文则选取其中的四个做了基准测试。 Python 其实是一种相当快的语言,...

    YancyYe 评论0 收藏0
  • cxfreeze打包python,飞一般的感觉

    摘要:总所周知,因库多,语法优雅,深受开发者的喜爱。于我来说,写一些小型程序,在不需要考虑太多问题的时候,无疑是我的第一选择。当一切都配置好后,使用打包相应脚本有两种方法。 总所周知,python因库多,语法优雅,深受开发者的喜爱。 于我来说,写一些小型程序,在不需要考虑太多问题的时候,python无疑是我的第一选择。而有的时候,虽然是小型程序,但我还是需要他们通用,即使不考虑使他跨平台...

    hellowoody 评论0 收藏0
  • 教你如何一键编译获取任何微信小程序源代码(图形化界面,傻瓜式操作)

    摘要:很想一窥源码,查看究竟,看看大厂的前端大神们是如何规避了小程序的各种奇葩的坑。头发减减可是问题是呐好看的小程序,又获得不到源代码。所以啊,才能容易的反编译出来,如果是那就很难了一键获取微信小程序源代码   1 Tips: 2   一键获取微信小程序源码, 使用了C#加nodejs制作 直接解压在D盘根目录下后就可以使用 将小程序文件放到 wxapkg目录下3 这个目录下有一些demo...

    RyanQ 评论0 收藏0

发表评论

0条评论

xbynet

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<