题目:
两个文件,一个level1,一个output.txt
1、将level1加后缀exe,用脱壳工具“Exeinfo PE万能查壳软件”发现没有壳,是64位的。
2、用反编译工具IDA(64)打开level1.exe
.text:0000000000400666 push rbp
.text:0000000000400667 mov rbp, rsp
.text:000000000040066A sub rsp, 30h
.text:000000000040066E mov rax, fs:28h
.text:0000000000400677 mov [rbp+var_8], rax
.text:000000000040067B xor eax, eax
.text:000000000040067D mov esi, offset modes ; "r"
.text:0000000000400682 mov edi, offset filename ; "flag"
.text:0000000000400687 call _fopen
.text:000000000040068C mov [rbp+stream], rax
.text:0000000000400690 mov rdx, [rbp+stream]
.text:0000000000400694 lea rax, [rbp+ptr]
.text:0000000000400698 mov rcx, rdx ; stream
.text:000000000040069B mov edx, 14h ; n
.text:00000000004006A0 mov esi, 1 ; size
.text:00000000004006A5 mov rdi, rax ; ptr
.text:00000000004006A8 call _fread
.text:00000000004006AD mov rax, [rbp+stream]
.text:00000000004006B1 mov rdi, rax ; stream
.text:00000000004006B4 call _fclose
.text:00000000004006B9 mov [rbp+var_2C], 1
.text:00000000004006C0 jmp short loc_40071B
看到flag字样,按F5查看伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+4h] [rbp-2Ch]
FILE *stream; // [rsp+8h] [rbp-28h]
char ptr[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v7; // [rsp+28h] [rbp-8h]
v7 = __readfsqword(0x28u);
stream = fopen("flag", "r");
fread(ptr, 1uLL, 0x14uLL, stream);
fclose(stream);
for ( i = 1; i <= 19; ++i )
{
if ( (i & 1) != 0 )
printf("%ld\n", (unsigned int)(ptr[i] << i));
else
printf("%ld\n", (unsigned int)(i * ptr[i]));
}
return 0;
}
3、分析代码
i&1 – 按位与运算,取 2进制整数 i 的最低位,如果最低位是1 则得1,如果最低位是0 则得0。 奇数 i 的最低位 是1,偶数i 的最低位 是0。
output.txt文件中输出的数字,是通过i是奇数还是偶数,决定了输出的值。
4、解题
out = [198,
232,
816,
200,
1536,
300,
6144,
984,
51200,
570,
92160,
1200,
565248,
756,
1474560,
800,
6291456,
1782,
65536000
]
for i in range(1,20):
if(i%2!=0):
print(chr(out[i-1]>>i),end='')
else:
print(chr(out[i-1]//i),end='')
5、输出结果
ctf2020{d9-dE6-20c}