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

使用Python標準庫對.pyc進行反編譯的全過程

 更新時間:2026年03月09日 10:05:43   作者:feifeiyechuan  
在生產環(huán)境中,我們經常只能拿到?Python?的編譯文件(.pyc),而沒有原始?.py?源碼,本文記錄一次完整的從?.pyc?到可讀源碼的實踐過程,需要的朋友可以參考下

在生產環(huán)境中,我們經常只能拿到 Python 的編譯文件(.pyc),而沒有原始 .py 源碼。
本文記錄一次完整的.pyc 到可讀源碼的實踐過程,并整理成可復用的“知識庫條目”,后續(xù)你可以對其他 .pyc 復用同樣的方法。

環(huán)境說明(模擬場景):

  • 解釋器:CPython 3.x
  • 目標文件:module_a.pyc(某業(yè)務模塊的編譯文件)
  • 工具:只使用 Python 標準庫 dis、marshal(無第三方反編譯器依賴)

一、整體思路概覽

面對一個 .pyc 文件,我們的目標是:

  1. .pyc 里拿到 Code 對象(Python 的內部字節(jié)碼表示);
  2. dis 把字節(jié)碼反匯編成可讀的文本指令(生成 your_module_dis.txt 之類的文本);
  3. 基于該文本里的指令列表,手工/半自動還原出邏輯等價的 Python 源碼(得到 recovered_module.py 這樣的還原版源碼);
  4. 通過對比運行效果,驗證還原代碼與原模塊行為一致。

本文重點記錄第 ①~③ 步的細節(jié)和踩坑點,方便后續(xù)你作為“知識庫”查閱。

二、CPython.pyc文件的基本結構

了解一點 .pyc 結構有助于理解為什么要先 f.read(16)

  • 前 16 字節(jié)是頭部(header),包含:
    • 魔數(magic number)
    • 標志位(flags)
    • 時間戳 / 源文件哈希
    • 源碼大小等
  • 后面才是真正的 code object 數據,通過 marshal 模塊進行序列化。

所以大致結構是:

[ 16 字節(jié)頭部 ] + [ marshal.dump(code_object) 的二進制數據 ]

只要我們跳過前 16 字節(jié),再用 marshal.load 讀取,就能拿回一個可以被 dis 反匯編的 code 對象。

三、用dis + marshal導出字節(jié)碼到文本(示例腳本)

核心導出腳本如下(示例腳本 disassemble_example.py):

import dis, marshal, types

# 示例:從業(yè)務模塊 module_a.pyc 中讀取字節(jié)碼
with open(r"D:\demo_project\bin\module_a.pyc", "rb") as f:
    f.read(16)  # 跳過頭部
    code = marshal.load(f)

with open("your_module_dis.txt", "w", encoding="utf-8") as out:
    dis.dis(code, file=out)

關鍵點說明:

  • f.read(16):跳過 .pyc 頭 16 字節(jié),只保留真正的字節(jié)碼部分;
  • marshal.load(f):從剩余二進制流中反序列化出一個 code 對象;
  • dis.dis(code, file=out):對這個頂層 code 對象做反匯編,結果寫入 your_module_dis.txt。

執(zhí)行完成后,會在同目錄下生成一個比較長的 your_module_dis.txt,里面是類似這樣的內容(下面是完全虛構的模擬輸出片段,用于說明格式與思路):

  0           0 RESUME                   0

  2           2 LOAD_CONST               0 (0)
              4 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (json)
              8 STORE_NAME               0 (json)

  3          10 LOAD_CONST               0 (0)
             12 LOAD_CONST               1 (None)
             14 IMPORT_NAME              1 (re)
             16 STORE_NAME               1 (re)

  ...

  66          74 LOAD_CONST               6 (<code object extract_main_syms at 0x..., file "/app/demo_project/module_a.py", line 19>)
             104 MAKE_FUNCTION            0
             106 STORE_NAME              15 (extract_main_syms)

從這種輸出格式中,可以看出:

  • 模塊會先導入若干依賴模塊;
  • 然后依次把若干 code object 綁定為函數。

