題目來源至 https://www.malwaretech.com/beginner-malware-reversing-challenges
所有挑戰都是在不使用調試器的情況下完成的,你的目標應該是能夠在不運行exe的情況下完成每個挑戰。
string3難度等級爲2星
strings3.exe包含存儲在可執行文件中的未加密flag。運行時,程序將輸出flag的MD5哈希值,但不輸出原始值。你能得到flag嗎?
本地解壓後如下:
拖進IDA裏,查看下,發現與string1與string2完全不一樣。
還是原先的步驟,先找到hash生成函數。
這裏發現生成hash的函數使用了類的結構,因爲call ??0MD5@@QAE@XZ ; MD5::MD5(void) 執行了類對象的構造方法。
重點來到 call ?digestString@MD5@@QAEPADPAD@Z ; MD5::digestString(char *)
這裏是生成hash的主方法,IDA標識了eax爲char* 類型,與這個方法的參數類型一致,所以判斷push eax爲參數入棧。
lea eax, [ebp+var_4A0]
eax的值爲var_4A0變量的地址,var_4A0變量在上面的call ds:LoadStringA這個API函數中有涉及。
LoadStringA函數
從與指定模塊關聯的可執行文件中加載字符串資源,並將字符串複製到具有終止空字符的緩衝區中,或者返回指向字符串資源本身的只讀指針。
int LoadStringA( HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int cchBufferMax );
參數
hInstance
類型:HINSTANCE
可執行文件包含字符串資源的模塊實例的句柄。要獲取應用程序本身的句柄,請使用NULL調用GetModuleHandle函數。
uID
輸入:UINT
要加載的字符串的標識符。
lpBuffer
類型:LPTSTR
接收字符串的緩衝區(如果cchBufferMax非零)或者是字符串資源本身的只讀指針(如果cchBufferMax爲零)。長度必須足以容納指針(8個字節)。
cchBufferMax
輸入:int
緩衝區的大小,以字符爲單位。如果字符串長於指定的字符數,則該字符串將被截斷並以null結尾。如果此參數爲0,則lpBuffer將接收指向字符串資源本身的只讀指針。
來源: https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-loadstringa
win32 API函數的調用約定爲stdcall,參數從右至左入棧。
所以上面的4個push操作就是參數入棧。
mov [ebp+var_8], eax
mov eax, 1
shl eax, 8
xor edx, edx
inc edx
shl edx, 4
or eax, edx
mov [ebp+var_4], eax
push 3FFh
lea ecx, [ebp+var_4A0]
push ecx
mov edx, [ebp+var_4]
push edx
push 0
call ds:LoadStringA
cchBufferMax爲3FFh,十進制爲1023
lpBuffer爲ecx
uID爲edx
hInstance爲0,也就是爲NULL
mov [ebp+var_4A0], 0
lea ecx, [ebp+var_4A0]
lpBuffer爲ecx,ecx爲var_4A0變量所在的地址,而往上查,發現var_4A0已經被賦值爲0,所以ecx爲0。
uID爲edx,edx=[ebp+var_4],而[ebp+var_4]=eax。
eax的計算是下面這幾條彙編指令:
mov eax, 1
shl eax, 8
xor edx, edx
inc edx
shl edx, 4
or eax, edx
最後算得eax=272。
LoadStringA(0, 272, &var_4A0, 1023);
這裏還有個快速的方法,F5反編譯。直接使用IDAF5插件反編譯功能翻譯成僞c代碼。
LoadStringA函數是加載字符串資源,所以目前需要使用另一個工具,ResourceHacker。
uID爲要加載的字符串的標識符,使用ResourceHacker打開string3,來到字符串資源處。
查找下272標識符裏的內容
正確flag