写了逆向方向7个题

ASM?Signin!

汇编题,直接梭

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
# 处理后的DATA1数组(经过DO1过程)
processed_data1 = [
0x26, 0x27, 0x24, 0x25,
0x3F, 0x27, 0x34, 0x11,
0x32, 0x33, 0x30, 0x00,
0x36, 0x37, 0x34, 0x35,
0x3A, 0x3B, 0x38, 0x39,
0x3E, 0x3F, 0x3C, 0x3D,
0x2A, 0x2B, 0x28, 0x00,
0x2E, 0x2F, 0x2C, 0x2D
]

# DATA2数组(加密后的目标数据)
data2 = [
0x69, 0x77, 0x77, 0x66,
0x73, 0x72, 0x4F, 0x46,
0x03, 0x47, 0x6F, 0x79,
0x07, 0x41, 0x13, 0x47,
0x5E, 0x67, 0x5F, 0x09,
0x0F, 0x58, 0x63, 0x7D,
0x5F, 0x77, 0x68, 0x35,
0x62, 0x0D, 0x0D, 0x50
]

# 解密每个块
flag_bytes = []
for i in range(8):
# 获取DATA2的当前四字节块
e0, e1, e2, e3 = data2[i*4 : (i+1)*4]

# 获取对应的处理后的DATA1块
d_block = processed_data1[i*4 : (i+1)*4]
d1 = d_block[1] # 第二个字节用于异或e0
d2 = d_block[2] # 第三个字节用于异或e1和e2
d3 = d_block[3] # 第四个字节用于异或e3

# 异或解密
b0 = e0 ^ d1
b1 = e1 ^ d2
b2 = e2 ^ d2
b3 = e3 ^ d3

flag_bytes.extend([b0, b1, b2, b3])

# 将字节转换为字符串
flag = bytes(flag_bytes).decode('utf-8')
print(flag)
#NSSCTF{W0w_y0u're_g00d_@t_@5M!!}

FishingKit

hook+tea+z3

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rdx
__int64 v4; // r8
__int64 v5; // rdx
__int64 v6; // r8
__int64 v7; // rdx
__int64 v8; // r8
__int64 v10; // rdx
__int64 v11; // r8
char v13[24]; // [rsp+20h] [rbp-98h] BYREF
char v14[56]; // [rsp+38h] [rbp-80h] BYREF
char Str1[56]; // [rsp+70h] [rbp-48h] BYREF

memset(v13, 0, 0x14ui64);
memset(v14, 0, 0x32ui64);
memset(Str1, 0, 0x32ui64);
sub_140002FD0("Give me the bait:", argv, envp);
sub_140003050("%s", v13);
if ( sub_140001150((unsigned __int8 *)v13) )
{
sub_140002FD0("Yes!This bait is a good one.\n\n", v3, v4);
sub_140002FD0("Give me the second thing:", v5, v6);
sub_140003050("%s", v14);
sub_140002FD0("\nFishing...\n\n", v7, v8);
Sleep(0x3E8u);
sub_140002460(v14, Str1, v13);
if ( strcmp(Str1, &Str2) )
sub_140002FD0("Didn't the fish take the bait?\n", v10, v11);
else
sub_140002FD0("Did the fish take the bait?\n", v10, v11);
}
else
{
sub_140002FD0("Oops...This bait is terrible.\n", v3, v4);
}
system("pause");
return 0;
}

第一个是z3约束求解

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
from z3 import *

# 定义 10 个整型变量,a0 表示 a0,其余 a1~a9
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = Ints('a0 a1 a2 a3 a4 a5 a6 a7 a8 a9')
s = Solver()

s.add(
202 * a8 + 216 * a5 - 4 * a4 - 330 * a9 - 13 * a4 - 268 * a6 == -14982,
325 * a8 + 195 * a0 + 229 * a1 - 121 * a6 - 409 * a6 - (a1 << 7) == 22606,
489 * a1 + 480 * a6 + 105 * a2 + 367 * a3 - 135 * a4 - 482 * a9 == 63236,
493 * a1 - 80 * a4 - 253 * a8 - 121 * a2 - 177 * a0 - 243 * a9 == -39664,
275 * a4 + 271 * a6 + 473 * a7 - 72 * a5 - 260 * a4 - 367 * a4 == 14255,
286 * a0 + 196 * a7 + 483 * a2 + 442 * a1 - 495 * a8 - 351 * a4 == 41171,
212 * a2 + 283 * a7 - 329 * a8 - 429 * a9 - 362 * a2 - 261 * a6 == -90284,
456 * a5 + 244 * a7 + 92 * a4 + 348 * a7 - 225 * a1 - 31 * a2 == 88447,
238 * a9 + 278 * a7 + 216 * a6 + 237 * a0 + 8 * a2 - 17 * a9 == 83838,
323 * a9 + 121 * a1 + 370 * a7 - (a4 << 6) - 196 * a9 - 422 * a0 == 26467,
166 * a9 + 90 * a1 + 499 * a2 + 301 * a8 - 31 * a2 - 206 * a2 == 88247,
355 * a0 + 282 * a4 + 44 * a9 + 359 * a8 - 167 * a5 - 62 * a3 == 76658,
488 * a6 + 379 * a9 + 318 * a2 - 85 * a1 - 357 * a2 - 277 * a5 == 35398,
40 * a0 + 281 * a4 + 217 * a5 - 241 * a1 - 407 * a7 - 309 * a7 == -35436,
429 * a3 + 441 * a3 + 115 * a1 + 96 * a8 + 464 * a1 - 133 * a7 == 157448
)
# 求解约束
if s.check() == sat:
m = s.model()
# 假设求解出来的 a0~a9 是 ASCII 码,将其转换为字符并拼接成字符串
flag = ''.join([chr(m[v].as_long()) for v in (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)])
print("Solution:", flag)
else:
print("No solution found")

后面的函数点进去像是魔改rc4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__int64 __fastcall sub_140002460(const char *a1, __int64 a2, __int64 a3)
{
__int64 result; // rax
unsigned __int8 v4; // [rsp+20h] [rbp-18h]
unsigned __int8 v5; // [rsp+21h] [rbp-17h]
unsigned int i; // [rsp+24h] [rbp-14h]
unsigned int v7; // [rsp+28h] [rbp-10h]

v4 = 0;
v5 = 0;
sub_1400028B0(a3);
v7 = strlen(a1);
for ( i = 0; i < v7; ++i )
{
v5 += byte_1400060C0[++v4];
sub_140002D90(&byte_1400060C0[v4], &byte_1400060C0[v5]);
*(_BYTE *)(a2 + i) = byte_1400060C0[(unsigned __int8)(byte_1400060C0[v5] + byte_1400060C0[v4])] ^ a1[i];
*(_BYTE *)(a2 + i) ^= 0x14u;
}
result = v7;
*(_BYTE *)(a2 + v7) = 0;
return result;
}

但是有问题,我在看交换函数sub_140002D90的时候发现了交叉引用

1
2
3
4
.rdata:0000000140004230 38 32 00 40 01 00 00 00       dq offset ?pre_cpp_initialization@@YAXXZ ; pre_cpp_initialization(void)
.rdata:0000000140004238 00 10 00 40 01 00 00 00 dq offset sub_140001000
.rdata:0000000140004240 20 10 00 40 01 00 00 00 dq offset sub_140001020
.rdata:0000000140004248 40 10 00 40 01 00 00 00 dq offset sub_140001040

他们的根源都是这个,并且可以猜到是init,初始化的时候调用的,sub_140001000点进去会发现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
char sub_140001AD0()
{
int i; // [rsp+20h] [rbp-48h]
int j; // [rsp+24h] [rbp-44h]
HMODULE hModule; // [rsp+28h] [rbp-40h]
FARPROC ProcAddress; // [rsp+30h] [rbp-38h]
CHAR ProcName[8]; // [rsp+38h] [rbp-30h] BYREF
CHAR ModuleName[16]; // [rsp+40h] [rbp-28h] BYREF

qmemcpy(ModuleName, "fpagqr`v=w", 10);
ModuleName[10] = 127;
ModuleName[11] = 127;
ModuleName[12] = 0;
for ( i = 0; i < 12; ++i )
ModuleName[i] ^= 0x13u;
hModule = GetModuleHandleA(ModuleName); //dll
strcpy(ProcName, "`gap~c");
for ( j = 0; j < 6; ++j )
ProcName[j] ^= 0x13u;
ProcAddress = GetProcAddress(hModule, ProcName); //strcmp
sub_140001C00(ProcAddress, sub_140001CE0);
return 1;
}

第一个是dll的名字,第二个是strcmp函数,所以这里实现了对strcmp函数的hook,后续调用strcmp的时候实际上是调用了sub_140001CE0

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
__int64 __fastcall sub_140001CE0(_BYTE *a1, unsigned __int8 *a2)
{
unsigned int v3; // [rsp+20h] [rbp-108h]
unsigned int num; // [rsp+20h] [rbp-108h]
unsigned int numa; // [rsp+20h] [rbp-108h]
unsigned int v6; // [rsp+24h] [rbp-104h]
unsigned int v7; // [rsp+24h] [rbp-104h]
unsigned int v8; // [rsp+24h] [rbp-104h]
unsigned int v9; // [rsp+28h] [rbp-100h]
unsigned int v10; // [rsp+28h] [rbp-100h]
unsigned int v11; // [rsp+28h] [rbp-100h]
char v12; // [rsp+2Ch] [rbp-FCh]
int i; // [rsp+30h] [rbp-F8h]
int j; // [rsp+34h] [rbp-F4h]
int ii; // [rsp+38h] [rbp-F0h]
int jj; // [rsp+3Ch] [rbp-ECh]
int kk; // [rsp+40h] [rbp-E8h]
int mm; // [rsp+44h] [rbp-E4h]
int nn; // [rsp+48h] [rbp-E0h]
int v20; // [rsp+4Ch] [rbp-DCh]
int k; // [rsp+50h] [rbp-D8h]
int m; // [rsp+54h] [rbp-D4h]
int n; // [rsp+58h] [rbp-D0h]
HMODULE hModule; // [rsp+60h] [rbp-C8h]
FARPROC ProcAddress; // [rsp+68h] [rbp-C0h]
CHAR LibFileName[16]; // [rsp+70h] [rbp-B8h] BYREF
CHAR ProcName[16]; // [rsp+80h] [rbp-A8h] BYREF
char v28[3]; // [rsp+90h] [rbp-98h] BYREF
char v29[11]; // [rsp+93h] [rbp-95h] BYREF
char v30[8]; // [rsp+9Eh] [rbp-8Ah] BYREF
char v31[32]; // [rsp+A8h] [rbp-80h] BYREF
int v32[6]; // [rsp+C8h] [rbp-60h] BYREF
int v33[14]; // [rsp+E0h] [rbp-48h] BYREF
_BYTE *v34; // [rsp+130h] [rbp+8h]

v34 = a1;
memset(v32, 0, 0x14ui64);
memset(v33, 0, 0x32ui64);
for ( i = 0; i < 20; ++i )
*((_BYTE *)v32 + i) = a1[i - 80];
for ( j = 0; j < 50; ++j )
*((_BYTE *)v33 + j) = a1[j - 56];
v3 = 0;
v6 = v33[0];
v9 = v33[1];
for ( k = 0; k < 24; ++k )
{
v6 += (v32[v3 & 3] + v3) ^ (v9 + ((v9 >> 5) ^ (16 * v9)));
v3 += 1719109785;
v9 += (v32[(v3 >> 11) & 3] + v3) ^ (v6 + ((v6 >> 5) ^ (16 * v6)));
}
v33[0] = v6;
v33[1] = v9;
num = 0;
v7 = v33[2];
v10 = v33[3];
for ( m = 0; m < 24; ++m )
{
v7 += (v32[num & 3] + num) ^ (v10 + ((v10 >> 5) ^ (16 * v10)));
num += 1719109785;
v10 += (v32[(num >> 11) & 3] + num) ^ (v7 + ((v7 >> 5) ^ (16 * v7)));
}
v33[2] = v7;
v33[3] = v10;
numa = 0;
v8 = v33[4];
v11 = v33[5];
for ( n = 0; n < 24; ++n )
{
v8 += (v32[numa & 3] + numa) ^ (v11 + ((v11 >> 5) ^ (16 * v11)));
numa += 1719109785;
v11 += (v32[(numa >> 11) & 3] + numa) ^ (v8 + ((v8 >> 5) ^ (16 * v8)));
}
v33[4] = v8;
v33[5] = v11;
v12 = 1;
for ( ii = 0; ii < 24; ++ii )
{
if ( byte_1400063C8[ii] != *((unsigned __int8 *)v33 + ii) )
{
v12 = 0;
break;
}
}
if ( v12 )
{
strcpy(LibFileName, "dbtc\"#?u}}");
for ( jj = 0; jj < 10; ++jj )
LibFileName[jj] ^= 0x11u;
hModule = LoadLibraryA(LibFileName);
strcpy(ProcName, "\\tbbpvtS~iP");
for ( kk = 0; kk < 11; ++kk )
ProcName[kk] ^= 0x11u;
ProcAddress = GetProcAddress(hModule, ProcName);
strcpy(v31, "H~d6gt1rpdvye1p1sxv1wxby0");
for ( mm = 0; mm < 25; ++mm )
v31[mm] ^= 0x11u;
qmemcpy(v28, "R~", 2);
v28[2] = 127;
qmemcpy(v29, "vcped}pex~", 10);
v29[10] = 127;
strcpy(v30, "000");
for ( nn = 0; nn < 17; ++nn )
v28[nn] ^= 0x11u;
((void (__fastcall *)(_QWORD, char *, char *, _QWORD))ProcAddress)(0i64, v31, v28, 0i64);
}
while ( 1 )
{
v20 = (unsigned __int8)*v34 - *a2;
if ( v20 || !*v34 )
break;
++v34;
++a2;
}
if ( v20 > 0 )
return 1i64;
if ( v20 >= 0 )
return 0i64;
return 0xFFFFFFFFi64;
}

