算法详解

AES(Advanced Encryption Standard)是新一代的加密标准,其分组长度为128位,密钥长度常为128位。AES的SPN(Substitution-Permutation Network,代换-置换网络) 结构是其加密过程的核心设计思想。SPN 是一种对称密钥分组密码结构,通过多轮重复的 代换(Substitution) 和 置换(Permutation) 操作,结合密钥扩展机制,实现高效的混淆(Confusion)和扩散(Diffusion),从而确保安全性。

AES加密算法的SPN结构有四步操作:逐字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。

  1. 逐字节替代SubBytes:

    AES 加密中的核心非线性操作步骤,通过S盒对状态矩阵的每个字节进行替换,实现混淆。代码中,SubBytes通过查表高效实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// S 盒定义(部分)
unsigned char S[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
// ... 其余 240 个字节
};

// SubBytes 函数
int subBytes(uint8_t (*state)[4]) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = S[state[i][j]]; // 直接查表替换
}
}
return 0;
}
  1. 行移位ShiftRows:

    行移位(ShiftRows)​ 是 AES 加密中的关键步骤,属于 ​置换(Permutation)​ 操作,负责在状态矩阵的行方向上扩散字节,增强算法的 ​扩散性(Diffusion)​,使得单个字节的变化能在多轮迭代后扩散到整个密文分组。其代码实现为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int shiftRows(uint8_t (*state)[4]) {
uint32_t block[4] = {0};

// 将每行 4 字节转换为 32 位整数
for (int i = 0; i < 4; ++i) {
LOAD32H(block[i], state[i]);
}

// 按行循环左移不同偏移量
block[1] = ROF32(block[1], 8); // 行1左移1字节
block[2] = ROF32(block[2], 16); // 行2左移2字节
block[3] = ROF32(block[3], 24); // 行3左移3字节

// 将32位整数转回字节数组
for (int i = 0; i < 4; ++i) {
STORE32H(block[i], state[i]);
}

return 0;
}
  1. 列混淆MixColumns:

    是 AES 加密中的核心线性变换步骤,属于​扩散(Diffusion)操作,负责在状态矩阵的列方向上混合字节,使得单个字节的变化扩散到整个列。其通过​矩阵乘法对每一列进行变换,代码实现为:

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
// 有限域乘法函数
uint8_t GMul(uint8_t a, uint8_t b) {
uint8_t p = 0;
for (int i = 0; i < 8; ++i) {
if (b & 0x01) {
p ^= a;
}
int hiBitSet = (a & 0x80);
a <<= 1;
if (hiBitSet) {
a ^= 0x1B; // 异或不可约多项式 0x11B(去最高位)
}
b >>= 1;
}
return p;
}

// 列混淆(加密)
int mixColumns(uint8_t (*state)[4]) {
uint8_t tmp[4][4];
uint8_t M[4][4] = {{0x02, 0x03, 0x01, 0x01},
{0x01, 0x02, 0x03, 0x01},
{0x01, 0x01, 0x02, 0x03},
{0x03, 0x01, 0x01, 0x02}};

// 复制原始状态到临时矩阵
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
tmp[i][j] = state[i][j];
}
}

// 矩阵乘法
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
state[i][j] = GMul(M[i][0], tmp[0][j]) ^
GMul(M[i][1], tmp[1][j]) ^
GMul(M[i][2], tmp[2][j]) ^
GMul(M[i][3], tmp[3][j]);
}
}
return 0;
}
  1. 轮密钥异或AddRoundKey:

    是 AES 加密和解密中的关键步骤,在每轮中通过 ​异或(XOR)操作 将当前状态矩阵与轮密钥(Round Key)结合,确保密钥信息融入每一轮的处理过程。它是 AES 中唯一直接使用密钥的步骤,承担了密钥混淆的核心作用。在代码中,轮密钥通常以 ​32 位字(uint32_t)​ 存储,需转换为 4×4 字节矩阵后再异或:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int addRoundKey(uint8_t (*state)[4], const uint32_t *roundKey) {
uint8_t keyBytes[4][4]; // 将轮密钥从uint32_t[4]转换为4x4字节矩阵

// 提取轮密钥的每个字节
for (int col = 0; col < 4; col++) {
keyBytes[0][col] = (uint8_t)(roundKey[col] >> 24); // 高位字节
keyBytes[1][col] = (uint8_t)(roundKey[col] >> 16);
keyBytes[2][col] = (uint8_t)(roundKey[col] >> 8);
keyBytes[3][col] = (uint8_t)(roundKey[col] & 0xFF); // 低位字节
}

// 逐字节异或
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
state[row][col] ^= keyBytes[row][col];
}
}
return 0;
}

而AES的密钥生成过程则是将初始密钥(128/192/256位)扩展为多轮加密所需的​轮密钥(Round Keys)​ 的过程。以 AES-128(128位密钥,10轮加密)为例,密钥扩展生成11个轮密钥​(每轮使用一个)。

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
// 密钥扩展函数
void KeyExpansion(const uint8_t *key, uint32_t *w) {
// 加载初始密钥到w[0]-w[3]
for (int i = 0; i < 4; i++) {
w[i] = ((uint32_t)key[4*i] << 24) |
((uint32_t)key[4*i+1] << 16) |
((uint32_t)key[4*i+2] << 8) |
(uint32_t)key[4*i+3];
}

// 生成后续字(w[4]-w[43])
for (int i = 4; i < 44; i++) {
uint32_t temp = w[i-1];
if (i % 4 == 0) {
temp = SubWord(RotWord(temp)) ^ Rcon[i/4];
}
w[i] = w[i-4] ^ temp;
}
}

