简析一道白盒AES逆向题

要附件可以找我

是个apk文件,java层没啥

直接看so层

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
bool __fastcall sub_F7B8(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
int8x16_t *v6; // x21
unsigned __int8 *v7; // x19
__int64 n16; // x8
_BYTE *v9; // x9
unsigned __int64 v10; // x11
char v11; // w12
_BOOL8 result; // x0
int v13; // w9
unsigned __int64 n31; // x12
unsigned __int64 n0x1E; // x11
int v16; // w14
int v17; // w13
unsigned __int8 v18; // [xsp+0h] [xbp-50h]
_BYTE v19[51]; // [xsp+1h] [xbp-4Fh] BYREF
unsigned __int8 v20[20]; // [xsp+34h] [xbp-1Ch] BYREF
__int64 v21; // [xsp+48h] [xbp-8h]

v21 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
v6 = (int8x16_t *)(*(__int64 (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)a1 + 1352LL))(a1, a3, 0LL);
v7 = (unsigned __int8 *)(*(__int64 (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)a1 + 1352LL))(a1, a4, 0LL);
sub_EDB0(v6, v20);
n16 = 0LL;
v9 = v19;
do
{
v10 = v20[n16++];
v11 = a0123456789abcd[v10 >> 4];
LOBYTE(v10) = a0123456789abcd[v10 & 0xF];
*(v9 - 1) = v11;
*v9 = v10;
v9 += 2;
}
while ( n16 != 16 );
result = 0LL;
v13 = *v7;
v19[31] = 0;
if ( (v18 ^ 7) == v13 )
{
n31 = 0LL;
do
{
n0x1E = n31;
if ( n31 == 31 )
break;
v16 = v7[n31 + 1];
v17 = byte_86AB[n31 + 1] ^ (unsigned __int8)v19[n31];
++n31;
}
while ( v17 == v16 );
return n0x1E > 0x1E;
}
return result;
}

有个异或和类似base家族的编码

image-20251106085504948

image-20251106085516545