后面这个函数实际上就是实现了tea的魔改,三组就是24位刚好符合,key呢就是前面第一次的输入

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

//DeluxeBait
void detea(unsigned int* middle,unsigned int* key) {
unsigned int a1, a2;
a1 = middle[0];
a2 = middle[1];
unsigned int v3 = 0;

//for (int i = 0; i < 24; ++i)
//{
// a1 += (key[v3 & 3] + v3) ^ (a2 + ((a2 >> 5) ^ (16 * a2)));
// v3 += 1719109785;
// a2 += ((key[(v3 >> 11) & 3] + v3) ^ (a1 + ((a1 >> 5) ^ (16 * a1))));
//}
for (int i = 0; i < 24; i++)
{
v3 += 1719109785;
}
for (int i = 0; i < 24; ++i)
{
a2 -= ((key[(v3 >> 11) & 3] + v3) ^ (a1 + ((a1 >> 5) ^ (16 * a1))));
v3 -= 1719109785;
a1 -= (key[v3 & 3] + v3) ^ (a2 + ((a2 >> 5) ^ (16 * a2)));
}
printf("%x %x\n", a1, a2);
middle[0] = a1;
middle[1] = a2;
}
int main() {
unsigned int flag[6] = {
0xA6975621, 0xDEC4D51A, 0x4D829CA4, 0x56C845D1, 0x5C96B4A7, 0x2087494D
};
unsigned int key[]= {
0x756C6544, 0x61426578, 0x00007469, 0x00000000,
};
unsigned int *middle;
for (int i = 0; i < 6; i+=2)
{
middle = &flag[i];
detea(middle, key);
}
unsigned char a[24] = { 0 };
//char类型转换
for (int k = 0; k < 6; k++) {
a[k * 4] = (flag[k]);
a[k * 4 + 1] = (flag[k] >> 8);
a[k * 4 + 2] = (flag[k] >> 16);
a[k * 4 + 3] = (flag[k] >> 24);
}
printf("%s", a);
return 0;
}
//DeluxeBait
//NSSCTF{Wh@t_@_b1g_F1sh}

彩蛋,后面hook了MessageboxA

LockedSecret

upx改壳+32,而且和一般壳不太一样,我选择和ida配合手脱

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+0h] [ebp-108h]
char v5; // [esp+0h] [ebp-108h]
int i; // [esp+0h] [ebp-108h]
char Str[256]; // [esp+4h] [ebp-104h] BYREF

memset(Str, 0, sizeof(Str));
sub_6D1050(Format, v4);
sub_6D10C0("%32s", Str);
if ( strlen(Str) != 32 )
{
sub_6D1050(aWrongLength, v5);
system(Command);
exit(0);
}
sub_6D1100();
sub_6D1190((int *)Str);
for ( i = 0; i < 32; ++i )
{
if ( unk_6D4060[i] != Str[i] )
{
sub_6D1050(aWrong, i);
system(aPause_0);
exit(0);
}
}
sub_6D1050(aRight, i);
system(aPause_1);
return 0;
}

第一个字写函数是造盒,用于初始化第二个函数里的key,第二个函数确实难看,提示说在Ghidra中查看

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

void __cdecl FUN_006d1190(int param_1)

{
uint uVar1;
uint uVar2;
bool bVar3;
uint local_34;
int local_30;
int local_2c;
int local_28;
int local_24;
int local_20;
byte local_1c [16];
char local_c;
uint local_8;

local_8 = DAT_006d4000 ^ (uint)&stack0xfffffffc;
local_1c._0_4_ = s_IamTheKeyYouKnow_006d3120._0_4_;
local_1c._4_4_ = s_IamTheKeyYouKnow_006d3120._4_4_;
local_1c._8_4_ = s_IamTheKeyYouKnow_006d3120._8_4_;
local_1c._12_4_ = s_IamTheKeyYouKnow_006d3120._12_4_;
local_c = s_IamTheKeyYouKnow_006d3120[0x10];
for (local_34 = 0; (int)local_34 < 0xf; local_34 = local_34 + 1) {
uVar1 = local_34 & 0x80000007;
if ((int)uVar1 < 0) {
uVar1 = (uVar1 - 1 | 0xfffffff8) + 1;
}
local_1c[local_34] = local_1c[local_34] ^ (byte)*(undefined4 *)(&DAT_006d43d8 + uVar1 * 4);
}
local_2c = 0;
local_28 = 0;
local_24 = 0;
local_20 = 0;
memcpy(&local_2c,local_1c,0x10);
local_30 = 4;
do {
uVar1 = *(uint *)(param_1 + 4 + (4 - local_30) * 8);
uVar2 = (uVar1 * 0x10 + local_2c ^ uVar1 + 0x5e2377ff ^ (uVar1 >> 5) + local_28) +
*(int *)(param_1 + (4 - local_30) * 8);
uVar1 = (uVar2 * 0x10 + local_24 ^ uVar2 + 0x5e2377ff ^ (uVar2 >> 5) + local_20) + uVar1;
uVar2 = (uVar1 * 0x10 + local_2c ^ uVar1 + 0xbc46effe ^ (uVar1 >> 5) + local_28) + uVar2;
uVar1 = (uVar2 * 0x10 + local_24 ^ uVar2 + 0xbc46effe ^ (uVar2 >> 5) + local_20) + uVar1;
uVar2 = (uVar1 * 0x10 + local_2c ^ uVar1 + 0x1a6a67fd ^ (uVar1 >> 5) + local_28) + uVar2;
uVar1 = (uVar2 * 0x10 + local_24 ^ uVar2 + 0x1a6a67fd ^ (uVar2 >> 5) + local_20) + uVar1;
uVar2 = (uVar1 * 0x10 + local_2c ^ uVar1 + 0x788ddffc ^ (uVar1 >> 5) + local_28) + uVar2;
uVar1 = (uVar2 * 0x10 + local_24 ^ uVar2 + 0x788ddffc ^ (uVar2 >> 5) + local_20) + uVar1;
uVar2 = (uVar1 * 0x10 + local_2c ^ uVar1 + 0xd6b157fb ^ (uVar1 >> 5) + local_28) + uVar2;
uVar1 = (uVar2 * 0x10 + local_24 ^ uVar2 + 0xd6b157fb ^ (uVar2 >> 5) + local_20) + uVar1;
uVar2 = (uVar1 * 0x10 + local_2c ^ uVar1 + 0x34d4cffa ^ (uVar1 >> 5) + local_28) + uVar2;
uVar1 = (uVar2 * 0x10 + local_24 ^ uVar2 + 0x34d4cffa ^ (uVar2 >> 5) + local_20) + uVar1;
uVar2 = (uVar1 * 0x10 + local_2c ^ uVar1 + 0x92f847f9 ^ (uVar1 >> 5) + local_28) + uVar2;
uVar1 = (uVar2 * 0x10 + local_24 ^ uVar2 + 0x92f847f9 ^ (uVar2 >> 5) + local_20) + uVar1;
uVar2 = (uVar1 * 0x10 + local_2c ^ uVar1 + 0xf11bbff8 ^ (uVar1 >> 5) + local_28) + uVar2;
*(uint *)(param_1 + (4 - local_30) * 8) = uVar2 ^ 0xf;
*(uint *)(param_1 + 4 + (4 - local_30) * 8) =
(uVar2 * 0x10 + local_24 ^ uVar2 + 0xf11bbff8 ^ (uVar2 >> 5) + local_20) + uVar1 ^ 0xf;
bVar3 = local_30 != 0;
local_30 = local_30 + -1;
} while (bVar3);
FUN_006d173b(local_8 ^ (uint)&stack0xfffffffc);
return;
}