這些信息就是后續(xù)還原源碼時用于搭建結構的“骨架”,這里只是虛構的示例格式,不對應任何真實業(yè)務代碼。

四、分析導出的文本:從字節(jié)碼骨架還原模塊結構

在導出的文本一開始,你一般會看到類似這樣的模式(同樣是虛構的模擬片段):

  11          74 LOAD_CONST               0 (0)
             76 LOAD_CONST               2 (('log_info', 'log_error'))
             78 IMPORT_NAME              9 (core)
             80 IMPORT_FROM             10 (log_info)
             82 STORE_NAME              10 (log_info)
             84 IMPORT_FROM             11 (log_error)
             86 STORE_NAME              11 (log_error)
             88 POP_TOP

  13          90 LOAD_CONST               3 ('DEMO_CODE')
             92 STORE_GLOBAL            12 (code_str)

  15          94 LOAD_CONST               4 ('https://api.example.com/i')
             96 STORE_NAME              13 (service_url)

  16          98 LOAD_CONST               5 (False)
            100 STORE_NAME              14 (debug_mode)

結合經驗,可以直接還原為類似下面的偽代碼形式(示例依然是虛構的,注意其中的配置項和值都只是演示用):

from core import log_error, log_info

code_str: str = "DEMO_CODE"
ICD_service_url: str = "https://api.example.com"
debug_mode: bool = False

還原模塊級結構的一般步驟:

  1. 先關注所有 IMPORT_NAME / IMPORT_FROM:恢復頂層 import 語句;
  2. 找所有 STORE_NAME + 常量字符串:通常是模塊級常量配置,如 code_str / URL / debug 開關;
  3. LOAD_CONST (<code object ...>) + MAKE_FUNCTION + STORE_NAME
    • 可以直接得到函數名:STORE_NAME 15 (extract_main_syms)def extract_main_syms(...):
    • 然后在 Disassembly of <code object extract_main_syms ...> 下面繼續(xù)分析函數內部邏輯。

到這里為止,我們已經能搭出一個大致的模塊輪廓。

五、函數內部:從字節(jié)碼反推高層邏輯(虛構示例)

拿某個函數(例如 extract_main_syms)舉例,在導出文本中它的反匯編開頭可能類似(示意片段,完全虛構):

Disassembly of <code object extract_main_syms at 0x..., file "/app/demo_project/module_a.py", line 19>:
 19           0 RESUME                   0

 20           2 BUILD_LIST               0
              4 STORE_FAST               2 (result_syms)

 21           6 LOAD_FAST                0 (input_data)
              8 LOAD_CONST               1 ('record')
             10 BINARY_SUBSCR
             20 LOAD_CONST               2 ('main_field')
             22 BINARY_SUBSCR
             32 STORE_FAST               3 (main_text)

 22          34 LOAD_FAST                0 (input_data)
             36 LOAD_CONST               1 ('record')
             38 BINARY_SUBSCR
             48 LOAD_CONST               3 ('history_field')
             50 BINARY_SUBSCR
             60 STORE_FAST               4 (history_text)

根據變量名,可以還原出類似這樣的偽代碼(同樣是虛構示例):

def extract_main_syms(input_data: Dict[str, Any]) -> List[str]:
    result_syms: List[str] = []

    record = input_data.get("record", {}) or {}
    history_text: str = record.get("history_field", "") or ""
    ...

