題目來源至 https://www.malwaretech.com/beginner-malware-reversing-challenges
所有挑戰都是在不使用調試器的情況下完成的,你的目標應該是能夠在不運行exe的情況下完成每個挑戰。
ransomware1
勒索解密,難度等級1星。
題目說是一個腳本小子寫的勒索軟件,問能否解密flag.txt文件?
僅爲靜態分析,不需要使用調試器。
下載解壓完如圖:
文件夾爲加密過的文件,exe爲加密程序demo。
先分析exe文件,使用IDA打開。
自動識別了start程序,進入看看。
進入sub_401000
之前已分析過,所以已經做了些註釋與重命名。
這個函數有兩個參數,通過API可知,有打開文件與寫入文件的操作,這裏應該就是加密的核心了。
查snprintf函數的四個參數,結合已經加密的文件特徵可以知道a1爲需要加密的原始文件的文件名,這裏的作用僅僅是拼接字符串作爲加密後的文件名。
接下來的CreateFileA函數是打開已經存在的文件,第二個CreateFileA函數是新建一個文件。
do while循環裏第一步先檢查讀取文件時是否成功,如果成功讀取4096個字節則執行for循環。
for循環循環的次數爲ReadFile實際讀取的字節數v6,如果文件超過4096個字節,則v6第一次讀取就爲4096。
如果文件小於4096個字節,則v6爲實際文件的大小。
for循環裏有個參數a2未知,將a2的值加上i與0x20的取模運算後的結果再與當前文件從文件開頭的第i個字節的值進行異或,
最後的結果再賦值到源位置裏。
循環4096次後,就結束循環。最後關閉文件句柄,退出。
加密的原理是對文件的前4096個字節進行計算後重新賦值,如果文件小於4096就對整個文件內容進行處理再在對應位置賦值。
問題的關鍵是a2的值是什麼?
第一次不使用a2,直接對flag.txt進行處理,發現打開後是亂碼,說明解密不成功。
這裏的話確實要發揮腦洞了,壓縮包裏給了兩類文件,一類是加密後的圖片,一類是存在flag的txt文件。
先看圖片文件,發現是英文命名的,後綴都爲jpg格式。既然a2的值是固定的,加上jpg格式都是有一定特徵的,那麼如果這些jpg文件裏有部分內容是一樣的話,說明就可以通過再進行異或運算得到a2這個key的值。
使用Beyond Compare依次打開這些圖片,然後一一比較,發現前22個字節是一致的(這裏以爲找到了突破口,發現卻不是)。
說明圖片是突破口,然後弄了半天沒有發現如果找到圖片開頭的特徵碼,因爲每個jpg文件好像除了開頭兩個字節是特徵碼之外,其餘的字節不一定是一致的,我陷入了無解中。
然後突然覺得這個很難解密了,因爲無法知道a2的值到底是什麼。
帶着懷疑就複製加密後的文件名Chrysanthemum去谷歌搜索下,發現了原來是Win7 自帶的壁紙圖片,啊啊啊,確實不能放過任何信息。
突然醒悟,或許這就是突破口,馬上打開Win7尋找原始的壁紙圖片,編輯器打開,與加密後的文件進行對比。
源壁紙文件如下圖:
加密後的壁紙文件如下圖:
最後,通過上述兩個圖片裏前4096個字節的每個字節進行異或運算後得到規律發現a2的取值是一個字節數組。
key = [
0x6E, 0xF7, 0x9B, 0x0E, 0x45, 0x55, 0x5E, 0x95,
0x96, 0xFE, 0xAB, 0x75, 0x80, 0xB4, 0x0E, 0x40,
0x3D, 0xF5, 0xA7, 0x1B, 0xED, 0xD5, 0x5B, 0x80,
0xA9, 0xD3, 0x8D, 0x2C, 0xB8, 0x0A, 0x40, 0x0F
]
並且經過32個字節運算後,會重複這個過程,直到處理的字節數達到4096個。
得到key值後,可以通過之前逆出的加密流程對flag.txt_encrypted進行解密了。
解密腳本如下:
# coding:utf-8
key = [
0x6E, 0xF7, 0x9B, 0x0E, 0x45, 0x55, 0x5E, 0x95,
0x96, 0xFE, 0xAB, 0x75, 0x80, 0xB4, 0x0E, 0x40,
0x3D, 0xF5, 0xA7, 0x1B, 0xED, 0xD5, 0x5B, 0x80,
0xA9, 0xD3, 0x8D, 0x2C, 0xB8, 0x0A, 0x40, 0x0F
]
decrypted = ''
file_name = "flag.txt_encrypted"
with open(file_name, 'rb') as f:
encrypted = f.read()
for i in range(len(encrypted)):
decrypted += chr(encrypted[i] ^ key[i % 0x20])
with open(file_name.replace('_encrypted', ''), 'w') as f:
f.write(decrypted)
print(decrypted)