加密代码:

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
int8x16_t __fastcall sub_EDB0(int8x16_t *a1, unsigned __int8 *a2)
{
unsigned __int8 *v2; // x11
__int64 v3; // x9
__int64 n9; // x10
char *v5; // x13
char *v6; // x14
unsigned __int8 *v7; // x15
unsigned __int8 *v8; // x16
unsigned __int8 *v9; // x17
unsigned __int8 *v10; // x2
char *v11; // x3
__int64 n24576; // x19
unsigned __int8 *v13; // x20
__int64 v14; // x21
unsigned __int64 v15; // x25
unsigned __int64 v16; // x24
unsigned __int64 v17; // x23
unsigned __int64 v18; // x22
unsigned __int8 v19; // w26
unsigned __int8 v20; // w27
unsigned __int8 v21; // w8
__int64 v22; // x30
__int64 v23; // x1
char *v24; // x23
unsigned __int8 v25; // w12
unsigned __int64 v26; // x22
char *v27; // x12
unsigned __int64 v28; // x24
unsigned __int64 v29; // x25
unsigned __int64 v30; // x23
char v31; // w8
int8x16_t result; // q0
unsigned __int8 v33; // w10
_BYTE *v34; // x11
__int64 v35; // x13
_BYTE *v36; // x12
_BYTE *v37; // x12
__int64 v38; // x13
_BYTE *v39; // x12
__int64 v40; // x13
_BYTE *v41; // x12
__int64 v42; // x13
_BYTE *v43; // x12
__int64 v44; // x13
_BYTE *v45; // x12
__int64 v46; // x13
_BYTE *v47; // x12
__int64 v48; // x13
_BYTE *v49; // x12
__int64 v50; // x13
_BYTE *v51; // x12
__int64 v52; // x13
_BYTE *v53; // x12
__int64 v54; // x13
_BYTE *v55; // x12
__int64 v56; // x13
_BYTE *v57; // x12
__int64 v58; // x13
_BYTE *v59; // x12
__int64 v60; // x13

v2 = (unsigned __int8 *)&unk_84610;
v3 = 0LL;
n9 = 0LL;
v5 = (char *)&unk_85D10;
v6 = (char *)&unk_85C10;
v7 = (unsigned __int8 *)&unk_85B10;
v8 = (unsigned __int8 *)&unk_85A10;
v9 = (unsigned __int8 *)&unk_85910;
v10 = (unsigned __int8 *)&unk_85810;
v11 = (char *)&unk_85710;
_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
do
{
n24576 = 0LL;
v13 = &a1->n128_u8[3];
v14 = v3;
*a1 = vqtbl1q_s8(*a1, (int8x16_t)xmmword_7360);
do
{
v15 = *(unsigned int *)((char *)&dword_38610[*(v13 - 3)] + v14);
v16 = *(unsigned int *)((char *)&dword_38610[*(v13 - 2) + 256] + v14);
v17 = *(unsigned int *)((char *)&dword_38610[*(v13 - 1) + 512] + v14);
v18 = *(unsigned int *)((char *)&dword_38610[*v13 + 768] + v14);
v19 = v2[16 * v2[((v16 >> 24) & 0xF | (16 * ((v15 >> 24) & 0xF))) + 512 + n24576]
+ 1280
+ v2[((v18 >> 24) & 0xF | (16 * ((v17 >> 24) & 0xF))) + 768 + n24576]
+ n24576] | (16
* v2[16 * v2[((v15 >> 24) & 0xF0 | (v16 >> 28)) + n24576]
+ 1024
+ v2[((v17 >> 24) & 0xF0 | (v18 >> 28)) + 256 + n24576]
+ n24576]);
*(v13 - 3) = v19;
v20 = v2[16 * v2[((v16 >> 16) & 0xF | (16 * ((v15 >> 16) & 0xF))) + 2048 + n24576]
+ 2816
+ v2[((v18 >> 16) & 0xF | (16 * ((v17 >> 16) & 0xF))) + 2304 + n24576]
+ n24576] | (16
* v2[16 * v2[((v16 >> 20) & 0xF | (16 * ((v15 >> 20) & 0xF))) + 1536 + n24576]
+ 2560
+ v2[((v18 >> 20) & 0xF | (16 * ((v17 >> 20) & 0xF))) + 1792 + n24576]
+ n24576]);
*(v13 - 2) = v20;
v21 = v11[16 * v2[((v16 >> 8) & 0xF | (16 * ((v15 >> 8) & 0xF))) + 3584 + n24576]
+ v2[((v18 >> 8) & 0xF | (16 * ((v17 >> 8) & 0xF))) + 3840 + n24576]
+ n24576] | (16
* v2[16
* v2[(((unsigned __int16)v16 >> 12) & 0xFFFFFFFFFFFFFF0FLL | (16
* (((unsigned __int16)v15 >> 12) & 0xFLL)))
+ 3072
+ n24576]
+ 4096
+ v2[(((unsigned __int16)v18 >> 12) & 0xFFFFFFFFFFFFFF0FLL | (16
* (((unsigned __int16)v17 >> 12) & 0xFLL)))
+ 3328
+ n24576]
+ n24576]);
v22 = ((unsigned __int8)v18 >> 4) | (16LL * ((unsigned __int8)v17 >> 4));
*(v13 - 1) = v21;
v23 = v7[(v18 & 0xF | (16 * (v17 & 0xF))) + n24576] + 16LL * v8[(v16 & 0xF | (16 * (v15 & 0xF))) + n24576];
v24 = (char *)&dword_5C610[v20] + v14;
v25 = v5[v23 + n24576] | (16
* v6[16
* v10[(((unsigned __int8)v16 >> 4) | (16LL * ((unsigned __int8)v15 >> 4))) + n24576]
+ v9[v22 + n24576]
+ n24576]);
*v13 = v25;
v26 = *(unsigned int *)((char *)&dword_5C610[v19] + v14);
v27 = (char *)&dword_5C610[v25] + v14;
v28 = *(unsigned int *)((char *)&dword_5C610[v21 + 512] + v14);
v14 += 4096LL;
v29 = *((unsigned int *)v24 + 256);
v30 = *((unsigned int *)v27 + 768);
*(v13 - 3) = v2[16 * v2[((v29 >> 24) & 0xF | (16 * ((v26 >> 24) & 0xF))) + 512 + n24576]
+ 1280
+ v2[((v30 >> 24) & 0xF | (16 * ((v28 >> 24) & 0xF))) + 768 + n24576]
+ n24576] | (16
* v2[16 * v2[((v26 >> 24) & 0xF0 | (v29 >> 28)) + n24576]
+ 1024
+ v2[((v28 >> 24) & 0xF0 | (v30 >> 28)) + 256 + n24576]
+ n24576]);
*(v13 - 2) = v2[16 * v2[((v29 >> 16) & 0xF | (16 * ((v26 >> 16) & 0xF))) + 2048 + n24576]
+ 2816
+ v2[((v30 >> 16) & 0xF | (16 * ((v28 >> 16) & 0xF))) + 2304 + n24576]
+ n24576] | (16
* v2[16 * v2[((v29 >> 20) & 0xF | (16 * ((v26 >> 20) & 0xF))) + 1536 + n24576]
+ 2560
+ v2[((v30 >> 20) & 0xF | (16 * ((v28 >> 20) & 0xF))) + 1792 + n24576]
+ n24576]);
*(v13 - 1) = v11[16 * v2[((v29 >> 8) & 0xF | (16 * ((v26 >> 8) & 0xF))) + 3584 + n24576]
+ v2[((v30 >> 8) & 0xF | (16 * ((v28 >> 8) & 0xF))) + 3840 + n24576]
+ n24576] | (16
* v2[16
* v2[(((unsigned __int16)v29 >> 12) & 0xFFFFFFFFFFFFFF0FLL | (16
* (((unsigned __int16)v26 >> 12) & 0xFLL)))
+ 3072
+ n24576]
+ 4096
+ v2[(((unsigned __int16)v30 >> 12) & 0xFFFFFFFFFFFFFF0FLL | (16
* (((unsigned __int16)v28 >> 12) & 0xFLL)))
+ 3328
+ n24576]
+ n24576]);
LOBYTE(v27) = v6[16 * v10[(((unsigned __int8)v29 >> 4) | (16LL * ((unsigned __int8)v26 >> 4))) + n24576]
+ v9[(((unsigned __int8)v30 >> 4) | (16LL * ((unsigned __int8)v28 >> 4))) + n24576]
+ n24576];
v31 = v5[16 * v8[(v29 & 0xF | (16 * (v26 & 0xF))) + n24576]
+ v7[(v30 & 0xF | (16 * (v28 & 0xF))) + n24576]
+ n24576];
n24576 += 6144LL;
*v13 = v31 | (16 * (_BYTE)v27);
v13 += 4;
}
while ( n24576 != 24576 );
++n9;
v2 += 24576;
v5 += 24576;
v6 += 24576;
v7 += 24576;
v8 += 24576;
v9 += 24576;
v10 += 24576;
v11 += 24576;
v3 += 0x4000LL;
}
while ( n9 != 9 );
result = vqtbl1q_s8(*a1, (int8x16_t)xmmword_7360);
*a1 = result;
v33 = byte_37610[a1->n128_u8[0]];
v34 = &byte_37610[a1->n128_u8[1]];
v35 = a1->n128_u8[3];
v36 = &byte_37610[a1->n128_u8[2]];
a1->n128_u8[0] = v33;
a1->n128_u8[1] = v34[256];
LOBYTE(v34) = v36[512];
v37 = &byte_37610[v35];
v38 = a1->n128_u8[4];
a1->n128_u8[2] = (unsigned __int8)v34;
LOBYTE(v34) = v37[768];
v39 = &byte_37610[v38];
v40 = a1->n128_u8[5];
a1->n128_u8[3] = (unsigned __int8)v34;
LOBYTE(v34) = v39[1024];
v41 = &byte_37610[v40];
v42 = a1->n128_u8[6];
a1->n128_u8[4] = (unsigned __int8)v34;
LOBYTE(v34) = v41[1280];
v43 = &byte_37610[v42];
v44 = a1->n128_u8[7];
a1->n128_u8[5] = (unsigned __int8)v34;
LOBYTE(v34) = v43[1536];
v45 = &byte_37610[v44];
v46 = a1->n128_u8[8];
a1->n128_u8[6] = (unsigned __int8)v34;
LOBYTE(v34) = v45[1792];
v47 = &byte_37610[v46];
v48 = a1->n128_u8[9];
a1->n128_u8[7] = (unsigned __int8)v34;
LOBYTE(v34) = v47[2048];
v49 = &byte_37610[v48];
v50 = a1->n128_u8[10];
a1->n128_u8[8] = (unsigned __int8)v34;
LOBYTE(v34) = v49[2304];
v51 = &byte_37610[v50];
v52 = a1->n128_u8[11];
a1->n128_u8[9] = (unsigned __int8)v34;
LOBYTE(v34) = v51[2560];
v53 = &byte_37610[v52];
v54 = a1->n128_u8[12];
a1->n128_u8[10] = (unsigned __int8)v34;
LOBYTE(v34) = v53[2816];
v55 = &byte_37610[v54];
v56 = a1->n128_u8[13];
a1->n128_u8[11] = (unsigned __int8)v34;
LOBYTE(v34) = v55[3072];
v57 = &byte_37610[v56];
v58 = a1->n128_u8[14];
a1->n128_u8[12] = (unsigned __int8)v34;
LOBYTE(v34) = v57[3328];
v59 = &byte_37610[v58];
v60 = a1->n128_u8[15];
a1->n128_u8[13] = (unsigned __int8)v34;
a1->n128_u8[14] = v59[3584];
a1->n128_u8[15] = byte_37610[v60 + 3840];
*a2 = v33;
*(_QWORD *)(a2 + 1) = *(unsigned __int64 *)((char *)a1->n128_u64 + 1);
*(_DWORD *)(a2 + 9) = *(unsigned __int32 *)((char *)&a1->n128_u32[2] + 1);
*(_WORD *)(a2 + 13) = *(unsigned __int16 *)((char *)&a1->n128_u16[6] + 1);
a2[15] = a1->n128_u8[15];
return result;
}