通用還原技巧:

  • BUILD_LIST 0 + STORE_FAST (xxx)xxx = []
  • LOAD_FAST ... BINARY_SUBSCR 多連串 → 多級下標 / dict 取值;
  • 頻繁出現的字符串常量(中文問診要點、病史名稱)→ 可以直接在源碼里用同樣的文本補回去;
  • CALL_FUNCTION / `CALL_METHOD`` 結合函數名、參數個數,大多數時候可以明確調用意圖。

通過這一套操作,可以逐步把若干核心函數(例如 extract_main_syms 等)都還原為結構清晰、類型標注完善的 Python 源碼(在你自己的還原文件中,例如 recovered_module.py)。

六、把反匯編結果固化為“知識庫”:還原源碼的實現策略

在一次完整的實踐中,我們可以在一個還原文件(例如 recovered_module.py)中遵循下面幾個原則:

  • 保持對外行為一致:函數名、參數、返回結構盡量和原模塊保持兼容;
  • 邏輯等價優(yōu)先,而非逐指令對齊:我們關注的是“相同輸入 → 相同輸出”,不追求一模一樣的實現寫法;
  • 適當增加類型標注和注釋:方便后續(xù)維護和閱讀,特別是復雜的業(yè)務流程;
  • 抽出可配置項:如 code_strICD_service_url、日期限制 date_limite 等統一放在模塊頂部。

例如,頂層配置在還原后被集中到了模塊開頭(這里用模擬數據舉例):

code_str: str = "DEMO_CODE"
ICD_service_url: str = "https://api.example.com/icd"
debug_mode: bool = False

對于某些主流程函數,可以按照原字節(jié)碼中調用順序,清晰劃出若干步驟,例如:

  • 權限或授權有效期檢查;
  • 輸入參數解析及預處理;
  • 關鍵信息抽取、實體標注或特征工程;
  • 業(yè)務規(guī)則判斷、打分與過濾;
  • 結果歸組、加權及 Top-N 輸出。

這些結構在源碼層面被“語義化”之后,不再只是 LOAD_CONST / JUMP_FORWARD 這樣的指令堆,而是清晰的業(yè)務流程。

七、實踐經驗與踩坑記錄

反編譯 .pyc 到可維護源碼,過程中有一些值得記錄的點(下面都以虛構示例來說明思路):

1)優(yōu)先搞清楚“輸入/輸出”約定

  • 先從接口調用方(如外部服務或其它模塊)入手,反向推函數參數含義,比直接看字節(jié)碼更有效。

2)對復雜 if/for 結構,不要硬記指令,先畫流程

  • 可以根據 JUMP_IF_FALSE_OR_POPPOP_JUMP_FORWARD_IF_FALSE 之類的跳轉位置,畫一張小流程圖,再還原成 if/elif/else。

3)保持一個“對照文件”

  • 建議始終保留一對文件:例如 your_module_dis.txt 作為原始反匯編結果,recovered_module.py 是還原后的源碼,兩邊對照非常重要。

4)不要迷信自動反編譯工具

  • 對于邏輯復雜、包含大量中文業(yè)務規(guī)則的代碼,自動反編譯經常給出難以閱讀的結果,
    手工+半自動(基于 dis 的文本)更適合做“可維護的重構”。

八、如何復用這套方法處理其他.pyc

當你以后再遇到一個新的 .pyc,可以按下面的模板操作(完全和具體業(yè)務無關,只關注技術流程):

準備一個類似前文的 disassemble_example.py,只改文件路徑

import dis, marshal

with open(r"你的目標文件.pyc", "rb") as f:
    f.read(16)
    code = marshal.load(f)

with open("your_module_dis.txt", "w", encoding="utf-8") as out:
    dis.dis(code, file=out)

打開生成的 your_module_dis.txt

  • 先定位所有 IMPORT_NAME / MAKE_FUNCTION + STORE_NAME,搭好模塊骨架;
  • 再逐個函數分析 Disassembly of <code object ...> 部分。

在新建的 .py 文件中,還原可讀源碼

  • 先實現外部接口簽名;
  • 再根據字節(jié)碼實現內部邏輯;
  • 最后寫一些測試用例,對比行為。

把還原心得也整理到類似本篇這樣的 markdown 中

  • 方便你自己未來查閱,也方便團隊里其他同事快速接手。

九、小結

  • 使用 Python 標準庫的 marshal + dis,可以在不依賴第三方庫的前提下,從 .pyc 中獲取字節(jié)碼并反匯編到文本;
  • 基于反匯編文本(如 your_module_dis.txt),可以逐步還原出結構清晰的源碼文件(例如 recovered_module.py),作為長期維護版本;
  • 將整個流程和經驗沉淀成 markdown 知識庫(本文)后,可以非常方便地復用于今后所有 .pyc 分析與還原工作。

只要掌握了這一套流程,你在面對“只有 .pyc、沒有源碼”的場景時,就不會再那么無助,而是有一套穩(wěn)定可復用的反編譯+重構方法 論。

以上就是使用Python標準庫對.pyc進行反編譯的全過程的詳細內容,更多關于Python標準庫對.pyc反編譯的資料請關注腳本之家其它相關文章!

相關文章

  • Python利用yarl實現輕松操作url

    Python利用yarl實現輕松操作url

    在諸如網絡爬蟲、web應用開發(fā)等場景中,我們需要利用Python完成大量的url解析、生成等操作。本文為大家介紹了Pythonyarl操作url的方法,需要的可以了解一下
    2022-10-10
  • Python如何獲取文件指定行的內容

    Python如何獲取文件指定行的內容

    在本篇文章里小編給大家分享的是關于Python獲取文件指定行的內容的方法,有需要的朋友們可以學習下。
    2020-05-05
  • 使用python爬蟲實現子域名探測問題

    使用python爬蟲實現子域名探測問題

    子域名枚舉是為一個或多個域查找子域的過程,它是信息收集階段的重要組成部分,這篇文章主要介紹了使用python實現子域名探測,需要的朋友可以參考下
    2022-07-07
  • Python利用GDAL模塊實現讀取柵格數據并對指定數據加以篩選掩膜

    Python利用GDAL模塊實現讀取柵格數據并對指定數據加以篩選掩膜

    這篇文章主要為大家詳細介紹了如何基于Python語言中gdal模塊,對遙感影像數據進行柵格讀取與計算,同時基于QA波段對像元加以篩選、掩膜的操作,需要的可以參考一下
    2023-02-02
  • Pandas爆炸函數的使用技巧

    Pandas爆炸函數的使用技巧

    同事舉了個簡單的例子來說明爆炸函數的功能,我當場就記下了這個函數名稱:爆炸函數。Hive在我的工作中使用的并不多,于是我在想:Pandas能夠實現這個功能嗎?本文就來了解一下
    2021-05-05
  • python實現從wind導入數據

    python實現從wind導入數據

    今天小編就為大家分享一篇python實現從wind導入數據,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • python GUI庫圖形界面開發(fā)之PyQt5滾動條控件QScrollBar詳細使用方法與實例

    python GUI庫圖形界面開發(fā)之PyQt5滾動條控件QScrollBar詳細使用方法與實例

    這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5滾動條控件QScrollBar詳細使用方法與實例,需要的朋友可以參考下
    2020-03-03
  • Python爬蟲實戰(zhàn)之12306搶票開源

    Python爬蟲實戰(zhàn)之12306搶票開源

    今天小編就為大家分享一篇關于Python爬蟲實戰(zhàn)之12306搶票開源,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Python中的DateTime和TimeDelta詳解

    Python中的DateTime和TimeDelta詳解

    這篇文章主要介紹了Python中的DateTime和TimeDelta詳解,在Python中,date,time和datetime類提供了許多函數來處理日期、時間和時間間隔,每當您操縱日期或時間時,都需要導入DateTime函數,需要的朋友可以參考下
    2023-07-07
  • Pandas之缺失數據的實現

    Pandas之缺失數據的實現

    這篇文章主要介紹了Pandas之缺失數據的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01

最新評論

郑州市| 永修县| 新绛县| 伊川县| 团风县| 泰州市| 黑龙江省| 绥宁县| 大渡口区| 抚宁县| 富蕴县| 清镇市| 隆回县| 旌德县| 沙河市| 鹤峰县| 鸡东县| 麦盖提县| 绿春县| 卓尼县| 深州市| 都匀市| 溧阳市| 娄烦县| 郧西县| 岳普湖县| 汝城县| 太湖县| 鄂伦春自治旗| 荥经县| 义乌市| 丰顺县| 贵南县| 吴江市| 龙海市| 鄂尔多斯市| 读书| 清涧县| 无极县| 甘泉县| 临沭县|