// 循环左移1字节
uint32_t RotWord(uint32_t x) {
return (x << 8) | (x >> 24);
}

// S盒替换
uint32_t SubWord(uint32_t x) {
return (S[(x >> 24) & 0xFF] << 24) |
(S[(x >> 16) & 0xFF] << 16) |
(S[(x >> 8) & 0xFF] << 8) |
S[x & 0xFF];
}

代码实现

完整的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
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
#include <stdio.h>
#include <stdlib.h>

void she(int *p)//S盒
{
int i;
int s[256] =
{
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
};
for (i = 0; i < 16; i++)*(p + i) = s[*(p + i)];
}

void gshe(int *p)//g-S盒
{
int i;
int s[256] =
{
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
};
for (i = 0; i < 4; i++)*(p + i) = s[*(p + i)];
}

void left(int *p)//行移位
{
int i, j;
int b[4][4];
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
b[j][i] = *(p + j * 4 + (i + j) % 4);
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
*(p + i + j * 4) = b[j][i];
}

void addbyte16(int *p, int *q)//4*4矩阵字节加法,结果保存到左加数,也为轮密钥加
{
int i, j;
for (j = 0; j < 4; j++)for (i = 0; i < 4; i++)
*(p + j * 4 + i) = *(p + j * 4 + i) ^ *(q + j * 4 + i);
}

void addbyte4(int *p, int *q)//1*4矩阵字节加法,结果保存到左加数
{
int i;
for (i = 0; i < 4; i++)
*(p + i) = *(p + i) ^ *(q + i);
}

int mul(int b,int a)//有限域上的乘法,只定义了01、02、03与其他数相乘
{
if (b == 0x02)
{
if (a < 0x80)a = (a * 0x02);
else a = ((a % 0x80) * 0x02) ^ 0x1b;
}
if (b == 0x03)
{
if (a < 0x80)b = (a * 0x02);
else b = ((a % 0x80) * 0x02) ^ 0x1b;
a = a^b;
}
return a;
}

void column(int *p, int *q)//列混淆
{
int i, j;
int a[4][4];
for (j = 0; j < 4; j++)for (i = 0; i < 4; i++)
{
a[j][i] = mul(*(q + j * 4 + 0), *(p + 0 * 4 + i)) ^ mul(*(q + j * 4 + 1), *(p + 1 * 4 + i)) ^
mul(*(q + j * 4 + 2), *(p + 2 * 4 + i)) ^ mul(*(q + j * 4 + 3), *(p + 3 * 4 + i));
}
for (j = 0; j < 4; j++)for (i = 0; i < 4; i++)*(p + j * 4 + i) = a[j][i];
}

void g(int *p,int j)//g函数
{
int rc[10] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36 };
int i,a = *p;
for (i = 0; i < 3; i++)*(p+i) = *(p + i + 1);*(p + 3) = a;
gshe(p);
*p = *p^rc[j];
}

void keyextension(int *p, int j)//密钥扩展
{
int a[4], b[4], c[4], d[4], d1[4];
int i, *q1 = &a[0], *q2 = &b[0], *q3 = &c[0], *q4 = &d[0], *q5 = &d1[0];
for (i = 0; i < 4; i++)a[i] = *(p + i * 4 + 0);
for (i = 0; i < 4; i++)b[i] = *(p + i * 4 + 1);
for (i = 0; i < 4; i++)c[i] = *(p + i * 4 + 2);
for (i = 0; i < 4; i++)d[i] = *(p + i * 4 + 3);
for (i = 0; i < 4; i++)d1[i] = *(p + i * 4 + 3);
g(q5, j);
addbyte4(q1, q5);
addbyte4(q2, q1);
addbyte4(q3, q2);
addbyte4(q4, q3);
for (i = 0; i < 4; i++)*(p + i * 4 + 0) = a[i];
for (i = 0; i < 4; i++)*(p + i * 4 + 1) = b[i];
for (i = 0; i < 4; i++)*(p + i * 4 + 2) = c[i];
for (i = 0; i < 4; i++)*(p + i * 4 + 3) = d[i];
}

int main(int argc, char *argv[]) {
int i, j;
int u[4][4],key[4][4];

//输入明文
printf("input plaintext:\n");
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
scanf("%x",&u[j][i]);

//输入密钥
printf("input key:\n");
for (j = 0; j < 4; j++)
for (i = 0; i < 4; i++)
scanf("%x",&key[j][i]);

//列混淆常数矩阵
int u1[4][4] =
{
0x02,0x03,0x01,0x01,
0x01,0x02,0x03,0x01,
0x01,0x01,0x02,0x03,
0x03,0x01,0x01,0x02
};
int *p = &u[0][0];
int *q = &u1[0][0];
int *k = &key[0][0];

//第一轮前
addbyte16(p,k);

//第一轮到第九轮(0~8)
for(i=0;i<9;i++)
{
she(p);
left(p);
column(p,q);
keyextension(k,i);
addbyte16(p,k);
}

//第十轮
she(p);
left(p);
keyextension(k,9);
addbyte16(p,k);

//密文输出
printf("ciphertext:\n");
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)printf("%x ", u[i][j]);
printf("\n");
}

