[N1BOOK 第五章 CTF之RE章]BabyAlgorithm

题目链接:BUUCTF [第五章 CTF之RE章]BabyAlgorithm

太久不做题脑袋空空了…

扫描

64位无壳

代码逻辑

主函数:

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
67
68
69
70
71
72
73
74
75
76
77
78
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 result; // rax
int i; // [rsp+Ch] [rbp-E4h]
char v5[16]; // [rsp+10h] [rbp-E0h] BYREF
char s[64]; // [rsp+20h] [rbp-D0h] BYREF
char v7[64]; // [rsp+60h] [rbp-90h] BYREF
char v8[72]; // [rsp+A0h] [rbp-50h] BYREF
unsigned __int64 v9; // [rsp+E8h] [rbp-8h]

v9 = __readfsqword(0x28u);
memset(v8, 0, 0x40uLL);
v8[0] = -58;
v8[1] = 33;
v8[2] = -54;
v8[3] = -65;
v8[4] = 81;
v8[5] = 67;
v8[6] = 55;
v8[7] = 49;
v8[8] = 117;
v8[9] = -28;
v8[10] = -114;
v8[11] = -64;
v8[12] = 84;
v8[13] = 111;
v8[14] = -113;
v8[15] = -18;
v8[16] = -8;
v8[17] = 90;
v8[18] = -94;
v8[19] = -63;
v8[20] = -21;
v8[21] = -91;
v8[22] = 52;
v8[23] = 109;
v8[24] = 113;
v8[25] = 85;
v8[26] = 8;
v8[27] = 7;
v8[28] = -78;
v8[29] = -88;
v8[30] = 47;
v8[31] = -12;
v8[32] = 81;
v8[33] = -114;
v8[34] = 12;
v8[35] = -52;
qmemcpy(&v8[36], "3S1", 3);
v8[40] = 64;
v8[41] = -42;
v8[42] = -54;
v8[43] = -20;
v8[44] = -44;
puts("Input flag: ");
__isoc99_scanf("%63s", s);
if ( strlen(s) == 45 )
{
strcpy(v5, "Nu1Lctf233");
sub_400874(v5, s, v7);
for ( i = 0; i <= 44; ++i )
{
if ( v7[i] != v8[i] )
{
puts("GG!");
return 0LL;
}
}
puts("Congratulations!");
result = 0LL;
}
else
{
puts("GG!");
result = 0LL;
}
return result;
}

定义了一堆数组v8,输入经过sub_400874操作后结果要与v8相同

进sub_400874函数,分两个小函数

image-20251105090955244

sub_40067A

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
__int64 __fastcall sub_40067A(const char *a1, __int64 a2)
{
int v3; // [rsp+10h] [rbp-10h]
int i; // [rsp+14h] [rbp-Ch]
int j; // [rsp+18h] [rbp-8h]
int v6; // [rsp+1Ch] [rbp-4h]

v6 = strlen(a1);
v3 = 0;
for ( i = 0; i <= 255; ++i )
*(_BYTE *)(i + a2) = i;
for ( j = 0; j <= 255; ++j )
{
v3 = (*(unsigned __int8 *)(j + a2) + v3 + a1[j % v6]) % 256;
sub_400646(j + a2, a2 + v3);
}
return 0LL;
}

sub_400753

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
__int64 __fastcall sub_400753(__int64 a1, const char *a2, __int64 a3)
{
int v5; // [rsp+24h] [rbp-1Ch]
int v6; // [rsp+28h] [rbp-18h]
size_t v7; // [rsp+30h] [rbp-10h]
size_t v8; // [rsp+38h] [rbp-8h]

v5 = 0;
v6 = 0;
v7 = 0LL;
v8 = strlen(a2);
while ( v7 < v8 )
{
v5 = (v5 + 1) % 256;
v6 = (v6 + *(unsigned __int8 *)(v5 + a1)) % 256;
sub_400646(v5 + a1, a1 + v6);
*(_BYTE *)(a3 + v7) = a2[v7] ^ *(_BYTE *)((unsigned __int8)(*(_BYTE *)(v5 + a1) + *(_BYTE *)(v6 + a1)) + a1);
++v7;
}
return 0LL;
}

这个小函数sub_400646是swap

1
2
3
4
5
6
7
8
9
10
11
char *__fastcall sub_400646(char *a1, char *a2)
{
char *result; // rax
char v3; // [rsp+1Ch] [rbp-4h]

v3 = *a1;
*a1 = *a2;
result = a2;
*a2 = v3;
return result;
}

都有%256,以及swap,猜测是RC4。那么key就是Nu1Lctf233

解密

丢进RC4代码里跑一下,能看到flag格式,但是有乱码

image-20251105092439622

查到最后发现是因为v8里有个0。这里只定义了36 37 38,40 41,还有个39没定义,还是初始化时默认的0

image-20251105095755993

那么RC4代码也要改变一下,因为现在用的strlen,碰到0就会截断。直接改成45

image-20251105100216171

flag:

1
n1book{us1nG_f3atur3s_7o_de7erm1n3_4lg0ri7hm}