是个白盒AES

如何识别?

image-20251106090217855

不是 SM4:SM4 是 32 轮、32 位字为核心的结构,这里只有 9 次外层轮\

高度疑似白盒 AES

  • 使用 vqtbl1q_s8 做字节重排(像 ShiftRows 的固定置换)。
  • 大量 Nibble/Byte 级多级查表T-Table/合成盒(composition box) 风格的组合。
  • 最后一层对每个字节用 位置相关 S 盒byte_37610[byte + pos*256])做外部编码(external encoding)。
  • 多个巨大常量表分块、以 4096/24576 为步长滚动使用;这正是白盒里把“轮函数+轮密钥”都固化到表里后的典型形态。

与标准 AES 轮数不完全对齐:标准 AES-128 有 10 轮;这里外层循环 9 次,且每轮内又分两段表混合+末尾还有一层位置相关替换与重排。白盒里常把“首/末轮”和外部编码折叠到表里,导致表象轮数与标准描述不一致,这并不反常。

白盒AES简述:

白盒AES算法详解(一)-密码应用-看雪论坛-安全社区|非营利性质技术交流社区

详解白盒AES以及C代码实现(以CTF赛题讲解白盒AES)-先知社区

使用frida分析白盒aes,DFA攻击 - GGBomb - 博客园

