在 Tiny AES Library 好移植加密函式庫 文章裡提到客戶來洽談的合作方案,不只有加密的需求,而且還需要”透明式” (transparently) 的加密。什麼是透明式加密??以往我所知道的密碼方法,都是會先用一塊 Block device 當做一個 image,然後將它 mount 成一個 folder,往裡面存取的檔案最終就會被加密的存在 image 內,下次 mount device 時就需要密碼才行。像是我用過的 dmcrypt 就是這種。
而 transparent 的方式則是針對個別檔案(當然針對檔案就可以處理整個 disk,透過攔截標準的 FILE IO 的方式,在做操作時進行加解密(其實也是我猜的,跟客戶還沒談到這麼細)。這個方式比較通用,不需要 root 權限,檔名也都可以辨識,但內容是看不到的。這用在一些網路硬碟 (ex. Google driver or dropbox),也可以有效保護隱私。當然,檔名被看到就好像不是這麼安全,這也算是一種選擇吧。
總之,這個覆寫 function 的東西對我很新奇。實驗了一下,就順便記下來了。
原理
完整的測試包附在檔尾,以下說明程式碼。其主要是先透過 Linux 的 LD_PRELOAD 變數先預載要覆寫的function, 在載入程式進行FILE IO時,就會先使用自己的 FILE IO,使用完再呼叫 LIBC 的 IO。這邊的例子是覆寫 sleep(),換成 fopen 或 open 都可以。
Makefile
1 2 3 4 5 6 7 8 |
all: gcc mysleep.c -shared -o libmysleep.so -ldl gcc mysleep_try.c -o mysleep_try echo "Run 'make run' to try it" run: echo "Without libmysleep.so" && ./mysleep_try echo "With libmysleep.so" && LD_PRELOAD=./libmysleep.so ./mysleep_try |
行2: mysleep.c 是實作自己的 sleep() 原始檔,將其編成 .so 以便稍後載入。自定的sleep() 執行到時會印出一些訊息
行3: mysleep_try.c 是簡單的 sleep() 程式,睡的前後會印出訊息。
行7~8: 在行7先執行無覆載的 mysleep_try 程式,會看到單純的sleep訊息。行8則是會先載入 libmysleep.so,因此在執行myslep_try時會多印出一些訊息
mysleep.c – 自定的 sleep()
1 2 3 4 5 6 7 8 9 10 11 |
#include <stdio.h> #include <stdlib.h> #define __USE_GNU #include <dlfcn.h> void sleep(int sec) { printf("Hello . My sleep.Done. do libc sleep\n"); int (*sleep_real)(int sec) = NULL; sleep_real = dlsym(RTLD_NEXT, "sleep"); sleep_real(sec); } |
行3~4: include 後面 RTLD_NEXT 的 header
行7: 呼叫自定 sleep() 時,印出個訊息
行8: 宣告 libc sleep() 的 function pointer,稍後會取得 libc sleep() 的 pointer
行9: 在已載入的所有 library 內,尋找下一個 symbol 為 sleep 的 function,也就是原本 libc 的 sleep
行10: 呼叫原本libc的 sleep
mysleep_try.c – 單純的呼叫 sleep
1 2 3 4 5 6 7 8 9 |
#include <stdio.h> #include <math.h> int main() { printf("before Sleep 5 sec\n"); sleep(5); printf("Done Sleep 5 sec\n"); return 0; } |
行6: 此處呼叫的 sleep,就看當時是否有透過 LD_PRELOAD 載入 libmysleep.so。若有,則先呼叫自定的,再呼叫libc。無的話,則只呼叫libc。
結語
這個攔截 LIBC function 還蠻有趣的 (可怕?),透過攔截就可以先做一些加密或壓縮的處理。當然,想的壞一點,就可以做一些側錄,放毒的事…
開始跟不同領域的人接觸後,才知道 Linux 有多廣泛,要學的東西還很多啊~~~