轉自:http://blog.csdn.net/chenyulancn/article/details/77168621
最近,我在做一個需要使用Cython來保護整個代碼庫的Python項目。
起初盡管保護Python源碼免受逆向工程的影響似乎是一項徒勞無功的任務,但是所有代碼的cythonizing都會帶來合理的安全性(二進制文件非常難以拆解,但是還可以通過程序的猴子補丁程序來完成)。
這種安全性是有代價的 - Cython的主要用途是編寫可以輕松與Python代碼連接的編譯擴展。
因此,對復雜模塊/包結構的支持是相當有限的,我們必須做一些額外的工作來實現所需的結果。
我們必須克服的第一個障礙是很難用Cython編譯整個Python包(如“包含__init__.py文件的目錄”)。想象一下下面的結構:
推薦的cythonizing方法是使用setup.py文件,如下所示:
setup.py或多或少是使用Cython的項目所期望的。但是有兩件事要注意。第一,always_allow_keywords指令通過禁用具有大量參數的函數只允許使用關鍵字參數這一優化,使Flask視圖函數可以正常工作。其次,我們不使用一些指南建議的ext_package參數,因為這會將cythonized代碼放入另一個包中。通過省略這個參數,編譯的代碼保存在同一個地方。
但是,在使用python setup.py build_ext構建項目之后,我們注意到生成的程序包無法導入 - 它缺少__init__.py文件。__init__.so可以從Python導入,但這還不足以使目錄成為Python的一個包。 無法導入包不是唯一的問題 - 其中的代碼也無法執行包相對導入(例如.foo import foo),這會破壞其功能。
要解決這個問題,我們可以在構建項目的其余部分后從源代碼樹中復制__init__.py文件。 一個很好的方法是覆蓋setup.py中的build_ext類:
我們已經成功地創建了可以導入的Python包。它們在build / lib.linux-x86_64-3.6或類似的目錄下。 遺憾的是,這不足以分發我們的包。理想情況下,我們希望安裝一個僅包含已編譯代碼的軟件包。目前Python存檔的標准是wheel格式(.whl),其目的是替換.egg格式。所以,讓我們嘗試用python setup.py bdist_wheel創建wheel格式! 命令完成后,應該有一個包含wheel文件的dist文件夾。打開就能產生這樣的東西:
顯然,歸檔不僅包含編譯代碼,還包含源代碼。有一種方法可以解決這個問題,但是它似乎是反直覺的。我們需要在調用setup時刪除packages參數中的包名。這樣,仍然可以構建擴展並包含在wheel中,但源代碼將不會在其中。
構建的wheel的內容應該如下所示:
可以使用pip install dist/*.whl安裝wheel。如果我們不需要檢查wheel或手動分配wheel,我們可以在項目目錄中運行pip install,構建並安裝wheel。
也可以從.egg存檔中刪除Python源代碼,但它涉及到從setuptools覆蓋bdist_egg命令。我不會在這里覆蓋,但如果您有興趣,請查看上述命令類的--exclude-source-files選項和zap_pyfiles方法。
通過遵循本指南,你應該能夠利用復雜軟件包/模塊結構對Python代碼庫進行cythonize,從而讓惡意黑客難以對其進行逆向工程並竊取你的編程成果。
英文原文:https://bucharjan.cz/blog/using-cython-to-protect-a-python-codebase.html