白盒AES的初探 | twogoat/showmakerの小站

白盒AES加密DFA逆向 - 简书

在白盒攻击环境中,密钥变得无所遁形,因此诞生了一系列的魔改算法,其中应用最广、效果最好的莫过于白盒算法,该算法在白盒攻击环境下被提出,能够保证密钥在内存分析、动态调试过程中不被发现。

DFA:

在加密过程中 故意引入一个错误(例如在某一轮注入一个字节错位或随机改写)。

比较 **正确输出与 故障输出 的差异(按字节或按列)。

利用 AES 的内部结构把这些差异“反推出”最后一轮的子密钥字节,然后通过逆向密钥调度恢复主密钥。

对 AES,最常见/有效的模型是在 倒数第 2 轮与倒数第 1 轮之间(即 Round-9 与 Round-10 之间)引入 1 字节故障,这会导致最后密文呈现特定可利用的差分模式,从而可以穷举并验证某些候选轮密钥字节(每列独立)。

phoenixAES 是一个 Python 工具/库,用于对 AES(以及 white-box AES 等变体)执行 DFA 恢复最后几轮子密钥 / 主密钥的攻击。项目托管在 JeanGrey / SideChannelMarvels 仓库,并在 PyPI 有包。它实现了 Piret & Quisquater 等经典 DFA 模型(例如“simple R9”模型),并提供 crack_file 等接口来处理事先记录的密文文件。

用DFA的板子去搞出故障文

需要把这几个盒先dump下来

1
2
3
ida_bytes.get_bytes(0x37610, 16 * 256) # Tbox
ida_bytes.get_bytes(0x5C610, 10 * 16 * 256 * 4) # mixBijOut
ida_bytes.get_bytes(0x38610, 9 * 16 * 256 * 4) # TyiBoxes

