声明
1)该文章部分借鉴于[BUUCTF]Reverse——[SWPU2019]ReverseMe。
2)博主是萌新上路,文中如有不当之处,请各位大佬指出,共同进步,谢谢。
题目
题目链接:ReverseMe
分析
1)查壳,
2)无壳,扔进ida,
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // ecx
int *v4; // eax
int v5; // ecx
int *v6; // eax
int v8; // [esp+0h] [ebp-C4h]
char v9[16]; // [esp+84h] [ebp-40h] BYREF
v4 = sub_CD2DA0(v3, "Please input your flag: ");
sub_CD3050((int)v4);
sub_CD37B0(v8);
strcpy(v9, "SWPU_2019_CTF");
v6 = sub_CD2DA0(v5, "Try again!\r\n");
sub_CD3050((int)v6);
sub_CDADBE("pause");
return 0;
}
3)点开各个函数,有好多复杂的函数,静态分析有难度,进行动调,在程序入口的头部下断点,即0x00CD2810
,
4)F8单步往下直到输入,即运行到call sub_CF37B0
,
5)先随便输入继续往下看,输入结束后将 ebp-0x90
处的值跟32比较,更改 ZF 标志位,0xCF28C7
处的 jz 会根据这边的情况进行跳转,如果 ZF 标志位为0,则跳转,否则就会输出 Try again,退出程序。ebp-0x90
处放的是我们输入的字符串的长度,因此我们输入的字符串的长度必须是32,
补充:汇编语言的标志位 ZF:零标志位。相关指令执行后结果为0那么 ZF=1,结果不为0则 ZF=0;
6)输入32位字符串重新动调,这是第一个对输入的字符串进行操作的地方,
7)查看一下异或之后的结果,值存在 ecx 中,
8)继续往下,发现此处在往 eax 中存值,
9)接着往下,eax 与 edx 进行比较,如果不一样则跳转结束,
eax 的值:
edx的值:
10)整理一下,edx 是由 ecx 在 call sub_CD25C0
中异或产生的,因此通过 edx 异或 ecx 可以得出这一组数 temp[]
,那么程序运行思路就是:输入 --> 与 SWPU_2019_CTF
异或 --> 再与 temp[]
异或 --> 最后与 eax 进行比较。
PayLoad:
ecx = [0x62, 0x66, 0x61, 0x64, 0x6e, 0x03, 0x01, 0x00,
0x08, 0x6e, 0x72, 0x65, 0x77, 0x62, 0x66, 0x61,
0x64, 0x6e, 0x03, 0x01, 0x00, 0x08, 0x6e, 0x72,
0x65, 0x77, 0x62, 0x66, 0x61, 0x64, 0x6e, 0x03]
edx = [0xE4, 0x6A, 0x5F, 0xAE, 0xF6, 0xD4, 0xAF, 0x19,
0xEA, 0x19, 0x19, 0xC3, 0x1D, 0xC3, 0x11, 0xD1,
0x0D, 0xFF, 0x34, 0x04, 0x7A, 0xF1, 0x15, 0x42,
0x26, 0x2D, 0x29, 0x76, 0xE7, 0x19, 0xBA, 0x2B]
eax = [0xB3, 0x37, 0x0F, 0xF8, 0xBC, 0xBC, 0xAE, 0x5D,
0xBA, 0x5A, 0x4D, 0x86, 0x44, 0x97, 0x62, 0xD3,
0x4F, 0xBA, 0x24, 0x16, 0x0B, 0x9F, 0x72, 0x1A,
0x65, 0x68, 0x6D, 0x26, 0xBA, 0x6B, 0xC8, 0x67]
temp = [0]*32
str = "SWPU_2019_CTF"
flag=""
for i in range(32):
temp[i] = int(hex(edx[i]^ecx[i]),16)^eax[i]
flag += chr(temp[i]^ord(str[i%len(str)]))
print(flag)
# flag{Y0uaretheB3st!#@_VirtualCC}