開發(fā)筆記:如何對【動態(tài)鏈接庫】文件進行加密保護?
問題描述
昨天,因產(chǎn)品需求,需要在Windows操作系統(tǒng)下寫一個小工具。
這個小工具中調(diào)用一個比較重要的DLL動態(tài)庫文件,來完成一些重要的功能。
一般來說,最直接的做法就是調(diào)用Win32 API函數(shù),來動態(tài)的加載、獲取函數(shù)地址、釋放:
- LoadLibrary(...);
- GetProcAddress(...);
- FreeLibrary(...);
但是,由于這個動態(tài)庫比較重要,如果直接把DLL文件放在文件目錄中,就增加了文件被反編譯的風(fēng)險。
也就是說為了提高DLL文件的安全性,最好不要讓用戶看到/拿到文件;
即使拿到了文件,也不要讓用戶很容易的破解文件。
問題解決
關(guān)于分析過程就不多說了,這里直接給出目前的處理方式:
1.寫一個小工具軟件,對 DLL 文件進行加密
使用了AES對稱加密算法,主要是為了管理秘鑰簡單。

加密后的文件liba_enc.png與可執(zhí)行文件放在一起。
此時,如果用戶獲取到了這個動態(tài)庫,由于沒有秘鑰,理論上是無法解開這個文件的。
不過,道高一尺魔高一丈。。。
2.修改應(yīng)用程序,對加密的 DLL 文件進行解密
這個動態(tài)庫最終肯定是要被加載到應(yīng)用程序的內(nèi)存空間中被使用的,因此在被加載之前,需要被使用者(也就是應(yīng)用程序)解密。
那么,應(yīng)該解密到哪里呢?
用來加載動態(tài)庫的API?函數(shù)LoadLibrary(),需要的參數(shù)是文件的路徑。
也就是說:必須要把一個動態(tài)庫文件的路徑傳遞給該函數(shù),才可以被正確的加載到內(nèi)存中。
假如是在Linux?系統(tǒng)中,可以解壓到/tmp臨時文件系統(tǒng)中。
在動態(tài)庫使用期間文件一直存在;一旦使用結(jié)束就立刻刪除掉。
但是在Windows系統(tǒng)中沒有臨時文件系統(tǒng)之說。
即使存在類似的臨時文件空間,即使該DLL文件的使用周期非常短,仍然存在暴露給用戶的可能性。
只要用戶有機會能夠看到這個解密后的文件,就有方法把它dump出來,然后進行反編譯...

3.把加密的 DLL 文件解密到內(nèi)存緩沖區(qū)中
目前,能想到的最好的方法就是:先把加密的DLL?文件解壓到一塊空閑的內(nèi)存緩沖區(qū)中(比如:從堆空間中malloc出來的一塊空間),然后再按照動態(tài)庫的加載流程從這塊緩沖區(qū)中讀取字節(jié)流,加載到動態(tài)庫所屬的代碼空間中。
剛才說過,LoadLibrary(...)函數(shù)只能接受文件路徑作為參數(shù),我們不能把緩沖區(qū)的首地址傳給它,因此需要使用其它方式來加載。
剛好,在github?上看到這樣一個開源C代碼:

圖中描述的功能正是我所需要的,簡直是量身定做:
- 先把 DLL 文件讀取到一個緩沖區(qū)中;
- 再從緩沖區(qū)中加載動態(tài)庫的內(nèi)容;
只需要一個頭文件MemoryModule.h?和一個C?文件:MemoryModule.c,提供的函數(shù)也足夠簡單:
HMEMORYMODULE MemoryLoadLibrary(const void *, size_t);
FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR);
void MemoryFreeLibrary(HMEMORYMODULE);
與Win32?提供的3個函數(shù)在語義上是對應(yīng)的,唯一的區(qū)別是加載函數(shù)傳入的參數(shù)是:緩沖區(qū)的地址和長度。
經(jīng)過測試證明:這個方法工作的很好,很完美的解決了我的問題!
4. Linux 操作系統(tǒng)怎么辦?
因為目前我只在Windows平臺上有這個需求,這個方法相當(dāng)于重寫了一套動態(tài)庫加載函數(shù)。
那么,在Linux系統(tǒng)上如果也存在類似的需求,是否也有類似的:從內(nèi)存緩沖區(qū)加載動態(tài)庫的實現(xiàn)?
我目前還沒有發(fā)現(xiàn)類似的代碼,如果您知道的話,不妨在留言中分享一下?灰常感謝!



