C++代码不贴了,想要的私我

这个是个示例脚本:

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
public static void AAA(byte[] aaa, byte[] bbb)
{
for (int i = 0; i < 9; i++)
{
Program.GGG(aaa); // 第十轮时在这里更改一个字节的密文
for (int j = 0; j < 4; j++)
{
uint num = Program.v11[i, 4 * j, (int)aaa[4 * j]];
uint num2 = Program.v11[i, 4 * j + 1, (int)aaa[4 * j + 1]];
uint num3 = Program.v11[i, 4 * j + 2, (int)aaa[4 * j + 2]];
uint num4 = Program.v11[i, 4 * j + 3, (int)aaa[4 * j + 3]];
uint num5 =
(uint)Program.v12[i, 24 * j, (int)(num >> 28 & 15U), (int)(num2 >> 28 & 15U)];
uint num6 = (uint)Program.v12[i, 24 * j + 1, (int)(num3 >> 28 & 15U), (int)(num4 >> 28 & 15U)];
uint num7 = (uint)Program.v12[i, 24 * j + 2, (int)(num >> 24 & 15U), (int)(num2 >> 24 & 15U)];
uint num8 = (uint)Program.v12[i, 24 * j + 3, (int)(num3 >> 24 & 15U), (int)(num4 >> 24 & 15U)];
aaa[4 * j] = (byte)((int)Program.v12[i, 24 * j + 4, (int)num5, (int)num6] << 4 | (int)Program.v12[i, 24 * j + 5, (int)num7, (int)num8]);
num5 = (uint)Program.v12[i, 24 * j + 6, (int)(num >> 20 & 15U), (int)(num2 >> 20 & 15U)];
num6 = (uint)Program.v12[i, 24 * j + 7, (int)(num3 >> 20 & 15U), (int)(num4 >> 20 & 15U)];
num7 = (uint)Program.v12[i, 24 * j + 8, (int)(num >> 16 & 15U), (int)(num2 >> 16 & 15U)];
num8 = (uint)Program.v12[i, 24 * j + 9, (int)(num3 >> 16 & 15U), (int)(num4 >> 16 & 15U)];
aaa[4 * j + 1] = (byte)((int)Program.v12[i, 24 * j + 10, (int)num5, (int)num6] << 4 | (int)Program.v12[i, 24 * j + 11, (int)num7, (int)num8]);
num5 = (uint)Program.v12[i, 24 * j + 12, (int)(num >> 12 & 15U), (int)(num2 >> 12 & 15U)];
num6 = (uint)Program.v12[i, 24 * j + 13, (int)(num3 >> 12 & 15U), (int)(num4 >> 12 & 15U)];
num7 = (uint)Program.v12[i, 24 * j + 14, (int)(num >> 8 & 15U), (int)(num2 >> 8 & 15U)];
num8 = (uint)Program.v12[i, 24 * j + 15, (int)(num3 >> 8 & 15U), (int)(num4 >> 8 & 15U)];
aaa[4 * j + 2] = (byte)((int)Program.v12[i, 24 * j + 16, (int)num5, (int)num6] << 4 | (int)Program.v12[i, 24 * j + 17, (int)num7, (int)num8]);
num5 = (uint)Program.v12[i, 24 * j + 18, (int)(num >> 4 & 15U), (int)(num2 >> 4 & 15U)];
num6 = (uint)Program.v12[i, 24 * j + 19, (int)(num3 >> 4 & 15U), (int)(num4 >> 4 & 15U)];
num7 = (uint)Program.v12[i, 24 * j + 20, (int)(num & 15U), (int)(num2 & 15U)];
num8 = (uint)Program.v12[i, 24 * j + 21, (int)(num3 & 15U), (int)(num4 & 15U)];
aaa[4 * j + 3] = (byte)((int)Program.v12[i, 24 * j + 22, (int)num5, (int)num6] << 4 | (int)Program.v12[i, 24 * j + 23, (int)num7, (int)num8]);
num = Program.v13[i, 4 * j, (int)aaa[4 * j]];
num2 = Program.v13[i, 4 * j + 1, (int)aaa[4 * j + 1]];
num3 = Program.v13[i, 4 * j + 2, (int)aaa[4 * j + 2]];
num4 = Program.v13[i, 4 * j + 3, (int)aaa[4 * j + 3]];
num5 = (uint)Program.v12[i, 24 * j, (int)(num >> 28 & 15U), (int)(num2 >> 28 & 15U)];
num6 = (uint)Program.v12[i, 24 * j + 1, (int)(num3 >> 28 & 15U), (int)(num4 >> 28 & 15U)];
num7 = (uint)Program.v12[i, 24 * j + 2, (int)(num >> 24 & 15U), (int)(num2 >> 24 & 15U)];
num8 = (uint)Program.v12[i, 24 * j + 3, (int)(num3 >> 24 & 15U), (int)(num4 >> 24 & 15U)];
aaa[4 * j] = (byte)((int)Program.v12[i, 24 * j + 4, (int)num5, (int)num6] << 4 | (int)Program.v12[i, 24 * j + 5, (int)num7, (int)num8]);
num5 = (uint)Program.v12[i, 24 * j + 6, (int)(num >> 20 & 15U), (int)(num2 >> 20 & 15U)];
num6 = (uint)Program.v12[i, 24 * j + 7, (int)(num3 >> 20 & 15U), (int)(num4 >> 20 & 15U)];
num7 = (uint)Program.v12[i, 24 * j + 8, (int)(num >> 16 & 15U), (int)(num2 >> 16 & 15U)];
num8 = (uint)Program.v12[i, 24 * j + 9, (int)(num3 >> 16 & 15U), (int)(num4 >> 16 & 15U)];
aaa[4 * j + 1] = (byte)((int)Program.v12[i, 24 * j + 10, (int)num5, (int)num6] << 4 | (int)Program.v12[i, 24 * j + 11, (int)num7, (int)num8]);
num5 = (uint)Program.v12[i, 24 * j + 12, (int)(num >> 12 & 15U), (int)(num2 >> 12 & 15U)];
num6 = (uint)Program.v12[i, 24 * j + 13, (int)(num3 >> 12 & 15U), (int)(num4 >> 12 & 15U)];
num7 = (uint)Program.v12[i, 24 * j + 14, (int)(num >> 8 & 15U), (int)(num2 >> 8 & 15U)];
num8 = (uint)Program.v12[i, 24 * j + 15, (int)(num3 >> 8 & 15U), (int)(num4 >> 8 & 15U)];
aaa[4 * j + 2] = (byte)((int)Program.v12[i, 24 * j + 16, (int)num5, (int)num6] << 4 | (int)Program.v12[i, 24 * j + 17, (int)num7, (int)num8]);
num5 = (uint)Program.v12[i, 24 * j + 18, (int)(num >> 4 & 15U), (int)(num2 >> 4 & 15U)];
num6 = (uint)Program.v12[i, 24 * j + 19, (int)(num3 >> 4 & 15U), (int)(num4 >> 4 & 15U)];
num7 = (uint)Program.v12[i, 24 * j + 20, (int)(num & 15U), (int)(num2 & 15U)];
num8 = (uint)Program.v12[i, 24 * j + 21, (int)(num3 & 15U), (int)(num4 & 15U)];
aaa[4 * j + 3] = (byte)((int)Program.v12[i, 24 * j + 22, (int)num5, (int)num6] << 4 | (int)Program.v12[i, 24 * j + 23, (int)num7, (int)num8]);
}
}
Program.GGG(aaa);
for (int k = 0; k < 16; k++)
{
aaa[k] = Program.v14[9, k, (int)aaa[k]];
}
for (int l = 0; l < 16; l++)
{
bbb[l] = aaa[l]; // 获取结果
}
}

