附件是.exe文件,放入ExeInfoPE中,发现是linux可执行文件
放入IDA64中,F5查看伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[24]; // [rsp+0h] [rbp-20h] BYREF
int v5; // [rsp+18h] [rbp-8h]
int i; // [rsp+1Ch] [rbp-4h]
for ( i = 0; i <= 181; ++i )
judge[i] ^= 0xCu;
printf("Please input flag:");
__isoc99_scanf("%20s", s);
v5 = strlen(s);
if ( v5 == 14 && (*(unsigned int (__fastcall **)(char *))judge)(s) )
puts("Right!");
else
puts("Wrong!");
return 0;
}
逻辑分析
先将judge内存区的181个字节都与0xC做异或运算,然后输入flag。
易知flag长度为14。
重点:
if ( v5 == 14 && (*(unsigned int (__fastcall **)(char *))judge)(s) )
显然输入的flag(s)要传入judge函数做变换,而前面分析出judge所指向的内存是数据区而不是代码,在IDA中查看确实如此
所以judge函数的内容要经过异或0xC之后才能变为代码。
考察点:动态函数
解题:
在linux中用gdb调试。
1)断点打到printf处
在IDA中找到printf的地址
打断点并运行
pwndbg> b *0x000000000040064A
Breakpoint 1 at 0x40064a
pwndbg> r
...
2)以指令的形式查看judge所指向的内存
pwndbg> x /100i 0x0000000000600B00
0x600b00 <judge>: push rbp
0x600b01 <judge+1>: mov rbp,rsp
0x600b04 <judge+4>: mov QWORD PTR [rbp-0x28],rdi
0x600b08 <judge+8>: mov BYTE PTR [rbp-0x20],0x66
0x600b0c <judge+12>: mov BYTE PTR [rbp-0x1f],0x6d
0x600b10 <judge+16>: mov BYTE PTR [rbp-0x1e],0x63
0x600b14 <judge+20>: mov BYTE PTR [rbp-0x1d],0x64
0x600b18 <judge+24>: mov BYTE PTR [rbp-0x1c],0x7f
0x600b1c <judge+28>: mov BYTE PTR [rbp-0x1b],0x6b
0x600b20 <judge+32>: mov BYTE PTR [rbp-0x1a],0x37
0x600b24 <judge+36>: mov BYTE PTR [rbp-0x19],0x64
0x600b28 <judge+40>: mov BYTE PTR [rbp-0x18],0x3b
0x600b2c <judge+44>: mov BYTE PTR [rbp-0x17],0x56
0x600b30 <judge+48>: mov BYTE PTR [rbp-0x16],0x60
0x600b34 <judge+52>: mov BYTE PTR [rbp-0x15],0x3b
0x600b38 <judge+56>: mov BYTE PTR [rbp-0x14],0x6e
0x600b3c <judge+60>: mov BYTE PTR [rbp-0x13],0x70
0x600b40 <judge+64>: mov DWORD PTR [rbp-0x4],0x0
0x600b47 <judge+71>: jmp 0x600b71 <judge+113>
0x600b49 <judge+73>: mov eax,DWORD PTR [rbp-0x4]
0x600b4c <judge+76>: movsxd rdx,eax
0x600b4f <judge+79>: mov rax,QWORD PTR [rbp-0x28]
0x600b53 <judge+83>: add rax,rdx
0x600b56 <judge+86>: mov edx,DWORD PTR [rbp-0x4]
0x600b59 <judge+89>: movsxd rcx,edx
0x600b5c <judge+92>: mov rdx,QWORD PTR [rbp-0x28]
0x600b60 <judge+96>: add rdx,rcx
0x600b63 <judge+99>: movzx edx,BYTE PTR [rdx]
0x600b66 <judge+102>:mov ecx,DWORD PTR [rbp-0x4]
0x600b69 <judge+105>:xor edx,ecx
0x600b6b <judge+107>:mov BYTE PTR [rax],dl
0x600b6d <judge+109>:add DWORD PTR [rbp-0x4],0x1
0x600b71 <judge+113>:cmp DWORD PTR [rbp-0x4],0xd
0x600b75 <judge+117>:jle 0x600b49 <judge+73>
0x600b77 <judge+119>:mov DWORD PTR [rbp-0x4],0x0
0x600b7e <judge+126>:jmp 0x600ba9 <judge+169>
0x600b80 <judge+128>:mov eax,DWORD PTR [rbp-0x4]
0x600b83 <judge+131>:movsxd rdx,eax
0x600b86 <judge+134>:mov rax,QWORD PTR [rbp-0x28]
0x600b8a <judge+138>:add rax,rdx
0x600b8d <judge+141>:movzx edx,BYTE PTR [rax]
0x600b90 <judge+144>:mov eax,DWORD PTR [rbp-0x4]
0x600b93 <judge+147>:cdqe
0x600b95 <judge+149>:movzx eax,BYTE PTR [rbp+rax*1-0x20]
0x600b9a <judge+154>:cmp dl,al
0x600b9c <judge+156>:je 0x600ba5 <judge+165>
0x600b9e <judge+158>:mov eax,0x0
0x600ba3 <judge+163>:jmp 0x600bb4 <judge+180>
0x600ba5 <judge+165>:add DWORD PTR [rbp-0x4],0x1
0x600ba9 <judge+169>:cmp DWORD PTR [rbp-0x4],0xd
0x600bad <judge+173>:jle 0x600b80 <judge+128>
0x600baf <judge+175>:mov eax,0x1
0x600bb4 <judge+180>:pop rbp
0x600bb5 <judge+181>:ret
0x600bb6 <completed.6661>: add BYTE PTR [rax],al
...
pwndbg>
3)分析
0x600b04 <judge+4>: mov QWORD PTR [rbp-0x28],rdi
0x600b08 <judge+8>: mov BYTE PTR [rbp-0x20],0x66
0x600b0c <judge+12>: mov BYTE PTR [rbp-0x1f],0x6d
0x600b10 <judge+16>: mov BYTE PTR [rbp-0x1e],0x63
0x600b14 <judge+20>: mov BYTE PTR [rbp-0x1d],0x64
0x600b18 <judge+24>: mov BYTE PTR [rbp-0x1c],0x7f
0x600b1c <judge+28>: mov BYTE PTR [rbp-0x1b],0x6b
0x600b20 <judge+32>: mov BYTE PTR [rbp-0x1a],0x37
0x600b24 <judge+36>: mov BYTE PTR [rbp-0x19],0x64
0x600b28 <judge+40>: mov BYTE PTR [rbp-0x18],0x3b
0x600b2c <judge+44>: mov BYTE PTR [rbp-0x17],0x56
0x600b30 <judge+48>: mov BYTE PTR [rbp-0x16],0x60
0x600b34 <judge+52>: mov BYTE PTR [rbp-0x15],0x3b
0x600b38 <judge+56>: mov BYTE PTR [rbp-0x14],0x6e
0x600b3c <judge+60>: mov BYTE PTR [rbp-0x13],0x70
内存[rbp-0x20]到[rbp-4]刚好14个数据。
0x600b47 <judge+71>: jmp 0x600b71 <judge+113>
0x600b49 <judge+73>: mov eax,DWORD PTR [rbp-0x4]
0x600b4c <judge+76>: movsxd rdx,eax
0x600b4f <judge+79>: mov rax,QWORD PTR [rbp-0x28]
0x600b53 <judge+83>: add rax,rdx
0x600b56 <judge+86>: mov edx,DWORD PTR [rbp-0x4]
0x600b59 <judge+89>: movsxd rcx,edx
0x600b5c <judge+92>: mov rdx,QWORD PTR [rbp-0x28]
0x600b60 <judge+96>: add rdx,rcx
0x600b63 <judge+99>: movzx edx,BYTE PTR [rdx]
0x600b66 <judge+102>:mov ecx,DWORD PTR [rbp-0x4]
0x600b69 <judge+105>:xor edx,ecx
0x600b6b <judge+107>:mov BYTE PTR [rax],dl
0x600b6d <judge+109>:add DWORD PTR [rbp-0x4],0x1
0x600b71 <judge+113>:cmp DWORD PTR [rbp-0x4],0xd
0x600b75 <judge+117>:jle 0x600b49 <judge+73>
这段代码的意思是,将我们输入的数据按字节与[rbp-0x4]中的数据异或,[rbp-0x4]从零开始,每执行一次加一
0x600b77 <judge+119>:mov DWORD PTR [rbp-0x4],0x0
0x600b7e <judge+126>:jmp 0x600ba9 <judge+169>
0x600b80 <judge+128>:mov eax,DWORD PTR [rbp-0x4]
0x600b83 <judge+131>:movsxd rdx,eax
0x600b86 <judge+134>:mov rax,QWORD PTR [rbp-0x28]
0x600b8a <judge+138>:add rax,rdx
0x600b8d <judge+141>:movzx edx,BYTE PTR [rax]
0x600b90 <judge+144>:mov eax,DWORD PTR [rbp-0x4]
0x600b93 <judge+147>:cdqe
0x600b95 <judge+149>:movzx eax,BYTE PTR [rbp+rax*1-0x20]
0x600b9a <judge+154>:cmp dl,al
0x600b9c <judge+156>:je 0x600ba5 <judge+165>
0x600b9e <judge+158>:mov eax,0x0
0x600ba3 <judge+163>:jmp 0x600bb4 <judge+180>
0x600ba5 <judge+165>:add DWORD PTR [rbp-0x4],0x1
0x600ba9 <judge+169>:cmp DWORD PTR [rbp-0x4],0xd
0x600bad <judge+173>:jle 0x600b80 <judge+128>
0x600baf <judge+175>:mov eax,0x1
这段代码的意思是,[rbp-0x20]-[rbp-0x13]中的数据和上一步异或后的数据比较,相同时返回1,不同返回0。
所以flag是[rbp-0x20]-[rbp-0x13]中的数据异或range(0,14)
解密脚本
judge = [0x66, 0x6d, 0x63, 0x64, 0x7f, 0x6b, 0x37,
0x64, 0x3b, 0x56, 0x60, 0x3b, 0x6e, 0x70]
flag = ''
for i in range(len(judge)):
flag += chr(i ^ judge[i])
print(flag)
解密脚本
judge = [0x66, 0x6d, 0x63, 0x64, 0x7f, 0x6b, 0x37,
0x64, 0x3b, 0x56, 0x60, 0x3b, 0x6e, 0x70]
flag = ''
for i in range(len(judge)):
flag += chr(i ^ judge[i])
print(flag)
得到
flag{n1c3_j0b}