一下就很好看了,是tea,常数是在模拟+=delta,key的实现动调看,dump下来是0x423DF72D, 0x05F59A01, 0x633FCF1D, 0x77D19122

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include<stdint.h>
void detea(unsigned int* mi, unsigned int* key) {
unsigned int a1, a2;
int a = 0;
unsigned int num = 0;
a1 = mi[0]^0xf;
a2 = mi[1]^0xf;
for (int i = 0; i < 8; i++)
{
num += 0x5e2377ff;
}
printf("num=%x\n", num);
for (int i = 0; i < 8; i++)
{
a2 -= (a1 * 16 + key[2] ^ a1 + num ^ (a1 >> 5) + key[3]);
a1 -= (a2 * 16 + key[0] ^ a2 + num ^ (a2 >> 5) + key[1]);
num -= 0x5e2377ff;
}
//for (int i = 0; i < 8; i++)
//{
// num += 0x5e2377ff;
// printf("%x %x\n", a1, a2);
// a1 += (a2 * 16 + key[0] ^ a2 + num ^ (a2 >> 5) + key[1]);
// a2 += (a1 * 16 + key[2] ^ a1 + num ^ (a1 >> 5) + key[3]);
//}
printf("%x %x\n", a1, a2);
mi[0] = a1;
mi[1] = a2;

}
int main() {
unsigned int key[] = { 0x423DF72D, 0x05F59A01, 0x633FCF1D, 0x77D19122 };
unsigned int input[] = {
0x031E45DC, 0x2776E989, 0x01234847, 0x64CED270, 0x33467FDA, 0xA34903B1, 0x2CD10027, 0x75BDB337
};
unsigned int* middle;
for (int i = 0; i < 8; i += 2)
{
middle = &input[i];
detea(middle, key);
}
unsigned char a[33] = { 0 };
//char类型转换
for (int k = 0; k < 8; k++) {
a[k * 4] = (input[k]);
a[k * 4 + 1] = (input[k] >> 8);
a[k * 4 + 2] = (input[k] >> 16);
a[k * 4 + 3] = (input[k] >> 24);
}
printf("%s", a);
//NSSCTF{!!!Y0u_g3t_th3_s3cr3t!!!}
return 0;
}

Mio?Ryo?Soyo?

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
import math

class R85:
Mbox = "".join([chr(Miiooooooooo) for Miiooooooooo in range(33, 118)])

@staticmethod
def M(M1: bytes) -> str:
M5 = ""
M2 = (4 - len(M1) % 4) % 4
M1 += b'\x00' * M2
for M7 in range(0, len(M1), 4):
M6 = M1[M7[:M7 + 4]]
M4 = int.from_bytes(M6, "big")
M3 = ""
for _ in range(5):
M3 = R85.Mbox[M4 % 85] + M3
M4 //= 85
else:
M5 += M3

else:
if M2:
M5 = M5[None[:-M2]]
return M5


class R45:
Rbox = "".join([chr(RRRRouto) for RRRRouto in range(48, 93)])

@staticmethod
def R(Rin: bytes) -> str:
Rout = []
Ri = 0
while Ri < len(Rin):
if Ri + 1 < len(Rin):
Rmi = Rin[Ri] << 8 | Rin[Ri + 1]
Rout.append(R45.Rbox[Rmi % 45])
Rmi //= 45
Rout.append(R45.Rbox[Rmi % 45])
Rmi //= 45
Rout.append(R45.Rbox[Rmi])
Ri += 2
else:
Rmi = Rin[Ri]
Rout.append(R45.Rbox[Rmi % 45])
Rmi //= 45
Rout.append(R45.Rbox[Rmi])
Ri += 1

return "".join(Rout)


def S(S2, num):
Sre = []
for S1 in S2:
if "a" <= S1 <= "z":
S3 = (ord(S1) - ord("a") + num) % 26
Sre.append(chr(ord("a") + S3))
elif "0" <= S1 <= "9":
S3 = (ord(S1) - ord("0") - num) % 10
Sre.append(chr(ord("0") + S3))
else:
Sre.append(S1)
else:
return "".join(Sre)

sssssssssssss = bytes([57, 118, 33, 114, 68, 56, 117, 115, 34, 52, 52, 95, 78, 40, 49, 59,
95, 85, 63, 122, 54, 33, 77, 110, 49, 54, 34, 109, 106, 122, 60,
92, 108, 91, 61, 51, 42, 62, 35, 38, 52, 67, 62, 122, 116, 48,
76, 50, 67, 51, 59, 41, 122, 45, 45, 51, 90])

def l(_: str):
return S(R85.M(S(R45.R(_.encode()), 7).encode()), 9)


from Secret import *
if __name__ == "__main__":
print("输入:", end="")
aaaaaaaaaaaaa = input()
wwwwwwwwwww = l(aaaaaaaaaaaaa)
if sssssssssssss == wwwwwwwwwww.encode():
print("哦,对的。")
else:
print("哎,并非。")
input()

简单分析base45->凯撒->base85->凯撒,直接解密即可

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
# 反向偏移的函数
def reverse_SSSooooyyooo(s: str, offset: int) -> str:
result = []
for char in s:
if 'a' <= char <= 'z':
new_char = chr((ord(char) - ord('a') - offset) % 26 + ord('a'))
result.append(new_char)
elif '0' <= char <= '9':
new_char = chr((ord(char) - ord('0') + offset) % 10 + ord('0'))
result.append(new_char)
else:
result.append(char)
return ''.join(result)

# 反向MMMMiiiiiio函数
def reverse_MMMMiiiiiio(encoded_str: str, reverse_offset: int) -> str:
MMiiiiiiooo = "".join([chr(Miiooooooooo) for Miiooooooooo in range(33, 118)])
decoded_bytes = []
for char in encoded_str:
index = MMiiiiiiooo.find(char)
if index != -1:
decoded_bytes.append(index)
decoded_str = bytes(decoded_bytes).decode('utf-8')
return reverse_SSSooooyyooo(decoded_str, reverse_offset)

# 反向RRRRyyooo函数
def reverse_RRRRyyooo(encoded_str: str) -> str:
RRRRyooooooo = "".join([chr(RRRRRRRyyyyyoooo) for RRRRRRRyyyyyoooo in range(48, 93)])
decoded_str = []
i = 0
while i < len(encoded_str):
char1 = encoded_str[i]
char2 = encoded_str[i+1] if i+1 < len(encoded_str) else ''
decoded_str.append(RRRRyooooooo[int(char1) % 45])
decoded_str.append(RRRRyooooooo[int(char2) % 45] if char2 else '')
i += 2
return ''.join(decoded_str)

# 解密整个过程
def decrypt_input(input_bytes: bytes) -> str:
step1 = reverse_RRRRyyooo(input_bytes.decode())
step2 = reverse_MMMMiiiiiio(step1, 9)
return step2

# 加密后的数据 sssssssssssss
sssssssssssss = bytes([57, 118, 33, 114, 68, 56, 117, 115, 34, 52, 52, 95, 78, 40, 49, 59,
95, 85, 63, 122, 54, 33, 77, 110, 49, 54, 34, 109, 106, 122, 60,
92, 108, 91, 61, 51, 42, 62, 35, 38, 52, 67, 62, 122, 116, 48,
76, 50, 67, 51, 59, 41, 122, 45, 45, 51, 90])

# 解密并输出
decrypted_output = decrypt_input(sssssssssssss)
print(f"解密后的结果: {decrypted_output}")

TimeSpaceRescue

拖入ida

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int v4; // [esp+0h] [ebp-11Ch]
signed int i; // [esp+4h] [ebp-118h]
char Str[256]; // [esp+8h] [ebp-114h] BYREF
int Src[4]; // [esp+108h] [ebp-14h] BYREF

sub_B220E0("Before input the key, make sure you're on the same spacetime as Liv.\n");
sub_B220E0("Try your key:");
memset(Str, 0, sizeof(Str));
sub_B22130("%s", Str);
memset(Src, 0, sizeof(Src));
initkey(Src);
v4 = strlen(Str);
aes(Src, 0x10u, Str, v4);
for ( i = 0; i < v4; ++i )
{
if ( Str[i] != byte_B26104[i] )
{
sub_B220E0("Spacetime turbulence is detected, and rescue fails!\n");
system("pause");
exit(0);
}
}
sub_B220E0("Congratulations on rescuing Liv and successfully protecting the world!\n");
system("pause");
return 0;
}

先造aes用到的key,然后加密输入,所以先看initkey

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
int __cdecl sub_B21DD0(int a1)
{
__time64_t v1; // rax
HANDLE CurrentProcess; // eax
int result; // eax
int v4; // [esp+0h] [ebp-28h]
int j; // [esp+4h] [ebp-24h]
int i; // [esp+8h] [ebp-20h]
__time64_t Time; // [esp+Ch] [ebp-1Ch] BYREF
BOOL pbDebuggerPresent; // [esp+14h] [ebp-14h] BYREF
int Src[3]; // [esp+18h] [ebp-10h] BYREF

LODWORD(v1) = sub_B22180(0);
Time = v1;
v4 = sub_B21F80(&Time);
memset(Src, 0, sizeof(Src));
pbDebuggerPresent = 0;
CurrentProcess = GetCurrentProcess();
CheckRemoteDebuggerPresent(CurrentProcess, &pbDebuggerPresent);
if ( !pbDebuggerPresent )
memcpy(Src, (v4 + 12), sizeof(Src));
md5(Src, 0xCu, a1);
for ( i = 0; i < 16; ++i )
*(i + a1) ^= 0x14u;
result = 11673238;
for ( j = 0; j < 16; ++j )
{
result = j + a1;
*(j + a1) ^= 0x11u;
}
return result;
}

看到time我就有不好的预感,果然是根据时间戳,md5加密生成key,这里有个细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.text:00B21E8E                               loc_B21E8E:                             ; CODE XREF: initkey+96↑j
.text:00B21E8E 50 push eax
.text:00B21E8F 33 C0 xor eax, eax
.text:00B21E91 E8 00 00 00 00 call $+5
.text:00B21E91
.text:00B21E96 83 C0 05 add eax, 5
.text:00B21E99 83 C0 06 add eax, 6
.text:00B21E9C 83 C0 07 add eax, 7
.text:00B21E9F D1 E0 shl eax, 1
.text:00B21EA1 83 F0 02 xor eax, 2
.text:00B21EA4 83 C0 01 add eax, 1
.text:00B21EA7 83 F8 71 cmp eax, 71h ; 'q'
.text:00B21EAA 74 01 jz short loc_B21EAD
.text:00B21EAA
.text:00B21EAC retn
.text:00B21EAC
.text:00B21EAD
.text:00B21EAD loc_B21EAD:

本来这个位置是返回,但是看ida汇编代码就会发现,这里有点像花指令,因为再运行的时候会发现这个地方是要跳过的,所以可以nop了,然后就可以看到我的那个伪代码界面了

所以这个函数实现了,md5加密时间戳,然后简单加密生成key(注意,这个时间戳是否赋值是要根据是否处于反调试的)提到这里还有个细节,这个程序肯定要多次调试做,然后就会发现,无论怎么再main中下断点都会退出程序,我直接再start下断点追本溯源发现

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
  if ( dword_B264DC )
{
v1 = 1;
}
else
{
dword_B264DC = 1;
initterm(&dword_B24110, &dword_B24124);
dword_B264DC = 2;
}
__scrt_release_startup_lock(v10);
v2 = sub_B22C41();
v3 = v2;
if ( *v2 && __scrt_is_nonwritable_in_current_image(v2) )
(*v3)(*v3, 0, 2, 0);
v4 = sub_B22C47();
v5 = v4;
if ( *v4 && __scrt_is_nonwritable_in_current_image(v4) )
register_thread_local_exe_atexit_callback(*v5);
initial_narrow_environment = get_initial_narrow_environment();
v7 = *_p___argv();
v8 = _p___argc();
a1 = main(*v8, v7, initial_narrow_environment);
if ( !sub_B22D6A() )
LABEL_17:
exit(a1);
if ( !v1 )
cexit();
__scrt_uninitialize_crt(1, 0);
return a1;
}

