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

Python項(xiàng)目進(jìn)行加密打包的實(shí)踐指南

 更新時(shí)間:2026年01月15日 09:36:03   作者:@fai  
在實(shí)際開發(fā)中,我們有時(shí)需要將 Python 項(xiàng)目交付給客戶或部署到不受控環(huán)境中,但又不希望源代碼被輕易查看甚至篡改,所以本文將基于一個(gè)自研的 Encryptor 工具類,分享如何實(shí)現(xiàn)一個(gè)輕量級(jí)、可擴(kuò)展的 Python 項(xiàng)目加密打包方案,需要的朋友可以參考下

引言

在實(shí)際開發(fā)中,我們有時(shí)需要將 Python 項(xiàng)目交付給客戶或部署到不受控環(huán)境中,但又不希望源代碼被輕易查看甚至篡改。雖然 Python 作為解釋型語言天然難以完全隱藏邏輯,但我們?nèi)钥赏ㄟ^編譯為字節(jié)碼 + 自定義加密 + 運(yùn)行時(shí)解密執(zhí)行的方式,大幅提升逆向分析的門檻。

本文將基于一個(gè)自研的 Encryptor 工具類,分享如何實(shí)現(xiàn)一個(gè)輕量級(jí)、可擴(kuò)展的 Python 項(xiàng)目加密打包方案。

整體思路

我們的目標(biāo)是:

  1. 保留原有項(xiàng)目結(jié)構(gòu)(包括子目錄、.py.pyw 文件);
  2. 將每個(gè) Python 源文件編譯為字節(jié)碼并加密;
  3. 生成一個(gè)“運(yùn)行時(shí)”模塊,用于在運(yùn)行時(shí)動(dòng)態(tài)解密并執(zhí)行加密后的字節(jié)碼;
  4. 輸出一個(gè)獨(dú)立的加密項(xiàng)目副本,無需原始源碼即可運(yùn)行。

整個(gè)流程如下:

原始項(xiàng)目 (testproject/)
├── main.py
├── utils/
│   └── helper.py
└── ...

↓ Encryptor.encryptProject()

加密項(xiàng)目 (testproject-dist/)
├── main.py        ← 內(nèi)容變?yōu)? from __runtime__ import __run__; __run__(b'...', globals())
├── utils/
│   └── helper.py  ← 同上
└── __runtime__/   ← 包含解密和執(zhí)行邏輯

一、準(zhǔn)備工作

由于我們需要在運(yùn)行時(shí)動(dòng)態(tài)解密并執(zhí)行加密后的字節(jié)碼,但是又不想暴露解密算法,那么需要將解密函數(shù)單獨(dú)編譯為.pyd或者其他(.so/.dll)機(jī)器碼文件,這里給出示例:

# runtime.py
def __run__(en_code: bytes, globals_: dict):
    import struct
    import marshal

    def decrypt(en_code: bytes) -> bytes:
        en_code, offset_bytes = en_code[:-4], en_code[-4:]  # 去除偏移量
        insert_offset = struct.unpack("<I", offset_bytes)[0]
        key = en_code[insert_offset : insert_offset + 64]  # 提取key
        en_code = en_code[:insert_offset] + en_code[insert_offset + 64 :]  # 去除key
        # 解密
        de_code = bytes([en_code[i] ^ key[i % len(key)] for i in range(len(en_code))])
        return de_code

    code = marshal.loads(decrypt(en_code))
    exec(code, globals_, globals_)

完成編譯后,新建runtime文件夾,將pyd文件(如runtime.cp312-win_amd64.pyd)放入,并新建__init.py__文件,輸入一行代碼:

from .runtime import __run__ 

python解釋器會(huì)根據(jù)目前設(shè)備自動(dòng)選擇runtime.cp312-win_amd64.pyd,所以并不需要更改文件名。

二、核心實(shí)現(xiàn)解析

1. 密鑰生成:動(dòng)態(tài)隨機(jī) + SHA3-512

def __generateKey(self) -> bytes:
    key = "".join([chr(randint(33, 126)) for _ in range(64)])
    return hashlib.sha3_512(key.encode("utf-8")).digest()
  • 每次加密一個(gè)文件時(shí),都會(huì)獨(dú)立生成一個(gè) 64 字節(jié)的隨機(jī)密鑰
  • 使用 sha3_512 哈希確保密鑰分布均勻且不可預(yù)測(cè);
  • 注意:密鑰不會(huì)保存在外部,而是直接嵌入加密數(shù)據(jù)中(見下文)。

安全提示:此設(shè)計(jì)便于單文件自包含,但若攻擊者能提取密鑰,則可解密。適用于防普通用戶查看,非高強(qiáng)度安全場(chǎng)景。

2. 加密流程:字節(jié)碼 + 異或 + 隨機(jī)插入密鑰

code = compile(..., "exec")
bytecode = marshal.dumps(code)
en_code = bytes([bytecode[i] ^ key[i % len(key)] for i in range(len(bytecode))])
insert_offset = randint(0, len(en_code) - 1)
en_code = en_code[:insert_offset] + key + en_code[insert_offset:]
en_code += struct.pack("<I", insert_offset)  # 尾部記錄偏移

