题目:
通过题目我们可以知道,我们能成功输入的值就是我们的flag
下载附件后,发现是一个可执行的文件,执行一下,发现:
输入值后,直接闪退啦!查壳发现无壳后拖入IDA(32bit)内,f5反编译进入主函数,发现
DialogBoxParamA函数里的DialogFunc参数就很像网络编程中基于消息的WSAAsyncSelect模型里的消息处理函数,点进去后发现
if ( (_WORD)a3 == 1001 ) { memset(&String, 0, 0xFFFFu); GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF);#这里要输入字符串 if ( strlen(&String) == 8 )#长度为八 { v7 = 90; v8 = 74; v9 = 83; v10 = 69; v11 = 67; v12 = 97; v13 = 78; v14 = 72; v15 = 51; v16 = 110; v17 = 103; sub_4010F0(&v7, 0, 10);#这里对v7字符串进行了处理 memset(&v26, 0, 0xFFFFu); v26 = v23; v28 = v25; v27 = v24; v4 = (const char *)sub_401000(&v26, strlen(&v26));#这里可以推出以v23为首地址的字符串(长度为3) memset(&v26, 0, 0xFFFFu); v27 = v21; v26 = v20; v28 = v22; v5 = (const char *)sub_401000(&v26, strlen(&v26));#这里可以推出以v20为首地址的字符串(长度为3) if ( String == v7 + 34 && v19 == v11 && 4 * v20 - 141 == 3 * v9 && v21 / 4 == 2 * (v14 / 9) && !strcmp(v4, "ak1w") && !strcmp(v5, "V1Ax") ) { MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0); } } return 0; } if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 ) return 0; EndDialog(hDlg, (unsigned __int16)a3);
通过大概的分析程序,我们可以发现,我们输入的字符串的长度为8字节,通过点进去v19、v20,发现v18处地址对应的就是我们输入字符串的首地址,v19、v20、...v25处地址就分别是字符串每个字符的地址
所以,我们只需把每个对应的字符逆推出来,那么也就得到了我们的flag啦。
开始逆推:
首先我们知道从v7至v17这11个变量的值,往后碰到 sub_4010F0(&v7, 0, 10)函数,点进去发现有对以v7为首地址的字符进行了处理,直接粘贴,用C语言解出处理后对应的值
#include#include using namespace std; int sub(char a1[], int a2, int a3) { int result; // eax int i; // esi int v5; // ecx int v6; // edx result = a3; for ( i = a2; i <= a3; a2 = i ) { v5 = i; //v6 = *(DWORD *)(4 * i + a1); v6 = a1[i]; if ( a2 < result && i < result ) { do { //if ( v6 > *(DWORD *)(a1 + 4 * result) ) if ( v6 > a1[result] ) { if ( i >= result ) break; ++i; //*(DWORD *)(v5 + a1) = *(DWORD *)(a1 + 4 * result); a1[v5] = a1[result]; if ( i >= result ) break; //while ( *(DWORD *)(a1 + 4 * i) <= v6 ) while ( a1[i] <= v6 ) { if ( ++i >= result ) goto LABEL_13; } if ( i >= result ) break; v5 = i; //*(DWORD *)(a1 + 4 * result) = *(DWORD *)(4 * i + a1); a1[result] = a1[i]; } --result; } while ( i < result ); } LABEL_13: //*(DWORD *)(a1 + 4 * result) = v6; a1[result]= v6; sub(a1, a2, i - 1); result = a3; ++i; } return result; } int main() { char a[11]={90,74,83,69,67,97,78,72,51,110,103}; cout<<">>>>sub"<<endl; sub(a,0,10); for (int i=0;i<11;i++) { cout<<"a["<"]"<" "<<int(a[i])<<endl; //cout< } }
运行结果为:
继续往下推,发现有 v4 = (const char *)sub_401000(&v26, strlen(&v26));和v5 = (const char *)sub_401000(&v26, strlen(&v26));点进去sub_401000发现(图没截全)
点进去byte_407830发现
可知,结果是经过base64编码得到的。
然后,我们继续往后推
if ( String == v7 + 34
&& v19 == v11
&& 4 * v20 - 141 == 3 * v9 && v21 / 4 == 2 * (v14 / 9) && !strcmp(v4, "ak1w") && !strcmp(v5, "V1Ax") ) { MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0); }
通过这里,我们知道
string(v18)=v7+34=51+34=86='U'
V19='J'
v20='W'
v21='P'
又因为v4='ak1w',v5='V1Ax',通过base64解码分别得,v4='jMp',v5='WP1',因此可知,v20='W',v21='P',v22='1'(v5);v23='j',v24='M',v25='p'(v4)
这样我们就得到我们的flag啦!!!即flag{UJWP1jMp}