在这里有反调试,也就是那个if判断,每一次都要手动跳过一下,好的接下来看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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
int __cdecl aes(void *Src, size_t Size, char *a3, unsigned int a4)
{
int j; // [esp+10h] [ebp-19Ch]
unsigned int i; // [esp+14h] [ebp-198h]
char *v7; // [esp+18h] [ebp-194h]
unsigned int k; // [esp+1Ch] [ebp-190h]
char *v9; // [esp+20h] [ebp-18Ch]
char v10[356]; // [esp+24h] [ebp-188h] BYREF
int key[4]; // [esp+188h] [ebp-24h] BYREF
int v12[4]; // [esp+198h] [ebp-14h] BYREF

v7 = a3;
v9 = v10;
memset(key, 0, sizeof(key));
memset(v12, 0, sizeof(v12));
if ( Size > 0x10 )
return -1;
if ( a4 % 0x10 )
return -1;
memcpy(key, Src, Size);
de2(key);
sub_B21490(key, 16, v10);
for ( i = 0; i < a4; i += 16 )
{
de3(a3);
sub_B21750(v12, a3);
sub_B21170(v12, v10);
for ( j = 1; j < 10; ++j )
{
v9 += 16;
sub_B21B90(v12);
sub_B21990(v12);
sub_B217C0(v12);
sub_B21170(v12, v9);
}
sub_B21B90(v12);
sub_B21990(v12);
sub_B21170(v12, v9 + 16);
sub_B21B30(v12, v7);
de2(v7);
v7 += 16;
a3 += 16;
v9 = v10;
}
if ( byte_B26100 )
{
for ( k = 0; k < a4; ++k )
a3[k] ^= 0x11u;
}
return 0;
}

经典AES_EBC,但是有小魔改,我标记成了de2和de3,同样的这个函数的末尾也有一个小花,不过观察发现,a3一共加了32字节,所以后面的异或是不影响输入明文的,最后与flag对比,逻辑就清晰了

time—md5—>key—de2—–AES-EBC

               ^

input—de2——— |

所以要。。。。。爆破时间,根据题目提示,2024的某一天

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
#pragma once
#ifndef MD5_H
#define MD5_H

typedef struct
{
unsigned int count[2];
unsigned int state[4];
unsigned char buffer[64];
}MD5_CTX;


#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX* context);
void MD5Update(MD5_CTX* context, unsigned char* input, unsigned int inputlen);
void MD5Final(MD5_CTX* context, unsigned char digest[16]);
void MD5Transform(unsigned int state[4], unsigned char block[64]);
void MD5Encode(unsigned char* output, unsigned int* input, unsigned int len);
void MD5Decode(unsigned int* output, unsigned char* input, unsigned int len);

#endif
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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
#include <stdio.h>
#include <stdlib.h>
#include "md5.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include<time.h>
#include <memory.h>

unsigned char PADDING[] = { 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

void MD5Init(MD5_CTX* context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX* context, unsigned char* input, unsigned int inputlen)
{
unsigned int i = 0, index = 0, partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if (context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;

if (inputlen >= partlen)
{
memcpy(&context->buffer[index], input, partlen);
MD5Transform(context->state, context->buffer);
for (i = partlen; i + 64 <= inputlen; i += 64)
MD5Transform(context->state, &input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index], &input[i], inputlen - i);
}
void MD5Final(MD5_CTX* context, unsigned char digest[16])
{
unsigned int index = 0, padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56) ? (56 - index) : (120 - index);
MD5Encode(bits, context->count, 8);
MD5Update(context, PADDING, padlen);
MD5Update(context, bits, 8);
MD5Encode(digest, context->state, 16);
}
void MD5Encode(unsigned char* output, unsigned int* input, unsigned int len)
{
unsigned int i = 0, j = 0;
while (j < len)
{
output[j] = input[i] & 0xFF;
output[j + 1] = (input[i] >> 8) & 0xFF;
output[j + 2] = (input[i] >> 16) & 0xFF;
output[j + 3] = (input[i] >> 24) & 0xFF;
i++;
j += 4;
}
}
void MD5Decode(unsigned int* output, unsigned char* input, unsigned int len)
{
unsigned int i = 0, j = 0;
while (j < len)
{
output[i] = (input[j]) |
(input[j + 1] << 8) |
(input[j + 2] << 16) |
(input[j + 3] << 24);
i++;
j += 4;
}
}
void MD5Transform(unsigned int state[4], unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x, block, 64);
FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */

/* Round 2 */
GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */

/* Round 3 */
HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], 23, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */

/* Round 4 */
II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}


unsigned char FA(unsigned char b);
unsigned char FB(unsigned char b);
unsigned char FC(unsigned char b);
unsigned char FD(unsigned char b);
unsigned char FE(unsigned char b);
unsigned char Ff(unsigned char b);
void Cipher(unsigned char* input, unsigned char* output, unsigned char* w);//加密
void InvCipher(unsigned char* input, unsigned char* output, unsigned char* w);//解密

static unsigned char AesSbox[16 * 16] =
{
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
};

static unsigned char AesiSbox[16 * 16] =
{
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
};
static unsigned char AesRcon[11 * 4] =
{
0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00,
0x1b, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00
};


unsigned char FA(unsigned char b) { if (b < 0x80) return (b << 1);else return ((b << 1) ^ (0x1b)); }
unsigned char FB(unsigned char b) { return FA(b) ^ b; }
unsigned char FC(unsigned char b) { return FA(FA(FA(b))) ^ b; }
unsigned char FD(unsigned char b) { return FA(FA(FA(b))) ^ FA(b) ^ b; }
unsigned char FE(unsigned char b) { return FA(FA(FA(b))) ^ FA(FA(b)) ^ b; }
unsigned char Ff(unsigned char b) { return FA(FA(FA(b))) ^ FA(FA(b)) ^ FA(b); }

void Cipher(unsigned char* input, unsigned char* output, unsigned char* exp_key)
{
int i, j;
int round;
unsigned char ttt[4 * 4];
unsigned char State[4][4];
for (i = 0;i < 16;i++) State[i % 4][i / 4] = input[i];
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = State[i][j] ^ exp_key[4 * j + i];
for (round = 1; round <= 9; round++)
{
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = AesSbox[State[i][j]];
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)ttt[4 * i + j] = State[i][j];
for (i = 1;i < 4;i++)for (j = 0;j < 4;j++)
{
if (i == 1)State[i][j] = ttt[4 * i + (j + 1) % 4];else if (i == 2)State[i][j] = ttt[4 * i + (j + 2) % 4];else if (i == 3)State[i][j] = ttt[4 * i + (j + 3) % 4];
}
for (j = 0;j < 4;j++) for (i = 0;i < 4;i++) ttt[4 * i + j] = State[i][j];
for (j = 0;j < 4;j++)
{
State[0][j] = FA(ttt[0 + j]) ^ FB(ttt[4 * 1 + j]) ^ ttt[4 * 2 + j] ^ ttt[4 * 3 + j];
State[1][j] = ttt[0 + j] ^ FA(ttt[4 * 1 + j]) ^ FB(ttt[4 * 2 + j]) ^ ttt[4 * 3 + j];
State[2][j] = ttt[0 + j] ^ ttt[4 * 1 + j] ^ FA(ttt[4 * 2 + j]) ^ FB(ttt[4 * 3 + j]);
State[3][j] = FB(ttt[0 + j]) ^ ttt[4 * 1 + j] ^ ttt[4 * 2 + j] ^ FA(ttt[4 * 3 + j]);
}
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = State[i][j] ^ exp_key[4 * ((round * 4) + j) + i];
}
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = AesSbox[State[i][j]];
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)ttt[4 * i + j] = State[i][j];
for (i = 1;i < 4;i++)for (j = 0;j < 4;j++)
{
if (i == 1)State[i][j] = ttt[4 * i + (j + 1) % 4];else if (i == 2)State[i][j] = ttt[4 * i + (j + 2) % 4];else if (i == 3)State[i][j] = ttt[4 * i + (j + 3) % 4];
}
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = State[i][j] ^ exp_key[4 * (40 + j) + i];
for (i = 0; i < 16; i++)output[i] = State[i % 4][i / 4];
}

//Aes解密函数
void InvCipher(unsigned char* input, unsigned char* output, unsigned char* exp_key)
{
int round;
int i, j;
unsigned char ttt[4 * 4];
unsigned char State[4][4];
for (i = 0; i < 16; i++)State[i % 4][i / 4] = input[i];
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = State[i][j] ^ exp_key[4 * (40 + j) + i];
for (round = 9; round >= 1; round--)
{
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)ttt[4 * i + j] = State[i][j];
for (i = 1;i < 4;i++)for (j = 0;j < 4;j++)
{
if (i == 1)State[i][j] = ttt[4 * i + (j + 3) % 4];else if (i == 2)State[i][j] = ttt[4 * i + (j + 2) % 4];else if (i == 3)State[i][j] = ttt[4 * i + (j + 1) % 4];
}
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = AesiSbox[State[i][j]];
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = State[i][j] ^ exp_key[4 * ((round * 4) + j) + i];
for (i = 0; i < 4; i++)for (j = 0; j < 4; j++) ttt[4 * i + j] = State[i][j];
for (j = 0; j < 4; j++)
{
State[0][j] = Ff(ttt[j]) ^ FD(ttt[4 + j]) ^ FE(ttt[4 * 2 + j]) ^ FC(ttt[4 * 3 + j]);
State[1][j] = FC(ttt[j]) ^ Ff(ttt[4 + j]) ^ FD(ttt[4 * 2 + j]) ^ FE(ttt[4 * 3 + j]);
State[2][j] = FE(ttt[j]) ^ FC(ttt[4 + j]) ^ Ff(ttt[4 * 2 + j]) ^ FD(ttt[4 * 3 + j]);
State[3][j] = FD(ttt[j]) ^ FE(ttt[4 + j]) ^ FC(ttt[4 * 2 + j]) ^ Ff(ttt[4 * 3 + j]);
}
}
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)ttt[4 * i + j] = State[i][j];
for (i = 1;i < 4;i++)for (j = 0;j < 4;j++)
{
if (i == 1)State[i][j] = ttt[4 * i + (j + 3) % 4];else if (i == 2)State[i][j] = ttt[4 * i + (j + 2) % 4];else if (i == 3)State[i][j] = ttt[4 * i + (j + 1) % 4];
}
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = AesiSbox[State[i][j]];
for (j = 0;j < 4;j++)for (i = 0;i < 4;i++)State[i][j] = State[i][j] ^ exp_key[4 * j + i];
for (i = 0; i < 16; i++)output[i] = State[i % 4][i / 4];
}

