0x01 Beijing
解题过程
拖进IDA查看main函数的伪C代码如下:
int __cdecl main()
{
char v0; // al
char v1; // al
char v2; // al
char v3; // al
char v4; // al
char v5; // al
char v6; // al
char v7; // al
char v8; // al
char v9; // al
char v10; // al
char v11; // al
char v12; // al
char v13; // al
char v14; // al
char v15; // al
char v16; // al
char v17; // al
char v18; // al
char v19; // al
char v20; // al
v0 = sub_8048460(dword_804A03C);
printf("%c", v0);
fflush(stdout);
v1 = sub_8048460(dword_804A044);
printf("%c", v1);
fflush(stdout);
v2 = sub_8048460(dword_804A0E0);
printf("%c", v2);
fflush(stdout);
v3 = sub_8048460(dword_804A050);
printf("%c", v3);
fflush(stdout);
v4 = sub_8048460(dword_804A058);
printf("%c", v4);
fflush(stdout);
v5 = sub_8048460(dword_804A0E4);
printf("%c", v5);
fflush(stdout);
v6 = sub_8048460(dword_804A064);
printf("%c", v6);
fflush(stdout);
v7 = sub_8048460(dword_804A0E8);
printf("%c", v7);
fflush(stdout);
v8 = sub_8048460(dword_804A070);
printf("%c", v8);
fflush(stdout);
v9 = sub_8048460(dword_804A078);
printf("%c", v9);
fflush(stdout);
v10 = sub_8048460(dword_804A080);
printf("%c", v10);
fflush(stdout);
v11 = sub_8048460(dword_804A088);
printf("%c", v11);
fflush(stdout);
v12 = sub_8048460(dword_804A090);
printf("%c", v12);
fflush(stdout);
v13 = sub_8048460(dword_804A098);
printf("%c", v13);
fflush(stdout);
v14 = sub_8048460(dword_804A0A0);
printf("%c", v14);
fflush(stdout);
v15 = sub_8048460(dword_804A0A8);
printf("%c", v15);
fflush(stdout);
v16 = sub_8048460(dword_804A0B0);
printf("%c", v16);
fflush(stdout);
v17 = sub_8048460(dword_804A0B8);
printf("%c", v17);
fflush(stdout);
v18 = sub_8048460(dword_804A0C0);
printf("%c", v18);
fflush(stdout);
v19 = sub_8048460(dword_804A0C8);
printf("%c", v19);
fflush(stdout);
v20 = sub_8048460(dword_804A0D0);
printf("%c", v20);
fflush(stdout);
printf("\n");
return 0;
}
发现从v0到v20这21个字符都是经过sub_8048460函数后输出,那么我们跟进这个函数:
int __cdecl sub_8048460(int a1)
{
char v2; // [esp+Fh] [ebp-1h]
switch ( a1 )
{
case 0:
v2 = byte_804A021 ^ byte_804A020;
break;
case 1:
v2 = byte_804A023 ^ byte_804A022;
break;
case 2:
v2 = byte_804A025 ^ byte_804A024;
break;
case 3:
v2 = byte_804A027 ^ byte_804A026;
break;
case 4:
v2 = byte_804A029 ^ byte_804A028;
break;
case 5:
v2 = byte_804A02B ^ byte_804A02A;
break;
case 6:
v2 = byte_804A02D ^ byte_804A02C;
break;
case 7:
v2 = byte_804A02F ^ byte_804A02E;
break;
case 8:
v2 = byte_804A031 ^ byte_804A030;
break;
case 9:
v2 = byte_804A033 ^ byte_804A032;
break;
case 10:
v2 = byte_804A035 ^ byte_804A034;
break;
case 11:
v2 = byte_804A037 ^ byte_804A036;
break;
case 12:
v2 = byte_804A039 ^ byte_804A038;
break;
case 13:
v2 = byte_804A03B ^ byte_804A03A;
break;
default:
v2 = 0;
break;
}
return v2;
}
从dword_804A03C起注意第一个数字都是双字,那么从v0到v20sub_8048460函数的参数分别为:0x6,0x9,?,0x1,0xa,?,0x8,?,0xb,0x2,0x3,0x1,0xd,0x4,0x5,0x2,0x7,0x2,0x3,0x1,0xc
从byte_804A020开始的数组的值如下:
按照顺序每两个字符异或后只有switch参数是0,1,2,3,4,6的时候才是正常字符,而这显然不是我们要的结果。而我们注意到每次异或的后面一项都是正常字符时,我们大胆猜测每次异或的前面那一项是干扰项,于是可以得出v0到v20输出结果为:fl?g{?m?zing_beijing}我们知道flag的格式为flag{……},那么?代表的字符就是a,带入得到最终flag为flag{amazing_beijing}
fflush(stdout)的作用
fflush(stdout):清空标准输出缓冲区。
fflush(stdin):清空标准输入缓冲区。
在使用多个输出(输入)函数进行连续多次输出(输入)的时候,因为上一个数据还没有输出(输入)完毕,还在缓冲区的时候,下一个输出(输入)函数就将另一个数据放入缓冲区,那么就覆盖掉了上一个数据,这样就会出现错误。但是如果加入fflush()函数及时进行刷新的话就不会出现这种错误。
eg1.
#include<stdio.h>
int main()
{
char c;
scanf("%c",&c);
printf("0x%x\n",c);
scanf("%c",&c);
printf("0x%x\n",c);
return 0;
}
我们在运行这个程序的过程中,如果只输入一个字符c,那么在我们的期待中输出的应该是0x63,但是在实际运行过程中输出的却是:
我们查看ascii码表发现0xa对应的是换行,也就是enter键,这说明scanf读取了两个字符,但是像换行这种字符明显不是我们所需要的,我们修改代码:
#include<stdio.h>
int main()
{
char c;
scanf("%c",&c);
printf("0x%x\n",c);
fflush(stdin);
scanf("%c",&c);
printf("0x%x\n",c);
return 0;
}
此时输入c输出结果为0x63,控制台等待我们再一次输入然后再输出。
这才是我们想要的答案。通过这个例子我们更清楚的了解fflush(stdin)的作用。
eg2.在笔者测试的几个使用的fflush(stdout)的代码运行时看不出什么差别,若读者有好的实例欢迎分享。
0x02 Blend
解题过程
0x03 Advanced
解题过程
首先我们观察到src文件的类型不明确,我们将这个文件放在kali中运行一下,如果直接运行会提示权限不够,于是我们给其增加执行权限。
chmod +x src
./src
运行后得到:
welcome, here is your identification, please keep it in your pocket: 4b404c4b5648725b445845734c735949405c414d5949725c45495a51
我们联想到题目的提示:please keep identification in your pocket :)。我们有理由相信这串数据很重要。先将其转换成ASCII码看一下:K@LKVHr[DXEsLsYI@\AMYIr\EIZQ,并得不到什么有用的信息。flag的格式应该是flag{……},我们将已知的这六个字符与字符串进行异或,发现0x2D和0x2C交替出现,我们将字符串依次异或0x2D和0x2C,得到flag为:flag{d_with_a_template_phew}