11. getit
进入环境,下载附件,使用exeinfo Exe打开,发现没有加壳,如图:
解法1. 静态分析,得到答案
我们直接将文件丢入IDA,找到main函数,F5反编译,查看代码,如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3;
__int64 v5;
int i;
FILE *stream;
char filename[8];
unsigned __int64 v9;
v9 = __readfsqword(0x28u);
LODWORD(v5) = 0; # 令V5=0
while ( (signed int)v5 < strlen(s) )
{
if ( v5 & 1 )
v3 = 1;
else
v3 = -1;
*(&t + (signed int)v5 + 10) = s[(signed int)v5] + v3; # 对t字符的内容进行改写,与v3内容有关
LODWORD(v5) = v5 + 1; # v5++
}
strcpy(filename, "/tmp/flag.txt"); # 创建一个flag.txt文件
stream = fopen(filename, "w");
fprintf(stream, "%s\n", u, v5);
for ( i = 0; i < strlen(&t); ++i ) # 依次将t字符写入文件中
{
fseek(stream, p[i], 0);
fputc(*(&t + p[i]), stream);
fseek(stream, 0LL, 0);
fprintf(stream, "%s\n", u);
}
fclose(stream);
remove(filename);
return 0;
}
可以看到,上面的代码主要是针对v3得到的值存入t中,再对t写入文件操作,那么t就是最终的flag值!我们尝试双击t字符,查看内容,如图: 我们右键,将53h转成字符,如图; 同理查看字符s,如图:
那么我们可以知道,字符s和t分别为:
t = SharifCTF{????????????????????????????????}
s = c61b68366edeb7bdce3c6820314b7498
接着代码复现:
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "c61b68366edeb7bdce3c6820314b7498";
char t[] = "SharifCTF{????????????????????????????????}";
int v5 = 0;
char v3;
while(v5 < strlen(s)){
if (v5 & 1)
v3 = 1;
else
v3 = -1;
*(t + v5 + 10) = s[v5] + v3;
v5++;
}
printf("%s\n",t);
return 0;
}
最终flag为:SharifCTF{b70c59275fcfa8aebf2d5911223c6589}
解法2. 通过IDA的patch功能
经过上述代码分析,发现运行文件没有的原因是最后将文件通过remove命令删除了,而且在for循环里,通过fprintf函数将u,也就是一堆*******符号写入flag文件。那么我们先找到这两处地方,如图: 找到位置后,通过小手轻轻的触动鼠标的右键,如图: 将其内容替换成nop,如图: 将其文件导出,并扔进kali中,通过./文件,运行更改后的文件。 最后我们可以通过命令得到结果:
cat /tmp/flag.txt
结果如图:
12. maze
下载附件,直接用IDA打开,查看内容,找到main函数,F5反编译,得到代码,如图: 一大堆代码,我们逐一分析:
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
const char *v3;
signed __int64 v4;
signed int v5;
char v6;
char v7;
const char *v8;
__int64 v10;
v10 = 0LL;
puts("Input flag:");
scanf("%s", &s1, 0LL);
if ( strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125 )
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
v4 = 5LL;
if ( strlen(&s1) - 1 > 5 )
{
while ( 1 )
{
v5 = *(&s1 + v4);
v6 = 0;
if ( v5 > 78 )
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 79 )
{
v7 = sub_400650((char *)&v10 + 4, v3);
goto LABEL_14;
}
if ( v5 == 111 )
{
v7 = sub_400660((char *)&v10 + 4, v3);
goto LABEL_14;
}
}
else
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 46 )
{
v7 = sub_400670(&v10, v3);
goto LABEL_14;
}
if ( v5 == 48 )
{
v7 = sub_400680(&v10, v3);
LABEL_14:
v6 = v7;
goto LABEL_15;
}
}
LABEL_15:
v3 = (const char *)HIDWORD(v10);
if ( !(unsigned __int8)sub_400690(asc_601060, HIDWORD(v10), (unsigned int)v10) )
goto LABEL_22;
if ( ++v4 >= strlen(&s1) - 1 )
{
if ( v6 )
break;
LABEL_20:
v8 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != 35 )
goto LABEL_20;
v8 = "Congratulations!";
LABEL_21:
puts(v8);
return 0LL;
}
同时我们双击asc_601060变量,得到的是一串字符串,如下:
.data:0000000000601060 asc_601060 db ' ******* * **** * **** * *** *# *** *** *** *********',0
再来看看难顶的函数:
__int64 __fastcall sub_400690(__int64 a1, int a2, int a3)
{
__int64 result;
result = *(unsigned __int8 *)(a1 + a2 + 8LL * a3);
LOBYTE(result) = (_DWORD)result == 32 || (_DWORD)result == 35;
return result;
}
00******
*000*00*
***0*0**
**00*0**
*00*
**0***0*
**00000*
********
起点(1,1),只能走0,要走到‘#’,找到路径右下右右下下左下下下右右右右上上左左
则对应的代码中字符为:o0oo00O000oooo…OO 带上前置括号,最终的字符为:nctf{o0oo00O000oooo…OO}
这个题感觉看的稀里糊涂的,后面再回头重做一下,代码还是太难阅读了。
|