第一次CTF参赛

第一次参加ctf,负责划水逆向题…虽然学长说这次的题水分很大(并且很快被他们做完了)但我觉得我仍然收获了很多

1.首先是心得:

开始下下来题后,是一道输入flag经过判断函数判断正确的题,习惯暴力破解的我一直在找简单方法避免分析判断函数,最后得到的结果是….不行,必须分析这种偷懒的心思浪费了不少时间

2.关于工具

首先用的od….虽然很快定位到了主函数和判断函数..但是纯汇编的算法让我分析了一阵子就崩溃了……于是该用xdbg反汇编…结果…也很难懂….最后用了不太熟的ida….md简直是神器..反出来的代码真好读……

3.关于解题法

来看看反汇编出的代码吧:
main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *v3; // eax@1
int v4; // edx@1
void *v5; // eax@3
int result; // eax@3
size_t v7; // eax@5
void *v8; // eax@7
void *v9; // eax@10
void *v10; // eax@12
void *v11; // eax@13
char v12; // [sp+Ch] [bp-CCh]@1
unsigned int i; // [sp+4Ch] [bp-8Ch]@4
char v14[4]; // [sp+50h] [bp-88h]@4
char v15[28]; // [sp+58h] [bp-80h]@1
char v16; // [sp+74h] [bp-64h]@9
memset(&v12, 0xCCu, 0xCCu);
v3 = (void *)sub_402B30(&unk_446360, "Give me your flag:");
sub_4013F0(v3, (int (__cdecl *)(void *))sub_403670);
sub_401440((int)&dword_4463F0, v4, (int)v15, 127);
if ( strlen(v15) < 0x1E && strlen(v15) > 4 )
{
strcpy(v14, "EIS{");
for ( i = 0; ; ++i )
{
v7 = strlen(v14);
if ( i >= v7 )
break;
if ( v15[i] != v14[i] )
{
v8 = (void *)sub_402B30(&unk_446360, "Sorry, keep trying! ");
sub_4013F0(v8, (int (__cdecl *)(void *))sub_403670);
return 0;
}
}
if ( v16 == 125 )
{
if ( sub_4011C0(v15) )
{
v11 = (void *)sub_402B30(&unk_446360, "Congratulations! ");
sub_4013F0(v11, (int (__cdecl *)(void *))sub_403670);
result = 0;
}
else
{
v10 = (void *)sub_402B30(&unk_446360, "Sorry, keep trying! ");
sub_4013F0(v10, (int (__cdecl *)(void *))sub_403670);
result = 0;
}
}
else
{
v9 = (void *)sub_402B30(&unk_446360, "Sorry, keep trying! ");
sub_4013F0(v9, (int (__cdecl *)(void *))sub_403670);
result = 0;
}
}
else
{
v5 = (void *)sub_402B30(&unk_446360, "Sorry, keep trying!");
sub_4013F0(v5, (int (__cdecl *)(void *))sub_403670);
result = 0;
}
return result;
}

判断函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
bool __cdecl sub_4011C0(char *a1)
{
bool result; // al@2
size_t v2; // eax@4
size_t v3; // eax@7
char v4; // [sp+Ch] [bp-F4h]@1
int v5; // [sp+4Ch] [bp-B4h]@15
int v6; // [sp+50h] [bp-B0h]@6
char v7[32]; // [sp+54h] [bp-ACh]@6
int v8; // [sp+74h] [bp-8Ch]@6
int i; // [sp+78h] [bp-88h]@3
unsigned int j; // [sp+7Ch] [bp-84h]@3
char v11[128]; // [sp+80h] [bp-80h]@5
memset(&v4, 0xCCu, 0xF4u);
if ( strlen(a1) > 4 )
{
j = 4;
for ( i = 0; ; ++i )
{
v2 = strlen(a1);
if ( j >= v2 - 1 )
break;
v11[i] = a1[j++];
}
v11[i] = 0;
v8 = 0;
v6 = 0;
memset(v7, 0, 0x20u);
for ( j = 0; ; ++j )
{
v3 = strlen(v11);
if ( j >= v3 )
break;
if ( v11[j] >= 97 && v11[j] <= 122 )
{
v11[j] -= 32;
v6 = 1;
}
if ( !v6 && v11[j] >= 65 && v11[j] <= 90 )
v11[j] += 32;
v5 = sub_4013C0(v11[j]);
v7[j] = byte_4420B0[j] ^ v5;
v6 = 0;
}
result = strcmp("GONDPHyGjPEKruv{{pj]X@rF", v7) == 0;
}
else
{
result = 0;
}
return result;
}
int __cdecl sub_4013C0(int a1)
{
return (a1 ^ 0x55) + 72;
}

注意俩个已有的串:

1
2
GONDPHyGjPEKruv{{pj]X@rF
byte_4420B0[j]=(0x0D, 0x13, 0x17, 0x11, 0x2, 0x1, 0x20, 0x1D, 0x0C, 0x2, 0x19, 0x2F, 0x17, 0x2B, 0x24, 0x1F, 0x1E, 0x16, 0x9, 0x0F, 0x15, 0x27, 0x13, 0x26, 0x0A, 0x2F, 0x1E, 0x1A, 0x2D, 0x0C, 0x22, 0x4)

开始的时候没看出第二个是已有的…..
好了,步骤:
设输入的串(答案)为s。已有的串q1,q2
1.看懂流程(画出流程图)
2.详细分析函数正向过程:比如此题为(1)大变小小变大(2)(s[i]^0x55+72)^q2[i]
3.结果与q1比较,一样就对。
好了,接下来是重点
设上述步骤为F(x);
接下来就是写出其反函数
这里涉及的离散知识为:若A=B^C,那么B=A^C;C=A^B
证明:A^C=B^C^C,C^C=0,B^0=B
于是写出逆向算法
1.((q1[i] ^ q2[i]) - 0x48) ^ 0x55;
2.大变小小变大
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "stdio.h"
int main(void)
{
char y[25] = { "GONDPHyGjPEKruv{{pj]X@rF" };
unsigned char x[0x20] = { 0x0D, 0x13, 0x17, 0x11, 0x2, 0x1, 0x20, 0x1D, 0x0C, 0x2, 0x19, 0x2F, 0x17, 0x2B, 0x24, 0x1F, 0x1E, 0x16, 0x9, 0x0F, 0x15, 0x27, 0x13, 0x26, 0x0A, 0x2F, 0x1E, 0x1A, 0x2D, 0x0C, 0x22, 0x4 };
for (int i = 0; i < 24; i++)
{
x[i] = ((x[i] ^ y[i]) - 0x48) ^ 0x55;
if (x[i] >= 'A' && x[i] <= 'Z')
x[i] += 0x20;
else if(x[i] >= 'a' && x[i] <= 'z')
x[i] -=0x20;
else
;
}
x[24] = 0;
printf("EIS{%s}", x);
return 0;
}

结语

虽然鄙视了自己一天….但最终还算看到点希望….逆向的硬功夫就是分析机器代码,多想多写。话说寻找反函数这或许就是加密解密之间的战争吧……嘛…..该去看看加密解密算法之类的了……
ctf的加密算法大多的已经存在的!!!!系统学习密码学