system("pause");
return 0;
}

python代码实现可表示为:

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
class AES:

MIX_C = [[0x2, 0x3, 0x1, 0x1], [0x1, 0x2, 0x3, 0x1], [0x1, 0x1, 0x2, 0x3], [0x3, 0x1, 0x1, 0x2]]
I_MIXC = [[0xe, 0xb, 0xd, 0x9], [0x9, 0xe, 0xb, 0xd], [0xd, 0x9, 0xe, 0xb], [0xb, 0xd, 0x9, 0xe]]
RCon = [0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000]

S_BOX = [[0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76],
[0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0],
[0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15],
[0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75],
[0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84],
[0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF],
[0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8],
[0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2],
[0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73],
[0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB],
[0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79],
[0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08],
[0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A],
[0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E],
[0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF],
[0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]]

I_SBOX = [[0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB],
[0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB],
[0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E],
[0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25],
[0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92],
[0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84],
[0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06],
[0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B],
[0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73],
[0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E],
[0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B],
[0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4],
[0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F],
[0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF],
[0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61],
[0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]]

def SubBytes(self, State):
# 字节替换
return [self.S_BOX[i][j] for i, j in
[(_ >> 4, _ & 0xF) for _ in State]]

def SubBytes_Inv(self, State):
# 字节逆替换
return [self.I_SBOX[i][j] for i, j in
[(_ >> 4, _ & 0xF) for _ in State]]

def ShiftRows(self, S):
# 行移位
return [S[ 0], S[ 5], S[10], S[15],
S[ 4], S[ 9], S[14], S[ 3],
S[ 8], S[13], S[ 2], S[ 7],
S[12], S[ 1], S[ 6], S[11]]

def ShiftRows_Inv(self, S):
# 逆行移位
return [S[ 0], S[13], S[10], S[ 7],
S[ 4], S[ 1], S[14], S[11],
S[ 8], S[ 5], S[ 2], S[15],
S[12], S[ 9], S[ 6], S[ 3]]

def MixColumns(self, State):
# 列混合
return self.Matrix_Mul(self.MIX_C, State)

def MixColumns_Inv(self, State):
# 逆列混合
return self.Matrix_Mul(self.I_MIXC, State)

def RotWord(self, _4byte_block):
# 用于生成轮密钥的字移位
return ((_4byte_block & 0xffffff) << 8) + (_4byte_block >> 24)

def SubWord(self, _4byte_block):
# 用于生成密钥的字节替换
result = 0
for position in range(4):
i = _4byte_block >> position * 8 + 4 & 0xf
j = _4byte_block >> position * 8 & 0xf
result ^= self.S_BOX[i][j] << position * 8
return result

def mod(self, poly, mod = 0b100011011):
# poly模多项式mod
while poly.bit_length() > 8:
poly ^= mod << poly.bit_length() - 9
return poly

def mul(self, poly1, poly2):
# 多项式相乘
result = 0
for index in range(poly2.bit_length()):
if poly2 & 1 << index:
result ^= poly1 << index
return result

def Matrix_Mul(self, M1, M2): # M1 = MIX_C M2 = State
# 用于列混合的矩阵相乘
M = [0] * 16
for row in range(4):
for col in range(4):
for Round in range(4):
M[row + col*4] ^= self.mul(M1[row][Round], M2[Round+col*4])
M[row + col*4] = self.mod(M[row + col*4])
return M