输出类似:

image-20251106110903404

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
import phoenixAES
with open('tracefile', 'wb') as t:
t.write("""6d77f89125479f13bfa46c0de402f9e2
6d4df89124479f13bfa46c94e402b5e2
6d71f89118479f13bfa46c29e402d0e2
6d771b9125309f130aa46c0de402f9fb
6d770a9125229f133fa46c0de402f9c0
6d77f85925474113bf146c0dcf02f9e2
6d77989125c99f136ca46c0de402f982
6dcef89152479f13bfa46cdfe4023ae2
6dcaf891cf479f13bfa46c39e40219e2
6d77e49125c89f13ada46c0de402f9ec
6dc5f891e9479f13bfa46cdae4025de2
6dbcf89188479f13bfa46c62e4029fe2
6d77f83225477413bf0b6c0da702f9e2
6d77f81b2547a113bfcf6c0d9b02f9e2
6d77599125669f1327a46c0de402f996
6d774e91251a9f132ca46c0de402f943
7f77f89125479f4fbfa4040de4aaf9e2
8577f89125479f3ebfa4e60de492f9e2
6d49f891f4479f13bfa46c76e4026ae2
6d776691253f9f1397a46c0de402f975
6d46f89109479f13bfa46c20e4021de2
6d76f89159479f13bfa46cebe40248e2
7277f89125479f10bfa4760de4d9f9e2
6de1f891ef479f13bfa46c5de40229e2
9677f89125479f06bfa4de0de499f9e2
6d77f80325477213bf566c0d9a02f9e2
6dc9f8919d479f13bfa46c09e40287e2
6d77f80025473a13bf036c0d9902f9e2
a577f89125479ffdbfa4e90de418f9e2
6d9bf891ef479f13bfa46c26e402ebe2
6d77f8e025472813bf636c0d9e02f9e2
6da1f89141479f13bfa46c99e402cee2
6d77f86325471713bfde6c0db102f9e2
6ddcf89191479f13bfa46c4ce40230e2
6d772691259f9f13c6a46c0de402f9fd
1677f89125479f03bfa4900de491f9e2
7677f89125479f2bbfa4830de4ddf9e2
6d82f891c2479f13bfa46c12e402c8e2
6d778b9125e79f13b5a46c0de402f975
e777f89125479f44bfa4900de4f4f9e2
6db0f8913f479f13bfa46c42e4029de2
de77f89125479f1cbfa43f0de4dcf9e2
6d77f85125477c13bfd36c0d2602f9e2
5b77f89125479f97bfa4cc0de473f9e2
e077f89125479fabbfa4230de45bf9e2
6d8ef89145479f13bfa46c35e40280e2
6dbaf891c7479f13bfa46c29e402b6e2
0877f89125479fd5bfa4410de47af9e2
6177f89125479f63bfa4f70de406f9e2
8777f89125479f49bfa4f90de445f9e2
6dddf891e1479f13bfa46c8ce4028fe2
6d77f8262547fb13bf2a6c0dc002f9e2
b277f89125479f31bfa4180de40ef9e2
6dabf89142479f13bfa46ceee402a5e2
6d77539125629f1353a46c0de402f998
6d774491259a9f139ca46c0de402f9a6
6d47f8914f479f13bfa46ce8e40272e2
6d77f8ae25473c13bf9b6c0d0002f9e2
6d77e791259d9f13faa46c0de402f9da
6d77e69125b59f1360a46c0de402f923
6d3af89111479f13bfa46c06e4027ce2
6d77f8ad25478613bfb56c0da202f9e2
6d77f85e2547d513bf666c0dcb02f9e2
6d77f82625474213bf5b6c0df502f9e2
""".encode('utf8'))

