shc(「通用 Shell 指令碼編譯器」)可以把一個 Shell 指令碼變成獨立的執行檔。這個名字很容易讓人誤會:指令碼的邏輯會被翻譯成機器碼,就像 C 編譯器把 .c 檔案變成原生指令一樣。這個假設是錯的,而shc聽起來在做的事、和它實際做的事之間的落差,正好可以說明該怎麼正確使用它,以及為什麼它藏不住任何想把內容取出來的人。
1. SHC 實際上做了什麼
shc 完全沒有編譯 Shell 邏輯。它會寫出一份 C 原始碼,把你原本的指令碼內容以密文形式嵌進去,再加上一小段執行期程式,負責把密文解密回一個暫存檔,然後透過指令碼 shebang 那一行指定的直譯器(/bin/sh、/bin/bash 等)去執行這個暫存檔。真正被 C 編譯器(cc)編譯的,是這個外殼程式,這也是為什麼輸出結果是貨真價實的 ELF 執行檔,看起來完全沒有 .sh 的痕跡。
加密方式是 RC4(ARC4)串流密碼的一個變體。每次執行 shc,它都會產生一組全新的 256 位元組隨機金鑰,把金鑰和密文一起烘進同一個執行檔裡。這整個過程完全不會檢視指令碼的控制流程、不會解析變數,也不會把任何指令變成機器指令——直譯器最終解析、執行的還是同一段文字,只是來源從 myscript.sh換成了一個暫存檔而已。
1.1 是遮蔽,不是編譯
這個區別很重要,因為「編譯」這個詞會帶來一些在 shc 身上完全不成立的預期。真正的編譯器——交叉編譯入門文章談的就是這種編譯器——會把原始碼翻譯成特定目標指令集的指令,產出的執行檔裡不會再留下任何形式的原始碼。shc 的執行檔則完整保留了你整份指令碼,一個位元組都沒少,只是被一把隨身攜帶的金鑰鎖在密文後面。把輸出檔從 .sh 改名成 .x,改變的只是呼叫方式,不會改變實際執行的內容。
2. 安裝 SHC
多數發行版的套件庫都能直接安裝 shc:
sudo apt install shc # Debian、Ubuntu
sudo dnf install shc # Fedora、RHEL
如果你的發行版沒有這個套件,原始碼是一個很小的 C 專案,可以直接複製下來用 make 建置——除了標準 C 工具鏈之外沒有其他外部函式庫依賴。
3. 編譯與執行指令碼
假設有一份指令碼 deploy.sh:
shc -f deploy.sh
這會產生兩個新檔案:deploy.sh.x,也就是你實際要執行的執行檔;以及 deploy.sh.x.c,shc 用來編譯出執行檔的那份 C 原始碼。兩者都含有你指令碼的加密內容,所以 .c 檔案也該和執行檔一樣小心對待——編譯完就刪掉它,連同原本的 deploy.sh 一起刪除,才算真正做到這件事的目的:
rm deploy.sh deploy.sh.x.c
./deploy.sh.x
3.1 常用參數
除了 -f 之外,以下幾個參數涵蓋了大多數實際用法:
-o outfile:自訂執行檔名稱,取代預設的<script>.x。-e dd/mm/yyyy:讓執行檔在指定日期之後拒絕執行,適合試用或展示用的指令碼。-x command:以printf格式自訂呼叫直譯器的指令,給需要非標準執行參數的指令碼使用。
3.2 讓執行檔可以搬到別台機器上跑
shc 預設編譯出來的執行檔,只保證在編譯它的那台機器上正常運作。把它複製到別的主機,可能直接跑不動,也可能行為怪怪的——第一次遇到時,很容易誤以為是打包出了問題。其實不是,這是刻意的限制。編譯時加上 -r 就能解除這個限制:
shc -r -f deploy.sh
只要執行檔要在編譯它的機器以外的地方執行,幾乎就是實際部署的常態,這時就該用 -r。
4. 為什麼這種加密保護不了機密
shc 自己的文件也明白寫著它是遮蔽工具,不是安全工具,而它的運作機制正好解釋了原因。用來加密指令碼的隨機金鑰,就和它要解密的密文放在同一個執行檔裡——要還原出可用的明文,只需要從執行檔中把金鑰找出來,再照著執行檔啟動時自己做的解密步驟重做一次即可。已經有公開工具在自動化做這件事。RC4 系列密碼本身就被認為強度不足(因此在 TLS 中被禁用),但就算換成強度更高的密碼,只要金鑰和密文放在一起,一樣防不住任何人——沒有任何密碼演算法能在金鑰隨貨附送的情況下保護資料。
如果你的指令碼裡有真正的機密——API 權杖、資料庫密碼、私鑰——shc 藏不住這些東西,藏不過任何有心人。它頂多能擋住那種純粹出於好奇、打開文字編輯器看一眼的人,門檻低得多。
5. 什麼時候該用 SHC,什麼時候不該
如果目的是防止別人隨手檢視或修改指令碼,shc 是合理的選擇:把內部工具發給不懂技術、可能手癢想「調整」一下的使用者,或者需要交付的東西看起來、用起來都得像個執行檔,而不是一眼就看得出可以編輯的指令碼。任何要離開建置機器的執行檔都該搭配 -r;過期日期參數則只該當成展示用的小功能,不要當成存取控制手段——使用者調整系統時間的難度,並不會比把金鑰取出來高多少。
但只要真正的需求是要防範有能力的攻擊者,shc 就是用錯工具了。那種需求該交給真正的機密管理機制——部署時注入的環境變數、機密管理系統,或是指令碼執行機器上的檔案權限與存取控制——而不是交給一支自己隨身帶著鑰匙的指令碼。