當前位置:
首頁 > 新聞 > 加密101系列:如何構建自己的解密工具

加密101系列:如何構建自己的解密工具

本篇是加密101系列的最後一篇,將介紹Princess Locker解密工具的源代碼。學習這篇文章,可以通過了解解密工具的工作原理和代碼來創建自己的解密工具。

代碼

先總體看一下程序中的所有函數,看看這些函數的功能以及如何配合使用。然後再詳細分析。

該工具的全部源碼如下:Princess Locker解密工具源代碼。研究人員強烈推薦在閱讀本文的時候在另一個窗口打開全部的源碼,文章與源碼對應,效果更佳。

首先看一下main.cpp文件:

#define CHARSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

還記得Princess的RNG部分嗎?生成的隨機數會被用於查找字元串中字母的索引。如果生成的隨機數是38,那麼就在受害者ID字元串中加一個字母c,因為c在數組中第38的位置。這就是CHARSET的定義和用途。

下面是一些比較重要的函數:

·find_key

·dump_key

·check_key

·find_start_seed

·find_seed

·find_key_seed

·find_uid_seed

·make_key

還有一些沒有提到的函數,這些函數要麼與加密或密鑰搜索沒有直接相關,要麼是自解釋的函數。比如,read_buffer就是幫助從文件中讀取緩存的函數。

·find_key – 用seed值遞增地生成密鑰,解密文件,檢查原始文件

·dump_key – 將密鑰寫入文件

·check_key – 用可能的密鑰,解密文件,與原始版本進行比對

·find_start_seed – 封裝函數,調用其他函數找到用作UID或ext的seed值;

·find_seed – 遞增的測試seed,產生隨機字元串來驗證UID

·find_key_seed – 未使用,NOT USED, find_seed的封裝

·find_uid_seed – find_seed的封裝,設置isKey參數為false

以上函數中, find_seed和find_key完成工作的主要部分。

Main函數

下面看一下wmain()函數和其他的邏輯細節。

看一下 314行, printf(「Searching the key…「);

圖中的所有都是輸入檢查,來確保提供的輸入值是合適的。

Main函數剩下的部分:

下一行是DWORD init_seed = time(NULL),這是獲取當前時間的函數。這也是第一個測試的seed。當前時間是隨機數生成器(RNG)的一個seed,所以我們用當前時間來測試密鑰的生成。

do {

DWORD uid_seed = find_start_seed(unique_id, extension, init_seed);

key = find_key(filename1, filename2, check_size, uid_seed, limit);

init_seed = uid_seed - 1;

} while (!key);

然後我們發現find_start_seed函數被調用了。其中的參數unique_id, extension, init_seed順序如下:ransom note ID 或NULL,如果不使用的話就是NULL。

隨著loop遞進,init_seed會遞減,因為必須在Princess感染髮生時找到第二個值。一共有三個不同的第二個值用來生成RNG seed,分別是擴展,UID和AES密鑰密碼。一旦找到其中的一個值,就很容易找到其他兩個。

下面看一下find_start_seed的細節,假設從勒索note中得到的UID如圖所示:

第一個調用是在find_uid_seed(),這是find_seed()的封裝函數。傳遞的false的布爾變數說明查找的UID只是遞減的。這是因為我們以當前時間開始,所以很明顯,感染是在過去發生的。find_uid_seed函數的結果就是seed值。大家注意UID變數的if,因為ransom ID不是必須的,這裡將結果變得更準確了。如果有人的UID並不是ransom ID,那麼就會用文件擴展名來解密。

因為UID是感染過程中RNG seed的一部分,隨機文件類型是另一個,AES密碼是第三個。所以,有了文件擴展或者UID就可以找出AES密碼seed了。如果有其中的兩個因素,就更加確認。

下面看一下擴展部分:

if (uid) {

ext_seed = find_uid_seed(ext, uid_seed, true);

}

else

{

ext_seed = find_uid_seed(ext, seed, false);

}

如果UID傳遞過來了,那就說明我們找到了UID的seed值。如果是這樣就可以用seed值作為尋找擴展seed的入口。在Princess Locker的分析中,發現UID是第一個seed然後會生成擴展RNG。

我們首先通過UID seed時間去找擴展seed時間。如果UID不是用戶提供的,就可以看到調用的false變數傳遞,seed就是當前時間的seed,也就是說在我們找到與擴展匹配的seed之前都需要進行回退。