/*****************************************************
*函数功能: AES加密, 模式CBC,数据块128位,填充方式:pkcs5padding
* 参数:
* input_buff:需要加密的数组指针
* InputLen:加密数据的字节长度
* p_key: 指向密钥数据的指针, 1~16字节长度
* output_buff:加密结果输出指针
*
* 返回值: OutLength 加密后的输出长度
*********************************************************/
unsigned long AES128_CBC_Encrypt(unsigned char* input_buff, unsigned long InputLen, unsigned char* p_key, unsigned char* output_buff, unsigned char* iv)
{
unsigned long OutLength = 0;
long i, j;
unsigned char* lpCurInBuff = input_buff;
unsigned char* lpCurOutBuff = output_buff;
long blocknum = InputLen / 16;
long leftnum = InputLen % 16;

int row;
unsigned char temp[4];
unsigned char ex_key[16 * 15];
for (row = 0;row < 4;row++) //拷贝seed 密钥
{
ex_key[4 * row + 0] = *(p_key + 4 * row);
ex_key[4 * row + 1] = *(p_key + 4 * row + 1);
ex_key[4 * row + 2] = *(p_key + 4 * row + 2);
ex_key[4 * row + 3] = *(p_key + 4 * row + 3);
}
for (row = 4;row < 44;row++)
{
temp[0] = ex_key[4 * row - 4]; //当前列的前一列
temp[1] = ex_key[4 * row - 3];
temp[2] = ex_key[4 * row - 2];
temp[3] = ex_key[4 * row - 1];
if (row % 4 == 0)
{
unsigned char exchange_buff = 0;
exchange_buff = temp[0];
temp[0] = AesSbox[16 * (temp[1] >> 4) + (temp[1] & 0x0f)];
temp[1] = AesSbox[16 * (temp[2] >> 4) + (temp[2] & 0x0f)];
temp[2] = AesSbox[16 * (temp[3] >> 4) + (temp[3] & 0x0f)];
temp[3] = AesSbox[16 * (exchange_buff >> 4) + (exchange_buff & 0x0f)];

temp[0] = temp[0] ^ AesRcon[4 * (row / 4) + 0];
temp[1] = temp[1] ^ AesRcon[4 * (row / 4) + 1];
temp[2] = temp[2] ^ AesRcon[4 * (row / 4) + 2];
temp[3] = temp[3] ^ AesRcon[4 * (row / 4) + 3];
}
ex_key[4 * row + 0] = ex_key[4 * (row - 4) + 0] ^ temp[0];
ex_key[4 * row + 1] = ex_key[4 * (row - 4) + 1] ^ temp[1];
ex_key[4 * row + 2] = ex_key[4 * (row - 4) + 2] ^ temp[2];
ex_key[4 * row + 3] = ex_key[4 * (row - 4) + 3] ^ temp[3];
}
for (i = 0;i < blocknum;i++)
{
for (j = 0; j < 16; j++)lpCurOutBuff[j] = lpCurInBuff[j] ^ iv[j];
Cipher(lpCurOutBuff, lpCurOutBuff, ex_key);
memcpy(iv, lpCurOutBuff, 16);
lpCurInBuff += 16;
lpCurOutBuff += 16;
OutLength += 16;
}
if (leftnum)
{
unsigned char inbuff[16];
memset(inbuff, 16 - leftnum, 16);
memcpy(inbuff, lpCurInBuff, leftnum);
for (j = 0; j < 16; j++)lpCurOutBuff[j] = inbuff[j] ^ iv[j];
Cipher(lpCurOutBuff, lpCurOutBuff, ex_key);
memcpy(iv, lpCurOutBuff, 16);
lpCurOutBuff += 16;
OutLength += 16;
}
else
{
unsigned char extrabuff[16];
memset(extrabuff, 16, 16);
for (j = 0; j < 16; j++)lpCurOutBuff[j] = extrabuff[j] ^ iv[j];
Cipher(lpCurOutBuff, lpCurOutBuff, ex_key);
memcpy(iv, lpCurOutBuff, 16);
OutLength += 16;
}
return OutLength;
}


/*******************************************************
*函数功能: AES解密, 模式CBC,数据块128位,填充方式:pkcs5padding
* 参数:
* input_buff:需要解密的数组指针
* InputLen:需要解密数据的字节长度
* p_key: 指向密钥数据的指针, 1~16字节长度
* output_buff:加密结果输出指针
*
* 返回值: OutLength 加密后的输出长度
********************************************************/
unsigned long AES128_CBC_Decrypt(unsigned char* input_buff, unsigned long InputLen, unsigned char* p_key, unsigned char* output_buff, unsigned char* iv)
{
unsigned long OutLength = 0;
long blocknum = InputLen / 16;
long leftnum = InputLen % 16;
long i, j;
unsigned char temp[16];

unsigned char* pCurInBuf = input_buff;
unsigned char* pCurOutBuf = output_buff;
int row;
unsigned char ex_key[16 * 15];
for (row = 0;row < 4;row++)
{
ex_key[4 * row + 0] = *(p_key + 4 * row);
ex_key[4 * row + 1] = *(p_key + 4 * row + 1);
ex_key[4 * row + 2] = *(p_key + 4 * row + 2);
ex_key[4 * row + 3] = *(p_key + 4 * row + 3);
}
for (row = 4;row < 44;row++)
{
temp[0] = ex_key[4 * row - 4]; //当前列的前一列
temp[1] = ex_key[4 * row - 3];
temp[2] = ex_key[4 * row - 2];
temp[3] = ex_key[4 * row - 1];
if (row % 4 == 0)
{
unsigned char exchange_buff = 0;
exchange_buff = temp[0];
temp[0] = AesSbox[16 * (temp[1] >> 4) + (temp[1] & 0x0f)];
temp[1] = AesSbox[16 * (temp[2] >> 4) + (temp[2] & 0x0f)];
temp[2] = AesSbox[16 * (temp[3] >> 4) + (temp[3] & 0x0f)];
temp[3] = AesSbox[16 * (exchange_buff >> 4) + (exchange_buff & 0x0f)];
temp[0] = temp[0] ^ AesRcon[4 * (row / 4) + 0];
temp[1] = temp[1] ^ AesRcon[4 * (row / 4) + 1];
temp[2] = temp[2] ^ AesRcon[4 * (row / 4) + 2];
temp[3] = temp[3] ^ AesRcon[4 * (row / 4) + 3];
}
ex_key[4 * row + 0] = ex_key[4 * (row - 4) + 0] ^ temp[0];
ex_key[4 * row + 1] = ex_key[4 * (row - 4) + 1] ^ temp[1];
ex_key[4 * row + 2] = ex_key[4 * (row - 4) + 2] ^ temp[2];
ex_key[4 * row + 3] = ex_key[4 * (row - 4) + 3] ^ temp[3];
}
for (i = 0;i < blocknum;i++)
{
InvCipher(pCurInBuf, pCurOutBuf, ex_key);
for (j = 0; j < 16; j++)
{
pCurOutBuf[j] = pCurOutBuf[j] ^ iv[j];
}
memcpy(iv, pCurInBuf, 16);
if (i == (blocknum - 1))
{
memset(temp, 0, 16);
if (pCurOutBuf[15] != 0x10)
{
if (pCurOutBuf[15] < 0x10)
{
OutLength = InputLen - pCurOutBuf[15];
memcpy(temp, pCurOutBuf, 16 - pCurOutBuf[15]);
memcpy(pCurOutBuf, temp, 16);
}
else
break;
}
else
{
OutLength = InputLen - 16;
memcpy(pCurOutBuf, temp, 16);
}
}
pCurInBuf += 16;
pCurOutBuf += 16;
}
return OutLength;
}
void md5(unsigned char* encrypt,unsigned char* decrypt)
{
int i;
MD5_CTX md5;
MD5Init(&md5);
MD5Update(&md5, encrypt, 0xc);
MD5Final(&md5, decrypt);
//for (i = 0; i < 16; i++)
//{
// printf("%02x", decrypt[i]);
//}

return 0;
}
void initkey(unsigned char* a1, char day, char month)
{
int year = 2024-1900;
int j; // [esp+4h] [ebp-24h]
int i; // [esp+8h] [ebp-20h]
char Src[12] = { 0 }; // [esp+18h] [ebp-10h] BYREF
char* src = Src;
memset(Src, 0, sizeof(Src));
Src[0] = day;
Src[4] = month - 1;
Src[8] = year;
//for (int i = 0; i < 0xc; i++)
//{
// printf("%02x ", Src[i]);
//}
//printf("\n");
md5(Src, a1);
//for (int i = 0; i < 16; i++)
//{
// printf("%x ", a1[i]);
//}
//printf("\n");
for (i = 0; i < 16; ++i)
a1[i] ^= 0x14u;
for (j = 0; j < 16; ++j)
a1[j] ^= 0x11u;
}
void de1(char* flag) {
for (int i = 0; i < 16; i++)
{
flag[i] ^= 0x11;
}
}
void de2(char* a1)
{
unsigned int i; // [esp+0h] [ebp-8h]
char v2; // [esp+7h] [ebp-1h]

for (i = 0; i < 0x10; i += 2)
{
v2 = a1[i] ^ 5;
a1[i] = a1[i + 1] ^ 5;
a1[i + 1] = v2;
}
}
void de3(char* a1)
{
unsigned int i; // [esp+0h] [ebp-Ch]
unsigned int v2; // [esp+4h] [ebp-8h]
char v3; // [esp+Bh] [ebp-1h]

v2 = 0;
for (i = 15; v2 < i; --i)
{
v3 = a1[v2] ^ 0xF;
a1[v2] = a1[i] ^ 0xF;
a1[i] = v3;
++v2;
}
}
void main(void)
{
unsigned char key[16] = { 0 };
char day=6, month=3;
for (month = 0; month < 13; month++)
{
for ( day = 0; day < 31; day++)
{
initkey(key, day, month);
de2(key);
//for (int i = 0; i < 16; i++)
//{
// printf("%x ", key[i]);
//}
unsigned char iv[32] = { 0 };
unsigned char flag[] = { 0xCD, 0x16, 0xDB, 0xB5, 0xD1, 0x02, 0xA4, 0x82, 0x8E, 0x59, 0x73, 0x9E, 0x96, 0x26, 0x56, 0xF2,
0x16, 0x8E, 0x46, 0xF2, 0x55, 0x7B, 0x92, 0x31, 0x30, 0xDC, 0xAA, 0x8A, 0xF3, 0x1C, 0xA0, 0xAA
};
unsigned char okflag[33] = { 0 };
unsigned char* f = flag;
unsigned char* ii = iv;
unsigned char* ff = okflag;
for (int i = 0; i < 32; i+=16)
{
//de1(f);
de2(f);
AES128_CBC_Decrypt(f, 16, key, ff, ii);
de3(ff);
f += 16;
ii += 16;
ff += 16;
}
if(okflag[0]=='N'&&okflag[1]=='S') {
printf("\n%d %d:", month, day);
for (int i = 0; i < 32; i++)
{
printf("%c", okflag[i]);
}
//NSSCTF{W0w_Y0u're_@n_AE5_M@5t3r}
}
}
}

return;
}

Room0

异常+SMC+rc4变

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+18h] [ebp-234h]
char v5; // [esp+18h] [ebp-234h]
char v6; // [esp+18h] [ebp-234h]
char v7; // [esp+18h] [ebp-234h]
char v8; // [esp+18h] [ebp-234h]
int i; // [esp+2Ch] [ebp-220h]
char v10[256]; // [esp+30h] [ebp-21Ch] BYREF
char Str[256]; // [esp+130h] [ebp-11Ch] BYREF
CPPEH_RECORD ms_exc; // [esp+234h] [ebp-18h]

ms_exc.registration.TryLevel = 0;
sub_4028C0("Welcome to the hostel!\n", v4);
sub_4028C0("Please input your informatioin to enter your room.\n", v5);
sub_4028C0("Input your flag:", v6);
memset(Str, 0, sizeof(Str));
sub_402900("%s", (char)Str);
sub_4028C0("Input your Key:", v7);
memset(v10, 0, sizeof(v10));
sub_402900("%s", (char)v10);
if ( sub_402000(v10) != 0x11451419 )
{
sub_4028C0("Not the key.\n", v8);
exit(0);
}
sub_402130(Str, 0x19);
for ( i = 0; i < 32; ++i )
{
if ( Str[i] != (unsigned __int8)byte_405000[i] )
{
sub_4028C0("Your flag is incorrect.\n", v8);
exit(0);
}
}
sub_4028C0("Welcome into your room\n", v8);
system("pause");
return 0;
}

