最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解如何將Python可執(zhí)行文件(.exe)反編譯為Python腳本

 更新時間:2024年03月25日 15:03:43   作者:Lorin洛林  
將?Python?可執(zhí)行文件(.exe)反編譯為?Python?腳本是一項有趣的技術(shù)挑戰(zhàn),可以幫助我們理解程序的工作原理,下面我們就來看看具體實(shí)現(xiàn)步驟吧

前言

Python 可執(zhí)行文件(.exe)反編譯為 Python 腳本是一項有趣的技術(shù)挑戰(zhàn),可以幫助我們理解程序的工作原理,以及可能包含的邏輯和算法。雖然反編譯不是一項簡單的任務(wù),并且對于使用各種保護(hù)措施的程序可能無效,但對于一般情況下的 Python 可執(zhí)行文件,我們可以嘗試使用一些工具來進(jìn)行反編譯。

下面我們就來學(xué)習(xí)如何將 Python 可執(zhí)行文件(.exe)反編譯為 Python 腳本。

版本

Python 3.9

反編譯

反編譯是將已編譯的程序代碼還原為其原始源代碼的過程。在 Python 中,由于其解釋性質(zhì),通常沒有像編譯語言那樣生成的二進(jìn)制文件,但是我們可以將 Python 腳本轉(zhuǎn)換為字節(jié)碼文件(.pyc),而 .exe 文件通常是由 pyinstaller、cx_Freeze 等工具編譯生成的。

Python 可執(zhí)行文件(.exe)反編譯

Python 可執(zhí)行文件(.exe)反編譯為 Python 腳本主要分為兩個步驟,(1)從 .exe 文件中提取 pyc 文件 (2)將 pyc 文件轉(zhuǎn)換為 Python 腳本。

打包一個簡單的 .exe 可執(zhí)行文件

# student.py
class Student:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def get_name(self):
        return self.name

    def get_age(self):
        return self.age

    def get_gender(self):
        return self.gender

    def set_name(self, name):
        self.name = name

    def set_age(self, age):
        self.age = age

    def set_gender(self, gender):
        self.gender = gender

    def display_info(self):
        print("Name:", self.name)
        print("Age:", self.age)
        print("Gender:", self.gender)

# main.py
import time

from student import Student

if __name__ == "__main__":
    # Create a student object
    student1 = Student("Alice", 20, "Female")

    # Display student information
    student1.display_info()

    # Update student information
    student1.set_age(21)
    student1.display_info()

    time.sleep(10)

# 使用 pyinstaller 構(gòu)建可執(zhí)行 .exe
pyinstaller --onefile   -p venv/Lib/site-packages .\print-student\main.py

提取 pyc 文件

使用腳本提取

pyi-archive_viewerPyInstaller 自己提供的工具,它可以直接提取打包結(jié)果exe中的pyc文件。

詳細(xì)介紹可參考官方文檔:pyinstaller.readthedocs.io/en/stable/a…

# 使用 pyi-archive_viewer 查看文件并提取
> pyi-archive_viewer .\main.exe

Options in 'main.exe' (PKG/CArchive):
 pyi-contents-directory _internal
Contents of 'main.exe' (PKG/CArchive):
 position, length, uncompressed_length, is_compressed, typecode, name
 0, 199, 269, 1, 'm', 'struct'
 199, 2008, 3700, 1, 'm', 'pyimod01_archive'
 2207, 7671, 17413, 1, 'm', 'pyimod02_importers'
 9878, 1760, 4029, 1, 'm', 'pyimod03_ctypes'
 11638, 644, 1074, 1, 'm', 'pyimod04_pywin32'
 12282, 603, 851, 1, 's', 'pyiboot01_bootstrap'
 12885, 229, 295, 1, 's', 'main'
......
 4721057, 408332, 1123832, 1, 'b', 'unicodedata.pyd'
 5129389, 702999, 702999, 0, 'z', 'PYZ-00.pyz'
?
U: go up one level
O <name>: open embedded archive with given name // 打開包查看文件
X <name>: extract file with given name // 提取文件
S: list the contents of current archive again
Q: quit
? x main        
Output filename? main.pyc
? o PYZ-00.pyz
Contents of 'PYZ-00.pyz' (PYZ):
 is_package, position, length, name
 0, 17, 2647, '_compat_pickle'
......
 0, 543553, 531, 'student'
 0, 544084, 19733, 'subprocess'
 0, 563817, 27425, 'tarfile'
 0, 591242, 5936, 'textwrap'
 0, 597178, 15612, 'threading'
 0, 612790, 1398, 'token'
 0, 614188, 8969, 'tokenize'
 0, 623157, 6659, 'tracemalloc'
 0, 629816, 27711, 'typing'
 1, 657527, 70, 'urllib'
 0, 657597, 13861, 'urllib.parse'
 0, 671458, 2188, 'uu'
 0, 673646, 26812, 'zipfile'
? x student
Output filename? student.pyc
? ls
U: go up one level
O <name>: open embedded archive with given name
X <name>: extract file with given name
S: list the contents of current archive again
Q: quit
? q

