asm_re

Arm汇编审计

当时虽然汇编指令没看懂,但是操作大概是能顺下来的。

找到加密过程和密文就行。

加密过程在loc_100003D00处

image-20240522220954819

大概就是说(((W8*0x50)+20)^0x4D)+30这样一个加密过程。

然后根据W8找到密文的位置。

image-20240522221026588

这里因为是用双字节去存储的,所以要提取双字节数字,注意小端序。

EXP:

1
2
3
4
5
x=[8151, 8631, 7751, 8231, 9959, 4311, 4391, 8199, 4551, 7751, 4119, 4119, 4599, 8199, 4151, 4359, 7959, 4311, 4119, 4119, 8039, 4119, 4551, 4551, 4119, 8151, 7959, 4359, 3911, 4391, 4151, 7751, 4151, 8151, 4359, 8151, 4359, 10119]

for i in range(len(x)):
y=(((x[i]-30)^0x4D)-20)/0x50
print(chr(int(y)),end="")

gdb_debug

动静结合

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int v3; // eax
void *v5; // rsp
size_t v6; // rax
size_t v7; // rax
size_t v8; // rax
size_t v9; // rax
void *v10; // rsp
size_t v11; // rax
char v12; // bl
size_t v13; // rax
size_t v14; // rax
void *v15; // rsp
size_t v16; // rax
__int64 v17[10]; // [rsp+0h] [rbp-130h] BYREF
unsigned __int8 v18; // [rsp+55h] [rbp-DBh]
char v19; // [rsp+56h] [rbp-DAh]
char v20; // [rsp+57h] [rbp-D9h]
unsigned __int64 ii; // [rsp+58h] [rbp-D8h]
unsigned __int64 n; // [rsp+60h] [rbp-D0h]
unsigned __int64 m; // [rsp+68h] [rbp-C8h]
size_t k; // [rsp+70h] [rbp-C0h]
unsigned __int64 j; // [rsp+78h] [rbp-B8h]
unsigned __int64 i; // [rsp+80h] [rbp-B0h]
size_t v27; // [rsp+88h] [rbp-A8h]
__int64 *v28; // [rsp+90h] [rbp-A0h]
void *ptr; // [rsp+98h] [rbp-98h]
size_t v30; // [rsp+A0h] [rbp-90h]
__int64 *v31; // [rsp+A8h] [rbp-88h]
char *v32; // [rsp+B0h] [rbp-80h]
char *s2; // [rsp+B8h] [rbp-78h]
size_t v34; // [rsp+C0h] [rbp-70h]
char *s1; // [rsp+C8h] [rbp-68h]
char s[40]; // [rsp+D0h] [rbp-60h] BYREF
unsigned __int64 v37; // [rsp+F8h] [rbp-38h]

v37 = __readfsqword(0x28u);
v3 = time(0LL);
srand(v3 & 0xF0000000);
puts("Please enter the flag string (ensuring the format is 'flag{}' and the total length is 38 characters).");
__isoc99_scanf("%39s", s);
if ( strlen(s) == 38 && s[0] == 102 && s[1] == 108 && s[2] == 97 && s[3] == 103 && s[4] == 123 && s[37] == 125 )
{
v27 = strlen(s);
v17[8] = v27 + 1;
v17[9] = 0LL;
v17[6] = v27 + 1;
v17[7] = 0LL;
v5 = alloca(16 * ((v27 + 16) / 0x10));
v28 = v17;
for ( i = 0LL; ; ++i )
{
v6 = strlen(s);
if ( i >= v6 )
break;
v20 = rand();
*(v28 + i) = s[i] ^ v20;
}
v7 = strlen(s);
ptr = malloc(v7);
if ( ptr )
{
for ( j = 0LL; ; ++j )
{
v8 = strlen(s);
if ( j >= v8 )
break;
*(ptr + j) = j;
}
for ( k = strlen(s) - 1; k; --k )
{
v18 = rand() % (k + 1);
v19 = *(ptr + k);
*(ptr + k) = *(ptr + v18);
*(ptr + v18) = v19;
}
v9 = strlen(s) + 1;
v30 = v9 - 1;
v17[4] = v9;
v17[5] = 0LL;
v17[2] = v9;
v17[3] = 0LL;
v10 = alloca(16 * ((v9 + 15) / 0x10));
v31 = v17;
for ( m = 0LL; ; ++m )
{
v11 = strlen(s);
if ( m >= v11 )
break;
*(v31 + m) = *(v28 + *(ptr + m));
}
for ( n = 0LL; ; ++n )
{
v13 = strlen(s);
if ( n >= v13 )
break;
v12 = *(v31 + n);
*(v31 + n) = rand() ^ v12;
}
putchar(10);
v32 = byte_10A0;
s2 = "congratulationstoyoucongratulationstoy";
v14 = strlen(byte_10A0) + 1;
v34 = v14 - 1;
v17[0] = v14;
v17[1] = 0LL;
v15 = alloca(16 * ((v14 + 15) / 0x10));
s1 = v17;
for ( ii = 0LL; ; ++ii )
{
v16 = strlen(v32);
if ( ii >= v16 )
break;
s1[ii] = *(v31 + ii) ^ v32[ii];
}
if ( !strcmp(s1, s2) )
puts("Correct.");
else
puts("Error. ");
free(ptr);
return 0LL;
}
else
{
fwrite("Memory allocation failed.\n", 1uLL, 0x1AuLL, stderr);
return 1LL;
}
}
else
{
puts("The input format is incorrect or the length does not meet the requirements.");
return 1LL;
}
}