phoenixAES.crack_file('tracefile')

output:55D5B46BC0D4E03D0FCF03D9D6BE2974

还有的故障注入方法如Frida和Unidbg

Unidbg:还挺麻烦你的好像:

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
public class Wbaes extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
private final Module module;

public Wbaes() {
emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("").build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM();
vm.setJni(this);
vm.setVerbose(false);
DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/wbaes/ex2/libhoneybee.so"), true);
module = dm.getModule();
}

public int randInt(int min, int max) {
Random rand = new Random();
return rand.nextInt(max - min) + min;
}

public void patch() {
// patch log
emulator.getMemory().pointer(module.base + 0x9342).setInt(0, 0xbf00bf00);
emulator.getMemory().pointer(module.base + 0x9354).setInt(0, 0xbf00bf00);
}

public void dfa() {
IHookZz hookZz = HookZz.getInstance(emulator);
hookZz.wrap(module.base + 0x9e59, new WrapCallback<HookZzArm32RegisterContext>() {
@Override
public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
final Pointer output = ctx.getR0Pointer();
ctx.push(output);

emulator.attach().addBreakPoint(module.base + 0xA2AC, new BreakPointCallback() {
int count = 0;
@Override
public boolean onHit(Emulator<?> emulator, long address) {
count += 1;
// System.out.println(count);
if (count == 9) {
output.setByte(randInt(0, 15), (byte) randInt(0, 255));
}
return true;
}
});
}

@Override
public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
Pointer output = ctx.pop();
byte[] outputHex = output.getByteArray(0, 16);
System.out.println(Hex.encodeHexString(outputHex));
}
});
}