输入分两个一个key一个input,看汇编码会发现

这里是有异常处理的,并且还是有模有样地,不难猜测会有地方触发异常,肉眼可见的没有,就看看函数

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
int __cdecl sub_402000(char *Str)
{
int v2; // [esp+0h] [ebp-1Ch]
int i; // [esp+4h] [ebp-18h]
int v4; // [esp+8h] [ebp-14h]
int v5; // [esp+Ch] [ebp-10h]
int v6; // [esp+10h] [ebp-Ch]
int v7; // [esp+10h] [ebp-Ch]
unsigned int v8; // [esp+14h] [ebp-8h]
int v9; // [esp+18h] [ebp-4h]

v2 = sub_402590(Str);
if ( !v2 )
return 0;
v6 = 0;
v9 = v2;
v8 = HIBYTE(v2);
v5 = BYTE2(v2);
v4 = BYTE1(v2);
for ( i = 0; i < 32; ++i )
{
v7 = v6 * (v8 + 1415881080) * (v9 - 1467486175) * ((v8 - v9) ^ (v8 >> 4));
v5 = (v9 + v5) ^ (8 * v4);
v4 = (v9 + v8) ^ (8 * v5);
v8 = (v9 + v4) ^ (8 * v5);
v9 -= v4 + v5 + v8;
v6 = v7 + (v8 + 1467486175) * (((v8 - v9) ^ (unsigned __int64)(v8 >> 4)) / (unsigned int)(v9 - 1415881080));
}
return v9 ^ v6;
}

/-div,能够引发除零异常,所以这里必然会引起异常到异常处理模块,这么一看题目名字room 0 原来意思是异常提示,真是旁观者清啊

那么看异常怎么做了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mov     esp, [ebp+ms_exc.old_esp]
mov ebx, [esp+224h+var_23C]
mov eax, ebp
sub eax, 21Ch
push eax ; Str
call sub_402590
push eax
call loc_402410
mov eax, ebp
sub eax, 11Ch
push ebx
push eax
call sub_401000
mov [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh

三个函数,第一个之前在验证函数就出现了,是ascii码转16进制,比如你输入的是1a,就会变成0x1a,类似于python代码的int(‘1a’,16)实现了

第二个函数有花指令去一下

这里是永真不爆红花,需要把retn去掉

后面是永真跳转

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
int __stdcall sub_402410(unsigned int a1)
{
int result; // eax
int v2; // [esp+10h] [ebp-30h]
char *v3; // [esp+18h] [ebp-28h]
int j; // [esp+20h] [ebp-20h]
__int16 v5; // [esp+24h] [ebp-1Ch]
HMODULE ModuleHandleW; // [esp+28h] [ebp-18h]
char *Str1; // [esp+2Ch] [ebp-14h]
int i; // [esp+30h] [ebp-10h]
int k; // [esp+34h] [ebp-Ch]
int v10; // [esp+38h] [ebp-8h]

ModuleHandleW = GetModuleHandleW(0);
v10 = 0;
for ( i = 0; i < 4; ++i )
*((_BYTE *)&v10 + i) = a1 >> (8 * (3 - i));
v5 = *(_WORD *)((char *)ModuleHandleW + *((_DWORD *)ModuleHandleW + 15) + 6);
result = (int)ModuleHandleW + *((_DWORD *)ModuleHandleW + 15) + 248;
Str1 = (char *)result;
for ( j = 0; j < v5; ++j )
{
if ( !strcmp(Str1, ".enc") )
{
v2 = *((_DWORD *)Str1 + 4);
v3 = (char *)ModuleHandleW + *((_DWORD *)Str1 + 3);
for ( k = 0; ; ++k )
{
result = k;
if ( k >= v2 )
break;
v3[k] ^= *((_BYTE *)&v10 + k % 4);
}
return result;
}
result = (int)(Str1 + 40);
Str1 += 40;
}
return result;
}

检测当前块是不是enc,如果是的话就进行SMC,解密而SMC异或的对象就是前面输入的key,那么问题来了,key应该是多少呢,这里我动调发现SMC解密的对象就是下一个要调用的函数,再因为一般函数的开头都是55 8B EC 第四个有多种可能,我后来尝试发现对应异或应该是d3,并且

我们能发现,这个函数后续都是75 5f f0 d3并且我计算出key的前几位也是75 5f f0,这也验证了第四位是d3的思路,这样这里SMC解密后就是0了,所以key就是755ff0d3

idc脚本:

1
2
3
4
5
start=0x00401000
key=[0x75, 0x5F, 0xF0, 0xD3]
end=0x00401600
for i in range(end-start):
patch_byte(start+i,get_wide_byte(start+i)^key[i%4])

这里如果是动调看的话有两种花各两个,一种是爆红的永真跳,另一种是不爆红的花,但是如果是脚本静态的看好像就不报错

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
int __cdecl sub_401000(char *Str, unsigned int a2)
{
unsigned __int8 v2; // al
char v4; // [esp-10h] [ebp-244h]
size_t v5; // [esp+0h] [ebp-234h]
char v6; // [esp+4h] [ebp-230h]
int v7; // [esp+8h] [ebp-22Ch]
int ii; // [esp+Ch] [ebp-228h]
size_t n; // [esp+10h] [ebp-224h]
int k; // [esp+14h] [ebp-220h]
int j; // [esp+18h] [ebp-21Ch]
int m; // [esp+1Ch] [ebp-218h]
int i; // [esp+20h] [ebp-214h]
char v14; // [esp+24h] [ebp-210h]
char v15; // [esp+25h] [ebp-20Fh]
unsigned __int8 v16; // [esp+26h] [ebp-20Eh]
unsigned __int8 v17; // [esp+27h] [ebp-20Dh]
char v18[256]; // [esp+28h] [ebp-20Ch] BYREF
char v19[256]; // [esp+128h] [ebp-10Ch] BYREF
int v20[2]; // [esp+228h] [ebp-Ch]

v20[0] = 0;
v20[1] = 0;
v2 = (unsigned __int8)memset(v19, 0, sizeof(v19));
for ( i = 0; i < 8; ++i )
{
if ( i >= 4 )
v6 = 7 - i;
else
v6 = i;
v2 = i;
*((_BYTE *)v20 + i) = a2 >> (8 * v6);
}
for ( j = 0; j < 256; ++j )
{
v2 = j;
v19[j] = j;
}
v4 = v2;
memset(v18, 0, sizeof(v18));
for ( k = 0; k < 256; ++k )
v18[k] = *((_BYTE *)v20 + k % 8);
v7 = 0;
for ( m = 0; m < 256; ++m )
{
v7 = ((unsigned __int8)v18[m] + v7 + (unsigned __int8)v19[m]) % 256;
v15 = v19[m];
v19[m] = v19[v7];
v19[v7] = v15;
}
v17 = 0;
v16 = 0;
v5 = strlen(Str);
for ( n = 0; n < v5; ++n )
{
v16 += v19[++v17];
v14 = v19[v17];
v19[v17] = v19[v16];
v19[v16] = v14;
Str[n] ^= *((_BYTE *)v20 + (v17 & 7)) ^ v19[((unsigned __int8)v19[v16] + (unsigned __int8)v19[v17]) % 256];
}
for ( ii = 0; ii < 32; ++ii )
{
if ( byte_405020[ii] != Str[ii] )
{
sub_4028C0("You shouldn't come here, get out of that room!\n", v4);
exit(0);
}
}
return 1;
}

可以看出来时rc4,但是再rc4最后一步异或的时候多异或了一个key,逻辑就是把a2 01233210的方式加倍生成8位key,然后rc4,所以现在只需要知道key就可以解密了,动调看把

后面我测试了一下,如果除零异常时手动将div ecx里面的ecx改成了0,则最终ebx,也就是a2传参就是0,但如果是正常的输入正确key然后运行过程中爆除零异常,那么ebx就会是正确的key

可以看到如果是正常输入的话,i==0xf的时候会变成0,这时候

ebx会是正确key,大概能猜到,这里的ebx就是之前那些计算留下来的数

解题脚本如下:

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
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include<time.h>
unsigned char keybox[256] = { 0 };
//标准RC4
unsigned char keyk[8] = { 0 };

void rc4(unsigned char* key, int key_Len, unsigned char* data, int data_Len) //加解密
{
int i = 0, j = 0, t = 0;
unsigned char s[256] = { 0 };
unsigned char* ps = s;
unsigned char tmp = 0;
for (i = 0;i < 256;i++) {
s[i] = i;
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + keybox[i]) % 256;
tmp = s[i];
s[i] = s[j]; //交换s[i]和s[j]
s[j] = tmp;
}
int q = 0;
i = j = 0;
for (q = 0;q < data_Len;q++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;

tmp = s[i];
s[i] = s[j]; //交换s[x]和s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
data[q] ^= s[t]^ keyk[i % 8];
}
}
int main() {
int i;
unsigned char flag[] = {
0x22, 0xC4, 0xA0, 0x5A, 0xDE, 0xED, 0x62, 0x5E, 0x25, 0xE2, 0x6D, 0xA6, 0x05, 0xA7, 0x20, 0x8D,
0x7D, 0x99, 0x52, 0x3E, 0x8C, 0xA7, 0x7F, 0xFA, 0x09, 0xD8, 0x62, 0xDB, 0x00, 0x80, 0xC2, 0xA9
};
//10E70D20C9D7B5FF171710364C502E6A0EFF70CEF380835E605587810080C2A9A9
unsigned int key = 0xF86D35D4;
//755FF0D3
char v6;
for (i = 0; i < 8; ++i)
{
if (i >= 4)
v6 = 7 - i;
else
v6 = i;
keyk[i] = key >> (8 * v6);
}

//for (i = 0; i < 8; i++)
//{
// printf("%x ", keyk[i]);
//}
//printf("\n");

for (i = 0; i < 256; i++)
{
keybox[i] = keyk[i % 8];
}

rc4(keyk, 8, flag, 32);

for ( i = 0; i < 32; i++)
{
printf("%c", flag[i]);

}
//NSSCTF{Int3r3st1ng_5MC_Pr0gr@m?}
return 0;
}

canno

就是考加解密的,拖进ida

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rdx
__int64 v4; // r8
__int64 v6; // rdx
__int64 v7; // r8
int j; // [rsp+20h] [rbp-1F8h]
int i; // [rsp+24h] [rbp-1F4h]
int v10; // [rsp+28h] [rbp-1F0h]
int v11[4]; // [rsp+30h] [rbp-1E8h]
__int64 v12; // [rsp+40h] [rbp-1D8h]
__int64 v13; // [rsp+48h] [rbp-1D0h]
__int64 v14; // [rsp+50h] [rbp-1C8h]
int v15[8]; // [rsp+58h] [rbp-1C0h]
int v16[4]; // [rsp+78h] [rbp-1A0h]
char input1[12]; // [rsp+88h] [rbp-190h] BYREF
char input2[12]; // [rsp+94h] [rbp-184h] BYREF
char input3[16]; // [rsp+A0h] [rbp-178h] BYREF
char i1[112]; // [rsp+B0h] [rbp-168h] BYREF
char i2[112]; // [rsp+120h] [rbp-F8h] BYREF
char i3[112]; // [rsp+190h] [rbp-88h] BYREF

