May 18, 2022

KCTF2022-石像病毒

(只能说还好做了Helen师傅的题,这题解起来没什么压力)

0x00 日常查壳

无壳32位

image-20220518210801277

0x01 分析主函数

主要的新鲜的还是这个异常,不过这个异常没干任何事情

image-20220518211234182

动调取数

IDA的忽略异常不知道咋设置,不过OD知道,直接ALT+O,全部忽略即可

image-20220518211404958

0x02 AESDecode

Extendkey

第一个要取的就是密钥,密钥扩展好像是改了什么?不过我们直接动调取即可,众所周知是176位(16位密钥 11轮)

image-20220519121518269

SubBytes

还有一个要提取的就是S盒了,因为经过一些修改,可以直接dump,直接取字节代换的地方取,注意要起始地址

image-20220519122047049

由于我们要解密所以弄出个逆S盒去解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main(void)
{
unsigned char SBox[256] = { 52, 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, 0x57, 0x7C, 0xF5, 0x6D, 0x56, 0x96, 0x77, 0x45, 0xB0, 0xBD, 0xA1, 0xC7, 0x89, 0xA5, 0xAB, 0xDC, 0xF4, 0xF2, 0x4B, 0xFE, 0xBE, 0xF5, 0xF5, 0x5C, 0x4D, 0x30, 0x42, 0x0F, 0x2B, 0x3B, 0xE6, 0xCB };
unsigned char DeSBox[256];
int i;

for ( i = 0; i < 256; i++ )
DeSBox[SBox[i]] = i;
for ( i = 0; i < 256; i++ )
printf("0x%X, ", DeSBox[i]);

return 0;
}

ShiftRows

不管是IDA分析或者是OD动调查看这个都可以,会发现是字符矩阵右移0 1 2 3,这也是魔改的一个点,所以我们解密字符矩阵就是就是左移 0 1 2 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void DeShiftRows(unsigned char (*stateMatrix)[4])
{
int i, j, count, t;

for ( i = 1; i <= 3; i++ )
{
count = 0;
while ( count++ < i )
{
t = stateMatrix[i][0]; // 矩阵还是一线还不确定 反正是逻辑左移0 1 2 3即可
for ( j = 0; j <= 2; j++ )
stateMatrix[i][j] = stateMatrix[i][j + 1];
stateMatrix[i][3] = t;
}
}
}

AddKey

既然我们已经有了密钥,那么轮密钥加就就没什么问题了,就是这边读取密钥的方式比较特别,然而并不是什么问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __cdecl sub_DB1970(int state, int key)
{
int j; // [esp+0h] [ebp-20h]
int i; // [esp+4h] [ebp-1Ch]
int v5[3]; // [esp+Ch] [ebp-14h] BYREF

memset(v5, 204, 10);
for ( i = 0; i < 4; ++i )
{
for ( j = 0; j < 4; ++j )
{
*(&v5[i] + j) = *(key + 4 * j) >> (8 * (3 - i));// 取单字节
*(state + 4 * i + j) ^= *(&v5[i] + j);
}
}
return 0;
}

读取的顺序稍微注意一下就好了

1
2
3
4
5
6
7
8
9
10
11
12
void AddRoundKey(unsigned char (*stateMatrix)[4], unsigned char * key)
{
int i, j;

for ( i = 1; i <= 4; i++ )
for ( j = 1; j <= 4; j++ )
{
// printf("0x%X ", stateMatrix[i - 1][j - 1]);
stateMatrix[i - 1][j - 1] ^= key[4 * j - i]; //魔改的一个地方
}

}

MixCol