步驟分解:

  1. 編譯源碼為 CodeObjectcompile()
  2. 序列化為字節(jié)碼marshal.dumps()(Python 內(nèi)部格式)
  3. 用密鑰異或加密(簡(jiǎn)單但有效,避免明文字節(jié)碼)
  4. 將密鑰隨機(jī)插入加密數(shù)據(jù)中間(增加靜態(tài)分析難度)
  5. 在末尾寫入 4 字節(jié)偏移量(小端無符號(hào)整數(shù)),用于運(yùn)行時(shí)定位密鑰位置

這種“密鑰內(nèi)嵌 + 偏移記錄”的設(shè)計(jì),使得每個(gè)加密文件都是自包含的,無需額外配置。

3. 輸出加密文件:注入運(yùn)行時(shí)調(diào)用

加密后的 .py 文件內(nèi)容變?yōu)椋?/p>

from __runtime__ import __run__
__run__(b'\x12\xaf...', globals())

其中 b'\x12\xaf...' 是加密后的字節(jié)數(shù)據(jù)(包含密鑰和偏移)。
當(dāng) Python 執(zhí)行該文件時(shí),會(huì)調(diào)用 __runtime__.__run__ 來解密并執(zhí)行原始邏輯。

4. 運(yùn)行時(shí)模塊(runtime/)

雖然本文未展示 runtime/__init__.py 的內(nèi)容,但其核心邏輯大致如下:

def __run__(en_code: bytes, globals_: dict):
    import struct
    import marshal

    def decrypt(en_code: bytes) -> bytes:
        en_code, offset_bytes = en_code[:-4], en_code[-4:]  # 去除偏移量
        insert_offset = struct.unpack("<I", offset_bytes)[0]
        key = en_code[insert_offset : insert_offset + 64]  # 提取key
        en_code = en_code[:insert_offset] + en_code[insert_offset + 64 :]  # 去除key
        # 解密
        de_code = bytes([en_code[i] ^ key[i % len(key)] for i in range(len(en_code))])
        return de_code

    code = marshal.loads(decrypt(en_code))
    exec(code, globals_, globals_)

此模塊需隨加密項(xiàng)目一同分發(fā),但本身不含敏感邏輯,可公開。

三、使用方式

只需一行代碼即可加密整個(gè)項(xiàng)目:

encryptor = Encryptor("testproject")  # 源目錄
encryptor.encryptProject()            # 輸出到 testproject-dist/

支持遞歸處理所有 .py.pyw 文件,并自動(dòng)創(chuàng)建目標(biāo)目錄結(jié)構(gòu)。

四、優(yōu)缺點(diǎn)分析

優(yōu)點(diǎn)

  • 簡(jiǎn)單有效:無需第三方依賴,僅用標(biāo)準(zhǔn)庫;
  • 自包含:每個(gè)文件獨(dú)立解密,無全局密鑰管理;
  • 保留結(jié)構(gòu):項(xiàng)目組織不變,兼容原有導(dǎo)入路徑;
  • 防小白:普通用戶無法直接閱讀源碼。

局限

  • 非高強(qiáng)度加密:異或加密可被內(nèi)存 dump 或動(dòng)態(tài)調(diào)試破解;
  • 性能開銷:每次執(zhí)行需解密,對(duì)啟動(dòng)速度有輕微影響;
  • 不防反編譯:一旦字節(jié)碼被還原,可用 uncompyle6 等工具反編譯;
  • 密鑰內(nèi)嵌風(fēng)險(xiǎn):熟練攻擊者可提取密鑰批量解密。

若需更高安全性,建議結(jié)合:

  • C 擴(kuò)展封裝核心邏輯
  • 商業(yè)混淆工具(如 PyArmor)
  • 網(wǎng)絡(luò)授權(quán)驗(yàn)證

五、總結(jié)

本文實(shí)現(xiàn)的 Encryptor 是一個(gè)教學(xué)級(jí)但實(shí)用的 Python 項(xiàng)目加密方案。它平衡了易用性與基礎(chǔ)保護(hù)能力,適合用于:

  • 內(nèi)部工具分發(fā)
  • 客戶端腳本保護(hù)
  • 防止 casual 代碼窺探

雖然不能做到“絕對(duì)安全”,但在多數(shù)場(chǎng)景下已足夠提升逆向成本。更重要的是,通過這個(gè)過程,我們深入理解了 Python 的編譯、字節(jié)碼、marshal 序列化等底層機(jī)制。

附:注意事項(xiàng)

  • 確保 runtime/ 目錄與加密腳本同級(jí);
  • 不要加密 __main__.py 以外的入口文件時(shí)破壞 if __name__ == "__main__" 邏輯;
  • 測(cè)試加密后項(xiàng)目是否能正常運(yùn)行!

以上就是Python項(xiàng)目進(jìn)行加密打包的實(shí)踐指南的詳細(xì)內(nèi)容,更多關(guān)于Python項(xiàng)目加密打包的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

洱源县| 宝应县| 明光市| 彝良县| 凯里市| 德清县| 新竹市| 遂平县| 搜索| 富阳市| 南江县| 泾源县| 东阳市| 柏乡县| 河津市| 娱乐| 那坡县| 莫力| 昭苏县| 乐亭县| 肇东市| 剑川县| 新乡市| 长岭县| 达拉特旗| 沁阳市| 苏州市| 苏尼特左旗| 郎溪县| 滨州市| 松桃| 甘孜县| 新兴县| 尚义县| 桂阳县| 庄河市| 盐山县| 钟祥市| 临沧市| 阿拉善左旗| 新龙县|