本题给的是一个exe文件,不管怎样先点开看看
得到的是这样一个弹窗,点击没有反应,也没有输入框,但一按回车就直接闪退
1.用exeinfope看看有没有壳
OK,一眼看过去是一个32位用c++写的程序
2.打开ida看看
INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
const char *v4; // esi
const char *v5; // edi
int v7[2]; // [esp+8h] [ebp-20030h] BYREF
int v8; // [esp+10h] [ebp-20028h]
int v9; // [esp+14h] [ebp-20024h]
int v10; // [esp+18h] [ebp-20020h]
int v11; // [esp+1Ch] [ebp-2001Ch]
int v12; // [esp+20h] [ebp-20018h]
int v13; // [esp+24h] [ebp-20014h]
int v14; // [esp+28h] [ebp-20010h]
int v15; // [esp+2Ch] [ebp-2000Ch]
int v16; // [esp+30h] [ebp-20008h]
CHAR String[65536]; // [esp+34h] [ebp-20004h] BYREF
char v18[65536]; // [esp+10034h] [ebp-10004h] BYREF
if ( a2 == 272 )
return 1;
if ( a2 != 273 )
return 0;
if ( (_WORD)a3 == 1001 )
{
memset(String, 0, 0xFFFFu);
GetDlgItemTextA(hDlg, 1000, String, 0xFFFF);
if ( strlen(String) == 8 )
{
v7[0] = 90;
v7[1] = 74;
v8 = 83;
v9 = 69;
v10 = 67;
v11 = 97;
v12 = 78;
v13 = 72;
v14 = 51;
v15 = 110;
v16 = 103;
sub_4010F0(v7, 0, 10);
memset(v18, 0, 0xFFFFu);
v18[0] = String[5];
v18[2] = String[7];
v18[1] = String[6];
v4 = (const char *)sub_401000(v18, strlen(v18));
memset(v18, 0, 0xFFFFu);
v18[1] = String[3];
v18[0] = String[2];
v18[2] = String[4];
v5 = (const char *)sub_401000(v18, strlen(v18));
if ( String[0] == v7[0] + 34
&& String[1] == v10
&& 4 * String[2] - 141 == 3 * v8
&& String[3] / 4 == 2 * (v13 / 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);
return 1;
}
简单看下来string应该就是我们要的flag
并且strlen(string) == 8我们可以得知flag是八位
看到一个叫sub_4010F0的函数点进去看看
int __cdecl sub_4010F0(int 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 = 4 * i;
v6 = *(_DWORD *)(4 * i + a1);
if ( a2 < result && i < result )
{
do
{
if ( v6 > *(_DWORD *)(a1 + 4 * result) )
{
if ( i >= result )
break;
++i;
*(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
if ( i >= result )
break;
while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
{
if ( ++i >= result )
goto LABEL_13;
}
if ( i >= result )
break;
v5 = 4 * i;
*(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
}
--result;
}
while ( i < result );
}
LABEL_13:
*(_DWORD *)(a1 + 4 * result) = v6;
sub_4010F0(a1, a2, i - 1);
result = a3;
++i;
}
return result;
}
不出意外这是一个给v7重定义的函数,对其进行逆向得
在这里,将伪代码转变为c语言的时候有类似于*(_DWORD *)(a1 + 4 * result)这样一段不知道该如何改写成C,查询过后这里直接借用 @别害怕我在 大佬wp中的解释
nt占四个字节,所以需要*4.如果是char类型,就不需要.
在这里,我也是找到一点资料。百度一下数组寻址公式。
从这里,我们知道a1+4*i,也就是a1【i】,a1+4 * result,也就是a1【result】。
将伪代码的寻址方式改为数组寻址,然后将*(_DWORD*) 删掉,因为这是汇编的表示。
所以伪代码变成了C语言代码。
#include<stdio.h>
int gkyj(char* a1,int a2,int a3){
int result,i,v5,v6;
result = a3;
for(i = a2;i<=a3;a2 = i){
v5 = 4*i;
v6 = a1[i];
if(a2 < result && i<result){
do{
if(v6 > a1[result]){
if(i>=result){
break;
}
++i;
a1[v5] = a1[result];
if(i>=result){
break;
}
while(a1[i] <= v6){
if(++i >= result){
goto LABEL_13;
}
}
if(i >= result){
break;
}
v5 = 4*i;
a1[result] = a1[i];
}
--result;
}while(i<result);
}
LABEL_13:
a1[result] = v6;
gkyj(a1,a2,i-1);
result = a3;
++i;
}
return result;
}
int main()
{
char str[] = "ZJSECaNH3ng";
gkyj(str,0,10);
printf("%s",str);
return 0;
}
由此可以得到v7被改写为“3CEHJNSZagn”
memset(v18, 0, 0xFFFFu);
v18[0] = String[5];
v18[2] = String[7];
v18[1] = String[6];
v4 = (const char *)sub_401000(v18, strlen(v18));
memset(v18, 0, 0xFFFFu);
v18[1] = String[3];
v18[0] = String[2];
v18[2] = String[4];
v5 = (const char *)sub_401000(v18, strlen(v18));
这看着是一个给v4和v5定义的过程
最后是一个if函数,通过对这个if逆向我们应该就能得到flag了
if ( String[0] == v7[0] + 34
&& String[1] == v10
&& 4 * String[2] - 141 == 3 * v8
&& String[3] / 4 == 2 * (v13 / 9)
&& !strcmp(v4, "ak1w")
&& !strcmp(v5, "V1Ax") )
{
3.看看String里有没有什么线索
看到了熟悉的base64加密的特征
结合上面v4和v5的定义以及最后if对v4和v5的比较,我们可以得知v4,v5定义的过程是一个base64加密的过程。通过在线base64解密:BASE64加密解密,我们可以得到加密前的v4和v5
即v4 = “jMp”,v5 = "WP1"
到这里,可以总结归纳一下我们现在有的东西
v7 = "3CEHJNSZagn"
v4 = "jMp"
v5 = "WP1"
String是我们要求的
所以通过最后的if函数,我们来求string的内容
第一句:String[0] == v7[0] + 34
这里的v7【0】,就是上面10个字符的第一个字符,我们通过加密函数之后,v7【0】由一开始的Z变成了3.
3的ASCII码是51,51 + 34 = 85,85的ASCII码对应的是大写的 U,所以String【0】对应U。
第二句:String[1] == v10
v10在之前没加密的时候,是排第五位,我们看看加密之后的第五位是谁,3CEHJNSZagn,可以看到,加密之后的第五位是 J,所以String【1】是J。
第三句:4 * String[2] - 141 == 3 * v8,v8在没加密之前,是排第三位,先看看加密之后的第三位是谁,可以看到是E,E的ASCII码是69,所以3*69 + 141 / 4 = 87 ,ASCII为W,String【2】是E。
第四句:String[3] / 4 == 2 * (v13 / 9),看到v13没加密之前排到数第四位,看看加密之后的到数第四位是谁,是Z,Z的ASCII是90,所以2*(90/9)*4 = 80 ,ASCII为P,String【3】是Z。
后面四个字符,就是base64加密的那几个,可以看到第三第四字符已经是WP了,说明,WP1在前,jMp在后。
将他们拼接在一起,得到,UJWP1jMp。
带上flag{},得到flag{UJWP1jMp}。