在上面的操作中,我們使用 pyi-archive_viewer 提取了 main.pyc、和 student.pyc 文件,當(dāng)時大家可以很清楚的看到弊端,即需要一個一個手動提取,對于大項目這是十分麻煩的,推薦使用下面的工具提取。

使用工具提取

我們可以使用開源項目 Python-exe-unpacker 中的腳本 pyinstxtractor.py 腳本進(jìn)行提取,地址:github.com/countercept/Python-exe-unpacker

\print-student> Python pyinstxtractor.py .\main.exe                                            
DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
[*] Processing .\main.exe
[*] Pyinstaller version: 2.1+
[*] Python version: 309
[*] Length of package: 5835756 bytes
[*] Found 59 files in CArchive
[*] Beginning extraction...please standby
[*] Found 81 files in PYZ archive
[*] Successfully extracted pyinstaller archive: .\main.exe

You can now use a python decompiler on the pyc files within the extracted directory

將 .pyc 文件轉(zhuǎn)換為 Python 腳本

入口運(yùn)行類

對于從 pyinstaller 提取出來的 pyc 文件并不能直接反編譯,入口運(yùn)行類共16字節(jié)的 magic 和 時間戳被去掉了。如果直接進(jìn)行反編譯,例如執(zhí)行 uncompyle6 main.pyc,則會報出如下錯誤:

ImportError: Unknown magic number 227 in main.pyc

我們可以使用支持16進(jìn)制編輯的文本編輯器進(jìn)行處理,比如:UltraEdit32

可以看到前16個字節(jié)都被去掉了,其中前四個字節(jié)是magic,這四個字節(jié)會隨著系統(tǒng)和Python版本發(fā)生變化,需要保持一致。后四個字節(jié)包括時間戳和一些其他的信息,都可以隨意填寫。我們可以通過 UltraEdit32 向提取的文件添加回信息。

這里我寫了一個 python 腳本實(shí)現(xiàn)這個過程:

# 讀取從pyz目錄抽取的pyc文件的前4個字節(jié)作基準(zhǔn)
pyz_dir = "./main.exe_extracted/PYZ-00.pyz_extracted"
for pyc_file in os.listdir(pyz_dir):
    if pyc_file.endswith(".pyc"):
        file = f"{pyz_dir}/{pyc_file}"
        break
with open(file, "rb") as f:
    head = f.read(4)

# 補(bǔ)全入口類文件
if os.path.exists("pycfile_tmp"):
    shutil.rmtree("pycfile_tmp")
os.mkdir("pycfile_tmp")
main_file_result = "pycfile_tmp/main.pyc"
with open("./main.exe_extracted/main.pyc", "rb") as read, open(main_file_result, "wb") as write:
    write.write(head)
    write.write(b"\0" * 12)
    write.write(read.read())

非入口運(yùn)行類

對于非入口運(yùn)行的pyc文件從12字節(jié)開始缺4個字節(jié)。

# 補(bǔ)全非入口類文件
pyz_dir = "main.exe_extracted/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())

轉(zhuǎn)換補(bǔ)全后的 pyc 文件

uncompyle6 反編譯

pip install uncompyle6
uncompyle6 xxx.pyc>xxx.py

如:uncompyle6 .\pycfile_tmp\main.pyc
# uncompyle6 version 3.9.0
# Python bytecode version base 3.9.0 (3425)
# Decompiled from: Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)]
# Embedded file name: main.py

Unsupported Python version, 3.9.0, for decompilation


# Unsupported bytecode in file .\pycfile_tmp\main.pyc
# Unsupported Python version, 3.9.0, for decompilation

由于我使用的是 3.9.0 版本,uncompyle6 不再支持 decompilation,有興趣的朋友可以去試試。

在線工具

我們也可以使用一些在線工具進(jìn)行解密,比如:ctfever.uniiem.com/tools/pyc-decompiler

可能遇到的問題

PYZ-00.pyz_extracted 文件為空

構(gòu)建 .exe 文件 Python 版本和解壓包時使用的版本不一致,比如我使用 Python 2.7 進(jìn)行解包:

>Python .\pyinstxtractor.py .\main.exe

[*] Processing .\main.exe
[*] Pyinstaller version: 2.1+
[*] Python version: 312
[*] Length of package: 7675728 bytes
[*] Found 60 files in CArchive
[*] Beginning extraction...please standby
[!] Warning: The script is running in a different python version than the one used to build the executable
    Run this script in Python312 to prevent extraction errors(if any) during unmarshalling
[!] Unmarshalling FAILED. Cannot extract PYZ-00.pyz. Extracting remaining files.
[*] Successfully extracted pyinstaller archive: .\main.exe

You can now use a python decompiler on the pyc files within the extracted directory

# 查看解壓后的文件
\print-student\main.exe_extracted\PYZ-00.pyz_extracted> ls
\print-student\main.exe_extracted\PYZ-00.pyz_extracted>

如何防止exe被反編譯

我們可以在打包命令后面添加 --key 參數(shù)來進(jìn)行加密,例如:

 pyinstaller --onefile   -p venv/Lib/site-packages .\print-student\main.py --key '1234'