这是没魔改的地方了,直接套原来的就好了(魔改了我估计要bangzhu一会

0x03 GetFlag

AES解密没什么问题,就是密文还进行了一次修改!!!我当时以为我哪里有问题,调了好久,后来突然想起可以

image-20220519122901769

对着密文按下X!!要不然早就出了呜呜呜

于是修改了两个值,直接改了就好

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
#include <stdio.h>

static const int S[256] =
{
0x52, 0x9, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0x71, 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, 0xB, 0x42, 0xFA, 0xC3, 0x4E, 0x8, 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, 0x0, 0x8C, 0xBC, 0xD3, 0xA, 0xF7, 0xE4, 0x58, 0x5, 0xB8, 0xB3, 0x45, 0x6, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0xF, 0x2, 0xC1, 0xAF, 0xBD, 0x3, 0x1, 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, 0xA3, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0xE, 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, 0x7, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0xD, 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, 0x4, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0xC, 0x7D
};

static const int deColM[4][4] =
{
0xE, 0xB, 0xD, 0x9,
0x9, 0xE, 0xB, 0xD,
0xD, 0x9, 0xE, 0xB,
0xB, 0xD, 0x9, 0xE
};

static unsigned char W[176] = {0xFF, 0xB1, 0x65, 0x2F, 0xD0, 0x86, 0xED, 0x31, 0x0F, 0x5C, 0x28, 0x9A, 0x9D, 0x05, 0x48, 0x40, 0xF6, 0xEF, 0x0E, 0x7C, 0x26, 0x69, 0xE3, 0x4D, 0x29, 0x35, 0xCB, 0xD7, 0xB4, 0x30, 0x83, 0x97, 0x7E, 0x62, 0x0A, 0x92, 0x58, 0x0B, 0xE9, 0xDF, 0x71, 0x3E, 0x22, 0x08, 0xC5, 0x0E, 0xA1, 0x9F, 0xA5, 0xC4, 0xA1, 0xA4, 0xFD, 0xCF, 0x48, 0x7B, 0x8C, 0xF1, 0x6A, 0x73, 0x49, 0xFF, 0xCB, 0xEC, 0x6B, 0xFF, 0xB7, 0xB3, 0x96, 0x30, 0xFF, 0xC8, 0x1A, 0xC1, 0x95, 0xBB, 0x53, 0x3E, 0x5E, 0x57, 0x30, 0x12, 0x05, 0xFB, 0xA6, 0x22, 0xFA, 0x33, 0xBC, 0xE3, 0x6F, 0x88, 0xEF, 0xDD, 0x31, 0xDF, 0xAE, 0xCD, 0xC4, 0x1C, 0x08, 0xEF, 0x3E, 0x2F, 0xB4, 0x0C, 0x51, 0xA7, 0x5B, 0xD1, 0x60, 0x78, 0x12, 0xF4, 0xFA, 0x8C, 0x1A, 0x1B, 0xC4, 0xA3, 0xAE, 0x17, 0x95, 0x04, 0xF5, 0xC6, 0xF5, 0x7C, 0x02, 0x12, 0x4E, 0xEA, 0x18, 0x09, 0x8A, 0x49, 0xB6, 0x1E, 0x1F, 0x4D, 0x43, 0xD8, 0xEA, 0x31, 0xC5, 0x08, 0x2F, 0x76, 0xDD, 0x01, 0xA5, 0x3F, 0x6B, 0x1F, 0xBA, 0x72, 0x28, 0xC7, 0x50, 0x43, 0xDF, 0x3C, 0xE9, 0x13, 0x02, 0x3D, 0x4C, 0x2C, 0x69, 0x22, 0xF6, 0x5E, 0x41, 0xE5, 0xA6, 0x1D};

void ExtendKey(unsigned char * key);
void AddRoundKey(unsigned char (*stateMatrix)[4], unsigned char * key);
void DeShiftRows(unsigned char (*stateMatrix)[4]);
void DeSubBytes(unsigned char (*stateMatrix)[4]);
void DeMixColumns(unsigned char (*stateMatrix)[4]);
void AESDecode(unsigned char * enc, unsigned char * plainText);

int main(void)
{
// unsigned char key[] = { 0x2F, 0x65, 0xB1, 0xFF, 0x31, 0xED, 0x86, 0xD0, 0x9A, 0x28, 0x5C, 0x0F, 0x40, 0x48, 0x05, 0x9D };
unsigned char enc[] = { 0x57, 0x7C, 0xF5, 0x6D, 0x56, 0x96, 0x77, 0x45, 0xB0, 0xBD, 0xA1, 0xC7, 0x89, 0xA5, 0xAB, 0xDC, 0xF2, 0xF4, 0x4B, 0xFE, 0xBE, 0xF5, 0xF5, 0x5C, 0x4D, 0x30, 0x42, 0x0F, 0x2B, 0x3B, 0xE6, 0xCB };
unsigned char plainText[32] = { 0 };
int i;
enc[16] = 0xF4;
enc[17] = 0xF2;

for ( i = 0; i < 32; i += 16)
AESDecode(enc + i, plainText + i);
for ( i = 0; i < 32; i++ )
printf("%c", plainText[i]);

return 0;
}

void GetStateMatrix(unsigned char (*stateMatrix)[4], unsigned char * enc)
{
int i, j;

for ( i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
stateMatrix[j][i] = enc[i * 4 + j];
}

void PutStateMatrix(unsigned char * plainText, unsigned char (*stateMatrix)[4])
{
int i, j;

for ( i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
plainText[i * 4 + j] = stateMatrix[j][i];
}

void AESDecode(unsigned char * enc, unsigned char * plainText)
{
int i, j;

unsigned char stateMatrix[4][4] = { 0 };
GetStateMatrix(stateMatrix, enc);

// for ( i = 0; i < 4; i++ )
// for ( j = 0; j < 4; j++ )
// printf("0x%X, ", stateMatrix[i][j]);
// printf("\n");

i = 10;
AddRoundKey(stateMatrix, W + i * 16);
for ( i--; ; i-- )
{
DeShiftRows(stateMatrix);
DeSubBytes(stateMatrix);
AddRoundKey(stateMatrix, W + i * 16);
if ( i == 0 )
break;
DeMixColumns(stateMatrix);
}

// for ( i = 0; i < 16; i++ )
// printf("0x%X, ", stateMatrix[i]);
PutStateMatrix(plainText, stateMatrix);
}

static int GFMul2(int s)
{
int result = s << 1;
int a7 = result & 0x00000100; //判断位移后的那位是否为 1

if ( a7 != 0 )
{
result = result & 0x000000FF;
result = result ^ 0x1B; //矩阵乘法的特殊性
}

return result;
}

static int GFMul3(int s)
{
return GFMul2(s) ^ s;
}

static int GFMul4(int s)
{
return GFMul2(GFMul2(s));
}

static int GFMul8(int s)
{
return GFMul2(GFMul4(s));
}

static int GFMul9(int s)
{
return GFMul8(s) ^ s;
}

static int GFMul11(int s)
{
return GFMul9(s) ^ GFMul2(s);
}

static int GFMul12(int s)
{
return GFMul8(s) ^ GFMul4(s);
}

static int GFMul13(int s)
{
return GFMul12(s) ^ s;
}

static int GFMul14(int s)
{
return GFMul12(s) ^ GFMul2(s);
}


/**
* GF上的二元运算
*/
static int GFMul(int n, int s)
{
int result;

if ( n == 1 )
result = s;
else if ( n == 2 )
result = GFMul2(s);
else if ( n == 3 )
result = GFMul3(s);
else if ( n == 9 )
result = GFMul9(s);
else if ( n == 0xB )
result = GFMul11(s);
else if ( n == 0xD )
result = GFMul13(s);
else if ( n == 0xE )
result = GFMul14(s);

return result;
}

void DeMixColumns(unsigned char (*stateMatrix)[4])
{
unsigned char tmpArray[4][4];
int i, j;

for ( i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
tmpArray[i][j] = stateMatrix[i][j];

for ( i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
stateMatrix[i][j] = GFMul(deColM[i][0], (int)tmpArray[0][j]) ^
GFMul(deColM[i][1], (int)tmpArray[1][j]) ^
GFMul(deColM[i][2], (int)tmpArray[2][j]) ^
GFMul(deColM[i][3], (int)tmpArray[3][j]);
}

void DeSubBytes(unsigned char (*stateMatrix)[4])
{
int i, j;

for ( i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
stateMatrix[i][j] = S[stateMatrix[i][j]];
}

void DeShiftRows(unsigned char (*stateMatrix)[4])
{
int i, j, count, t;

// for ( i = 0; i < 4; i++ )
// for ( j = 0; j < 4; j++ )
// printf("0x%X, ", stateMatrix[i][j]);
// printf("\n");
for ( i = 1; i <= 3; i++ )
{
count = 0;
while ( count++ < i )
{
t = stateMatrix[i][0]; // 矩阵还是一线还不确定 反正是逻辑左移0 1 2 3即可
for ( j = 0; j <= 2; j++ )
stateMatrix[i][j] = stateMatrix[i][j + 1];
stateMatrix[i][3] = t;
}
}
// for ( i = 0; i < 4; i++ )
// for ( j = 0; j < 4; j++ )
// printf("0x%X, ", stateMatrix[i][j]);
// printf("\n");
}

void AddRoundKey(unsigned char (*stateMatrix)[4], unsigned char * key)
{
int i, j;

for ( i = 1; i <= 4; i++ )
for ( j = 1; j <= 4; j++ )
{
// printf("0x%X ", stateMatrix[i - 1][j - 1]);
stateMatrix[i - 1][j - 1] ^= key[4 * j - i]; //魔改的一个地方
}

}

GetFlag!

image-20220519122959573

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.