大致浏览一下,加密逻辑简单,但是有随机函数rand(),一般来说都是伪随机,我们需要通过动调来找出rand() 的值。

先找到srand(), 看看是不是固定seed。

image-20240522221613155

很明显是一个固定值,那接下来就是动调出三个rand的值。

image-20240522221651671

这里固定格式为flag{}且总长度为38,随便构造一个输入符合格式的就行flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}

先找第一个rand()的值,找到rand()的位置,下断

image-20240522221952923

这里我们首先要明确,为什莫要求出来rand()的值,首先我们是不知道flag的,也就是说我们无法正推出rand的值,反推的话,我们就需要知道v20也就是rand()值与密文v28的异或,从而来推出我们最终的flag。

我们肯定是要从v28来入手,我们知道的是自己输入的flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}这一串字符,动调出v28的结果,我们就能直接算出此处rand()的值。

EXP:

1
2
3
4
5
6
7
8
9
x=b"flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}"
y=[0xBF, 0x63, 0x79, 0xDA, 0xBC, 0x77, 0xE0, 0xDF, 0x99, 0x2B,
0x04, 0x93, 0x3C, 0xCA, 0x4A, 0x52, 0xB5, 0xC4, 0x06, 0xF9,
0xFE, 0x1F, 0x4A, 0x3C, 0xA3, 0xCE, 0xEF, 0x5B, 0x2D, 0xC4,
0x14, 0x44, 0xD5, 0xEC, 0x82, 0x1A, 0xC2, 0x19]
rand1=[0]*len(x)
for i in range(len(x)):
rand1[i]=x[i]^y[i]
print(rand1)

第二个rand,这里其实知不知道rand的值的问题不大,因为我们最终要的是ptr的结果。

image-20240522223225082

这里的ptr相当于从0到0x25根据v18 = rand() % (k + 1)的值打乱顺序了,所以变化在ptr上,不需要知道这里的rand()值。所以rand的值不知道也没事,可以直接动调找到ptr的结果。

需要注意的是这里ptr是由malloc来分配的地址,分配的地址位置是随机的,找的时候注意别找错就行。

ptr=[0x12, 0x0E, 0x1B, 0x1E, 0x11, 0x05, 0x07, 0x01, 0x10, 0x22,

0x06, 0x17, 0x16, 0x08, 0x19, 0x13, 0x04, 0x0F, 0x02, 0x0D,

0x25, 0x0C, 0x03, 0x15, 0x1C, 0x14, 0x0B, 0x1A, 0x18, 0x09,

0x1D, 0x23, 0x1F, 0x20, 0x24, 0x0A, 0x00, 0x21]

然后下边v28是经过了一个打乱,最后的值赋给了v31,这里知道就好。

image-20240522223839223

来找第三个rand(),

image-20240522223921343

这里可以跟rand1一样,用异或直接得到rand()的值。调试出v12,和v31的值就行,注意这里必须要rand的值,跟第一个rand的理解一样。

