Splendid_MineCraft
題目標題就已經暗示這題是SMC了(self-modifying code)。
工具:exeinfo,x32dbg和IDA7.0
先丟進exeinfo裡檢視相關資訊:
用IDA開啟:
根據可以字串“Wrong!\n”直接鎖定sub_401080為main函式。
int sub_401080() { char *v0; // eax char *v1; // eax char *v2; // ST28_4 signed int i; // [esp+14h] [ebp-54h] int v5; // [esp+20h] [ebp-48h] char Str1; // [esp+24h] [ebp-44h] char v7; // [esp+3Dh] [ebp-2Bh] int v8; // [esp+44h] [ebp-24h] __int16 v9; // [esp+48h] [ebp-20h] char v10[4]; // [esp+4Ch] [ebp-1Ch] __int16 v11; // [esp+50h] [ebp-18h] int v12; // [esp+54h] [ebp-14h] __int16 v13; // [esp+58h] [ebp-10h] int v14; // [esp+5Ch] [ebp-Ch] __int16 v15; // [esp+60h] [ebp-8h] sub_401020((const char *)&unk_404118, (unsigned int)"Welcome to ACTF_Splendid_MineCraft!"); sub_401050((const char *)&unk_40411C, (unsigned int)&Str1); if ( strlen(&Str1) == 26 ) { if ( !strncmp(&Str1, "ACTF{", 5u) && v7 == 125 ) { v7 = 0; v0 = strtok(&Str1, "_"); v12 = *(_DWORD *)(v0 + 5); v13 = *(_WORD *)(v0 + 9); v14 = *(_DWORD *)(v0 + 5); v15 = *(_WORD *)(v0 + 9); v1 = strtok(0, "_"); v8 = *(_DWORD *)v1; v9 = *((_WORD *)v1 + 2); v2 = strtok(0, "_"); *(_DWORD *)v10 = *(_DWORD *)v2; v11 = *((_WORD *)v2 + 2); dword_403354 = (int)dword_4051D8; if ( ((int (__cdecl *)(int *))dword_4051D8[0])(&v12) ) { v5 = SBYTE2(v14) ^ SHIBYTE(v15) ^ (char)v14 ^ SHIBYTE(v14) ^ SBYTE1(v14) ^ (char)v15; for ( i = 256; i < 496; ++i ) byte_405018[i] ^= v5; JUMPOUT(__CS__, &byte_405018[256]); } sub_401020("Wrong\n"); } else { sub_401020("Wrong\n"); } } else { sub_401020("Wrong\n"); } return 0; }
由三個strtok函式可知,flag{}裡的內容應該是被_分成了三個部分,根據輸入長度猜測每個部分應該是6位元組長(這三個部分我們分別稱為flag_sec1,flag_sec2和flag_sec3)。
flag_sec1
因為是SMC基本上確定是要動態除錯的,所以大致瞭解一下main函式的結構,就丟進x32dbg裡開始除錯。
先搜尋字串,直接進入main函式:
到call CB1050時除錯會卡住,說明程式此時正在等待輸入,於是我們可以得到:
先隨便輸入一個flag:ACTF{123456_ABCDEF_abcdef}
我們向下瀏覽會發現有三個strtok()函式,如圖
正好與IDA反編譯的結果相吻合,所以這三個函式後面應該是對flag內容的比較。
在最後一個strtok()函式後面打個斷點,直接跳過中間的內容,然後進行單步除錯,直到進入這個call。
進入call後會發現很多奇怪的指令,這才進入到我們這篇WP真正的主題:SMC
一步一步F7除錯,會發現隨著如下迴圈的進行,奇怪的彙編指令也會被改變:
跳過SMC迴圈繼續除錯,會發現又有一個大迴圈:
經過一遍又一遍的除錯,會發現裡面的三條關鍵指令:
異或和求和的過程中並沒有用到我們的輸入,結果都儲存到ss:[ebp+eax-20]裡,直接執行完follow in dump:
這就是上面迴圈得到的結果。
閱讀迴圈可知:00CB5332的cmp edx,ecx就是比較使用者輸入和flag的過程。
flag_sec1 = yOu0y*
flag_sec2
這段也是SMC,修改後面jmp EAX裡面的程式碼。
重新除錯,輸入flag_sec1正確的字串繼續除錯。沒啥好說的,知道除錯到jmp eax:
一進去就遇到個迴圈,但是這個迴圈非常詭異,因為中間有多餘程式碼,其實不斷的除錯就會發現,中間的多餘程式碼是會被修改的!這其實就是SMC,但是本該是資料卻被x32dbg識別成了程式碼而已,通過
右鍵->Analysis->Treat from section as byte就可以將其轉化為資料了,如下圖:
這個迴圈只是把使用者輸入的flag_sec2儲存到了這個區域裡(ABCDEF對應著41-46)。
後面有個迴圈:
(一邊F7一邊檢視dump視窗。不好意思沒看出來有啥用,估計是煙霧彈)
其實就是EAX[flag_sec2[i]^(0x83+i)] == EAX[EDI+166]
flag_sec2 = knowo3
flag_sec3
題目裡直接明文strcmp,
flag_sec3 = 5mcsM<
綜上:flag{yOu0y*_knowo3_5mcsM<}