public void call_wb() {
List<Object> list = new ArrayList<>(10);
list.add(vm.getJNIEnv());
list.add(0);
list.add(vm.addLocalObject(new ByteArray(vm, "everhu".getBytes())));
Number ret = module.callFunction(emulator, 0x92cd, list.toArray());
byte[] bytes = (byte[]) vm.getObject(ret.intValue()).getValue();
// System.out.println(Hex.encodeHexString(bytes));
}

public static void main(String[] args) {
Wbaes test = new Wbaes();
test.patch();
test.dfa();
for (int i = 0; i<32; i++) {
test.call_wb();
}
}
}

Frida方法

这个是其它题目的板子

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
import frida
import sys
session = frida.attach("m1_read.exe")
script = session.create_script("""
var baseAddr = Module.findBaseAddress("m1_read.exe");
var whiteAES = new NativeFunction(baseAddr.add(0x4BF0), 'pointer', ['pointer', 'pointer'])
var count = 9;
Interceptor.attach(baseAddr.add(0x4C2C), {
onEnter: function(args) {
count++;
if(count == 9) {
// 在第十轮的输入[0:16]中随机修改其中一个字节
this.context.rdi.add(Math.floor(Math.random() * 16)).writeU8(Math.floor(Math.random() * 256));
}
},
onLeave: (retval) => {
}
})

for (let index = 0; index < 32; index++) {
var l = Memory.allocAnsiString("1234567890abcdef");
var b = Memory.alloc(16);
whiteAES(l, b);
// console.log(b.readByteArray(16));
console.log(Array.from(new Uint8Array(b.readByteArray(16))).map(byte => byte.toString(16).padStart(2, '0')).join(''));
count = 0;
}
""")
script.load()
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
let num = null;
function hook_change_state(){
let baseaddr = Module.findBaseAddress('libencrypt.so');
let data_state = null; //明文加密后的地址,故障文注入地址
let w20_addr = baseaddr.add(0x8970);
let aes_result = null; //aes加密结果

Interceptor.attach(baseaddr.add(0x86f8), {
onEnter:function(args){
aes_result = args[2]
},
onLeave:function(retval){
//console.log("aes加密结果为====>>>>>>",hexdump(aes_result))
let aes_data_to_print = Memory.readByteArray(aes_result, 16);
// 将字节数组转换为十六进制字符串
let hexString = Array.from(new Uint8Array(aes_data_to_print))
.map(b => ('0' + b.toString(16)).slice(-2)) // 转换为十六进制,确保两位
.join('');

console.log("aes加密结果为====>>>>>>", hexString);

}

})

Interceptor.attach(baseaddr.add(0x7874), {
onEnter:function(args){
//console.log("args[2]===>>>", hexdump(args[2]));
data_state = args[2];
},
onLeave:function(retval){
//console.log("state_addr==>>", hexdump(data_state));
}
})

Interceptor.attach(w20_addr, {
onEnter:function(args){
if(this.context.x20 == 0x8){
//console.log("state_data=====>>>>>>>>>>>>>>>>>>>>>>",hexdump(data_state));
Memory.writeByteArray(data_state, [num])
//console.log("修改的state如下:"+hexdump(data_state))
}
},
onLeave:function(retval){

}
})
}

function hook_call(){
let nums=[0x39,0x20,0x36,0x72,0x27]
hook_change_state()
for (let i = 0; i < nums.length; i++) {
num = nums[i]
//console.log("num====>>>", num)
call()
console.log("================================================")
}
}

然后就是求最终的密钥了

1
git clone https://github.com/SideChannelMarvels/Stark.git

然后进入目录make即可

image-20251106113312961

java层其实还有个admin的MD5做异或

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Cipher import AES
import hashlib

key = bytes.fromhex('4D31056BCB6C74BF923ACC9E96CD3EF6')
username_hash = b'21232f297a57a5a743894a0e4a801fc3'
cipher = AES.new(key, AES.MODE_ECB)

xor_key = bytes.fromhex('070201520757530D5553500154515153035701585704045350550F0503575B06')

e = [a ^ b for a, b in zip(username_hash, xor_key)]

flag = cipher.decrypt(bytes.fromhex(bytes(e).decode()))
print(hashlib.md5(flag).hexdigest())

451d4276e8ea8cffb66d6861d02732cf