再次解壓,抽取的中間結(jié)果變?yōu)榱?.pyc.encrypted,無法正常反編譯。

思考

Bytecode encryption was removed in PyInstaller v6.0. Please remove your --key=xxx argument. For the rationale and alternatives see https://github.com/pyinstaller/pyinstaller/pull/6999

可以看到在 PyInstaller v6.0 加密參數(shù)已經(jīng)被廢棄,大家可以思考一下原因。

總結(jié)

反編譯 Python 可執(zhí)行文件可以幫助我們理解程序的工作原理和邏輯,但在實(shí)踐中可能會受到許多因素的限制。對于復(fù)雜的程序,反編譯可能只是了解其工作原理的第一步,可能需要進(jìn)一步的分析和研究。最后,我們需要明白技術(shù)沒有好壞,需要謹(jǐn)守道德和法律的底線。

到此這篇關(guān)于詳解如何將Python可執(zhí)行文件(.exe)反編譯為Python腳本的文章就介紹到這了,更多相關(guān)Python可執(zhí)行文件反編譯為腳本內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 在Python中使用AOP實(shí)現(xiàn)Redis緩存示例

    在Python中使用AOP實(shí)現(xiàn)Redis緩存示例

    本篇文章主要介紹了在Python中使用AOP實(shí)現(xiàn)Redis緩存示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • python迭代器的使用方法實(shí)例

    python迭代器的使用方法實(shí)例

    這篇文章主要介紹了python迭代器的使用方法,代碼很簡單,大家可以參考使用
    2013-11-11
  • Python/Numpy判斷數(shù)組是否相等問題

    Python/Numpy判斷數(shù)組是否相等問題

    文章介紹了如何使用Python/Numpy判斷兩個數(shù)組是否相等,包括使用`array1==array2`返回邏輯值,以及通過`.all()`和`.any()`方法判斷所有或任意元素相等
    2026-02-02
  • python引入不同文件夾下的自定義模塊方法

    python引入不同文件夾下的自定義模塊方法

    今天小編就為大家分享一篇python引入不同文件夾下的自定義模塊方法。具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • django多對多表的創(chuàng)建,級聯(lián)刪除及手動創(chuàng)建第三張表

    django多對多表的創(chuàng)建,級聯(lián)刪除及手動創(chuàng)建第三張表

    這篇文章主要介紹了django多對多表的創(chuàng)建,級聯(lián)刪除及手動創(chuàng)建第三張表,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • python通過偽裝頭部數(shù)據(jù)抵抗反爬蟲的實(shí)例

    python通過偽裝頭部數(shù)據(jù)抵抗反爬蟲的實(shí)例

    下面小編就為大家分享一篇python通過偽裝頭部數(shù)據(jù)抵抗反爬蟲的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • 利用Python字符畫生成甜心教主

    利用Python字符畫生成甜心教主

    字符畫是一系列字符的組合,我們可以把字符看作是比較大塊的像素,一個字符能表現(xiàn)一種顏色,字符的種類越多,可以表現(xiàn)的顏色也越多,圖片也會更有層次感。?本文將利用Python字符畫繪制一個甜心教主王心凌,需要的可以參考一下
    2022-05-05
  • 基于Python實(shí)現(xiàn)wifi連接小程序

    基于Python實(shí)現(xiàn)wifi連接小程序

    這篇文章主要為大家詳細(xì)介紹了如何使用Python編程語言編寫一個簡單的連接Wi-Fi的程序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • 解決Cron定時任務(wù)中Pytest腳本無法發(fā)送郵件的問題

    解決Cron定時任務(wù)中Pytest腳本無法發(fā)送郵件的問題

    文章探討解決在 Cron 定時任務(wù)中運(yùn)行 Pytest 腳本時郵件發(fā)送失敗的問題,先優(yōu)化環(huán)境變量,再檢查 Pytest 郵件配置,接著配置文件確保 SMTP 服務(wù)正常,包括編輯相關(guān)文件、配置認(rèn)證信息等,還提及常見問題排查,如防火墻等,最終使郵件功能在定時任務(wù)中成功運(yùn)行
    2025-01-01
  • 使用OpCode繞過Python沙箱的方法詳解

    使用OpCode繞過Python沙箱的方法詳解

    這篇文章主要給大家介紹了關(guān)于如何使用OpCode繞過Python沙箱的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Python具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09

最新評論

榆树市| 库车县| 玉龙| 沁阳市| 宕昌县| 营口市| 达州市| 巴林左旗| 桐城市| 苗栗县| 南部县| 泗阳县| 连平县| 峨眉山市| 灵川县| 陇川县| 封开县| 米脂县| 武汉市| 洱源县| 聂荣县| 西昌市| 英山县| 乾安县| 龙门县| 理塘县| 新建县| 财经| 永靖县| 永年县| 黑水县| 开原市| 织金县| 玉林市| 高州市| 福泉市| 忻城县| 旬阳县| 贵州省| 靖西县| 罗定市|