拿到程序以后拖进IDA里shift+F12看一下:
双击跟进去,查看一下交叉引用,F5转一下伪代码就出来了:
flag为:flag{Sign_fDfkl_CTF}}
目前网上仍没有公布WP,当时参赛选手都没解出来...
拖IDA看一下,发现是ELF文件:
看一下main()函数的伪代码:
这是main()函数的伪代码:
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int i; // [esp+20h] [ebp-28h]
char s[17]; // [esp+2Bh] [ebp-1Dh]
unsigned int v6; // [esp+3Ch] [ebp-Ch]
v6 = __readgsdword(0x14u);
memcpy(&password, "IKAWTEQWJHQTVRCF", 0x10u); //初始化password
memset(s, 0, 0x11u);
printf("Enter the password: ");
__isoc99_scanf("%16s", s); //获取键盘输入的16个字符
for ( i = 0; i <= 15; ++i ) //将字符串放入循环
s[i] = complex_function(s[i], 18 - i); //这里是重点,将字符串存到s这个数组里,并调用complex_function()这个函数进行处理,然后在返回到s里。
if ( check_equals_IKAWTEQWJHQTVRCF(s, 16) ) //这里调用check_equals_IKAWTEQWJHQTVRCF()函数对处理后的password进行最多16次判断
puts("Good Job."); //若结果为真则输出Good job.
else
puts("Try again."); //若结果为假则输出Try again.
return 0;
}
我们在看一下它对我们输入的password进行了怎样的处理,也就是看一下complex_function()函数:
简单分析一下:
int __cdecl complex_function(signed int a1, int a2)
{
if ( a1 <= 64 || a1 > 90 ) //password对应的十进制只能在64~90之间
{
puts("Try again."); //若超出64~90则输出Try again.
exit(1); //运行到这里直接结束当前进程
}
return (a1 - 65 + 29 * a2) % 26 + 65; //如果语句没有执行,那么passwd经过处理后返回
}
接着我们分析它调用check_equals_IKAWTEQWJHQTVRCF()进行的判断:
分析一下伪代码,这里a1就是经过处理后的password,a2是16:
_BOOL4 __cdecl check_equals_IKAWTEQWJHQTVRCF(int a1, unsigned int a2)
{
int v3; // [esp+8h] [ebp-8h]
unsigned int i; // [esp+Ch] [ebp-4h]
v3 = 0; //定义一个局部变量v3用来存值
for ( i = 0; a2 > i; ++i ) //开始循环,每次循环结束i进行自加,最多循环16次
{
if ( *(_BYTE *)(i + a1) == *(_BYTE *)(i + 0x804C038) ) //这里是对原password跟处理后的password进行对比,如果相等就执行下面的语句,如果不相等就直接跳出去
++v3; //相等后进行自加
}
return v3 == a2;
}
/**
这里return v3 == a2的作用我感觉就是把结果转成0或1,
然后存到eax里,进行判断后选择跳或者不跳,如果程序成功执行了16次,
也就是v3 == a2成立,那么结果就是0,反之为1
**/
这是check_equals_IKAWTEQWJHQTVRCF()函数执行后的流程图,这里如果jnz判断不成立,也就是eax为0,那么就输出"Good job.“反之输出"Try again.”,跟我们分析的一样:
分析到这里我们就有解题思路了,有两种解题方法:
这里还是爆破比较方便,也比较简单:
passwd = 'IKAWTEQWJHQTVRCF' #定义原passwd
flag = '' #定义flag用来存值
for i in range(len(passwd)): #返回passwd的长度,也就是16
for a1 in range(64,91): #把64~90依次传给a1
if (a1 - 65 + (18-i)*29)%26 + 65 == ord(passwd[i]): #如果经过计算后a1的十进制结果如果等于原passwd的十进制结果
flag += chr(a1) #那么将结果依次转为对应的ASCII码赋值给flag
print('flag{%s}'%(flag)) #输出flag
成功拿到flag:flag{GLEDDRGPFGSYDCQW}
这题我看流程图感觉是将输入的内容进行异或,然后将异或的结果进行判断,若结果为真则结束进程,若为假则输出“err…"并结束进程:
这是它main()函数的伪代码
这里的关键就是在sub_400606()这个函数,它的伪代码非常复杂,很多个循环语句嵌套,水平实在是不够,分析不了,如果有大牛能分析或者感兴趣,私信我一起学习一下!
上一下sub_400606()函数的伪代码:
__int64 __fastcall sub_400606(signed int *a1)
{
signed __int64 v1; // rax
__int64 result; // rax
int v3; // [rsp+10h] [rbp-10h]
__int16 v4; // [rsp+14h] [rbp-Ch]
*a1 = 0;
do
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
do
{
v1 = *((_QWORD *)a1 + 1) + 6LL * *a1;
v3 = *(_DWORD *)v1;
v4 = *(_WORD *)(v1 + 4);
++*a1;
}
while ( BYTE1(v3) && BYTE1(v3) != a1[1] );
result = (unsigned __int8)v3;
if ( (unsigned __int8)v3 != 7 )
break;
*a1 = *(signed __int16 *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2));
}
if ( (signed int)result > 7 )
break;
if ( (_DWORD)result == 3 )
{
if ( *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2)) == *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2)) )
a1[1] = 1;
else
a1[1] = 2;
}
else if ( (signed int)result > 3 )
{
if ( (_DWORD)result == 5 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
}
else if ( (signed int)result > 5 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *a1;
}
else
{
*a1 += SHIWORD(v3);
}
}
else if ( (_DWORD)result == 1 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2))
+ *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
}
else if ( (_DWORD)result == 2 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2))
- *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
}
}
if ( (_DWORD)result != 10 )
break;
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *((_WORD *)a1
+ *(signed __int16 *)(2LL * v4 + *((_QWORD *)a1 + 2))
+ 8LL
+ 4);
}
if ( (signed int)result > 10 )
break;
if ( (_DWORD)result == 8 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = v4;
}
else if ( (_DWORD)result == 9 )
{
puts("err..");
}
}
if ( (_DWORD)result != 12 )
break;
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2)) ^ *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
}
if ( (signed int)result >= 12 )
break;
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *((_WORD *)a1
+ *(signed __int16 *)(2LL * v4 + *((_QWORD *)a1 + 2))
+ 32LL);
}
}
while ( (_DWORD)result != 255 );
return result;
}
这道题目前网上没有什么分析,只有一个解题脚本,也是通过异或试出来的:
a=[0x003C, 0x0030, 0x003F, 0x0007, 0x0019, 0x0012, 0x0000, 0x001E, 0x0018, 0x001A, 0x001A, 0x0042, 0x0046, 0x0010, 0x0010, 0x0010, 0x0014, 0x001F, 0x000C, 0x00FD]
x=90
for i in a:
print(chr(i^x),end='')
x+=2
运行后成功获得flag:flag{vfvrvt24dfhncr}