sub_7FF68C1A2470("Enter the flag: ", argv, envp);
sub_7FF68C1A24F0("%36s", input1); // aaaaaaaaaaaabbbbbbbbbbbbcccccccccccc
if ( strlen(input1) == 0x24 )
{
strncpy(i1, input1, 0xCui64);
v12 = 12i64;
i1[12] = 0;
strncpy(i2, input2, 0xCui64);
v13 = 12i64;
i2[12] = 0;
strncpy(i3, input3, 0xCui64);
v14 = 12i64;
i3[12] = 0; // 分三份
v15[0] = 1;
v15[1] = 5;
v15[2] = 6;
v15[3] = 3;
v15[4] = 4;
v15[5] = 1;
v15[6] = 4;
v15[7] = 5;
v16[0] = 0;
v16[1] = 1;
v16[2] = 2;
v11[0] = 0;
v11[1] = 0;
v11[2] = 0;
for ( i = 0; i < 8; ++i )
{
for ( j = 0; j < 3; ++j )
{
if ( i >= v16[j] )
{
v10 = v11[j];
if ( v10 < 8 )
{
if ( j )
{
if ( j == 1 )
{
crypt(i2, i3, v15[v10]);
}
else if ( j == 2 )
{
crypt(i3, i1, v15[v10]);
}
}
else
{
crypt(i1, i2, v15[v10]);
}
++v11[j];
}
}
}
}
if ( !strcmp(i1, "WgvDmssEvcY326bHo3nNro3vXvvfmgrz")
&& !strcmp(i2, "gX+Ri9PG=bt5=00B6hscPQOL")
&& !strcmp(i3, "T6bHgUPL2gXUd=xT=FNHtPzV") )
{
sub_7FF68C1A2470("Congratulations! You have found the flag!\n", v6, v7);
}
else
{
sub_7FF68C1A2470("Invalid flag!\n", v6, v7);
}
return 0;
}
else
{
sub_7FF68C1A2470("Invalid flag!\n", v3, v4);
return 0;
}
}

把输入拆成三部分(i1,i2,i3),然后根据 j 012决定谁做key谁做密文,看加密函数

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
void __fastcall crypt(char *a1, const char *a2, int a3)
{
size_t v3; // rax
signed int v4; // eax
size_t v5; // rax
signed int v6; // eax
signed int i; // [rsp+20h] [rbp-F8h]
signed int j; // [rsp+24h] [rbp-F4h]
signed int lena1; // [rsp+28h] [rbp-F0h]
int num6; // [rsp+2Ch] [rbp-ECh]
char v11; // [rsp+30h] [rbp-E8h]
int m; // [rsp+34h] [rbp-E4h]
int n; // [rsp+38h] [rbp-E0h]
signed int i1; // [rsp+3Ch] [rbp-DCh]
int k; // [rsp+40h] [rbp-D8h]
int ii; // [rsp+44h] [rbp-D4h]
int jj; // [rsp+48h] [rbp-D0h]
signed int v18; // [rsp+4Ch] [rbp-CCh]
int nn; // [rsp+50h] [rbp-C8h]
int kk; // [rsp+54h] [rbp-C4h]
int lena2; // [rsp+58h] [rbp-C0h]
int v22; // [rsp+5Ch] [rbp-BCh]
int mm; // [rsp+60h] [rbp-B8h]
char **Block; // [rsp+68h] [rbp-B0h]
int v25; // [rsp+7Ch] [rbp-9Ch]
int *a1_1; // [rsp+88h] [rbp-90h]
int *out2; // [rsp+90h] [rbp-88h]
int *out; // [rsp+98h] [rbp-80h]
char *Source; // [rsp+A0h] [rbp-78h]
char *v30; // [rsp+A8h] [rbp-70h]
char *v31; // [rsp+B0h] [rbp-68h]
int num[12]; // [rsp+B8h] [rbp-60h]
__int64 v33; // [rsp+E8h] [rbp-30h]
__int64 v34; // [rsp+F0h] [rbp-28h]

lena1 = strlen(a1);
lena2 = strlen(a2);
switch ( a3 )
{
case 1:
for ( i = 0; i < lena1; ++i )
{
v22 = a2[i % lena2];
if ( a1[i] < 65 || a1[i] > 90 )
{
if ( a1[i] < 97 || a1[i] > 122 )
{
if ( a1[i] >= 48 && a1[i] <= 57 )
a1[i] = (a1[i] + v22 - 48) % 10 + 48;
}
else
{
a1[i] = (a1[i] + v22 - 97) % 26 + 97;
}
}
else
{
a1[i] = (a1[i] + v22 - 65) % 26 + 65;
}
}
break;
case 2:
num[0] = 1;
num[1] = 3;
num[2] = 5;
num[3] = 7;
num[4] = 9;
num[5] = 11;
num[6] = 15;
num[7] = 17;
num[8] = 19;
num[9] = 21;
num[10] = 23;
num[11] = 25;
for ( j = 0; j < lena1; ++j )
{
if ( a1[j] < 65 || a1[j] > 90 )
{
if ( a1[j] >= 97 && a1[j] <= 122 )
a1[j] = (a2[j % lena2] + num[j % 12] * (a1[j] - 97)) % 26 + 97;
}
else
{
a1[j] = (a2[j % lena2] + num[j % 12] * (a1[j] - 65)) % 26 + 65;
}
}
break;
case 3:
num6 = *a2 % 10 + 2;
v33 = num6;
Block = malloc(saturated_mul(num6, 8ui64));
for ( k = 0; k < num6; ++k )
{
Block[k] = malloc(lena1 + 1);
memset(Block[k], 0, lena1 + 1);
}
for ( m = 0; num6 * m < lena1; ++m )
{
for ( n = 0; n < num6 && n + num6 * m < lena1; ++n )
Block[n][m] = a1[n + num6 * m];
}
v18 = 0;
for ( ii = 0; ii < num6; ++ii )
{
for ( jj = 0; jj < m; ++jj )
{
if ( Block[ii][jj] && v18 < lena1 )
a1[v18++] = Block[ii][jj];
}
}
a1[v18] = 0;
for ( kk = 0; kk < num6; ++kk )
free(Block[kk]);
free(Block);
break;
case 4:
v25 = *a2 % 10 + 2;
for ( mm = 0; mm < v25; ++mm )
{
v11 = a1[lena1 - 1];
for ( nn = lena1 - 1; nn > 0; --nn )
a1[nn] = a1[nn - 1];
*a1 = v11;
}
break;
case 5:
v34 = lena1;
a1_1 = malloc(saturated_mul(lena1, 4ui64));
for ( i1 = 0; i1 < lena1; ++i1 )
a1_1[i1] = (a2[i1 % lena2] + 57) ^ a1[i1];
Source = base64(a1_1, lena1);
strcpy(a1, Source);
free(a1_1);
free(Source);
break;
case 6:
v3 = saturated_mul(strlen(a1), 4ui64);
out2 = malloc(v3);
rc4(a1, a2, out2);
v4 = strlen(a1);
v30 = base64(out2, v4);
strcpy(a1, v30);
free(out2);
free(v30);
break;
case 7:
v5 = saturated_mul(strlen(a1), 4ui64);
out = malloc(v5);
rc4_0(a1, a2, out);
v6 = strlen(a1);
v31 = base64(out, v6);
strcpy(a1, v31);
free(out);
free(v31);
break;
}
}