if (uid && ext_seed - uid_seed > 100) {

printf("[WARNING] Inconsistency detected!
");

}

在找到UID seed時間和擴展seed後,進行最後的檢查,並確保差生小於100的。原因是因為在Princess Locker執行時,會生成UID seed,然後再很短的一個代碼流後,就會生成擴展seed。如果這兩個的時間超過100秒,就會發生一些奇怪的事情。

DWORD find_uid_seed(wchar_t* uid, DWORD start_seed, bool increment = true)

{

return find_seed(uid, start_seed, increment, false);

}

find_uid_seed只是sind_seed的封裝函數,sind_seed是seed搜索的主要代碼。

在變數初始化完成後,我們看一下loop的內容:

while (true) {

srand(seed);

一般在loop中勒索軟體會重新創建生成隨機數。這就是為什麼用srand(seed)開始,seed就是傳遞的時間。這也決定了用rand調用後的序列數。

在我們建立的loop中,用隨機數作為字符集的索引。如果生成的數字與用戶提供的UID不匹配,就說明seed不準確,那麼時間就遞減,並再次嘗試。

如果被調用來找ext擴展的函數在之前的調用中找到了UID,seed時間就會遞增。下面的圖解釋了在不同的時間和階段有遞增和遞減。

開始的階段會決定傳遞給find_seed函數的是true還是false,也決定了是時間遞增還是遞減。

主函數

我們了解了find seed函數的細節後,下面看一下回到find_start_seed再回到主函數。

find_start_seed是一系列loop,在調用後會找到一個工作的seed值。如果ransom ID和ext擴展都提供了,就會返回UID seed,UID seed的時間和AES密碼seed的時間很接近。

如果不提供UID,就會返回找到的ext擴展的seed。從時間上看,UID seed時間是在AES seed時間之後的。也就是說需要在loop中做一些事情:

·Seed值遞減1;

·用隨機seed生成AES密碼;

·加密和解密測試文件;

·與已有的純凈版的文件做檢查比對。

下面看一下find_key函數和上面的步驟:

wchar_t* find_key(IN wchar_t *filename1, IN wchar_t *filename2, size_t check_size, DWORD uid_seed, DWORD limit=100)

下面看一下第234行的代碼:

在ransom note ID生成的時候設定key_seed變數,發現find_start_seed也被傳入find_key函數中。

do {

key = make_key(MAX_KEY, key_seed, true);

找key的loop中第一行就是調用make_key。因為這和生成UID和ext是一樣的,所以這裡不再詳細描述。只是用字符集字元串中的索引來做seed並生成一個隨機大小的ransom note ID字元串。

下面是創建AES密鑰密碼和進行哈希操作的loop,這也正是Princess Locker做的。它本身並不會使用隨機生成的密碼,而是創建一個隨機的字元串,然後用sha256哈希,用哈希值作為最終的密鑰。最後,解密檢查key。

for (key_len = MIN_KEY; key_len

if (check_key(in_buf, expected_buf, check_size, key, key_len)) {

printf("
Match found, accuracy %d/%d
", check_size, BLOCK_LEN);

key[key_len] = 0;

found = true;

break;

}

}

check_key函數會執行下面的操作:

aes_decrypt(inbuf, outbuf, BLOCK_LEN, key_str, key_len)

用測試的隨機生成的密碼來創建AES加密,查看是否正常工作。

這個過程中可能有幾個爭議問題。比如,為什麼浪費時間來檢查其他的RNG?為什麼要找ext擴展和UID seed,什麼時候可以測試seed與測試的AES解密是否匹配?

理論上我們可以做,但是將字元串與下面列出的進行比較要更快一點:

·生成隨機字元串;

·對字元串進行哈希;

·創建AES密鑰;

·加密數據;

·與源文件比對。

這個過程就偏計算一些,而且會讓UID搜索時間變長。

因為AES key是在Princess Locker執行過程中生成的,ransom ID是在ransom note ID(UID)找到後馬上生成的,這兩個seed之間的時間差應該很短。所以,loop只需要執行一些加密檢查就可以了。

在完成find key函數後,我們可以做一些基本的檢查,確保找到正確的key。如果沒有找到正確的key,就需要繼續loop並且遞減計數器。

下面看一下main函數的最後一部分,320行:

如果在有限的集合里沒有找到正確的AES密碼,就是說UID的seed時間是不正確的。這個過程會繼續直到找到正確的UID seed為止。

結論

加密101系列為大家介紹了勒索軟體加密過程的漏洞,並講解了如何利用這些漏洞進行解密工具的開發。如果讀者了解了這些,那麼也很容易就可以創建一個新的勒索軟體。

而其中最難的部分就是核心概念。我們看到了常見的一些概念和技術以一種不常見的方式出現,最終也理解了這些底層的技術。最重要的是理解這些概念,然後識別和創建自己的漏洞利用過程,這樣就可以破解勒索軟體的加密過程。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

Windows Defender應用程序控制介紹
累覺不愛 Mac App Store 上竟然也有偷偷奴役你電腦挖礦的應用

TAG:嘶吼RoarTalk |