def round_key_generator(self, _16bytes_key):
# 轮密钥产生
w = [_16bytes_key >> 96,
_16bytes_key >> 64 & 0xFFFFFFFF,
_16bytes_key >> 32 & 0xFFFFFFFF,
_16bytes_key & 0xFFFFFFFF] + [0]*40
for i in range(4, 44):
temp = w[i-1]
if not i % 4:
temp = self.SubWord(self.RotWord(temp)) ^ self.RCon[i//4-1]
w[i] = w[i-4] ^ temp
return [self.num_2_16bytes(
sum([w[4 * i] << 96, w[4*i+1] << 64,
w[4*i+2] << 32, w[4*i+3]])
) for i in range(11)]

def AddRoundKey(self, State, RoundKeys, index):
# 异或轮密钥
return self._16bytes_xor(State, RoundKeys[index])

def _16bytes_xor(self, _16bytes_1, _16bytes_2):
return [_16bytes_1[i] ^ _16bytes_2[i] for i in range(16)]

def _16bytes2num(cls, _16bytes):
# 16字节转数字
return int.from_bytes(_16bytes, byteorder = 'big')

def num_2_16bytes(cls, num):
# 数字转16字节
return num.to_bytes(16, byteorder = 'big')

def aes_encrypt(self, plaintext_list, RoundKeys):
State = plaintext_list
State = self.AddRoundKey(State, RoundKeys, 0)
for Round in range(1, 10):
State = self.SubBytes(State)
State = self.ShiftRows(State)
State = self.MixColumns(State)
State = self.AddRoundKey(State, RoundKeys, Round)
State = self.SubBytes(State)
State = self.ShiftRows(State)
State = self.AddRoundKey(State, RoundKeys, 10)
return State

def aes_decrypt(self, ciphertext_list, RoundKeys):
State = ciphertext_list
State = self.AddRoundKey(State, RoundKeys, 10)
for Round in range(1, 10):
State = self.ShiftRows_Inv(State)
State = self.SubBytes_Inv(State)
State = self.AddRoundKey(State, RoundKeys, 10-Round)
State = self.MixColumns_Inv(State)
State = self.ShiftRows_Inv(State)
State = self.SubBytes_Inv(State)
State = self.AddRoundKey(State, RoundKeys, 0)
return State

if __name__ == '__main__':

aes = AES()
key = 0x000102030405060708090a0b0c0d0e0f
RoundKeys = aes.round_key_generator(key)

# 加密
plaintext = 0x00112233445566778899aabbccddeeff
# 0x00112233445566778899aabbccddeeff -> b'\x00\x11"3DUfw\x88\x99\xaa\xbb\xcc\xdd\xee\xff'
plaintext = aes.num_2_16bytes(plaintext)
ciphertext = aes.aes_encrypt(plaintext, RoundKeys)
print('ciphertext = ' + hex(aes._16bytes2num(ciphertext)))

# 解密
ciphertext = 0x69c4e0d86a7b0430d8cdb78070b4c55a
ciphertext = aes.num_2_16bytes(ciphertext)
plaintext = aes.aes_decrypt(ciphertext, RoundKeys)
print('plaintext = ' + hex(aes._16bytes2num(plaintext)))

若要使用Python的第三方库,可简化为:

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

password = b'1234567812345678' #秘钥,b就是表示为bytes类型
text = b'abcdefghijklmnhi' #需要加密的内容,bytes类型
aes = AES.new(password,AES.MODE_ECB) #创建一个aes对象
# AES.MODE_ECB 表示模式是ECB模式
en_text = aes.encrypt(text) #加密明文
print("密文:",en_text) #加密明文,bytes类型
den_text = aes.decrypt(en_text) # 解密密文
print("明文:",den_text)

这样使用要先安装对应的库

1
2
3
pip uninstall crypto
pip uninstall pycryptodome
pip install pycryptodome

例题

NepNep的面试题(题倒是做出来了,可惜最后也没能被录用,卡在面试上了),想做题的可加我QQ好友获取

Die查个壳先,Windows64位无壳,直接拖进IDA分析

定位到main函数,发现未分析为代码大量数据块,直接按C就能分析成汇编代码,由于使用故意除以零出发异常、代码自修改和栈帧破坏(用rbx作为新的基指针代替rbp)等混淆方式无法F5,只能啃汇编。在AI帮助和定位几个交互的语句大致定位出输入输出和部分关键代码的位置

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
.text:00000001400032BF                             loc_1400032BF:                          ; CODE XREF: main:loc_1400032BA↑j
.text:00000001400032BF -08 90 nop
.text:00000001400032C0 -08 44 8A 43 5D mov r8b, [rbx+5Dh]
.text:00000001400032C4 -08 8A 53 5E mov dl, [rbx+5Eh]
.text:00000001400032C7 -08 8A 4B 5F mov cl, [rbx+5Fh]
.text:00000001400032CA -08 48 8D 43 60 lea rax, [rbx+60h]
.text:00000001400032CE -08 48 89 83 48 01 00 00 mov [rbx+148h], rax
.text:00000001400032D5 -08 44 88 83 47 01 00 00 mov [rbx+147h], r8b
.text:00000001400032DC -08 88 93 46 01 00 00 mov [rbx+146h], dl
.text:00000001400032E2 -08 88 8B 45 01 00 00 mov [rbx+145h], cl
.text:00000001400032E8 -08 48 89 83 58 01 00 00 mov [rbx+158h], rax
.text:00000001400032EF -08 48 8B 8B 58 01 00 00 mov rcx, [rbx+158h]
.text:00000001400032F6 -08 48 89 8B D0 01 00 00 mov [rbx+1D0h], rcx
.text:00000001400032FD -08 48 8B 8B D0 01 00 00 mov rcx, [rbx+1D0h]
.text:0000000140003304 -08 48 89 4B 28 mov [rbx+28h], rcx
.text:0000000140003308 -08 C5 F8 57 C0 vxorps xmm0, xmm0, xmm0
.text:000000014000330C -08 C5 FC 11 83 B0 01 00 00 vmovups ymmword ptr [rbx+1B0h], ymm0
.text:0000000140003314 -08 C5 FC 29 83 A0 01 00 00 vmovaps ymmword ptr [rbx+1A0h], ymm0
.text:000000014000331C -08 48 BE 6D 75 F6 53 12 DF mov rsi, 92DFDF1253F6756Dh ; KEY_DATA
.text:000000014000331C -08 DF 92
.text:0000000140003326 -08 48 89 B3 A0 01 00 00 mov [rbx+1A0h], rsi
.text:000000014000332D -08 49 BB 0C 6D CC E8 91 A2 mov r11, 9619A291E8CC6D0Ch
.text:000000014000332D -08 19 96
.text:0000000140003337 -08 4C 89 9B A8 01 00 00 mov [rbx+1A8h], r11
.text:000000014000333E -08 49 BA 85 17 C6 AC BC FF mov r10, 873FFFBCACC61785h
.text:000000014000333E -08 3F 87
.text:0000000140003348 -08 4C 89 93 B0 01 00 00 mov [rbx+1B0h], r10
.text:000000014000334F -08 49 B9 8C 96 47 00 2D B6 mov r9, 0E47DB62D0047968Ch
.text:000000014000334F -08 7D E4
.text:0000000140003359 -08 4C 89 8B B8 01 00 00 mov [rbx+1B8h], r9
.text:0000000140003360 -08 49 B8 F2 38 89 33 B0 88 mov r8, 2A088B0338938F2h
.text:0000000140003360 -08 A0 02
.text:000000014000336A -08 4C 89 83 C0 01 00 00 mov [rbx+1C0h], r8
.text:0000000140003371 -08 48 BA FD 34 D3 55 D5 51 mov rdx, 44F651D555D334FDh
.text:0000000140003371 -08 F6 44
.text:000000014000337B -08 48 89 93 C8 01 00 00 mov [rbx+1C8h], rdx
.text:0000000140003382 -08 48 8B BB A0 01 00 00 mov rdi, [rbx+1A0h]
.text:0000000140003389 -08 48 89 39 mov [rcx], rdi
.text:000000014000338C -08 48 8B 39 mov rdi, [rcx]
.text:000000014000338F -08 48 89 BB 70 01 00 00 mov [rbx+170h], rdi
.text:0000000140003396 -08 48 8B BB A8 01 00 00 mov rdi, [rbx+1A8h]
.text:000000014000339D -08 48 89 79 08 mov [rcx+8], rdi
.text:00000001400033A1 -08 48 8B 79 08 mov rdi, [rcx+8]
.text:00000001400033A5 -08 48 89 BB 78 01 00 00 mov [rbx+178h], rdi
.text:00000001400033AC -08 48 8B BB B0 01 00 00 mov rdi, [rbx+1B0h]
.text:00000001400033B3 -08 48 89 79 10 mov [rcx+10h], rdi
.text:00000001400033B7 -08 48 8B 79 10 mov rdi, [rcx+10h]
.text:00000001400033BB -08 48 89 BB 80 01 00 00 mov [rbx+180h], rdi
.text:00000001400033C2 -08 48 8B BB B8 01 00 00 mov rdi, [rbx+1B8h]
.text:00000001400033C9 -08 48 89 79 18 mov [rcx+18h], rdi
.text:00000001400033CD -08 48 8B 79 18 mov rdi, [rcx+18h]
.text:00000001400033D1 -08 48 89 BB 88 01 00 00 mov [rbx+188h], rdi
.text:00000001400033D8 -08 48 8B BB C0 01 00 00 mov rdi, [rbx+1C0h]
.text:00000001400033DF -08 48 89 79 20 mov [rcx+20h], rdi
.text:00000001400033E3 -08 48 8B 79 20 mov rdi, [rcx+20h]
.text:00000001400033E7 -08 48 89 BB 90 01 00 00 mov [rbx+190h], rdi
.text:00000001400033EE -08 48 8B BB C8 01 00 00 mov rdi, [rbx+1C8h]
.text:00000001400033F5 -08 48 89 79 28 mov [rcx+28h], rdi
.text:00000001400033F9 -08 48 8B 49 28 mov rcx, [rcx+28h]
.text:00000001400033FD -08 48 89 8B 98 01 00 00 mov [rbx+198h], rcx
.text:0000000140003404 -08 48 8D 8B 70 01 00 00 lea rcx, [rbx+170h]
.text:000000014000340B -08 48 89 8B 60 01 00 00 mov [rbx+160h], rcx
.text:0000000140003412 -08 48 8D 8B A0 01 00 00 lea rcx, [rbx+1A0h]
.text:0000000140003419 -08 48 89 8B 68 01 00 00 mov [rbx+168h], rcx
.text:0000000140003420 -08 48 89 83 50 01 00 00 mov [rbx+150h], rax
.text:0000000140003427 -08 48 8B 83 50 01 00 00 mov rax, [rbx+150h]
.text:000000014000342E -08 48 89 43 40 mov [rbx+40h], rax
.text:0000000140003432 -08 48 89 83 58 02 00 00 mov [rbx+258h], rax
.text:0000000140003439 -08 48 8B 83 58 02 00 00 mov rax, [rbx+258h]
.text:0000000140003440 -08 48 B9 1F 34 90 3F 60 A7 mov rcx, 0E795A7603F90341Fh ; FAKE_FLAG
.text:0000000140003440 -08 95 E7
.text:000000014000344A -08 48 89 8B 20 02 00 00 mov [rbx+220h], rcx
.text:0000000140003451 -08 48 8B 8B 20 02 00 00 mov rcx, [rbx+220h]
.text:0000000140003458 -08 48 89 8B F0 01 00 00 mov [rbx+1F0h], rcx
.text:000000014000345F -08 48 B9 3C 09 AA 9C E9 F3 mov rcx, 0C65BF3E99CAA093Ch
.text:000000014000345F -08 5B C6
.text:0000000140003469 -08 48 89 8B 28 02 00 00 mov [rbx+228h], rcx
.text:0000000140003470 -08 48 8B 8B 28 02 00 00 mov rcx, [rbx+228h]
.text:0000000140003477 -08 48 89 8B F8 01 00 00 mov [rbx+1F8h], rcx
.text:000000014000347E -08 48 B9 E9 60 A0 99 C6 BC mov rcx, 0CF59BCC699A060E9h
.text:000000014000347E -08 59 CF
.text:0000000140003488 -08 48 89 8B 30 02 00 00 mov [rbx+230h], rcx
.text:000000014000348F -08 48 8B 8B 30 02 00 00 mov rcx, [rbx+230h]
.text:0000000140003496 -08 48 89 8B 00 02 00 00 mov [rbx+200h], rcx
.text:000000014000349D -08 48 B9 F6 E1 31 42 57 C0 mov rcx, 0A727C0574231E1F6h
.text:000000014000349D -08 27 A7
.text:00000001400034A7 -08 48 89 8B 38 02 00 00 mov [rbx+238h], rcx
.text:00000001400034AE -08 48 8B 8B 38 02 00 00 mov rcx, [rbx+238h]
.text:00000001400034B5 -08 48 89 8B 08 02 00 00 mov [rbx+208h], rcx
.text:00000001400034BC -08 48 B9 C3 5F FF 77 DC FC mov rcx, 52C9FCDC77FF5FC3h
.text:00000001400034BC -08 C9 52
.text:00000001400034C6 -08 48 89 8B 40 02 00 00 mov [rbx+240h], rcx
.text:00000001400034CD -08 48 8B 8B 40 02 00 00 mov rcx, [rbx+240h]
.text:00000001400034D4 -08 48 89 8B 10 02 00 00 mov [rbx+210h], rcx
.text:00000001400034DB -08 48 B9 90 60 82 68 D5 51 mov rcx, 44F651D568826090h
.text:00000001400034DB -08 F6 44
.text:00000001400034E5 -08 48 89 8B 48 02 00 00 mov [rbx+248h], rcx
.text:00000001400034EC -08 48 8B 8B 48 02 00 00 mov rcx, [rbx+248h]
.text:00000001400034F3 -08 48 89 8B 18 02 00 00 mov [rbx+218h], rcx
.text:00000001400034FA -08 48 8D 8B F0 01 00 00 lea rcx, [rbx+1F0h]
.text:0000000140003501 -08 48 89 8B E0 01 00 00 mov [rbx+1E0h], rcx
.text:0000000140003508 -08 48 8D 8B 20 02 00 00 lea rcx, [rbx+220h]
.text:000000014000350F -08 48 89 8B E8 01 00 00 mov [rbx+1E8h], rcx
.text:0000000140003516 -08 48 89 83 E8 02 00 00 mov [rbx+2E8h], rax
.text:000000014000351D -08 48 8B 8B E8 02 00 00 mov rcx, [rbx+2E8h]
.text:0000000140003524 -08 48 89 4B 30 mov [rbx+30h], rcx
.text:0000000140003528 -08 C5 FC 11 83 B0 02 00 00 vmovups ymmword ptr [rbx+2B0h], ymm0
.text:0000000140003530 -08 C5 FC 29 83 A0 02 00 00 vmovaps ymmword ptr [rbx+2A0h], ymm0
.text:0000000140003538 -08 48 89 B3 A0 02 00 00 mov [rbx+2A0h], rsi
.text:000000014000353F -08 4C 89 9B A8 02 00 00 mov [rbx+2A8h], r11
.text:0000000140003546 -08 4C 89 93 B0 02 00 00 mov [rbx+2B0h], r10
.text:000000014000354D -08 4C 89 8B B8 02 00 00 mov [rbx+2B8h], r9
.text:0000000140003554 -08 4C 89 83 C0 02 00 00 mov [rbx+2C0h], r8
.text:000000014000355B -08 48 89 93 C8 02 00 00 mov [rbx+2C8h], rdx
.text:0000000140003562 -08 48 8B 93 A0 02 00 00 mov rdx, [rbx+2A0h]
.text:0000000140003569 -08 48 89 11 mov [rcx], rdx
.text:000000014000356C -08 48 8B 11 mov rdx, [rcx]
.text:000000014000356F -08 48 89 93 70 02 00 00 mov [rbx+270h], rdx
.text:0000000140003576 -08 48 8B 93 A8 02 00 00 mov rdx, [rbx+2A8h]
.text:000000014000357D -08 48 89 51 08 mov [rcx+8], rdx
.text:0000000140003581 -08 48 8B 51 08 mov rdx, [rcx+8]
.text:0000000140003585 -08 48 89 93 78 02 00 00 mov [rbx+278h], rdx
.text:000000014000358C -08 48 8B 93 B0 02 00 00 mov rdx, [rbx+2B0h]
.text:0000000140003593 -08 48 89 51 10 mov [rcx+10h], rdx
.text:0000000140003597 -08 48 8B 51 10 mov rdx, [rcx+10h]
.text:000000014000359B -08 48 89 93 80 02 00 00 mov [rbx+280h], rdx
.text:00000001400035A2 -08 48 8B 93 B8 02 00 00 mov rdx, [rbx+2B8h]
.text:00000001400035A9 -08 48 89 51 18 mov [rcx+18h], rdx
.text:00000001400035AD -08 48 8B 51 18 mov rdx, [rcx+18h]
.text:00000001400035B1 -08 48 89 93 88 02 00 00 mov [rbx+288h], rdx
.text:00000001400035B8 -08 48 8B 93 C0 02 00 00 mov rdx, [rbx+2C0h]
.text:00000001400035BF -08 48 89 51 20 mov [rcx+20h], rdx
.text:00000001400035C3 -08 48 8B 51 20 mov rdx, [rcx+20h]
.text:00000001400035C7 -08 48 89 93 90 02 00 00 mov [rbx+290h], rdx
.text:00000001400035CE -08 48 8B 93 C8 02 00 00 mov rdx, [rbx+2C8h]
.text:00000001400035D5 -08 48 89 51 28 mov [rcx+28h], rdx
.text:00000001400035D9 -08 48 8B 49 28 mov rcx, [rcx+28h]
.text:00000001400035DD -08 48 89 8B 98 02 00 00 mov [rbx+298h], rcx
.text:00000001400035E4 -08 53 push rbx
.text:00000001400035E5 000 9C pushfq
.text:00000001400035E6 008 31 DB xor ebx, ebx
.text:00000001400035E8 008 85 DB test ebx, ebx
.text:00000001400035EA 008 75 2E jnz short near ptr loc_140003617+3
.text:00000001400035EC 008 0F 84 0E 00 00 00 jz loc_140003600
.text:00000001400035F2 008 C3 retn

此处的秘钥和密文通过异或+换表Base64得出了一个FAKEFLAG

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
key = [
0x92DFDF1253F6756D, 0x9619A291E8CC6D0C,
0x873FFFBCACC61785, 0xE47DB62D0047968C,
0x0002A088B0338938F2, 0x44F651D555D334FD
]

expected = [
0xE795A7603F90341F, 0xC65BF3E99CAA093C,
0xCF59BCC699A060E9, 0xA727C0574231E1F6,
0x52C9FCDC77FF5FC3, 0x44F651D568826090
]

flag = b""
for i in range(6):
# 将64位整数转换为8字节
key_bytes = key[i].to_bytes(8, 'little')
exp_bytes = expected[i].to_bytes(8, 'little')

# 逐字节异或解密
for a, b in zip(exp_bytes, key_bytes):
flag += bytes([a ^ b])

print(flag.decode('utf-8'))
# 将表换为abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/
# 解Base64得FAKE{Th1S_Is-a_fakeeee_fleg-233}

得到假FLAG后继续分析

实际的加密逻辑在如下位置:地址 off_140028348(17F271A60h) 指向的函数,跟着Success和Fail字符串定位到如下函数:

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
int __fastcall sub_140002CF0(const char *a1)
{
int v15; // eax
char v26[256]; // [rsp+180h] [rbp+100h] BYREF
__m256 v27; // [rsp+280h] [rbp+200h] BYREF
__m256 v28[2]; // [rsp+2A0h] [rbp+220h] BYREF
__m256 v29; // [rsp+2E0h] [rbp+260h]
__int64 v30; // [rsp+300h] [rbp+280h]
__int64 v31; // [rsp+308h] [rbp+288h]
__int64 v32; // [rsp+310h] [rbp+290h]
__int64 v33; // [rsp+318h] [rbp+298h]
__int64 v34[4]; // [rsp+320h] [rbp+2A0h] BYREF
__m256 v35; // [rsp+340h] [rbp+2C0h]
__m256 v36; // [rsp+360h] [rbp+2E0h]

if ( (strlen(a1) & 0xF) != 0 )
return printf("Fail!\n");
__asm
{
vxorps xmm0, xmm0, xmm0
vmovaps [rsp+390h+var_F0], ymm0
vmovups ymm0, cs:ymmword_14001D090
vmovaps [rsp+390h+var_B0], ymm0
}
v28[1] = v29;
v34[0] = 0xE795A7603F90341Fui64;
v30 = 0xE795A7603F90341Fui64;
v34[1] = 0xC65BF3E99CAA093Cui64;
v31 = 0xC65BF3E99CAA093Cui64;
v34[2] = 0xCF59BCC699A060E9ui64;
v32 = 0xCF59BCC699A060E9ui64;
v34[3] = 0xA727C0574231E1F6ui64;
v33 = 0xA727C0574231E1F6ui64;
__asm
{
vmovups ymm0, cs:ymmword_14001D090
vmovaps [rsp+390h+var_30], ymm0
}
v27 = v36;
v35 = v36;
_RCX = v34;
__asm { vmovdqa ymm1, ymmword ptr [rcx] }
_RCX = &v27;
__asm
{
vmovdqa ymm0, ymmword ptr [rcx]
vmovdqa [rsp+390h+var_250], ymm1
vmovdqa [rsp+390h+var_270], ymm0
vmovdqa ymm0, [rsp+390h+var_270]
vpxor ymm0, ymm0, [rsp+390h+var_250]
vmovdqa [rsp+390h+var_290], ymm0
vmovdqa ymm0, [rsp+390h+var_290]
}
_RCX = &v27;
__asm { vmovdqa ymmword ptr [rcx], ymm0 }
*(_OWORD *)v28[0].m256_f32 = *(_OWORD *)v27.m256_f32;
__asm { vzeroupper }
sub_1400054D0(v26, 0i64, 256i64);
v15 = strlen(a1);
sub_140002410((unsigned int)v28, 16, (_DWORD)a1, (unsigned int)v26, v15);
_RAX = v26;
__asm
{
vmovups ymm0, ymmword ptr [rax]
vmovups ymm1, cs:enc
vpxor ymm0, ymm0, ymm1
vptest ymm0, ymm0
}
if ( _ZF )
{
__asm { vzeroupper }
return printf("Success!");
}
else
{
__asm { vzeroupper }
return printf("Fail!");
}
}

这个函数中定义了一些重要的常量数据,继续跟踪sub_140002410 函数

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
__int64 __fastcall sub_140002410(__int64 a1, unsigned int a2, __int64 a3, __int64 a4, unsigned int a5)
{
int j; // [rsp+30h] [rbp-50h] AES
unsigned int i; // [rsp+34h] [rbp-4Ch]
char *v8; // [rsp+38h] [rbp-48h]
__int64 v9; // [rsp+40h] [rbp-40h]
char v15[16]; // [rsp+70h] [rbp-10h] BYREF
char v16[16]; // [rsp+80h] [rbp+0h] BYREF
char v17[20]; // [rsp+90h] [rbp+10h] BYREF
char v18[356]; // [rsp+A4h] [rbp+24h] BYREF

v9 = a4;
v8 = v18;
sub_1400054D0(v17, 0i64, 16i64);
sub_1400054D0(v16, 0i64, 16i64);
sub_1400054D0(v15, 0i64, 16i64);
if ( a1 && a3 && a4 )
{
if ( a2 <= 0x10 )
{
if ( (a5 & 0xF) != 0 )
{
printf("inLen is invalid.\n");
return (unsigned int)-1;
}
else
{
sub_140004E00(v16, a1, a2);
sub_140001A70(v16, 16i64, v18);
for ( i = 0; i < a5; i += 16 )
{
sub_140001930(v15, a3);
sub_140001E30(v15, v18);
for ( j = 1; j < 10; ++j )
{
v8 += 16;
sub_140001F40(v15);
sub_140001FE0(v15);
sub_140002240(v15);
sub_140001E30(v15, v8);
}
sub_140001F40(v15);
sub_140001FE0(v15);
sub_140001E30(v15, v8 + 16);
sub_1400019D0(v15, v9);
v9 += 16i64;
a3 += 16i64;
v8 = v18;
}
return 0;
}
}
else
{
printf("keyLen must be 16.\n");
return (unsigned int)-1;
}
}
else
{
printf("param err.\n");
return (unsigned int)-1;
}
}

经分析可知这个函数执行 AES-128 加密算法

在内存中定位ymmword_14001D090(初始化向量),ymmword_140028E60(最终校验值)两块内容

1
.rdata:000000014001D090 48 51 FC 5C 0F CA F0 A4     ymmword_14001D090 ymmword 4851FC5C0FCAF0A4684FFDF39B9F3FE7E960A099C6BC59CFF6E1314257C027A7
1
.data:0000000140028E60 00 00 00 00 00 00 00 00     enc             ymmword 0000000000000000000000000000000000000000000000000000000000000000

发现ymmword_140028E60(我重命名为了enc)全为0,怀疑是后续处理过程中被修改了,Ctrl+X查看调用,定位到如下的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
unsigned __int64 __fastcall TlsCallback_0(__int64 a1, int a2)
{
unsigned __int64 result; // rax

if ( a2 == 1 )
{
*(_QWORD *)ymmword_140028E60.m256_f32 = 0x7A90C58C47D4507Fi64;
*(_QWORD *)&ymmword_140028E60.m256_f32[2] = 0x9E9055008CD0D563ui64;
*(_QWORD *)&ymmword_140028E60.m256_f32[4] = 0xD1ECFF77563CB8B3ui64;
result = 0x8EBDCA36448856FFui64;
*(_QWORD *)&ymmword_140028E60.m256_f32[6] = 0x8EBDCA36448856FFui64;
}
return result;
}

由此便可写AES脚本解密:

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
import binascii
from Crypto.Cipher import AES
key_component1 = binascii.unhexlify("4851FC5C0FCAF0A4684FFDF39B9F3FE7E960A099C6BC59CFF6E1314257C027A7")
key_component2 = b""
for value in [
0xE795A7603F90341F,
0xC65BF3E99CAA093C,
0xCF59BCC699A060E9,
0xA727C0574231E1F6
]:
key_component2 += value.to_bytes(8, 'little')

aes_key = bytes(a ^ b for a, b in zip(key_component1[:16], key_component2[:16]))
print(f"计算出的AES密钥: {aes_key.hex()}")

ciphertext = binascii.unhexlify(
"7F50D4478CC5907A"
"63D5D08C0055909E"
"B3B83C5677FFECD1"
"FF56884436CABD8E"
)
cipher = AES.new(aes_key, AES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
try:
flag = plaintext.decode('utf-8').strip()
print(f"解密的Flag: {flag}")
except UnicodeDecodeError:
hex_flag = plaintext.hex()
print(f"解密结果(16进制): {hex_flag}")
printable = ''.join(chr(b) if 32 <= b <= 126 else '.' for b in plaintext)
print(f"解密结果(ASCII): {printable}")
# 得到真FLAG:flag{Y0u_get_tloe-success-f1ag!}