可以看到根据前文的v15来决定这里是哪种加密,一共7种case,所以先模拟出每一种的j对应的case,然后写每一种的解密

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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include<time.h>
#include<stdint.h>
unsigned char* base64_encode(const char* str0)
{
unsigned char* str = (unsigned char*)str0; //转为unsigned char无符号,移位操作时可以防止错误
unsigned char base64_map[] = "stuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr";//数组形式,方便修改
long len; //base64处理后的字符串长度
long str_len; //源字符串长度
long flag; //用于标识模3后的余数
unsigned char* res; //返回的字符串
str_len = strlen((const char*)str);
switch (str_len % 3) //判断模3的余数
{
case 0:flag = 0; len = str_len / 3 * 4; break;
case 1:flag = 1; len = (str_len / 3 + 1) * 4; break;
case 2:flag = 2; len = (str_len / 3 + 1) * 4; break;
}
res = (unsigned char*)malloc(sizeof(unsigned char) * len + 1);
for (int i = 0, j = 0; j < str_len - flag; j += 3, i += 4)//先处理整除部分
{
//注意&运算和位移运算的优先级,是先位移后与或非
res[i] = base64_map[str[j] >> 2];
res[i + 1] = base64_map[(str[j] & 0x3) << 4 | str[j + 1] >> 4];
res[i + 2] = base64_map[(str[j + 1] & 0xf) << 2 | (str[j + 2] >> 6)];
res[i + 3] = base64_map[str[j + 2] & 0x3f];
}
//不满足被三整除时,要矫正
switch (flag)
{
case 0:break; //满足时直接退出
case 1:res[len - 4] = base64_map[str[str_len - 1] >> 2]; //只剩一个字符时,右移两位得到高六位
res[len - 3] = base64_map[(str[str_len - 1] & 0x3) << 4];//获得低二位再右移四位,自动补0
res[len - 2] = res[len - 1] = '='; break; //最后两个补=
case 2:
res[len - 4] = base64_map[str[str_len - 2] >> 2]; //剩两个字符时,右移两位得高六位
res[len - 3] = base64_map[(str[str_len - 2] & 0x3) << 4 | str[str_len - 1] >> 4]; //第一个字符低二位和第二个字符高四位
res[len - 2] = base64_map[(str[str_len - 1] & 0xf) << 2]; //第二个字符低四位,左移两位自动补0
res[len - 1] = '='; //最后一个补=
break;
}
res[len] = '\0'; //补上字符串结束标识
return res;
}
unsigned char findPos(const unsigned char* base64_map, unsigned char c)//查找下标所在位置
{
for (int i = 0; i < strlen((const char*)base64_map); i++)
{
if (base64_map[i] == c)
return i;
}
}
int base64_decode(char* code0)
{
unsigned char* code = (unsigned char*)code0;
unsigned char base64_map[] = "stuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr";
long len, str_len, flag = 0;
char* res;
len = strlen((char*)code);
if (code[len - 1] == '=')
{
if (code[len - 2] == '=')
{
flag = 1;
str_len = len / 4 * 3 - 2;
}

else
{
flag = 2;
str_len = len / 4 * 3 - 1;
}

}
else
str_len = len / 4 * 3;
res = (unsigned char*)malloc(sizeof(unsigned char) * str_len + 1);
for (int i = 0, j = 0; j < str_len - flag; j += 3, i += 4)
{
unsigned char a[4];
a[0] = findPos(base64_map, code[i]); //code[]每一个字符对应base64表中的位置,用位置值反推原始数据值
a[1] = findPos(base64_map, code[i + 1]);
a[2] = findPos(base64_map, code[i + 2]);
a[3] = findPos(base64_map, code[i + 3]);
res[j] = a[0] << 2 | a[1] >> 4; //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的后2位进行组合
res[j + 1] = a[1] << 4 | a[2] >> 2; //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应bas464表的十进制数的后4位进行组合
res[j + 2] = a[2] << 6 | a[3]; //取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合
}

switch (flag)
{
char a[1024];
case 0:break;
case 1:
{
a[0] = findPos(base64_map, code[len - 4]);
a[1] = findPos(base64_map, code[len - 3]);
res[str_len - 1] = a[0] << 2 | a[1] >> 4;
break;
}
case 2: {
a[0] = findPos(base64_map, code[len - 4]);
a[1] = findPos(base64_map, code[len - 3]);
a[2] = findPos(base64_map, code[len - 2]);
res[str_len - 2] = a[0] << 2 | a[1] >> 4;
res[str_len - 1] = a[1] << 4 | a[2] >> 2;
break;
}
}
res[str_len] = '\0';
memcpy(code0, res, str_len);
return str_len;
}
void __fastcall rc41(unsigned char* a1, const char* a2, unsigned int* a3, int size)
{
__int64 v3; // kr00_8
int i; // [rsp+20h] [rbp-438h]
int j; // [rsp+20h] [rbp-438h]
int v6; // [rsp+20h] [rbp-438h]
int v7; // [rsp+24h] [rbp-434h]
int v8; // [rsp+24h] [rbp-434h]
int k; // [rsp+28h] [rbp-430h]
int v10; // [rsp+30h] [rbp-428h]
int v11; // [rsp+34h] [rbp-424h]
int v12[258]; // [rsp+50h] [rbp-408h]
for (i = 0; i < size; i++)
{
a3[i] = a1[i];
}
v7 = 0;
for (i = 0; i < 256; ++i)
v12[i] = i;
for (j = 0; j < 256; ++j)
{
v3 = a2[j % strlen(a2)] + v12[j] + v7;
v7 = v3 % 256;
v10 = v12[j];
v12[j] = v12[v7];
v12[v7] = v10;
}
v8 = 0;
v6 = 0;
for (k = 0; k<size; ++k)
{
v6 = (v6 + 1) % 256;
v8 = (v12[v6] + v8) % 256;
v11 = v12[v6];
v12[v6] = v12[v8];
v12[v8] = v11;
a1[k] = v12[(v12[v6] + v12[v8]) % 256] ^ (a3[k] - 57 + 256) % 256;
}
}
void __fastcall rc42(char* a1, const char* a2, int* a3, int size)
{
__int64 v3; // kr00_8
int i; // [rsp+20h] [rbp-438h]
int j; // [rsp+20h] [rbp-438h]
int v6; // [rsp+20h] [rbp-438h]
int v7; // [rsp+24h] [rbp-434h]
int v8; // [rsp+24h] [rbp-434h]
int k; // [rsp+28h] [rbp-430h]
int v10; // [rsp+30h] [rbp-428h]
int v11; // [rsp+34h] [rbp-424h]
int v12[258]; // [rsp+50h] [rbp-408h]
for (i = 0; i < size; i++)
{
a3[i] = a1[i];
}
v7 = 0;
for (i = 0; i < 256; ++i)
v12[i] = i;
for (j = 0; j < 256; ++j)
{
v3 = a2[j % strlen(a2)] + v12[j] + v7;
v7 = v3 % 256;
v10 = v12[j];
v12[j] = v12[v7];
v12[v7] = v10;
}
v8 = 0;
v6 = 0;
for (k = 0; k < size; ++k)
{
v6 = (v6 + 1) % 256;
v8 = (v12[v6] + v8) % 256;
v11 = v12[v6];
v12[v6] = v12[v8];
v12[v8] = v11;
a1[k] = v12[(v12[v8] + v12[v6]) % 256] ^ a3[k] ^ 0x39;
}
}
void decrypt_case1(char* a1, const char* a2) {
int lena1 = strlen(a1);
int lena2 = strlen(a2);
for (int i = 0; i < lena1; ++i) {
int key = a2[i % lena2];
if (a1[i] >= 'A' && a1[i] <= 'Z') {
a1[i] = (a1[i] - (key % 26) - 'A' + 26) % 26 + 'A';
}
else if (a1[i] >= 'a' && a1[i] <= 'z') {
a1[i] = (a1[i] - (key % 26) - 'a' + 26) % 26 + 'a';
}
else if (a1[i] >= '0' && a1[i] <= '9') {
a1[i] = (a1[i] - (key % 10) - '0' + 10) % 10 + '0';
}
}
}
void decrypt_case2(char* a1, const char* a2) {
int num_inv[] = { 1,9,21,15,3,19,7,23,11,5,17,25 };
int lena1 = strlen(a1);
int lena2 = strlen(a2);

for (int j = 0; j < lena1; ++j) {
char base = 0;
if (a1[j] >= 'A' && a1[j] <= 'Z') {
base = 'A';
}
else if (a1[j] >= 'a' && a1[j] <= 'z') {
base = 'a';
}
else continue;

int inv = num_inv[j % 12];
int shift = a2[j % lena2];
int val = (a1[j] - base - shift + 26) % 26;
a1[j] = (val * inv) % 26 + base;
}
}
void decrypt_case3(char* a1, const char* a2) {
int lena1 = strlen(a1);
int v10 = a2[0] % 10 + 2; // 必须与加密时相同的行数
int cols = (lena1 + v10 - 1) / v10; // 最大列数

// 分配二维矩阵(考虑不完整行)
char** Block = malloc(v10 * sizeof(char*));
for (int i = 0; i < v10; ++i) {
Block[i] = malloc(cols + 1); // 每行分配最大可能长度+1
memset(Block[i], 0, cols + 1);
}

// 动态计算每行的实际列数
int* row_lengths = malloc(v10 * sizeof(int));
for (int i = 0; i < v10; ++i) {
row_lengths[i] = lena1 / v10; // 基本列数
if (i < lena1 % v10) row_lengths[i]++; // 处理余数分配
}

// 按行填充数据(考虑不等长行)
int pos = 0;
for (int row = 0; row < v10; ++row) {
for (int col = 0; col < row_lengths[row]; ++col) {
if (pos < lena1) {
Block[row][col] = a1[pos++];
}
}
}

// 按列读取恢复原始数据(处理不规则形状)
pos = 0;
for (int col = 0; col < cols; ++col) {
for (int row = 0; row < v10; ++row) {
// 只读取有效列范围内的数据
if (col < row_lengths[row] && pos < lena1) {
a1[pos++] = Block[row][col];
}
}
}
a1[pos] = '\0'; // 终止字符串

// 清理内存
free(row_lengths);
for (int i = 0; i < v10; ++i) free(Block[i]);
free(Block);
}

void decrypt_case4(char* str, const char* key) {
// 手动计算有效字符串长度(包含空格)
int len = 0;
while (str[len] != '\0') len++;
if (len == 0) return;
// 计算等效逆向移位次数
int shift = (key[0] % 10 + 2) % len; // 加密时的实际有效移位
int decrypt_shift = (len - shift) % len;

// 执行逆向循环右移
for (int i = 0; i < decrypt_shift; ++i) {
// 保存最后一个有效字符(包括空格)
char last = str[len - 1];

// 整体右移一位
for (int j = len - 1; j > 0; --j) {
str[j] = str[j - 1];
}

// 恢复首字符
str[0] = last;
}
}
void decrypt_case5(char* a1, const char* a2) {
int lena2 = strlen(a2);
int lena1 = base64_decode(a1);
for (int i = lena1; i < lena1 + 10; i++)
{
a1[i] = 0;
}
for (int i = 0; i < lena1; ++i) {
a1[i] ^= (a2[i % lena2] + 57);
}
//printf("%s", a1);
}
void decrypt_case6(char* a1,const char* a2) {
int lena1 = base64_decode(a1);
unsigned int* a3 = malloc(100);
memset(a3, 0, 100);
for (int i = lena1; i < lena1 + 10; i++)
{
a1[i] = 0;
}
rc41(a1, a2, a3, lena1);
}
void decrypt_case7(char *a1,const char* a2) {
int lena1 = base64_decode(a1);
int* a3 = malloc(100);
for (int i = lena1; i < lena1 + 10; i++)
{
a1[i] = 0;
}
rc42(a1, a2, a3, lena1);

}
void crypt(char *a1,const char* a2,int a3) {
switch (a3) {
case 1:
decrypt_case1(a1, a2);
break;
case 2:
decrypt_case2(a1, a2);
break;
case 3:
decrypt_case3(a1, a2);
break;
case 4:
decrypt_case4(a1, a2);
break;
case 5:
decrypt_case5(a1, a2);
break;
case 6:
decrypt_case6(a1, a2);
break;
case 7:
decrypt_case7(a1, a2);
break;
}
}
int main() {
char v15[8];
char v16[3];
char v11[3];
int i, j, v10;
char i1[100] = "WgvDmssEvcY326bHo3nNro3vXvvfmgrz";
char i2[100] = "gX+Ri9PG=bt5=00B6hscPQOL";
char i3[100] = "T6bHgUPL2gXUd=xT=FNHtPzV";
//aaaaaaaaaaaabbbbbbbbbbbbcccccccccccc
v15[0] = 1;
v15[1] = 5;
v15[2] = 6;
v15[3] = 3;
v15[4] = 4;
v15[5] = 1;
v15[6] = 4;
v15[7] = 5;
v16[0] = 0;
v16[1] = 1;
v16[2] = 2;
v11[0] = 0;
v11[1] = 0;
v11[2] = 0;
char ca1[] = { 1,4,5,4,1,4,3,4,1,6,3,4,5,6,3,1,5,6,1,5,1, };
char jj[] = { 2,1,0,2,1,0,2,1,0,2,1,0,2,1,0,2,1,0,1,0,0, };
for (int i = 0; i < 21; i++)
{
switch (jj[i]) {
case 0:
crypt(i1, i2, ca1[i]);
printf("i1 i2\n%d-%d:", jj[i], ca1[i]);
printf("%s", i1);
printf("\n");
break;
case 1:
crypt(i2, i3, ca1[i]);
printf("i2 i3\n%d-%d:", jj[i], ca1[i]);
printf("%s", i2);
printf("\n");
break;
case 2:
crypt(i3, i1, ca1[i]);
printf("i3 i1\n%d-%d:", jj[i], ca1[i]);
printf("%s", i3);
printf("\n");
break;
}
printf("i1:%s\ni2:%s\ni3:%s\n\n", i1, i2, i3);
}
//for (i = 0; i < 8; ++i)
//{
// for (j = 0; j < 3; ++j)
// {
// if (i >= v16[j])
// {
// v10 = v11[j];
// if (v10 < 8)
// {
// if (j)
// {
// if (j == 1)
// {
// //crypt(i2, i3, ca1);
// printf("%d,", j);
// }
// else if (j == 2)
// {
// //crypt(i3, i1, ca1);
// printf("%d,", j);
// }
// }
// else
// {
// //crypt(i1, i2, ca1);
// printf("%d,", j);
// }
// ++v11[j];
// }
// }
// }
//}
for (int i = 0; i < 12; i++)
{
printf("%c", i1[i]);
}
for (int i = 0; i < 12; i++)
{
printf("%c", i2[i]);
}
for (int i = 0; i < 12; i++)
{
printf("%c", i3[i]);
}
//char ca[] = { 0,0,1,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2, };
//for (int i = 0; i < 21; i++)
//{
// printf("%d,",ca[21 -1- i]);
//}
//for (int i = strlen(ca)-1; i >= 0; i--)
//{
// switch (ca[i]) {
// case 1:
// decrypt_case1();
// }
//}
return 0;
//NSSCTF{P4ch3Lbel's_C@n0n_1n_D_mAjOr}
}

解决了