Ransomware Locky Analysis
Locky的變種非常的多,這個(gè)樣本來(lái)自下面的Url,是最新的一種變種。?
這是程序在剛開(kāi)始執(zhí)行時(shí)與釋放了Image并替換了之后的對(duì)比,很明顯發(fā)生了進(jìn)程替換,因此進(jìn)行分析之前有必要把它內(nèi)部釋放出來(lái)的image提取出來(lái),分析這個(gè)image才能搞清楚它是如何做加密的。
?
?Locky存在一個(gè)未知的殼,IDA并不能檢測(cè)出這個(gè)殼,因?yàn)樗膶?dǎo)入表等信息并沒(méi)有被破壞。它在運(yùn)行起來(lái)后
,執(zhí)行相當(dāng)大量的垃圾代碼干擾調(diào)試,依據(jù)是在調(diào)試的過(guò)程中它進(jìn)行相當(dāng)多的寄存器操作但6個(gè)通用寄存器的值始終是0。
這這些垃圾代碼中隱藏著它獲取Kernel32.dll的Addr的邏輯,它會(huì)獲取Kernel32的BaseAddress并通過(guò)偏移計(jì)算出API的地址。
它會(huì)調(diào)用VirtualAlloc分配一塊可寫可執(zhí)行的內(nèi)存塊,大小是61BB,可執(zhí)行意味著會(huì)釋放代碼到這塊內(nèi)存區(qū)中,應(yīng)該著重分析。(0x404587)
TextSegment中存在一部分未被IDA識(shí)別的func,位置在(0x402940)。這部分代碼的作用是將一些數(shù)據(jù)(在TextSegment中)釋放到剛才通過(guò)VirtualAlloc分配的內(nèi)存中去。
GenerateShellCodes(PVOID?lpShellCodes,?BYTE* pDataInTextSegment,?DWORD?dwLen,?DWORD?dwHEX);
其中bl寄存器用來(lái)作為臨時(shí)存儲(chǔ)一個(gè)字節(jié)的寄存器,ebx寄存器用作計(jì)數(shù)器,它從函數(shù)參數(shù)中獲得Data的Length,然后遞減,如果等于0就跳出循環(huán),esi是指向VirtualAlloc返回的內(nèi)存地址。處理完畢后,會(huì)在指定的位置寫入一堆數(shù)據(jù),這些數(shù)據(jù)還需要進(jìn)行異或處理才能變成真正可以被執(zhí)行的代碼。
以下是沒(méi)有被處理的數(shù)據(jù),只是單純的填充了緩沖區(qū)。
它的解這部分Code的算法如下:
其中dwHEX是這個(gè)處理函數(shù)的第四個(gè)參數(shù)。解完了以后的數(shù)據(jù)如下:
下面已經(jīng)完成了部分ShellCodes的釋放,接下來(lái)將跳轉(zhuǎn)到ShellCode去執(zhí)行代碼。
這段ShellCode的目的釋放一個(gè)被壓縮的PE文件,并加載這個(gè)PE文件,整個(gè)過(guò)程沒(méi)有釋放任何文件出來(lái),無(wú)法被監(jiān)控軟件發(fā)現(xiàn),釋放PE文件使用了非常精巧的方式加載到當(dāng)前進(jìn)程中,并完成了進(jìn)程替換。
被釋放的ShellCode本身還有很多代碼沒(méi)有釋放出來(lái),在ShellCode的Offset=247處有一個(gè)func用于釋放ShellCode中的代碼(釋放不太嚴(yán)謹(jǐn),應(yīng)該是通過(guò)一些異或操作把原來(lái)不是代碼的數(shù)據(jù)轉(zhuǎn)換成代碼)。
這個(gè)操作會(huì)將ShellCode頭部的一些代碼釋放出來(lái)。在后面經(jīng)過(guò)調(diào)試發(fā)現(xiàn),這個(gè)func會(huì)被反復(fù)的多次調(diào)用,用于釋放存在ShellCode中的數(shù)據(jù)(轉(zhuǎn)換成可以被執(zhí)行的CPU代碼)。因此這里應(yīng)該是釋放ShellCode自身代碼的邏輯。
sub_1D1020用來(lái)獲得Kernel32的BaseAddr:
GetModuleHandle
?
?
再被釋放的ShellCode+1020處有一個(gè)Func(SC_GetModuleAddr)它用來(lái)根據(jù)傳入的HardCode得到對(duì)應(yīng)的Module的基地址,例如Kernel32.dll Advapi32.dll等。
LPVOID SC_GetModuleAddr(DWORD dwHEX);
對(duì)應(yīng)的在ShellCode+1122處有一個(gè)Func(SC_GetFuncAddr)它用來(lái)根據(jù)傳入的HardCode得到對(duì)應(yīng)的func的基地址,例如Kernel32的GetProcAddress等。
PFUNC?SC_GetFuncAddr(DWORD?dwHEX,?LPVOID?lpModuleBaseAddr);
如下圖:
ShellCode會(huì)調(diào)用這段代碼GetProcAddress,并傳入Module的基地址以及要獲取的函數(shù)名。這里函數(shù)的名字被嵌入到了ShellCode中,被解釋稱代碼了,需要重新解析成字符串。注冊(cè)服務(wù),隱藏自己的行為。
后面的邏輯大致符合如下描述:
例如:用同樣的方法獲得了EnumServicesStatusExA的函數(shù)地址。
這里調(diào)用GlobalAlloc(ShellCode+001D0686)在堆上分配內(nèi)存分配的內(nèi)存用0初始化,大小是0x4214。(可能是一個(gè)結(jié)構(gòu))因?yàn)楸会尫诺袅恕?/p>
這里又使用API分配了一塊內(nèi)存,大小是1799C。頁(yè)屬性是可讀寫不可執(zhí)行。這個(gè)函數(shù)的參數(shù)很值得注意,居然是當(dāng)前進(jìn)程的基地址。
這里從當(dāng)前的進(jìn)程中釋放了一堆壓縮數(shù)據(jù)到剛才分配的內(nèi)存中,然后又繼續(xù)調(diào)用VirtualAlloc分配了一塊大小1AE00的內(nèi)存,頁(yè)屬性依然是可讀寫不可以執(zhí)行,這塊內(nèi)存用于解壓縮剛才釋放的壓縮數(shù)據(jù)。
程序接下來(lái)調(diào)用了RtlDecompressBuffer這個(gè)Undocument的API。用于釋放壓縮的數(shù)據(jù)到指定的Buffer中。釋放出來(lái)的文件是一個(gè)PE Image。(ShellCode+318E)
把這個(gè)PE dump出來(lái)之后可以從導(dǎo)入表中發(fā)現(xiàn)一堆Crypt相關(guān)的API,它就是真正加密用戶數(shù)據(jù)的PE。
到這里后面的分析都與Ransomware沒(méi)有關(guān)系了,只要能拿到內(nèi)部的加密數(shù)據(jù)的文件進(jìn)行分析就可以了。下面是這段ShellCode作為加載器還有一些什么具體行為的分析。
這里釋放了壓縮數(shù)據(jù)所占用的內(nèi)存。
這里打開(kāi)了通過(guò)獲取當(dāng)前殼進(jìn)程的ImagePath,然后調(diào)用CreateFile打開(kāi)文件并計(jì)算文件的Size。
計(jì)算出來(lái)的文件大小是31000,然后調(diào)用VirtualAlloc分配相同大小的空間。下面是VirtualAlloc的參數(shù)。可讀可寫不可以執(zhí)行。
?
然后調(diào)用ReadFile從當(dāng)前Image的文件中讀取數(shù)據(jù),一次讀取完畢。
然后關(guān)閉文件。
現(xiàn)在內(nèi)存中有2份PE文件了,一份原始的殼的Image,還有一個(gè)被脫殼后真正做加密工作的Image。
上面是原始?xì)さ腜E數(shù)據(jù)
上面是被脫殼后的PE數(shù)據(jù)
判斷它最后會(huì)還原回去,不然沒(méi)有必要保存一份在內(nèi)存中。這樣可以不用釋放文件,監(jiān)控軟件監(jiān)控不到,非常精明的設(shè)計(jì)。
這里調(diào)用VirtualProtect來(lái)對(duì)0x400000位置的當(dāng)前Image設(shè)置可寫權(quán)限,要開(kāi)始覆蓋當(dāng)前的數(shù)據(jù)了。
開(kāi)始將Image的內(nèi)容清空:
然后從debug021:001D17E9開(kāi)始的一大段代碼用于填充新數(shù)據(jù)到當(dāng)前的Image中去。好大的一段代碼,因?yàn)閮?nèi)存中的PE的Offset與加載到內(nèi)存后的Offset不一樣,所以需要小心的分段加載PE數(shù)據(jù),這里的代碼類似一個(gè)進(jìn)程加載器。
寫完后的數(shù)據(jù)已經(jīng)與上面釋放出來(lái)的PE一樣了(對(duì)照0x200000地址數(shù)據(jù)),這里發(fā)生了進(jìn)程替換,它肯定還要找到新的PE的EntryPoint開(kāi)始新的調(diào)用。
調(diào)用RtlZeroMemory把釋放出來(lái)的在內(nèi)存中的做加密的PEImage擦除掉。
然后調(diào)用VirtualFree釋放掉內(nèi)存(清理現(xiàn)場(chǎng))。
?
現(xiàn)在調(diào)用VirtualProtect把在0x400000位置的新的PEImage頁(yè)屬性設(shè)為只讀。
PEHeader,第一個(gè)頁(yè)面。繼續(xù)設(shè)置代碼段為可執(zhí)行可讀。
到這里,新的PE已經(jīng)加載完畢了,應(yīng)該可以準(zhǔn)備執(zhí)行了。
這里會(huì)把一些API用到的都取出來(lái)保存在棧上,后面用。有一些,不過(guò)我最關(guān)注的是CreateThread,然后它會(huì)清理ShellCode,清理犯罪現(xiàn)場(chǎng)。通過(guò)使用下面的API調(diào)用。清理的過(guò)程分幾個(gè)階段,頭部的ShellCode還保留,只是把除了頭部以外的都清理成0.
可以看到從F6之后都是0了。
然后調(diào)用VirtualFree把這整段Code刪除掉。到這里ShellCode的使命已經(jīng)完成,簡(jiǎn)單來(lái)說(shuō)它的目的就是將內(nèi)部的一個(gè)PE釋放出來(lái),并替換當(dāng)前進(jìn)程,并把當(dāng)前進(jìn)程的數(shù)據(jù)緩存到內(nèi)存中。
然后,程序會(huì)執(zhí)行CreateThread,執(zhí)行新的PE代碼。
405152就是新的進(jìn)程的EntryPoint,可以通過(guò)對(duì)提取的PEImage的分析佐證。
至此,脫殼完成并且成功的分析到了這個(gè)殼的運(yùn)作機(jī)制。
=========================運(yùn)行測(cè)試==========================
這3個(gè)Sample的行為觀測(cè)很相似,但是從反匯編角度分析的話,技術(shù)在不斷的演進(jìn)。雖然都沒(méi)有檢測(cè)到殼的存在,但是在運(yùn)行的過(guò)程中會(huì)從代碼段或數(shù)據(jù)段釋放code出來(lái)執(zhí)行,也許有進(jìn)程替換。也懷疑有虛擬機(jī)檢查,因?yàn)槎紱](méi)有行為出現(xiàn)。
========================脫殼后分析========================
脫殼后的程序可以正常運(yùn)行,但是之前也講過(guò)即使在物理機(jī)器上也沒(méi)有跑出行為,所以進(jìn)一步分析原因,以及分析Locky的整體運(yùn)作方式。
這段程序的entrypoint據(jù)我判斷是手動(dòng)編寫的,非經(jīng)過(guò)編譯器產(chǎn)生。他在開(kāi)始調(diào)用C runtime的入口之前做了一些自定義的隱蔽工作,這并非編譯器的行為。它的詭異行為如下面所述:.reloc是一個(gè)配置塊,它的數(shù)據(jù)結(jié)構(gòu)用C來(lái)表述如下:
程序會(huì)根據(jù)這個(gè)結(jié)構(gòu)的信息做對(duì)應(yīng)的處理,例如如果選擇模仿svchost,它就會(huì)偽裝成svchost,如果選擇自動(dòng)啟動(dòng),就會(huì)在注冊(cè)表中注冊(cè)自己,如果選擇了地區(qū)保護(hù),就會(huì)只針對(duì)相應(yīng)的地區(qū)展開(kāi)攻擊,等待時(shí)間被用來(lái)隱蔽自身,不立即運(yùn)行。
?
其中有2個(gè)目前仍然可以ping通。這些IP地址在內(nèi)存中的位置,被它保存到了一個(gè)全局指針中。
?
| MEM_IMAGE
0x1000000 | Indicates that the memory pages within the region are mapped into the view of an image section. |
?
這個(gè)操作使得原始Image程序的main函數(shù)不會(huì)被進(jìn)入,反調(diào)試。
Jump2NewImage會(huì)跳轉(zhuǎn)到已經(jīng)解決了重定位問(wèn)題的新的在內(nèi)存中Image中,并開(kāi)始從pop這條指令開(kāi)始執(zhí)行,從下面圖可以看出指令是一致的。
這里已經(jīng)分析出了它實(shí)際會(huì)返回到調(diào)用指令的下一跳指令中,只不過(guò)不再是同一個(gè)內(nèi)存中的Image,解決這個(gè)問(wèn)題直接打掉patch就可以。如下圖:
將PerpareForRunInOtherImage打上Patch,這個(gè)func的目的是反調(diào)試,會(huì)堅(jiān)持程序斷點(diǎn),同時(shí)它會(huì)跳到一個(gè)內(nèi)存中的其它位置執(zhí)行相同的程序,同時(shí)調(diào)整重定向表,因此在這個(gè)函數(shù)內(nèi)部打patch沒(méi)用,因?yàn)橹囟ㄏ虮肀恍薷暮髸?huì)導(dǎo)致程序崩潰。
最簡(jiǎn)單的修改方法。現(xiàn)在,所有的障礙都已經(jīng)掃除可以調(diào)試并分析這個(gè)Sample了。
程序在進(jìn)入主函數(shù)之后,立即安裝一個(gè)頂級(jí)的未處理異常處理器,會(huì)在發(fā)生無(wú)法解決的異常后重新啟動(dòng)自己。
然后程序會(huì)把藏在上述中起迷惑作用的.reloc段中的4個(gè)Ip地址以及包含Ip地址的數(shù)據(jù)結(jié)構(gòu)取出來(lái),Ip地址會(huì)被放到一個(gè)vector中保存起來(lái)。
從上面的一張內(nèi)存截圖可以看到,IP地址是使用逗號(hào)分隔的。
查找逗號(hào)在String中。
加入全局的std::vector<std::string>中。
接下來(lái)它會(huì)檢查藏在.reloc中的數(shù)據(jù)結(jié)構(gòu)中的相應(yīng)的值。
它會(huì)避開(kāi)俄語(yǔ)區(qū)用戶,LABEL_21處有個(gè)function,調(diào)用它會(huì)先將當(dāng)前程序的File找到,然后移除所有屬性,隨后生成一個(gè)臨時(shí)目錄,將Image移動(dòng)過(guò)去,可能會(huì)失敗,會(huì)采用MOVEFILE_DELAY_UNTIL_REBOOT來(lái)調(diào)用MoveFileEx標(biāo)記為重啟刪除。緊接著構(gòu)造一個(gè)“cmd.exe /C del /Q /F”串并把原路徑文件加入到這個(gè)串的后面,調(diào)用CreateProcess來(lái)刪除文件,最后退出程序。
接下來(lái)會(huì)根據(jù)藏在.reloc中的數(shù)據(jù)然后根據(jù)數(shù)值去等待,目前等待的時(shí)間超過(guò)3天,這是我們無(wú)論如何都沒(méi)有跑出行為的原因。
這里打上patch,跳過(guò)這些邏輯,使得程序可以正常運(yùn)行,避免一些內(nèi)部邏輯導(dǎo)致的程序不運(yùn)作不能反映出真實(shí)行為。
接下來(lái)的代碼會(huì)通過(guò)”GetVolumeNameForVolumeMountPoint”API,根據(jù)Volume獲取一個(gè)GUID,然后對(duì)這個(gè)GUID進(jìn)行hash得到一個(gè)hash值,再通過(guò)這個(gè)hash值得到一個(gè)字符串并把它鏈接到HKLM\Software\{xxxxxxxxxxx}用于創(chuàng)建一個(gè)注冊(cè)表項(xiàng)。
緊接著它會(huì)用藏在.reloc中的數(shù)據(jù)結(jié)構(gòu)中的值判斷是否需要模仿svchost運(yùn)行,如果是它會(huì)將自己Copy到一個(gè)隨機(jī)目錄并重命名為svchost.exe,并通過(guò)CreateProcess重啟進(jìn)程并結(jié)束自己的當(dāng)前運(yùn)行。
接下來(lái)會(huì)先去獲取本地機(jī)器的信息,之前通過(guò)Volume的GUID算出的一個(gè)hash被用作機(jī)器信息的ID,這部分?jǐn)?shù)據(jù)會(huì)被提交到作者的服務(wù)器上面去。
“id=D2BCC112BD05308A&act=getkey&affid=3&lang=en&corp=0&serv=0&os=Windows+7&sp=1&x64=0”
然后用MD5對(duì)這部分?jǐn)?shù)據(jù)進(jìn)行hash:
程序接下來(lái)將系統(tǒng)信息的hash數(shù)據(jù)追加到系統(tǒng)信息的頭部,作者可以利用這個(gè)hash值校驗(yàn)數(shù)據(jù)一致性,然后通過(guò)一個(gè)循環(huán)移位加異或算法對(duì)這部分?jǐn)?shù)據(jù)加密,如下圖。
接下來(lái)它準(zhǔn)備要發(fā)送數(shù)據(jù)到作者的WebServer上面去,最開(kāi)始說(shuō)了作者在偽裝的.reloc中藏了一些配置信息,同時(shí)包含4個(gè)主機(jī)地址,在程序一開(kāi)始,這四個(gè)主機(jī)地址被加入了一個(gè)vector中,程序通過(guò)獲取一個(gè)隨機(jī)數(shù)字,并對(duì)存儲(chǔ)在vector中的ip_addrnum取余數(shù)來(lái)隨機(jī)選擇一個(gè)Ip地址用于訪問(wèn)。
它先構(gòu)建一個(gè)http地址:使用上面的信息創(chuàng)建一個(gè)http對(duì)象,然后設(shè)置一些參數(shù):
發(fā)送和接收的延遲設(shè)置為30000,重試次數(shù)1次。
這里發(fā)生了問(wèn)題,首先我可以連接到服務(wù)器,但是在向?qū)Ψ桨l(fā)送數(shù)據(jù)的時(shí)候,失敗了返回的HttpError 403 Forbidden:資源不可用。服務(wù)器理解客戶的請(qǐng)求,但拒絕處理它。通常由于服務(wù)器上文件或目錄的權(quán)限設(shè)置導(dǎo)致。所以這個(gè)sample因?yàn)闊o(wú)法將用戶信息上傳出去,陷入了一個(gè)軟件異常,不會(huì)繼續(xù)執(zhí)行加密操作。這里得想辦法讓他跳過(guò)這個(gè)發(fā)送的步驟直接去加密用戶數(shù)據(jù)。以下是嘗試發(fā)送的數(shù)據(jù),包含了用戶的SysInfo和一個(gè)用于校驗(yàn)的Hash被循環(huán)左移右移異或擾亂后的數(shù)據(jù)。
?
修改2處檢查點(diǎn),讓它不發(fā)送Crypt信息,直接開(kāi)始加密文件,但我判斷在發(fā)送了用戶的SysInfo后,服務(wù)器可能會(huì)計(jì)算一個(gè)PublicKey并通過(guò)網(wǎng)絡(luò)返回到本地,因?yàn)長(zhǎng)ocky如果請(qǐng)求不到網(wǎng)絡(luò)的話它不會(huì)做任何事情,因此判斷可能不存在Default的Key。
?
上面的判斷是正確的,因?yàn)樵谙旅娴姆治鲋?#xff0c;當(dāng)準(zhǔn)備開(kāi)始加密數(shù)據(jù)的時(shí)候,程序調(diào)用了一個(gè)API函數(shù):CryptImportKey,在這個(gè)函數(shù)的參數(shù)中送入了一個(gè)全局變量,通過(guò)IDA xref我可以看到這個(gè)全局變量既是服務(wù)器返回的數(shù)據(jù),因此可以判斷出程序使用用戶機(jī)器的相關(guān)信息計(jì)算出一個(gè)PublicKey,用這個(gè)Key對(duì)數(shù)據(jù)進(jìn)行加密(部分,或加密對(duì)稱加密的Key),因此這個(gè)API也許可以去Hook,然后替換一個(gè)自己的Key,用于日后解密。
?
我們打上Patch,讓他不發(fā)送用戶信息到服務(wù)器上面去,直接開(kāi)始加密文件,進(jìn)入到枚舉驅(qū)動(dòng)器資源的階段(我看過(guò)的所有Ransomware都有這個(gè)步驟),首先它會(huì)去枚舉網(wǎng)絡(luò)驅(qū)動(dòng)器,例如Nas,這里我們不管它,因?yàn)樵诿杜e網(wǎng)絡(luò)驅(qū)動(dòng)器的時(shí)候虛擬機(jī)調(diào)試會(huì)拋出異常,我也patch了。
?
枚舉到的所有網(wǎng)絡(luò)驅(qū)動(dòng)器資源它會(huì)先將它們放到一個(gè)vector<std::string>向量描述的鏈表中保存起來(lái)。
接下來(lái)會(huì)繼續(xù)枚舉本地磁盤驅(qū)動(dòng)器,下面會(huì)有一堆的判定條件是否要處理這個(gè)磁盤,首先會(huì)排除所有帶有remote屬性的,并且如果是可以拔插的如USB也不處理,如果磁盤的總大小低于A00000(1MB)跳過(guò),如果磁盤類型是Fixed、Removable以及Ramdisk都不處理,如果磁盤信息中包含的SystemFlags超過(guò)了19也不處理,邏輯如下:
程序?qū)⑺蟹弦蟮拇疟P依次加入vector中保存起來(lái),最后會(huì)返回這個(gè)vector(其實(shí)這是一個(gè)在棧上的vector,程序最后會(huì)將這個(gè)vector的內(nèi)容復(fù)制到作為入?yún)⒌耐獠縱ector中)。
?
當(dāng)準(zhǔn)備好所有的可以加密的驅(qū)動(dòng)器后,程序會(huì)針對(duì)每一個(gè)驅(qū)動(dòng)器啟動(dòng)一個(gè)線程來(lái)執(zhí)行加密工作,在線程加密的同時(shí),程序會(huì)刪除掉系統(tǒng)還原的影子盤,最后程序會(huì)block自己知道wait到了所有的線程執(zhí)行完畢的event。在這個(gè)進(jìn)入waiting之前,它會(huì)根據(jù).reloc中的配置選擇是不是要安裝自啟動(dòng)。這些操作都完畢后,主線程進(jìn)入wait狀態(tài)。
接著程序會(huì)進(jìn)入到線程中執(zhí)行,線程執(zhí)行的代碼是加密用戶數(shù)據(jù)。加密線程首先枚舉當(dāng)前驅(qū)動(dòng)器中的所有文件,并加入到vector中。這個(gè)過(guò)程中,篩選的文件會(huì)過(guò)濾掉一些指定的文件路徑,也會(huì)過(guò)濾掉不感興趣的后綴名文件。
過(guò)濾特定的文件路徑
過(guò)濾特定的后綴
?
Locky也是按照訪問(wèn)時(shí)間順序排序的,也就是說(shuō)最后被訪問(wèn)的文件最先被加密,不過(guò)它存在一個(gè)Bug,它會(huì)先找最后被訪問(wèn)的文件夾,比如在一個(gè)超大文件夾中有一個(gè)文件被修改了,那么這個(gè)文件夾的訪問(wèn)時(shí)間也會(huì)被修改,但是這個(gè)文件夾中其它的文件很長(zhǎng)一段時(shí)間都沒(méi)有被訪問(wèn),Locky會(huì)最先加密這個(gè)文件夾中size最小的文件,直到加密完整個(gè)文件夾,才去找下一個(gè)文件夾,如果下一個(gè)文件夾中所有的文件都是最近訪問(wèn)過(guò)的,它也會(huì)優(yōu)先加密只有一個(gè)文件是最后訪問(wèn)時(shí)間的文件夾,Locky沒(méi)有處理這種情況。
在我的機(jī)器中,它會(huì)優(yōu)先加密IDA文件夾。顯然Ransomware也存在如何精確定位有價(jià)值信息這個(gè)問(wèn)題。
接著,程序開(kāi)始將通過(guò)WebServer計(jì)算得到的對(duì)應(yīng)用戶SysInfo的PublicKey從內(nèi)存中取出來(lái),通過(guò)API:CryptImportKey來(lái)得到一個(gè)PublicKey對(duì)象。因?yàn)檫@里我們之前分析無(wú)法訪問(wèn)Locky作者的WebServer 403拒絕訪問(wèn)了,因此這里會(huì)丟出軟件異常,無(wú)法開(kāi)始加密數(shù)據(jù)。
這里的pbData是從全局對(duì)象中取出來(lái)的,因?yàn)檫@里沒(méi)有publickey,我需要構(gòu)造一個(gè)自己Key送進(jìn)去,讓他繼續(xù)工作,因此我生成了一個(gè)公私鑰對(duì)送了一個(gè)自己的PublicKey給程序。
PublicKey
?
這里程序初始化了一個(gè)內(nèi)部使用的CryptObject,它的數(shù)據(jù)結(jié)構(gòu)如下:
其中hKey是已經(jīng)導(dǎo)入的PublicKey的句柄,剩下的16個(gè)字節(jié)是對(duì)應(yīng)于用戶Machine的系統(tǒng)信息產(chǎn)生的Hash被用于用戶標(biāo)識(shí)。
初始化完CryptObject后,程序得到了PublicKey以及User的機(jī)器ID,將這個(gè)對(duì)象傳入EncryptFile開(kāi)始執(zhí)行加密工作。
加密函數(shù)除了Crypt對(duì)象外,還吃一個(gè)filename,來(lái)決定加密哪一個(gè)文件。
在內(nèi)部,程序會(huì)根據(jù)傳進(jìn)來(lái)的filename計(jì)算一個(gè)hash,然后CryptObj中包含一個(gè)User機(jī)器的ID,新文件名=UserMachineID+filename_hash+.locky;
接著程序會(huì)打開(kāi)需要加密的文件,并把源文件重命名為上面的這種文件名,Locky接著會(huì)去檢查是否有硬件加速可以用,如果有的話采用增強(qiáng)指令集加速加密的過(guò)程。
Advanced Encryption Standard Instruction Set (or the Intel Advanced Encryption Standard New Instructions; AES-NI) is an extension to the x86 instruction set architecture for microprocessors from Intel and AMD proposed by Intel in March 2008.[1] The purpose of the instruction set is to improve the speed of applications performing encryption and decryption using the Advanced Encryption Standard (AES).
?
Locky通過(guò)WindowsAPI CryptGenRandom生成一個(gè)16字節(jié)的種子值。
如果有硬件加速可以用(目前CPU基本都支持硬件加速),分配一個(gè)以16字節(jié)對(duì)齊的內(nèi)存塊。接著用16字節(jié)種子初始化這個(gè)內(nèi)存塊。
隨后,Locky使用之前傳進(jìn)來(lái)的PublicKey調(diào)用API:CryptEncrypt對(duì)種子值進(jìn)行加密。
Size=16,pbBuffer存儲(chǔ)的是通過(guò)CryptGenRandom生成的隨機(jī)值。
?
如果加密后的返回的數(shù)據(jù)塊的大小不等于256,那么會(huì)丟出異常,這里的作用是判斷生成的Key長(zhǎng)度是不是正確。
?
在這個(gè)加密函數(shù)中,有一個(gè)數(shù)據(jù)結(jié)構(gòu)和派生自一個(gè)基類的兩個(gè)類值得說(shuō)一下,其中EncryptBlock這個(gè)數(shù)據(jù)結(jié)構(gòu)大致的作用是用來(lái)保存當(dāng)前加密用的上下文,它保存了兩個(gè)固定的用于xor的4字節(jié)數(shù)據(jù),用戶的SysInfo的ID,一個(gè)128位的種子值(通過(guò)CryptGenRandom得到),一個(gè)MAX_LEN長(zhǎng)度的雙字節(jié)數(shù)組用于保存當(dāng)前文件的文件名,還有代表當(dāng)前文件屬性的bitmap,以及文件size,結(jié)構(gòu)如下。
?
另外兩個(gè)類對(duì)象是Encrypto的主體,它們都用Encrypto派生出來(lái),一個(gè)帶有硬件加速功能EncryptoAC,一個(gè)沒(méi)有帶有硬件加速功能EncryptoNoAC。
?
我只分析了帶有硬件加速的對(duì)象,它有5個(gè)方法,它的數(shù)據(jù)成員中包含一個(gè)AESkey,它是用EncryptBlock中的128位隨機(jī)數(shù)生成的(需要知道的是,當(dāng)用這個(gè)隨機(jī)數(shù)初始化完畢AESKey之后,隨機(jī)數(shù)即被作者用PublicKey加密了),生成的算法如下:
?
生成完AESKey之后,加密對(duì)象會(huì)先將當(dāng)前加密上下文用AESKey加密了,
緊接著,將文件待加密的文件讀到內(nèi)存中,然后加密文件。
這里可能發(fā)現(xiàn)參數(shù)不一樣了,實(shí)際上因?yàn)榇嬖趦蓚€(gè)加密對(duì)象,根據(jù)是否支持硬件加速選擇不同的加密對(duì)象,所以IDA這里翻譯的有點(diǎn)問(wèn)題,不用在意,實(shí)際上就是一個(gè)function。
緊接著會(huì)把加密后的文件寫入磁盤,完成一個(gè)文件的加密工作,剩下的工作有寫一些幫助(勒索)文件向用戶提示應(yīng)該如何轉(zhuǎn)賬之類的操作,不細(xì)說(shuō)了。下面總結(jié)一下Locky的加密邏輯。
?
?
?
解密邏輯,猜測(cè):
?
目前解法就是暴力破解隨機(jī)數(shù),看起來(lái)是不可行的。
?
從solution的角度,有兩個(gè)點(diǎn),一個(gè)是生成隨機(jī)數(shù)的地方,Hook:CryptGenRandrom,然后替換一個(gè)自己的隨機(jī)數(shù),這樣我們可以用自己的隨機(jī)數(shù)推出AESKey,這樣就可以解開(kāi)文件。
?
另外一個(gè)辦法,Hook:CryptImportKey,將從WebServer返回的PublicKey替換成自己的Key,這樣我們可以用自己的PrivateKey解開(kāi)解密塊中的隨機(jī)值,推出AESKey,也可以解開(kāi)文件。
?
下面有一組測(cè)試用的資料:由于安全原因就不上傳了,有興趣可以@ tedzhang2891@gmail.com與我聯(lián)系。
原文地址:?http://ec2-52-196-167-189.ap-northeast-1.compute.amazonaws.com/wordpress/index.php/2016/08/07/ransomware-locky-analysis/
總結(jié)
以上是生活随笔為你收集整理的Ransomware Locky Analysis的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Algorithm, Secret ke
- 下一篇: Ransomware Cerber An