Exp:

1
2
3
4
5
6
7
8
9
10
11
12
v31=[0x06, 0x4A, 0x5B, 0x14, 0xC4, 0x77, 0xDF, 0x63, 0xB5, 0x82,
0xE0, 0x3C, 0x4A, 0x99, 0xCE, 0xF9, 0xBC, 0x52, 0x79, 0xCA,
0x19, 0x3C, 0xDA, 0x1F, 0x2D, 0xFE, 0x93, 0xEF, 0xA3, 0x2B,
0xC4, 0x1A, 0x44, 0xD5, 0xC2, 0x04, 0xBF, 0xEC]
result=[ 0xD8, 0xE0, 0x19, 0xE8, 0xCD, 0x9F, 0x6D, 0x65, 0xB8, 0x11,
0x81, 0xC8, 0x6E, 0xD0, 0xDB, 0xF8, 0x6B, 0xF9, 0x7D, 0xD2,
0xD6, 0xD5, 0x0F, 0x89, 0x1E, 0x34, 0x6A, 0xC5, 0xFD, 0xC1,
0xE9, 0x26, 0xD0, 0xBA, 0xFA, 0x99, 0xE7, 0x06]
rand3=[0]*len(v31)
for i in range(len(v31)):
rand3[i]=v31[i]^result[i]
print(rand3)

image-20240522224116669

这里s1,s2做比较,那s2就是密文,已经给出,这个s1是byte_55C59C2010A0的值

跟进提取出来,然后这两个值进行异或得出v31的值,

到这里就通了,逆过程推回去就好。

EXP:

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
v32=[ 0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73,
0xAC, 0xF1, 0x06, 0xBE, 0xAD, 0x88, 0x04, 0xD7, 0x12, 0xFE,
0xB5, 0xE2, 0x61, 0xB7, 0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2,
0x9D, 0x4D, 0xBC, 0x81, 0x8C, 0xE9, 0x88, 0x78]
s1=b"congratulationstoyoucongratulationstoy"
v31=[0]*len(v32)
for i in range(len(s1)):
v31[i]=s1[i]^v32[i]
print(v31)
v12=[0]*len(v32)
rand3=[222, 170, 66, 252, 9, 232, 178, 6, 13, 147, 97, 244, 36, 73, 21, 1, 215, 171, 4, 24, 207, 233, 213, 150, 51, 202, 249, 42, 94, 234, 45, 60, 148, 111, 56, 157, 88, 234]
for i in range(len(v12)):
v12[i]=rand3[i]^v31[i]
print(v12)
v18=[0x21,0x0,0xa,0x0,0x20,0x1f,0xa,0x1d,0x9,0x18,0x1a,0xb,0x14,0x18,0x15,0x3,0xc,0xa,0xd,0x2,0xf,0x4,0xd,0xa,0x8,0x3,0x3,0x6,0x0,0x4,0x1,0x1,0x5,0x4,0x0,0x0,0x1]
ptr=[0x12, 0x0E, 0x1B, 0x1E, 0x11, 0x05, 0x07, 0x01, 0x10, 0x22,
0x06, 0x17, 0x16, 0x08, 0x19, 0x13, 0x04, 0x0F, 0x02, 0x0D,
0x25, 0x0C, 0x03, 0x15, 0x1C, 0x14, 0x0B, 0x1A, 0x18, 0x09,
0x1D, 0x23, 0x1F, 0x20, 0x24, 0x0A, 0x00, 0x21]
v28=[0]*len(ptr)
for i in range(len(ptr)):
v28[ptr[i]]=v12[i]
print(v28)
rand1=[0xD9, 0x0f, 0x18, 0xbd, 0xc7, 0x16, 0x81, 0xbe, 0xf8, 0x4A, 0x65, 0xf2, 0x5D, 0xab, 0x2B, 0x33, 0xd4, 0xa5, 0x67, 0x98, 0x9f, 0x7E, 0x2B, 0x5D, 0xc2, 0xaf, 0x8e, 0x3A, 0x4C, 0xa5, 0x75, 0x25, 0xb4, 0x8d, 0xe3, 0x7B, 0xa3, 0x64
]
s=[0]*0x26
for i in range(len(rand1)):
print(chr(v28[i]^rand1[i]),end="")