新聞中心
本篇是加密101系列的***一篇,將介紹Princess Locker解密工具的源代碼。學(xué)習(xí)這篇文章,可以通過了解解密工具的工作原理和代碼來創(chuàng)建自己的解密工具。

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、重慶小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了常寧免費(fèi)建站歡迎大家使用!
代碼
先總體看一下程序中的所有函數(shù),看看這些函數(shù)的功能以及如何配合使用。然后再詳細(xì)分析。
該工具的全部源碼如下:Princess Locker解密工具源代碼。研究人員強(qiáng)烈推薦在閱讀本文的時候在另一個窗口打開全部的源碼,文章與源碼對應(yīng),效果更佳。
首先看一下main.cpp文件:
- #define CHARSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
還記得Princess的RNG部分嗎?生成的隨機(jī)數(shù)會被用于查找字符串中字母的索引。如果生成的隨機(jī)數(shù)是38,那么就在受害者ID字符串中加一個字母c,因為c在數(shù)組中第38的位置。這就是CHARSET的定義和用途。
下面是一些比較重要的函數(shù):
- find_key
- dump_key
- check_key
- find_start_seed
- find_seed
- find_key_seed
- find_uid_seed
- make_key
還有一些沒有提到的函數(shù),這些函數(shù)要么與加密或密鑰搜索沒有直接相關(guān),要么是自解釋的函數(shù)。比如,read_buffer就是幫助從文件中讀取緩存的函數(shù)。
- find_key – 用seed值遞增地生成密鑰,解密文件,檢查原始文件
- dump_key – 將密鑰寫入文件
- check_key – 用可能的密鑰,解密文件,與原始版本進(jìn)行比對
- find_start_seed – 封裝函數(shù),調(diào)用其他函數(shù)找到用作UID或ext的seed值;
- find_seed – 遞增的測試seed,產(chǎn)生隨機(jī)字符串來驗證UID
- find_key_seed – 未使用,NOT USED, find_seed的封裝
- find_uid_seed – find_seed的封裝,設(shè)置isKey參數(shù)為false
以上函數(shù)中, find_seed和find_key完成工作的主要部分。
Main函數(shù)
下面看一下wmain()函數(shù)和其他的邏輯細(xì)節(jié)。
看一下 314行, printf(“Searching the key…“);
圖中的所有都是輸入檢查,來確保提供的輸入值是合適的。
Main函數(shù)剩下的部分:
下一行是DWORD init_seed = time(NULL),這是獲取當(dāng)前時間的函數(shù)。這也是***個測試的seed。當(dāng)前時間是隨機(jī)數(shù)生成器(RNG)的一個seed,所以我們用當(dāng)前時間來測試密鑰的生成。
- 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);
然后我們發(fā)現(xiàn)find_start_seed函數(shù)被調(diào)用了。其中的參數(shù)unique_id, extension, init_seed順序如下:ransom note ID 或NULL,如果不使用的話就是NULL。
隨著loop遞進(jìn),init_seed會遞減,因為必須在Princess感染發(fā)生時找到第二個值。一共有三個不同的第二個值用來生成RNG seed,分別是擴(kuò)展,UID和AES密鑰密碼。一旦找到其中的一個值,就很容易找到其他兩個。
下面看一下find_start_seed的細(xì)節(jié),假設(shè)從勒索note中得到的UID如圖所示:
***個調(diào)用是在find_uid_seed(),這是find_seed()的封裝函數(shù)。傳遞的false的布爾變量說明查找的UID只是遞減的。這是因為我們以當(dāng)前時間開始,所以很明顯,感染是在過去發(fā)生的。find_uid_seed函數(shù)的結(jié)果就是seed值。大家注意UID變量的if,因為ransom ID不是必須的,這里將結(jié)果變得更準(zhǔn)確了。如果有人的UID并不是ransom ID,那么就會用文件擴(kuò)展名來解密。
因為UID是感染過程中RNG seed的一部分,隨機(jī)文件類型是另一個,AES密碼是第三個。所以,有了文件擴(kuò)展或者UID就可以找出AES密碼seed了。如果有其中的兩個因素,就更加確認(rèn)。
下面看一下擴(kuò)展部分:
- if (uid)
- {
- ext_seed = find_uid_seed(ext, uid_seed, true);
- }
- else
- {
- ext_seed = find_uid_seed(ext, seed, false);
- }
如果UID傳遞過來了,那就說明我們找到了UID的seed值。如果是這樣就可以用seed值作為尋找擴(kuò)展seed的入口。在Princess Locker的分析中,發(fā)現(xiàn)UID是***個seed然后會生成擴(kuò)展RNG。
我們首先通過UID seed時間去找擴(kuò)展seed時間。如果UID不是用戶提供的,就可以看到調(diào)用的false變量傳遞,seed就是當(dāng)前時間的seed,也就是說在我們找到與擴(kuò)展匹配的seed之前都需要進(jìn)行回退。
- if (uid && ext_seed - uid_seed > 100) {
- printf("[WARNING] Inconsistency detected!\n");
- }
在找到UID seed時間和擴(kuò)展seed后,進(jìn)行***的檢查,并確保差生小于100的。原因是因為在Princess Locker執(zhí)行時,會生成UID seed,然后再很短的一個代碼流后,就會生成擴(kuò)展seed。如果這兩個的時間超過100秒,就會發(fā)生一些奇怪的事情。
- 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的封裝函數(shù),sind_seed是seed搜索的主要代碼。
在變量初始化完成后,我們看一下loop的內(nèi)容:
- while (true) {
- srand(seed);
一般在loop中勒索軟件會重新創(chuàng)建生成隨機(jī)數(shù)。這就是為什么用srand(seed)開始,seed就是傳遞的時間。這也決定了用rand調(diào)用后的序列數(shù)。
在我們建立的loop中,用隨機(jī)數(shù)作為字符集的索引。如果生成的數(shù)字與用戶提供的UID不匹配,就說明seed不準(zhǔn)確,那么時間就遞減,并再次嘗試。
如果被調(diào)用來找ext擴(kuò)展的函數(shù)在之前的調(diào)用中找到了UID,seed時間就會遞增。下面的圖解釋了在不同的時間和階段有遞增和遞減。
開始的階段會決定傳遞給find_seed函數(shù)的是true還是false,也決定了是時間遞增還是遞減。
主函數(shù)
我們了解了find seed函數(shù)的細(xì)節(jié)后,下面看一下回到find_start_seed再回到主函數(shù)。
find_start_seed是一系列l(wèi)oop,在調(diào)用后會找到一個工作的seed值。如果ransom ID和ext擴(kuò)展都提供了,就會返回UID seed,UID seed的時間和AES密碼seed的時間很接近。
如果不提供UID,就會返回找到的ext擴(kuò)展的seed。從時間上看,UID seed時間是在AES seed時間之后的。也就是說需要在loop中做一些事情:
- Seed值遞減1;
- 用隨機(jī)seed生成AES密碼;
- 加密和解密測試文件;
- 與已有的純凈版的文件做檢查比對。
下面看一下find_key函數(shù)和上面的步驟:
- 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生成的時候設(shè)定key_seed變量,發(fā)現(xiàn)find_start_seed也被傳入find_key函數(shù)中。
- do {
- key = make_key(MAX_KEY, key_seed, true);
找key的loop中***行就是調(diào)用make_key。因為這和生成UID和ext是一樣的,所以這里不再詳細(xì)描述。只是用字符集字符串中的索引來做seed并生成一個隨機(jī)大小的ransom note ID字符串。
下面是創(chuàng)建AES密鑰密碼和進(jìn)行哈希操作的loop,這也正是Princess Locker做的。它本身并不會使用隨機(jī)生成的密碼,而是創(chuàng)建一個隨機(jī)的字符串,然后用sha256哈希,用哈希值作為最終的密鑰。***,解密檢查key。
- for (key_len = MIN_KEY; key_len <= MAX_KEY; key_len++) {
- if (check_key(in_buf, expected_buf, check_size, key, key_len)) {
- printf("\nMatch found, accuracy %d/%d\n", check_size, BLOCK_LEN);
- key[key_len] = 0;
- found = true;
- break;
- }
- }
check_key函數(shù)會執(zhí)行下面的操作:
- aes_decrypt(inbuf, outbuf, BLOCK_LEN, key_str, key_len)
用測試的隨機(jī)生成的密碼來創(chuàng)建AES加密,查看是否正常工作。
這個過程中可能有幾個爭議問題。比如,為什么浪費(fèi)時間來檢查其他的RNG?為什么要找ext擴(kuò)展和UID seed,什么時候可以測試seed與測試的AES解密是否匹配?
理論上我們可以做,但是將字符串與下面列出的進(jìn)行比較要更快一點(diǎn):
- 生成隨機(jī)字符串;
- 對字符串進(jìn)行哈希; 創(chuàng)建AES密鑰;
- 加密數(shù)據(jù);
- 與源文件比對。
這個過程就偏計算一些,而且會讓UID搜索時間變長。
因為AES key是在Princess Locker執(zhí)行過程中生成的,ransom ID是在ransom note ID(UID)找到后馬上生成的,這兩個seed之間的時間差應(yīng)該很短。所以,loop只需要執(zhí)行一些加密檢查就可以了。
在完成find key函數(shù)后,我們可以做一些基本的檢查,確保找到正確的key。如果沒有找到正確的key,就需要繼續(xù)loop并且遞減計數(shù)器。
下面看一下main函數(shù)的***一部分,320行:
加密101系列:如何構(gòu)建自己的解密工具
如果在有限的集合里沒有找到正確的AES密碼,就是說UID的seed時間是不正確的。這個過程會繼續(xù)直到找到正確的UID seed為止。
結(jié)論
加密101系列為大家介紹了勒索軟件加密過程的漏洞,并講解了如何利用這些漏洞進(jìn)行解密工具的開發(fā)。如果讀者了解了這些,那么也很容易就可以創(chuàng)建一個新的勒索軟件。
而其中最難的部分就是核心概念。我們看到了常見的一些概念和技術(shù)以一種不常見的方式出現(xiàn),最終也理解了這些底層的技術(shù)。最重要的是理解這些概念,然后識別和創(chuàng)建自己的漏洞利用過程,這樣就可以破解勒索軟件的加密過程。
當(dāng)前題目:加密101系列:如何構(gòu)建自己的解密工具
URL網(wǎng)址:http://fisionsoft.com.cn/article/dpcddhh.html


咨詢
建站咨詢
