戰(zhàn):用 Python 把 EXE 反編譯復(fù)原流程封裝成可復(fù)用 Skill)
1. 為什么 EXE 復(fù)原總在重復(fù)造輪子手里拿到一個打包好的 EXE想還原成可讀的 Python 源碼這件事本身不復(fù)雜復(fù)雜的是每次都要重新走一遍相同的判斷這是 PyInstaller 還是別的打包器、提取出來的 pyc 用哪個版本反編譯、反編譯結(jié)果里哪些是函數(shù)錯位哪些是字符串丟失、重建之后怎么驗(yàn)證不炸掉原目錄。做過三五次之后你會發(fā)現(xiàn)真正花時間的不是反編譯那一條命令而是圍繞它的證據(jù)盤點(diǎn)、結(jié)果比對和安全驗(yàn)證。Codex 在這里的價值不是替你反編譯而是把「收集證據(jù) → 識別打包方式 → 對比反編譯結(jié)果 → 重建結(jié)構(gòu) → 驗(yàn)證行為」這條鏈路固化成可重復(fù)調(diào)用的 Skill。你只需要說一句「用 DecodePyExe 繼續(xù)復(fù)原當(dāng)前目錄」它就知道該看哪些文件、不該碰哪些目錄、先恢復(fù)什么后恢復(fù)什么、驗(yàn)證到什么程度算通過。這篇就把這個 Skill 的目錄骨架、config.toml 配置片段和一次完整復(fù)原驗(yàn)證動作拆開講清楚讓你能直接照著搭一套。適合誰看手頭有歷史打包程序需要還原結(jié)構(gòu)的后端或工具開發(fā)者、經(jīng)常處理 pyc 和反編譯產(chǎn)物的安全分析人員、以及想把零散命令沉淀成 Codex Skill 的工程效率愛好者。前置要求只有兩個本機(jī)裝好 Python 和 Codex能跑通一次模型對話確認(rèn)鏈路正常。2. 用 TaoToken 打通 Codex 的模型調(diào)用鏈路Codex 執(zhí)行 Skill 時需要穩(wěn)定的模型入口否則你剛把流程跑順一次請求超時就前功盡棄。我這邊習(xí)慣用 TaoToken 作為統(tǒng)一入口它把模型對話、Coding Plan、API Keys 管理放在同一個控制臺里配置一次就能在 Codex 里長期復(fù)用不用每次換環(huán)境重新折騰。具體來說Codex 的 config.toml 里需要填一個 base_url 和 api_key。base_url 指向 TaoToken 的 API 地址api_key 在控制臺的 API Keys 頁面生成。這樣 Codex 發(fā)起的所有模型請求都會走這個入口Skill 里定義的復(fù)原步驟才能被穩(wěn)定執(zhí)行。如果你只是偶爾驗(yàn)證一下模型輸出可以直接用模型對話頁面手動測如果是要長期跑編碼和 Agent 任務(wù)建議開 Coding Plan配額和并發(fā)更穩(wěn)。接入文檔里有完整的參數(shù)說明第一次配的時候?qū)χ匆槐槟苁〔簧倥挪闀r間。注意API 地址用 https://taotoken.net/api不要在后面拼多余的路徑config.toml 里的 base_url 填到這一層就夠了。3. Skill 目錄骨架與 config.toml 配置片段先把目錄結(jié)構(gòu)定下來。Codex Skill 的約定是放在項(xiàng)目根目錄的.codex/skills/下每個 Skill 一個文件夾里面至少有一個SKILL.md描述觸發(fā)條件和執(zhí)行步驟。我建議再加一個references/放流程細(xì)節(jié)一個scripts/放可復(fù)用的輔助腳本。.codex/ skills/ DecodePyExe/ SKILL.md references/ recovery-flow.md safety-checklist.md scripts/ inventory.py verify_recovered.pySKILL.md的頭部用 YAML front matter 寫觸發(fā)描述正文寫步驟。描述要寫清楚「什么時候用」和「禁止什么」這樣 Codex 在匹配任務(wù)時不會誤觸發(fā)。--- name: DecodePyExe description: Recover readable Python source from PyInstaller executables, extracted PYZ folders, .pyc files, and decompiler output. Use when asked to restore, reconstruct, clean up, or continue recovering source from Python exe artifacts while avoiding unrelated local source code. --- # DecodePyExe ## 使用時機(jī) - 當(dāng)前目錄存在 .exe、.pyc、PYZ 提取目錄或反編譯產(chǎn)物 - 用戶要求復(fù)原、重建、整理源碼 - 用戶說「繼續(xù)復(fù)原」并指向當(dāng)前目錄 ## 證據(jù)邊界 只參考當(dāng)前目錄內(nèi)的文件。禁止讀取其他本地項(xiàng)目的源碼。 ## 執(zhí)行步驟 1. 盤點(diǎn)目錄列出所有候選證據(jù)文件 2. 識別打包方式查找 pyiboot / pyimod / PYZ / pyi_rth 線索 3. 區(qū)分業(yè)務(wù)模塊與第三方依賴 4. 對比多個反編譯結(jié)果提取函數(shù)名、類名、調(diào)用順序、字符串常量 5. 重建為 xxx_recovered.py不覆蓋原始反編譯文件 6. 先 py_compile 再 import 驗(yàn)證不貿(mào)然運(yùn)行主入口 ## 輸出格式 - 重建文件列表 - 每步驗(yàn)證命令與結(jié)果 - 不確定處的注釋標(biāo)記config.toml 里除了模型入口還可以給這個 Skill 單獨(dú)指定溫度復(fù)原任務(wù)需要穩(wěn)定輸出溫度調(diào)低一點(diǎn)更合適。# ~/.codex/config.toml model claude-sonnet-4-20250514 model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY [skills.DecodePyExe] enabled true temperature 0.2api_key 不要硬編碼在 config.toml 里用環(huán)境變量注入。Windows 下在 PowerShell 里設(shè)一次$env:TAOTOKEN_API_KEY sk-你的keyLinux 或 macOS 寫進(jìn) shell 配置export TAOTOKEN_API_KEYsk-你的key配好之后跑一次模型對話確認(rèn)鏈路通再進(jìn)下一步。如果返回 401八成是 key 沒讀到或者 base_url 多寫了路徑。4. 一次完整的 EXE 復(fù)原驗(yàn)證動作假設(shè)當(dāng)前目錄里有一個legacy_tool.exe還有提取出來的PYZ-00.pyz_extracted/和一份反編譯結(jié)果decompiled/。下面按 Skill 定義的步驟走一遍。第一步盤點(diǎn)目錄。Skill 里的inventory.py負(fù)責(zé)把候選證據(jù)列出來避免手動翻。# scripts/inventory.py import os from pathlib import Path EVIDENCE_SUFFIXES {.exe, .pyc, .pyz, .pyi, .log, .json, .ini, .cfg} EVIDENCE_DIRS {PYZ-00.pyz_extracted, decompiled, resources} def inventory(root: str .): root_path Path(root) found {files: [], dirs: []} for p in root_path.rglob(*): if p.is_file() and p.suffix.lower() in EVIDENCE_SUFFIXES: found[files].append(str(p.relative_to(root_path))) if p.is_dir() and p.name in EVIDENCE_DIRS: found[dirs].append(str(p.relative_to(root_path))) return found if __name__ __main__: result inventory() print(候選文件:) for f in result[files]: print( , f) print(候選目錄:) for d in result[dirs]: print( , d)跑一下python scripts/inventory.py輸出會列出legacy_tool.exe、PYZ-00.pyz_extracted/下的 pyc、decompiled/下的 py 文件。這一步的目標(biāo)是搞清楚手里有哪些證據(jù)不是馬上開始反編譯。第二步識別打包方式。在提取目錄里搜打包器特征文件rg --files PYZ-00.pyz_extracted | rg pyiboot|pyimod|pyi_rth如果命中pyiboot01_bootstrap或pyimod02_importers基本可以確認(rèn)是 PyInstaller 打包。這一步?jīng)Q定了后續(xù)入口文件大概長什么樣。第三步區(qū)分業(yè)務(wù)模塊和依賴。提取目錄里通常混著requests、urllib3這類第三方庫不要陷進(jìn)去。優(yōu)先找文件名帶業(yè)務(wù)語義的模塊比如config_loader.pyc、report_builder.pyc。第三方依賴只需要知道被引用了不需要復(fù)原。第四步對比反編譯結(jié)果。如果decompiled/下有兩份不同工具產(chǎn)出的結(jié)果分別看它們的優(yōu)勢一份可能字符串保留更全另一份函數(shù)邊界更清楚。重建時綜合兩邊證據(jù)而不是復(fù)制其中一份。第五步重建源碼。新建legacy_tool_recovered.py不要覆蓋decompiled/里的原始文件。重建順序按 Skill 定義走imports → 配置讀取 → 工具函數(shù) → 小模塊 → 核心類 → 主流程 → 異常處理。不確定的分支加注釋# Reconstructed from bytecode order; exact original branch may differ. if mode batch: run_batch() else: run_single()第六步安全驗(yàn)證。先編譯檢查python -m py_compile legacy_tool_recovered.py沒有輸出就是通過。再做導(dǎo)入檢查# scripts/verify_recovered.py import importlib.util import sys def verify(module_path: str, module_name: str recovered): spec importlib.util.spec_from_file_location(module_name, module_path) module importlib.util.module_from_spec(spec) sys.modules[module_name] module try: spec.loader.exec_module(module) print(import ok) return True except Exception as e: print(fimport failed: {e}) return False if __name__ __main__: verify(legacy_tool_recovered.py)跑python scripts/verify_recovered.py輸出import ok說明模塊級代碼沒有副作用、語法和導(dǎo)入都正常。到這一步為止不要運(yùn)行主入口因?yàn)榇虬绦虻闹髁鞒炭赡軐懳募⒁苿幽夸浕騿油獠砍绦?。只有確認(rèn)副作用可控后才考慮單獨(dú)測試純函數(shù)或配置解析函數(shù)。5. 復(fù)原過程中最容易踩的坑反編譯結(jié)果當(dāng)答案直接跑。反編譯產(chǎn)物里函數(shù)錯位、try/except 丟失、return 位置錯誤都很常見。直接運(yùn)行輕則報錯重則觸發(fā)主流程的副作用。正確做法是把它當(dāng)證據(jù)提取結(jié)構(gòu)后重建。一上來就恢復(fù)細(xì)節(jié)。有人喜歡從第一行開始逐行還原結(jié)果卡在某個字符串亂碼上半天。先恢復(fù) imports 和配置讀取拿到一個能 import 的骨架再往里填細(xì)節(jié)節(jié)奏會順很多。誤讀其他項(xiàng)目的源碼。如果用戶明確說「只參考當(dāng)前目錄」就不要去翻本地其他項(xiàng)目。Skill 里把這條寫成硬約束Codex 執(zhí)行時不會越界。config.toml 里 base_url 寫錯。常見的是在https://taotoken.net/api后面又拼了/v1或/chat/completions導(dǎo)致 404。base_url 填到/api這一層剩下的路徑由 Codex 自己拼。api_key 沒注入環(huán)境變量。config.toml 里寫的是env_key TAOTOKEN_API_KEY如果環(huán)境變量沒設(shè)請求會直接 401。設(shè)完之后新開一個終端再跑避免舊會話讀不到。驗(yàn)證時直接跑主入口。python legacy_tool_recovered.py這種命令在沒確認(rèn)副作用前不要執(zhí)行。先用py_compile和import兩道檢查確認(rèn)安全后再考慮局部測試。Codex 重啟后上下文丟失。這是最常見也最影響效率的問題。解決辦法是在項(xiàng)目根目錄維護(hù)一個PROJECT_STATE.md記錄當(dāng)前目標(biāo)、已完成、關(guān)鍵文件、注意事項(xiàng)和下一步。重啟后第一句說「先讀 PROJECT_STATE.md然后繼續(xù)」Codex 就能接上。# 當(dāng)前目標(biāo) 復(fù)原 legacy_tool.exe 為可讀 Python 源碼 # 已完成 - 盤點(diǎn)目錄確認(rèn) PyInstaller 打包 - 重建 legacy_tool_recovered.py 的 imports 和配置讀取 - py_compile 通過 # 關(guān)鍵文件 - legacy_tool_recovered.py - decompiled/ 下的兩份反編譯結(jié)果 # 注意事項(xiàng) - 只參考當(dāng)前目錄 - 不要運(yùn)行主入口 # 下一步 - 恢復(fù)核心類結(jié)構(gòu) - 對比兩份反編譯結(jié)果的字符串常量6. 把流程固化下來之后Skill 搭好、config.toml 配好、PROJECT_STATE.md 維護(hù)起來之后下次遇到類似的 EXE 復(fù)原任務(wù)你只需要一句「使用 DecodePyExe繼續(xù)復(fù)原當(dāng)前目錄里的程序」Codex 就會按既定步驟走盤點(diǎn)證據(jù)、識別打包方式、對比反編譯結(jié)果、重建源碼、安全驗(yàn)證。不用每次重新解釋邊界和順序也不用擔(dān)心重啟后從零開始。如果你還沒配好模型入口先去控制臺生成一個 API Key然后對著接入文檔把 config.toml 填完。長期跑編碼和 Agent 任務(wù)的話Coding Plan 的配額更穩(wěn)適合把這類復(fù)原流程當(dāng)成日常工具用。配好之后跑一次模型對話確認(rèn)鏈路再回來把 Skill 目錄建起來整個流程就能跑通了。