L3HCTF 2025 WriteUp (Reverse方向)

13k 词

一刻也没有为耽误的生日而感到悲哀,立刻赶到的是L3HCTF 2025逆向WP

仅给出我个人解出的题目的WP

TemporalParadox

用字符串搜索程序主函数,发现有一个花指令,nop掉之后反编译:

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
__int64 __fastcall sub_7FF66C871D05(__time64_t *num, __int64 *a2, double a3, double a4, double a5, double a6)
{
int v6; // edx
int v7; // r8d
int v8; // r9d
__int64 v9; // rdx
int v10; // r8d
int v11; // r9d
__int64 v12; // rdx
int v13; // eax
_DWORD *v14; // rax
int v15; // edx
int v16; // r8d
int v17; // r9d
__int64 p__ZSt4cout; // rax
__int64 v19; // rax
__int64 v20; // rax
__int64 v21; // rdx
__int64 v22; // rdx
__int64 v23; // rax
__int64 v24; // rdx
int v25; // eax
_DWORD *v26; // rax
int v27; // edx
int v28; // r8d
int v29; // r9d
int v30; // r8d
int v31; // r9d
__int64 v32; // rax
__int64 v33; // rdx
__int64 v34; // rax
__int64 v35; // rdx
__int64 v37; // [rsp+0h] [rbp-168h]
int v38; // [rsp+8h] [rbp-160h]
_BYTE v39[32]; // [rsp+20h] [rbp-148h] BYREF
_BYTE v40[32]; // [rsp+40h] [rbp-128h] BYREF
_BYTE v41[32]; // [rsp+60h] [rbp-108h] BYREF
_QWORD v42[4]; // [rsp+80h] [rbp-E8h] BYREF
_DWORD v43[37]; // [rsp+A0h] [rbp-C8h] BYREF
char v44; // [rsp+136h] [rbp-32h] BYREF
_BYTE v45[9]; // [rsp+137h] [rbp-31h] BYREF
char *v46; // [rsp+140h] [rbp-28h]
SECURITY_INTEGER *TimeStamp; // [rsp+148h] [rbp-20h]

init((__int64)num, a2);
genkey((int)num, (int)a2, v6, v43, v7, v8);
TimeStamp = (SECURITY_INTEGER *)time64_w(num);
if ( TimeStamp > (SECURITY_INTEGER *)1751990400 && TimeStamp < (SECURITY_INTEGER *)1752052051 )
{
sub_7FF66C871963(num, (__int64)a2, v9, (__int64)v39, v10, v11, a3, a4, a5, a6);
v46 = &v44;
v13 = std::string::c_str(num, a2, v12, v39);
v14 = sub_7FF66C87A040((const char *)num, (int)a2, v13, v43);
sub_7FF66C87A820((const char *)num, (__int64)a2, (__int64)v14, (__int64)v40, (__int64)&v44);
sub_7FF66C87A6E0((_DWORD)num, (_DWORD)a2, v15, (unsigned int)&v44, v16, v17);
p__ZSt4cout = std::operator<<<std::char_traits<char>>(num, a2, "query: ", &std::cout);
v19 = std::operator<<<char>(num, a2, v39, p__ZSt4cout);
std::ostream::operator<<(num, a2, &std::endl<char,std::char_traits<char>>, v19);
v20 = std::operator<<<char>(num, a2, v40, &std::cout);
std::ostream::operator<<(num, a2, &std::endl<char,std::char_traits<char>>, v20);
std::string::~string(num, a2, v21, v40);
std::string::~string(num, a2, v22, v39);
}
std::string::basic_string(num, a2, v9, v42);
v23 = std::operator<<<std::char_traits<char>>(num, a2, "Please input the right query string I used:", &std::cout);
std::ostream::operator<<(num, a2, &std::endl<char,std::char_traits<char>>, v23);
std::operator>><char>(num, a2, v42, &std::cin);
*(_QWORD *)&v45[1] = v45;
v25 = std::string::c_str(num, a2, v24, v42);
v26 = sub_7FF66C87A040((const char *)num, (int)a2, v25, v43);
sub_7FF66C87A820((const char *)num, (__int64)a2, (__int64)v26, (__int64)v41, (__int64)v45);
sub_7FF66C87A6E0((_DWORD)num, (_DWORD)a2, v27, (unsigned int)v45, v28, v29);
if ( (unsigned __int8)cmp(
(_DWORD)num,
(_DWORD)a2,
(unsigned int)"8a2fc1e9e2830c37f8a7f51572a640aa",
(unsigned int)v41,
v30,
v31,
v37,
v38) )
{
v32 = std::operator<<<std::char_traits<char>>(num, a2, "Congratulations!", &std::cout);
std::ostream::operator<<(num, a2, &std::endl<char,std::char_traits<char>>, v32);
}
else
{
v34 = std::operator<<<std::char_traits<char>>(num, a2, "Wrong!", &std::cout);
std::ostream::operator<<(num, a2, &std::endl<char,std::char_traits<char>>, v34);
}
std::string::~string(num, a2, v33, v41);
std::string::~string(num, a2, v35, v42);
return 0;
}

时间戳位于1751990400 ~ 1752052051之间时有一个额外的打印逻辑,查看其核心函数:

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
__int64 __fastcall sub_7FF66C871963(
__time64_t *Time,
__int64 a2,
int a3,
__int64 a4,
int a5,
int a6,
double a7,
double a8,
double a9,
double a10)
{
__int64 v10; // rdx
double v11; // xmm6_8
double v12; // xmm2_8
__int64 v13; // rdx
__int64 v14; // rcx
__int64 v15; // r8
__int64 v16; // r9
double v17; // xmm4_8
double v18; // xmm5_8
double v19; // xmm6_8
double v20; // xmm7_8
double v21; // xmm0_8
__int64 v22; // rdx
__int64 v23; // rcx
__int64 v24; // r8
__int64 v25; // r9
double v26; // xmm4_8
double v27; // xmm5_8
__int64 p__ZSt4cout; // rax
__int64 v29; // rax
__int64 v30; // rax
__int64 v31; // rax
__int64 v32; // rax
__int64 v33; // rax
__int64 v34; // rbx
int v35; // r8d
int v36; // r9d
unsigned __int16 v37; // ax
__int64 v38; // rax
__int64 v39; // rax
__int64 v40; // rax
__int64 v41; // rax
__int64 v42; // rax
__int64 v43; // rax
__int64 v44; // rax
__int64 v45; // rdx
__int64 v46; // rdx
__int64 v48; // [rsp+0h] [rbp-80h]
__int64 v49; // [rsp+0h] [rbp-80h]
_QWORD v50[2]; // [rsp+20h] [rbp-60h] BYREF
__int64 v51; // [rsp+30h] [rbp-50h] BYREF
_QWORD v52[5]; // [rsp+1B0h] [rbp+130h] BYREF
unsigned int v53; // [rsp+1DCh] [rbp+15Ch]
__time64_t v54; // [rsp+1E0h] [rbp+160h]
int i; // [rsp+1ECh] [rbp+16Ch]
unsigned int v56; // [rsp+1F0h] [rbp+170h]
unsigned int v57; // [rsp+1F4h] [rbp+174h]
unsigned int v58; // [rsp+1F8h] [rbp+178h]
unsigned int v59; // [rsp+1FCh] [rbp+17Ch]

sub_7FF66C871518((_DWORD)Time, a2, a3, (unsigned int)v52, a5, a6);
v54 = time64_w(Time);
srandom((unsigned int)Time);
v59 = 0;
v58 = 0;
v57 = 0;
v56 = 0;
for ( i = 0; i < (int)random(); ++i )
{
v59 = random();
v58 = random();
v57 = random();
v56 = random();
}
v53 = random();
std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>::basic_stringstream(Time, a2, v10, v50);
v11 = (double)dword_7FF66C87B0E0;
v12 = (double)(int)(v59 | v57);
sub_7FF66C8733A0(v12, 2.0, v12, a10, v17, v18, (double)dword_7FF66C87B0E0, (__int64)Time, a2, v13, v14, v15, v16, v48);
v19 = v11 * v12;
v20 = (double)dword_7FF66C87B0E4;
v21 = (double)(int)(v58 | v56);
sub_7FF66C8733A0(v21, 2.0, v12, v21, v26, v27, v19, (__int64)Time, a2, v22, v23, v24, v25, v49);
p__ZSt4cout = std::operator<<<std::char_traits<char>>(Time, a2, "salt=", &v51);
v29 = std::operator<<<char>(Time, a2, v52, p__ZSt4cout);
v30 = std::operator<<<std::char_traits<char>>(Time, a2, "&t=", v29);
v31 = std::ostream::operator<<(Time, a2, v54, v30);
v32 = std::operator<<<std::char_traits<char>>(Time, a2, "&r=", v31);
v33 = std::ostream::operator<<(Time, a2, v53, v32);
if ( v19 == v21 * v20 )
{
v34 = std::operator<<<std::char_traits<char>>(Time, a2, "&cipher=", v33);
v37 = sub_7FF66C87184D((__int64)Time, a2, v54, v53, v35, v36);
std::ostream::operator<<(Time, a2, v37, v34);
}
else
{
v38 = std::operator<<<std::char_traits<char>>(Time, a2, "&a=", v33);
v39 = std::ostream::operator<<(Time, a2, v59, v38);
v40 = std::operator<<<std::char_traits<char>>(Time, a2, "&b=", v39);
v41 = std::ostream::operator<<(Time, a2, v58, v40);
v42 = std::operator<<<std::char_traits<char>>(Time, a2, "&x=", v41);
v43 = std::ostream::operator<<(Time, a2, v57, v42);
v44 = std::operator<<<std::char_traits<char>>(Time, a2, "&y=", v43);
std::ostream::operator<<(Time, a2, v56, v44);
}
std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>::str(Time, a2, v50, a4);
std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>::~basic_stringstream(Time, a2, v45, v50);
std::string::~string(Time, a2, v46, v52);
return a4;
}

这里的random是自定义的:

1
2
3
4
5
6
7
8
__int64 random()
{
unsigned int v1; // [rsp+Ch] [rbp-4h]

v1 = (((seed << 13) ^ (unsigned int)seed) >> 17) ^ (seed << 13) ^ seed;
seed = (32 * v1) ^ v1;
return seed & 0x7FFFFFFF;
}

用时间戳做随机数种子生成了5个random值拼合成一个字符串:salt=tlkyeueq7fej8vtzitt26yl24kswrgm5&t=时间戳&r=随机值&a=随机值&b=随机值&x=随机值&y=随机值

后面有个函数是md5,是直接对这个字符串进行md5,没有任何魔改

同构随机数生成方式后爆破时间戳即可:

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
#include <stdio.h> 
#include <string.h>
#include <openssl/md5.h>

unsigned int timemin = 1751990400;
unsigned int timemax = 1752052051;
unsigned int seed;

int random() {
unsigned int num1 = (seed << 13) ^ seed;
unsigned int num2 = (num1 >> 17) ^ num1;
seed = (num2 << 5) ^ num2;
return seed & 0x7FFFFFFF;
}

void md5hexToString(unsigned char *md, char *result) {
for (size_t i = 0; i < 16; i++) {
sprintf(result + i * 2, "%02x", md[i]);
}
printf("\n");
return;
}

int main() {
for (int time = timemin; time < timemax; time++){
seed = time;
int v59 = 0;
int v58 = 0;
int v57 = 0;
int v56 = 0;
for (int i = 0; i < (int)random(); ++i )
{
v59 = random();
v58 = random();
v57 = random();
v56 = random();
}
int v53 = random();

char query[512];
snprintf(query, sizeof(query), "salt=tlkyeueq7fej8vtzitt26yl24kswrgm5&t=%u&r=%d&a=%d&b=%d&x=%d&y=%d", time, v53, v59, v58, v57, v56);
printf("Query: %s\n", query);
unsigned char digest[16];
char result[33] = {0};
MD5((unsigned char *)query, strlen(query), digest);
md5hexToString(digest, result);
printf("%s", result);
if (!strcmp(result, "8a2fc1e9e2830c37f8a7f51572a640aa")){
return 0;
}
}
}

爆破结果:salt=tlkyeueq7fej8vtzitt26yl24kswrgm5&t=1751994277&r=101356418&a=1388848462&b=441975230&x=1469980073&y=290308156

L3HCTF{5cbbe37231ca99bd009f7eb67f49a98caae2bb0f}

感觉有点意义不明,不知道出题人想考什么

ez_android

java层看不出来东西,直接进so,找到字符串Congratulations!,定位到一个函数:

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
__int64 __usercall ez_android_lib::greet@<X0>(void *a1@<X0>, size_t n27@<X1>, __int64 *a3@<X8>)
{
__int64 v6; // x23
_QWORD *v7; // x0
_QWORD *v8; // x20
unsigned __int64 n0xE; // x8
unsigned __int64 n0xE_1; // x15
unsigned __int8 v11; // w13
__int64 n16; // x22
__int64 v16; // x0
__int64 n16_1; // x8
__int64 result; // x0
_BYTE v19[11]; // [xsp+10h] [xbp-50h] BYREF

qmemcpy(&v19[8], "O2*", 3);
*(_QWORD *)v19 = 0xFC020A4C0E2C7290LL;
if ( (n27 & 0x8000000000000000LL) != 0 )
{
v6 = 0;
goto LABEL_30;
}
if ( !n27 )
{
v8 = (_QWORD *)(&dword_0 + 1);
memcpy((char *)&dword_0 + 1, a1, 0);
goto LABEL_22;
}
v6 = 1;
v7 = (_QWORD *)_rust_alloc(n27, 1);
if ( !v7 )
LABEL_30:
alloc::raw_vec::handle_error(v6, n27, &anon_87fc6f247fa1f8b0fae38f081a8df7a4_43_llvm_1227004194129537882);// "C:\\Users\\yll20\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\\lib/rustlib/src/rust\\library/alloc/src/slice.rs"
v8 = v7;
memcpy(v7, a1, n27);
if ( n27 == 27 )
{
for ( n0xE = 0; n0xE != 27; ++n0xE )
{
n0xE_1 = n0xE - 14;
if ( n0xE < 0xE )
n0xE_1 = n0xE;
v11 = aDghpc2lzywtleq[(unsigned __int8)(((2 * n0xE) | 1) - 14 * ((147 * ((unsigned __int8)(2 * n0xE) | 1u)) >> 11))]
+ (*((_BYTE *)v8 + n0xE) ^ aDghpc2lzywtleq[n0xE_1]);
*((_BYTE *)v8 + n0xE) = aDghpc2lzywtleq[(unsigned __int8)(n0xE + 4) % 0xEu]
^ ((v11 << (aDghpc2lzywtleq[(unsigned __int8)(n0xE + 3) % 0xEu] & 7))
| (v11 >> (-aDghpc2lzywtleq[(unsigned __int8)(n0xE + 3) % 0xEu] & 7)));
}
if ( *v8 == 0xA409663A025150CLL
&& v8[1] == 0x1FE106294065165CLL
&& v8[2] == 0xFC020A4C0E2C7290LL
&& *(_QWORD *)((char *)v8 + 19) == *(_QWORD *)&v19[3] )
{
n16 = 16;
v16 = _rust_alloc(16, 1);
if ( v16 )
{
n16_1 = 16;
*(_OWORD *)v16 = xmmword_BE580;
goto LABEL_27;
}
}
else
{
n16 = 12;
v16 = _rust_alloc(12, 1);
if ( v16 )
{
*(_DWORD *)(v16 + 8) = 1919252339;
n16_1 = 12;
*(_QWORD *)v16 = *(_QWORD *)aWrongAnswer;
LABEL_27:
*a3 = n16_1;
a3[1] = v16;
a3[2] = n16_1;
return _rust_dealloc(v8, n27, 1);
}
}
LABEL_31:
alloc::raw_vec::handle_error(1, n16, &anon_87fc6f247fa1f8b0fae38f081a8df7a4_43_llvm_1227004194129537882);// "C:\\Users\\yll20\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\\lib/rustlib/src/rust\\library/alloc/src/slice.rs"
}
LABEL_22:
n16 = 12;
result = _rust_alloc(12, 1);
if ( !result )
goto LABEL_31;
*(_DWORD *)(result + 8) = 1919252339;
*(_QWORD *)result = *(_QWORD *)aWrongAnswer;
*a3 = 12;
a3[1] = result;
a3[2] = 12;
if ( n27 )
return _rust_dealloc(v8, n27, 1);
return result;
}

同构:

1
2
3
4
5
6
7
8
inp = bytearray(27)
key = b"dGhpc2lzYWtleQ"
target = bytearray.fromhex("0c1525a06396400a5c1665402906e11f90722c0e4c0a02fc4f322a")
for i in range(27):
num = i if i < 0xE else num = i - 0xE
tmp = 2 * i | 1
v11 = key[tmp - 14 * 147 * tmp >> 11)] + inp[i] ^ key[num]
inp[i] = key[(i + 4) % 0xE] ^ ((v11 << (key[(i + 3) % 0xE] & 7)) | (v11 >> (-key[(i + 3) % 0xEu] & 7)))

解密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
inp = bytearray(27)
key = b"dGhpc2lzYWtleQ"
target = bytearray.fromhex("0c1525a06396400a5c1665402906e11f90722c0e4c0a02fc4f322a")
res = bytearray()

for i in range(27):
for j in range(256):
num = i - 14 if i >= 14 else i
temp = (2 * i) | 1
v11 = (key[temp - 14 * (147 * temp >> 11)] + (j ^ key[num])) & 0xFF
kidx = key[(i + 3) % 0xE] & 7
out = (key[(i + 4) % 0xE] ^ ((v11 << kidx) | (v11 >> (8 - kidx)))) & 0xFF
if out == target[i]:
res.append(j)
print(res)

L3HCTF{ez_rust_reverse_lol}

同样不知道出题人想考什么

终焉之门

windows窗口程序,其中含有大量GLSL着色器函数:

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
int __fastcall main(int **argc, const char **argv, const char **envp)
{
int n99; // ebx
__m128i v4; // xmm6
unsigned int arg; // eax
unsigned int v6; // r13d
unsigned int v7; // eax
int v8; // eax
__int64 n99_2; // rdi
bool v10; // dl
bool v11; // al
double v12; // xmm0_8
unsigned int v13; // eax
char *inside; // r15
unsigned int hexidx; // ebx
int offins1; // eax
unsigned int lenhex; // r9d
int LOQUADBIT; // edx
int ins1; // eax
int ins2; // ecx
int HIQUADBIT; // eax
unsigned int v23; // [rsp+38h] [rbp-100h]
unsigned int v24; // [rsp+3Ch] [rbp-FCh]
unsigned int v25; // [rsp+40h] [rbp-F8h]
unsigned int v26; // [rsp+44h] [rbp-F4h]
unsigned int v27; // [rsp+48h] [rbp-F0h]
int n99_1; // [rsp+4Ch] [rbp-ECh]
__m128i v29; // [rsp+50h] [rbp-E8h] BYREF
int hextobyte; // [rsp+6Ch] [rbp-CCh] BYREF
_QWORD input[11]; // [rsp+70h] [rbp-C8h] BYREF
_QWORD v32[3]; // [rsp+C8h] [rbp-70h]

n99 = 0;
sub_7FF77676E370(argc, argv, envp);
sub_7FF776703480(8256);
create_window(1280, 800, "Password Checker");
sub_7FF776701100(&v29, 0, GLSL_code1);
v4 = _mm_loadu_si128(&v29);
arg = sub_7FF7766EE700((__int64)GLSL_code2, 0x91B9u);
v23 = sub_7FF7766EEEE0(arg);
v24 = sub_7FF7766EEFF0(0x2A0u, (__int64)Opcodes, 0x88EAu);
v6 = sub_7FF7766EEFF0(0x80u, (__int64)CoConsts, 0x88EAu);
v25 = sub_7FF7766EEFF0(0x40u, (__int64)Cipher, 0x88EAu);
v26 = sub_7FF7766EEFF0(0x400u, (__int64)Stack, 0x88EAu);
v7 = sub_7FF7766EEFF0(4u, (__int64)&tag, 0x88EAu);
v32[0] = 0;
v27 = v7;
memset(input, 0, sizeof(input));
*(_QWORD *)((char *)v32 + 5) = 0;
sub_7FF7767031A0(60);
while ( !(unsigned __int8)sub_7FF7766FCAC0() )
{
v8 = sub_7FF776705A40();
if ( v8 > 0 && n99 <= 99 )
{
n99_2 = n99 + 1;
do
{
*((_BYTE *)&hextobyte + n99_2 + 3) = v8;
n99 = n99_2;
v8 = sub_7FF776705A40();
v10 = (int)n99_2++ <= 99;
}
while ( v10 && v8 > 0 );
}
v11 = sub_7FF7767058E0(259);
if ( n99 > 0 && v11 )
*((_BYTE *)input + --n99) = 0;
if ( sub_7FF7767058E0(257)
&& strlen((const char *)input) == 40
&& !strncmp((const char *)input, "L3HCTF{", 7u)
&& HIBYTE(input[4]) == '}' )
{
n99_1 = n99;
inside = (char *)input + 7;
hexidx = 0;
do
{
ins1 = *inside;
ins2 = inside[1];
if ( ins1 > '`' )
offins1 = ins1 - 'W';
else
offins1 = ins1 - '0';
HIQUADBIT = 16 * offins1;
lenhex = hexidx;
LOQUADBIT = ins2 - '0';
if ( ins2 >= 'a' )
LOQUADBIT = ins2 - 'W';
inside += 2;
hexidx += 4;
hextobyte = LOQUADBIT + HIQUADBIT;
sub_7FF7766EF0B0(v6, (__int64)&hextobyte, 4, lenhex);
}
while ( (char *)&input[4] + 7 != inside );
n99 = n99_1;
sub_7FF7766EC100(v23);
sub_7FF7766EF180(v24, 0);
sub_7FF7766EF180(v6, 2);
sub_7FF7766EF180(v25, 3);
sub_7FF7766EF180(v26, 4);
sub_7FF7766EF180(v27, 5);
sub_7FF7766EEFE0(1, 1, 1);
sub_7FF7766EF140(v27, &tag, 4, 0);
sub_7FF7766EC110();
}
sub_7FF7766FFC90();
v29 = v4;
sub_7FF776700650(&v29);
v12 = sub_7FF7766FE170();
v29 = v4;
*(float *)&v12 = v12;
hextobyte = LODWORD(v12);
v13 = sub_7FF776701440(&v29, "time");
v29 = v4;
sub_7FF776701460(&v29, v13, &hextobyte, 0);
sub_7FF77671B9D0(0, 0, 1280, 800, -1);
sub_7FF776700690();
string_display((unsigned int)input, 100, 200, 40, -16777216);
if ( (_DWORD)tag == 1 )
string_display((unsigned int)"success", 100, 300, 40, -13863680);
else
string_display((unsigned int)"wrong password", 100, 300, 40, -13162010);
string_display((unsigned int)"Type password and press [Enter] to check!", 100, 100, 20, -8224126);
string_display((unsigned int)"Press [Backspace] to delete characters.", 100, 130, 20, -8224126);
screen_display(v12);
}
quit();
return 0;
}

解密得到的两份GLSL着色器代码分别为:

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
#version 330

#define S(a,b,t) smoothstep(a,b,t)

uniform float time;

out vec4 fragColor;

mat2 Rot(float a) {
float s = sin(a);
float c = cos(a);
return mat2(c, -s, s, c);
}

vec2 hash(vec2 p) {
p = vec2(dot(p, vec2(2127.1, 81.17)), dot(p, vec2(1269.5, 283.37)));
return fract(sin(p) * 43758.5453);
}

float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);

return mix(
mix(dot(-1.0 + 2.0 * hash(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)),
dot(-1.0 + 2.0 * hash(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x),
mix(dot(-1.0 + 2.0 * hash(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)),
dot(-1.0 + 2.0 * hash(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x),
u.y
) * 0.5 + 0.5;
}

void main() {
vec2 uSize = vec2(1280.0, 800.0);
vec2 uv = gl_FragCoord.xy / uSize;

float ratio = uSize.x / uSize.y;
vec2 tuv = uv - 0.5;

float degree = noise(vec2(time * 0.1, tuv.x * tuv.y));
tuv.y *= 1.0 / ratio;
tuv *= Rot(radians((degree - 0.5) * 720.0 + 180.0));
tuv.y *= ratio;

float frequency = 3.5;
float amplitude = 10.0;
float speed = time * 1.5;

tuv.x += sin(tuv.y * frequency + speed) / amplitude;
tuv.y += sin(tuv.x * frequency * 1.5 + speed) / (amplitude * 0.5);

vec3 color1 = vec3(0.8, 0.4, 0.9);
vec3 color2 = vec3(0.4, 0.7, 1.0);
vec3 color3 = vec3(1.0, 0.6, 0.4);
vec3 color4 = vec3(0.6, 1.0, 0.6);

vec3 layer1 = mix(color1, color2, S(-0.3, 0.2, (tuv * Rot(radians(-5.0))).x));
vec3 layer2 = mix(color3, color4, S(-0.3, 0.2, (tuv * Rot(radians(-5.0))).x));
vec3 finalColor = mix(layer1, layer2, S(0.5, -0.3, tuv.y));

fragColor = vec4(finalColor, 1.0);
}

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
#version 430 core

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(std430, binding = 0) buffer OpCodes { int opcodes[]; };
layout(std430, binding = 2) buffer CoConsts { int co_consts[]; };
layout(std430, binding = 3) buffer Cipher { int cipher[16]; };
layout(std430, binding = 4) buffer Stack { int stack_data[256]; };
layout(std430, binding = 5) buffer Out { int verdict; };

const int MaxInstructionCount = 1000;

void main()
{
if (gl_GlobalInvocationID.x > 0) return;

uint ip = 0u;
int sp = 0;
verdict = -233;

while (ip < uint(MaxInstructionCount))
{
int opcode = opcodes[int(ip)];
int arg = opcodes[int(ip)+1];

switch (opcode)
{
case 2:
stack_data[sp++] = co_consts[arg];
break;
case 7:
{
int b = stack_data[--sp];
int a = stack_data[--sp];
stack_data[sp++] = a + b;
break;
}
case 8:
{
int a = stack_data[--sp];
int b = stack_data[--sp];
stack_data[sp++] = a - b;
break;
}
case 14:
{
int b = stack_data[--sp];
int a = stack_data[--sp];
stack_data[sp++] = a ^ b;
break;
}

case 15:
{
int b = stack_data[--sp];
int a = stack_data[--sp];
stack_data[sp++] = int(a == b);
break;
}

case 16:
{
bool ok = true;
for (int i = 0; i < 16; i++)
{
if (stack_data[i] != (cipher[i] - 20))
{
ok = false;
break;
}
}
verdict = ok ? 1 : -1;
return;
}

case 18:
{
int c = stack_data[--sp];
if (c == 0) ip = uint(arg);
break;
}

default:
verdict = 500;
return;
}

ip+=2;
}
verdict = 501;
}

输入值为40字节的L3HCTF{开头}结尾的flag,中间的32字节会被按十六进制识别并转换为16字节的明文,提取数据后编写同构trace脚本:

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
opc = [0x02, 0x00, 0x02, 0x01, 0x02, 0x00, 0x0E, 0x00, 0x02, 0x10, 0x08, 0x00, 0x02, 0x02, 0x02, 0x01, 0x0E, 0x00, 0x02, 0x11, 0x08, 0x00, 0x02, 0x03, 0x02, 0x02, 0x0E, 0x00, 0x02, 0x12, 0x07, 0x00, 
0x02, 0x04, 0x02, 0x03, 0x0E, 0x00, 0x02, 0x13, 0x07, 0x00, 0x02, 0x05, 0x02, 0x04, 0x0E, 0x00, 0x02, 0x14, 0x08, 0x00, 0x02, 0x06, 0x02, 0x05, 0x0E, 0x00, 0x02, 0x15, 0x07, 0x00, 0x02, 0x07,
0x02, 0x06, 0x0E, 0x00, 0x02, 0x16, 0x07, 0x00, 0x02, 0x08, 0x02, 0x07, 0x0E, 0x00, 0x02, 0x17, 0x07, 0x00, 0x02, 0x09, 0x02, 0x08, 0x0E, 0x00, 0x02, 0x18, 0x07, 0x00, 0x02, 0x0A, 0x02, 0x09,
0x0E, 0x00, 0x02, 0x19, 0x07, 0x00, 0x02, 0x0B, 0x02, 0x0A, 0x0E, 0x00, 0x02, 0x1A, 0x07, 0x00, 0x02, 0x0C, 0x02, 0x0B, 0x0E, 0x00, 0x02, 0x1B, 0x08, 0x00, 0x02, 0x0D, 0x02, 0x0C, 0x0E, 0x00,
0x02, 0x1C, 0x08, 0x00, 0x02, 0x0E, 0x02, 0x0D, 0x0E, 0x00, 0x02, 0x1D, 0x07, 0x00, 0x02, 0x0F, 0x02, 0x0E, 0x0E, 0x00, 0x02, 0x1E, 0x08, 0x00, 0x10, 0x00, 0x02, 0x10, 0x02, 0x11, 0x0F, 0x00,
0x12, 0x54, 0x02, 0x1F, 0x01, 0x00, 0x03, 0x01]
con = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xC8, 0xFA, 0x86, 0x6E, 0x8F, 0xAF, 0xBF, 0xC9, 0x64, 0xD7, 0xC3, 0xE3, 0xEF, 0x87, 0x00]
enc = [0x000000F3, 0x00000082, 0x00000006, 0x000001FD, 0x00000150, 0x00000038, 0x000000B2, 0x000000DE, 0x0000015A, 0x00000197, 0x0000009C, 0x000001D7, 0x0000006E, 0x00000028, 0x00000146, 0x00000097]
stk = [0] * 0x100
tag = -233
ip = 0
sp = 0

inp = bytes.fromhex("12345678123456781234567812345678")
for i in range(16):
con[i] = inp[i]

def push(arg):
global stk, sp
stk[sp] = arg
sp += 1

def pop():
global stk, sp
sp -= 1
return stk[sp]

while ip < len(opc):
opcode = opc[ip]
arg = opc[ip+1]
if opcode == 2:
print(f"push stack[{sp}], con[{arg}] = {hex(con[arg])}")
push(con[arg])
elif opcode == 7:
b = pop()
a = pop()
print(f"add stack[{sp}] = {hex(a)}, stack[{sp+1}] = {hex(b)}\tpush stack[{sp}], res = {hex(a+b)}")
push(a + b)
elif opcode == 8:
a = pop()
b = pop()
print(f"sub stack[{sp+1}] = {hex(a)}, stack[{sp}] = {hex(b)}\tpush stack[{sp}], res = {hex(a-b)}")
push(a - b)
elif opcode == 14:
b = pop()
a = pop()
print(f"xor stack[{sp}] = {hex(a)}, stack[{sp+1}] = {hex(b)}\tpush stack[{sp}], res = {hex(a^b)}")
push(a ^ b)
elif opcode == 15:
b = pop()
a = pop()
tmp = True if a == b else False
print(f"cmp stack[{sp}] = {hex(a)}, stack[{sp+1}] = {hex(b)}\tpush stack[{sp}], res = {tmp}")
push(1 if tmp == True else 0)
elif opcode == 16:
tmp = True
for i in range(16):
print(f"cmp stk[{i}] = {hex(stk[i])}, cipher[{i}] = {hex(enc[i]-20)}")
if (stk[i] != (enc[i]-20)):
tmp = False
tag = 1 if tmp == True else -1
break
elif opcode == 18:
c = pop()
print(f"pop stack[{sp+1}] = {hex(c)}")
if c == 0:
print(f"jz to {hex(c)}")
ip = arg
else:
print(f"jnz denied")
else:
tag = 500
break
ip += 2

trace:

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
push stack[0], con[0] = 0x12
push stack[1], con[1] = 0x34
push stack[2], con[0] = 0x12
xor stack[1] = 0x34, stack[2] = 0x12 push stack[1], res = 0x26
push stack[2], con[16] = 0xb0
sub stack[2] = 0xb0, stack[1] = 0x26 push stack[1], res = 0x8a
push stack[2], con[2] = 0x56
push stack[3], con[1] = 0x34
xor stack[2] = 0x56, stack[3] = 0x34 push stack[2], res = 0x62
push stack[3], con[17] = 0xc8
sub stack[3] = 0xc8, stack[2] = 0x62 push stack[2], res = 0x66
push stack[3], con[3] = 0x78
push stack[4], con[2] = 0x56
xor stack[3] = 0x78, stack[4] = 0x56 push stack[3], res = 0x2e
push stack[4], con[18] = 0xfa
add stack[3] = 0x2e, stack[4] = 0xfa push stack[3], res = 0x128
push stack[4], con[4] = 0x12
push stack[5], con[3] = 0x78
xor stack[4] = 0x12, stack[5] = 0x78 push stack[4], res = 0x6a
push stack[5], con[19] = 0x86
add stack[4] = 0x6a, stack[5] = 0x86 push stack[4], res = 0xf0
push stack[5], con[5] = 0x34
push stack[6], con[4] = 0x12
xor stack[5] = 0x34, stack[6] = 0x12 push stack[5], res = 0x26
push stack[6], con[20] = 0x6e
sub stack[6] = 0x6e, stack[5] = 0x26 push stack[5], res = 0x48
push stack[6], con[6] = 0x56
push stack[7], con[5] = 0x34
xor stack[6] = 0x56, stack[7] = 0x34 push stack[6], res = 0x62
push stack[7], con[21] = 0x8f
add stack[6] = 0x62, stack[7] = 0x8f push stack[6], res = 0xf1
push stack[7], con[7] = 0x78
push stack[8], con[6] = 0x56
xor stack[7] = 0x78, stack[8] = 0x56 push stack[7], res = 0x2e
push stack[8], con[22] = 0xaf
add stack[7] = 0x2e, stack[8] = 0xaf push stack[7], res = 0xdd
push stack[8], con[8] = 0x12
push stack[9], con[7] = 0x78
xor stack[8] = 0x12, stack[9] = 0x78 push stack[8], res = 0x6a
push stack[9], con[23] = 0xbf
add stack[8] = 0x6a, stack[9] = 0xbf push stack[8], res = 0x129
push stack[9], con[9] = 0x34
push stack[10], con[8] = 0x12
xor stack[9] = 0x34, stack[10] = 0x12 push stack[9], res = 0x26
push stack[10], con[24] = 0xc9
add stack[9] = 0x26, stack[10] = 0xc9 push stack[9], res = 0xef
push stack[10], con[10] = 0x56
push stack[11], con[9] = 0x34
xor stack[10] = 0x56, stack[11] = 0x34 push stack[10], res = 0x62
push stack[11], con[25] = 0x64
add stack[10] = 0x62, stack[11] = 0x64 push stack[10], res = 0xc6
push stack[11], con[11] = 0x78
push stack[12], con[10] = 0x56
xor stack[11] = 0x78, stack[12] = 0x56 push stack[11], res = 0x2e
push stack[12], con[26] = 0xd7
add stack[11] = 0x2e, stack[12] = 0xd7 push stack[11], res = 0x105
push stack[12], con[12] = 0x12
push stack[13], con[11] = 0x78
xor stack[12] = 0x12, stack[13] = 0x78 push stack[12], res = 0x6a
push stack[13], con[27] = 0xc3
sub stack[13] = 0xc3, stack[12] = 0x6a push stack[12], res = 0x59
push stack[13], con[13] = 0x34
push stack[14], con[12] = 0x12
xor stack[13] = 0x34, stack[14] = 0x12 push stack[13], res = 0x26
push stack[14], con[28] = 0xe3
sub stack[14] = 0xe3, stack[13] = 0x26 push stack[13], res = 0xbd
push stack[14], con[14] = 0x56
push stack[15], con[13] = 0x34
xor stack[14] = 0x56, stack[15] = 0x34 push stack[14], res = 0x62
push stack[15], con[29] = 0xef
add stack[14] = 0x62, stack[15] = 0xef push stack[14], res = 0x151
push stack[15], con[15] = 0x78
push stack[16], con[14] = 0x56
xor stack[15] = 0x78, stack[16] = 0x56 push stack[15], res = 0x2e
push stack[16], con[30] = 0x87
sub stack[16] = 0x87, stack[15] = 0x2e push stack[15], res = 0x59
cmp stk[0] = 0x12, cipher[0] = 0xdf
cmp stk[1] = 0x8a, cipher[1] = 0x6e
cmp stk[2] = 0x66, cipher[2] = -0xe
cmp stk[3] = 0x128, cipher[3] = 0x1e9
cmp stk[4] = 0xf0, cipher[4] = 0x13c
cmp stk[5] = 0x48, cipher[5] = 0x24
cmp stk[6] = 0xf1, cipher[6] = 0x9e
cmp stk[7] = 0xdd, cipher[7] = 0xca
cmp stk[8] = 0x129, cipher[8] = 0x146
cmp stk[9] = 0xef, cipher[9] = 0x183
cmp stk[10] = 0xc6, cipher[10] = 0x88
cmp stk[11] = 0x105, cipher[11] = 0x1c3
cmp stk[12] = 0x59, cipher[12] = 0x5a
cmp stk[13] = 0xbd, cipher[13] = 0x14
cmp stk[14] = 0x151, cipher[14] = 0x132
cmp stk[15] = 0x59, cipher[15] = 0x83

爆破解密:

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
opc = [0x02, 0x00, 0x02, 0x01, 0x02, 0x00, 0x0E, 0x00, 0x02, 0x10, 0x08, 0x00, 0x02, 0x02, 0x02, 0x01, 0x0E, 0x00, 0x02, 0x11, 0x08, 0x00, 0x02, 0x03, 0x02, 0x02, 0x0E, 0x00, 0x02, 0x12, 0x07, 0x00, 
0x02, 0x04, 0x02, 0x03, 0x0E, 0x00, 0x02, 0x13, 0x07, 0x00, 0x02, 0x05, 0x02, 0x04, 0x0E, 0x00, 0x02, 0x14, 0x08, 0x00, 0x02, 0x06, 0x02, 0x05, 0x0E, 0x00, 0x02, 0x15, 0x07, 0x00, 0x02, 0x07,
0x02, 0x06, 0x0E, 0x00, 0x02, 0x16, 0x07, 0x00, 0x02, 0x08, 0x02, 0x07, 0x0E, 0x00, 0x02, 0x17, 0x07, 0x00, 0x02, 0x09, 0x02, 0x08, 0x0E, 0x00, 0x02, 0x18, 0x07, 0x00, 0x02, 0x0A, 0x02, 0x09,
0x0E, 0x00, 0x02, 0x19, 0x07, 0x00, 0x02, 0x0B, 0x02, 0x0A, 0x0E, 0x00, 0x02, 0x1A, 0x07, 0x00, 0x02, 0x0C, 0x02, 0x0B, 0x0E, 0x00, 0x02, 0x1B, 0x08, 0x00, 0x02, 0x0D, 0x02, 0x0C, 0x0E, 0x00,
0x02, 0x1C, 0x08, 0x00, 0x02, 0x0E, 0x02, 0x0D, 0x0E, 0x00, 0x02, 0x1D, 0x07, 0x00, 0x02, 0x0F, 0x02, 0x0E, 0x0E, 0x00, 0x02, 0x1E, 0x08, 0x00, 0x10, 0x00, 0x02, 0x10, 0x02, 0x11, 0x0F, 0x00,
0x12, 0x54, 0x02, 0x1F, 0x01, 0x00, 0x03, 0x01]

enc = [0x000000F3, 0x00000082, 0x00000006, 0x000001FD, 0x00000150, 0x00000038, 0x000000B2, 0x000000DE, 0x0000015A, 0x00000197, 0x0000009C, 0x000001D7, 0x0000006E, 0x00000028, 0x00000146, 0x00000097]
con = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xC8, 0xFA, 0x86, 0x6E, 0x8F, 0xAF, 0xBF, 0xC9, 0x64, 0xD7, 0xC3, 0xE3, 0xEF, 0x87, 0x00]

inp = bytearray(16)
for leng in range(16):
for cand in range(256):
inp[leng] = cand

stk = [0] * 0x100
tag = -233
ip = 0
sp = 0

for i in range(16):
con[i] = inp[i]

res = [0]*16

def push(arg):
global stk, sp
stk[sp] = arg
sp += 1

def pop():
global stk, sp
sp -= 1
return stk[sp]

while ip < len(opc):
opcode = opc[ip]
arg = opc[ip+1]
if opcode == 2:
push(con[arg])
elif opcode == 7:
b = pop()
a = pop()
push(a + b)
elif opcode == 8:
a = pop()
b = pop()
push(a - b)
elif opcode == 14:
b = pop()
a = pop()
push(a ^ b)
elif opcode == 15:
b = pop()
a = pop()
tmp = True if a == b else False
push(1 if tmp == True else 0)
elif opcode == 16:
tmp = True
for i in range(16):
if (stk[i] != (enc[i]-20)):
tmp = False
res[i] = 0
else:
res[i] = 1
tag = 1 if tmp == True else -1
break
elif opcode == 18:
c = pop()
if c == 0:
ip = arg
else:
pass
else:
tag = 500
break
ip += 2

if res[leng] == 1:
break

print("L3HCTF{"+inp.hex()+"}")

L3HCTF{df9d4ba41258574ccb7155b9d01f5c58}

ezvm

程序主函数:

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
__int64 __fastcall main(__int64 a1, __int64 Last)
{
__int64 v2; // rax
int v3; // edx
int v4; // r8d
int v5; // r9d
int v6; // r8d
int v7; // r9d
int v8; // r8d
int v9; // r9d
__int64 v10; // rax
__int64 v11; // rax
__int64 v12; // rdx
int v13; // r8d
int v14; // r9d
int v15; // edx
int v16; // r8d
int v17; // r9d
int v18; // edx
int v19; // r8d
int v20; // r9d
int v21; // edx
int v22; // r8d
int v23; // r9d
int v24; // edx
int v25; // r8d
int v26; // r9d
__int64 v28; // [rsp+0h] [rbp-80h]
__int64 v29; // [rsp+0h] [rbp-80h]
_QWORD v30[4]; // [rsp+20h] [rbp-60h] BYREF
unsigned int v31[2]; // [rsp+40h] [rbp-40h] BYREF

sub_7FF6869A5940(a1, Last);
v2 = std::operator<<<std::char_traits<char>>(
a1,
Last,
"Welcome to L3HCTF2025!!!Do you love cpp and vm?",
&libstdc___6__ZSt4cout);
std::ostream::operator<<(a1, Last, &std::wistream::operator>>, v2);
sub_7FF6869B1D30(a1, Last, v3, (__int64)v31, v4, v5);
sub_7FF6869B7DF0(a1, Last, (unsigned int)&dword_7FF6869C2040, (unsigned int)v30, v6, v7, v28);
sub_7FF6869B0700(a1, Last, (unsigned int)v30, (unsigned int)v31, v8, v9, v29);
v10 = std::operator<<<std::char_traits<char>>(
a1,
Last,
"Explore this virtual machine and have fun!",
&libstdc___6__ZSt4cout);
std::ostream::operator<<(a1, Last, &std::wistream::operator>>, v10);
v11 = std::operator<<<std::char_traits<char>>(a1, Last, "Plz show me flag:", &libstdc___6__ZSt4cout);
std::ostream::operator<<(a1, Last, &std::wistream::operator>>, v11);
getinput(a1, Last, v12, (int)v31, v13, v14);
VM(a1, Last, v15, (__int64)v31, v16, v17);
final_cmp(a1, Last, v18, (__int64)v31, v19, v20);
sub_7FF6869B7FC0(a1, Last, v21, v30, v22, v23);
sub_7FF6869B1DE0(a1, Last, v24, (int)v31, v25, v26);
return 0;
}

比较函数:

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
__int64 __fastcall final_cmp(__int64 a1, __int64 Last, int a3, __int64 a4, int a5, int a6)
{
__int64 v6; // rax
_DWORD v8[8]; // [rsp+20h] [rbp-30h]
int v9; // [rsp+40h] [rbp-10h] BYREF
int v10; // [rsp+44h] [rbp-Ch]
int n7; // [rsp+48h] [rbp-8h]
char v12; // [rsp+4Fh] [rbp-1h]

v8[0] = 0x877A62A6;
v8[1] = 0x6A55F1F3;
v8[2] = 0xAE194847;
v8[3] = 0xB1E643E7;
v8[4] = 0xA94FE881;
v8[5] = 0x9BC8A28A;
v8[6] = 0xC4CFAA9F;
v8[7] = 0xF1A00CA1;
v12 = 1;
for ( n7 = 0; n7 <= 7; ++n7 )
{
v9 = n7 + 2000;
v10 = *(_DWORD *)sub_7FF6869B5400(a1, Last, (__int64)&v9, a4 + 104, a5, a6);
if ( v10 != v8[n7] )
v12 = 0;
}
if ( v12 )
v6 = std::operator<<<std::char_traits<char>>(a1, Last, &unk_7FF6869BC088, &libstdc___6__ZSt4cout);
else
v6 = std::operator<<<std::char_traits<char>>(a1, Last, &unk_7FF6869BC0AF, &libstdc___6__ZSt4cout);
return std::ostream::operator<<(a1, Last, &std::wistream::operator>>, v6);
}

密文为[0x877A62A6, 0x6A55F1F3, 0xAE194847, 0xB1E643E7, 0xA94FE881, 0x9BC8A28A, 0xC4CFAA9F, 0xF1A00CA1],VM函数:

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
__int64 __fastcall vm_opc(int a1, int Last, int a3, __int64 a4)
{
v4 = *(_QWORD *)(a4 + 240);
if ( v4 >= sub_7FF6869B2B20(a1, Last, a3, (_QWORD *)a4) || *(_BYTE *)(a4 + 248) )
return 0;
v387 = sub_7FF6869B8360(a1, Last, *(_QWORD *)(a4 + 240), (_QWORD *)a4);
n2 = *(_BYTE *)v387;
if ( *(_BYTE *)v387 == 0xFF )
{
*(_BYTE *)(a4 + 248) = 1;
return 0;
}
else
{
if ( n2 < 0x60u )
{
if ( n2 == 84 )
{
if ( (unsigned __int8)sub_7FF6869B2AD0(a1, Last, v7, (int)a4 + 160, v8, v9, v320) != 1 )
{
v316 = (__int64 *)sub_7FF6869B78A0(a1, Last, v313, (int)a4 + 160, v314, v315, v322);
v317 = *v316;
*(_QWORD *)(a4 + 240) = *v316;
sub_7FF6869B7840(a1, Last, v317, a4 + 160, v318, v319, v323);
return 1;
}
}
else if ( n2 <= 0x54u )
{
switch ( n2 )
{
case 'S':
v348 = *(_QWORD *)(a4 + 240) + 1LL;
sub_7FF6869B7900(a1, Last, (unsigned int)&v348, a4 + 160, v8, v9, v320);
*(_QWORD *)(a4 + 240) = *(int *)(v387 + 4);
return 1;
case 'R':
if ( (unsigned __int8)sub_7FF6869B2AB0(a1, Last, v7, (int)a4 + 24, v8, v9) != 1 )
{
v386 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v293, (int)a4 + 24, v294, v295);
sub_7FF6869B76C0(a1, Last, v296, a4 + 24, v297, v298);
if ( v386 )
{
*(_QWORD *)(a4 + 240) = *(int *)(v387 + 4);
return 1;
}
}
break;
case 'Q':
if ( (unsigned __int8)sub_7FF6869B2AB0(a1, Last, v7, (int)a4 + 24, v8, v9) != 1 )
{
v385 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v287, (int)a4 + 24, v288, v289);
sub_7FF6869B76C0(a1, Last, v290, a4 + 24, v291, v292);
if ( !v385 )
{
*(_QWORD *)(a4 + 240) = *(int *)(v387 + 4);
return 1;
}
}
break;
case 'P':
*(_QWORD *)(a4 + 240) = *(int *)(v387 + 4);
return 1;
case 'A':
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v384 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v272, (int)a4 + 24, v273, v274);
sub_7FF6869B76C0(a1, Last, v275, a4 + 24, v276, v277);
v383 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v278, (int)a4 + 24, v279, v280);
sub_7FF6869B76C0(a1, Last, v281, a4 + 24, v282, v283);
v284 = v383;
v346 = v384;
*(_DWORD *)sub_7FF6869B5400(a1, Last, (__int64)&v346, a4 + 104, v285, v286) = v284;
}
break;
default:
if ( n2 <= 0x41u )
{
if ( n2 == 64 )
{
if ( (unsigned __int8)sub_7FF6869B2AB0(a1, Last, v7, (int)a4 + 24, v8, v9) != 1 )
{
v382 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v261, (int)a4 + 24, v262, v263);
sub_7FF6869B76C0(a1, Last, v264, a4 + 24, v265, v266);
v345 = v382;
v269 = sub_7FF6869B5400(a1, Last, (__int64)&v345, a4 + 104, v267, v268);
sub_7FF6869B77B0(a1, Last, v269, a4 + 24, v270, v271, v320);
}
}
else if ( n2 == 50 )
{
if ( (unsigned __int8)sub_7FF6869B2AB0(a1, Last, v7, (int)a4 + 24, v8, v9) != 1 )
{
v381 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v227, (int)a4 + 24, v228, v229);
sub_7FF6869B76C0(a1, Last, v230, a4 + 24, v231, v232);
v342 = v381 == 0;
sub_7FF6869B7780(a1, Last, (unsigned int)&v342, a4 + 24, v233, v234, v320);
}
}
else if ( n2 <= 0x32u )
{
switch ( n2 )
{
case '1':
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v380 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v212, (int)a4 + 24, v213, v214);
sub_7FF6869B76C0(a1, Last, v215, a4 + 24, v216, v217);
v379 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v218, (int)a4 + 24, v219, v220);
sub_7FF6869B76C0(a1, Last, v221, a4 + 24, v222, v223);
v226 = v379 || v380;
v341 = v226;
sub_7FF6869B7780(a1, Last, (unsigned int)&v341, a4 + 24, v224, v225, v320);
}
break;
case '0':
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v378 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v197, (int)a4 + 24, v198, v199);
sub_7FF6869B76C0(a1, Last, v200, a4 + 24, v201, v202);
v377 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v203, (int)a4 + 24, v204, v205);
sub_7FF6869B76C0(a1, Last, v206, a4 + 24, v207, v208);
v211 = v377 && v378;
v340 = v211;
sub_7FF6869B7780(a1, Last, (unsigned int)&v340, a4 + 24, v209, v210, v320);
}
break;
case '%':
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v376 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v183, (int)a4 + 24, v184, v185);
sub_7FF6869B76C0(a1, Last, v186, a4 + 24, v187, v188);
v375 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v189, (int)a4 + 24, v190, v191);
sub_7FF6869B76C0(a1, Last, v192, a4 + 24, v193, v194);
v339 = v375 >= v376;
sub_7FF6869B7780(a1, Last, (unsigned int)&v339, a4 + 24, v195, v196, v320);
}
break;
default:
if ( n2 <= 0x25u )
{
switch ( n2 )
{
case 0x24u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v374 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v169, (int)a4 + 24, v170, v171);
sub_7FF6869B76C0(a1, Last, v172, a4 + 24, v173, v174);
v373 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v175, (int)a4 + 24, v176, v177);
sub_7FF6869B76C0(a1, Last, v178, a4 + 24, v179, v180);
v338 = v374 < v373;
sub_7FF6869B7780(a1, Last, (unsigned int)&v338, a4 + 24, v181, v182, v320);
}
break;
case 0x23u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v372 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v155, (int)a4 + 24, v156, v157);
sub_7FF6869B76C0(a1, Last, v158, a4 + 24, v159, v160);
v371 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v161, (int)a4 + 24, v162, v163);
sub_7FF6869B76C0(a1, Last, v164, a4 + 24, v165, v166);
v337 = v372 >= v371;
sub_7FF6869B7780(a1, Last, (unsigned int)&v337, a4 + 24, v167, v168, v320);
}
break;
case 0x22u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v370 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v141, (int)a4 + 24, v142, v143);
sub_7FF6869B76C0(a1, Last, v144, a4 + 24, v145, v146);
v369 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v147, (int)a4 + 24, v148, v149);
sub_7FF6869B76C0(a1, Last, v150, a4 + 24, v151, v152);
v336 = v369 < v370;
sub_7FF6869B7780(a1, Last, (unsigned int)&v336, a4 + 24, v153, v154, v320);
}
break;
case 0x21u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v368 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v127, (int)a4 + 24, v128, v129);
sub_7FF6869B76C0(a1, Last, v130, a4 + 24, v131, v132);
v367 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v133, (int)a4 + 24, v134, v135);
sub_7FF6869B76C0(a1, Last, v136, a4 + 24, v137, v138);
v335 = v367 != v368;
sub_7FF6869B7780(a1, Last, (unsigned int)&v335, a4 + 24, v139, v140, v320);
}
break;
case 0x20u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v366 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v113, (int)a4 + 24, v114, v115);
sub_7FF6869B76C0(a1, Last, v116, a4 + 24, v117, v118);
v365 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v119, (int)a4 + 24, v120, v121);
sub_7FF6869B76C0(a1, Last, v122, a4 + 24, v123, v124);
v334 = v365 == v366;
sub_7FF6869B7780(a1, Last, (unsigned int)&v334, a4 + 24, v125, v126, v320);
}
break;
case 0x18u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v364 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v299, (int)a4 + 24, v300, v301);
sub_7FF6869B76C0(a1, Last, v302, a4 + 24, v303, v304);
v363 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v305, (int)a4 + 24, v306, v307);
sub_7FF6869B76C0(a1, Last, v308, a4 + 24, v309, v310);
v347 = v364 ^ v363;
sub_7FF6869B7780(a1, Last, (unsigned int)&v347, a4 + 24, v311, v312, v320);
}
break;
default:
if ( n2 <= 0x18u )
{
switch ( n2 )
{
case 0x17u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v362 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v248, (int)a4 + 24, v249, v250);
sub_7FF6869B76C0(a1, Last, v251, a4 + 24, v252, v253);
v361 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v254, (int)a4 + 24, v255, v256);
sub_7FF6869B76C0(a1, Last, v257, a4 + 24, v258, v259);
v344 = v361 >> v362;
sub_7FF6869B7780(a1, Last, (unsigned int)&v344, a4 + 24, a4 + 24, v260, v320);
}
break;
case 0x16u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v360 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v235, (int)a4 + 24, v236, v237);
sub_7FF6869B76C0(a1, Last, v238, a4 + 24, v239, v240);
v359 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v241, (int)a4 + 24, v242, v243);
sub_7FF6869B76C0(a1, Last, v244, a4 + 24, v245, v246);
v343 = v359 << v360;
sub_7FF6869B7780(a1, Last, (unsigned int)&v343, a4 + 24, a4 + 24, v247, v320);
}
break;
case 0x15u:
if ( (unsigned __int8)sub_7FF6869B2AB0(a1, Last, v7, (int)a4 + 24, v8, v9) != 1 )
{
v324 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v105, (int)a4 + 24, v106, v107);
sub_7FF6869B76C0(a1, Last, v108, a4 + 24, v109, v110);
sub_7FF6869B77B0(a1, Last, (unsigned int)&v324, a4 + 24, v111, v112, v320);
}
break;
case 0x14u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v358 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v91, (int)a4 + 24, v92, v93);
sub_7FF6869B76C0(a1, Last, v94, a4 + 24, v95, v96);
v357 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v97, (int)a4 + 24, v98, v99);
sub_7FF6869B76C0(a1, Last, v100, a4 + 24, v101, v102);
if ( v358 )
{
v333 = v357 % v358;
sub_7FF6869B7780(a1, Last, (unsigned int)&v333, a4 + 24, v103, v104, v320);
}
}
break;
case 0x13u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v356 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v77, (int)a4 + 24, v78, v79);
sub_7FF6869B76C0(a1, Last, v80, a4 + 24, v81, v82);
v355 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v83, (int)a4 + 24, v84, v85);
sub_7FF6869B76C0(a1, Last, v86, a4 + 24, v87, v88);
if ( v356 )
{
v332 = v355 / v356;
sub_7FF6869B7780(a1, Last, (unsigned int)&v332, a4 + 24, v89, v90, v320);
}
}
break;
case 0x12u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v354 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v63, (int)a4 + 24, v64, v65);
sub_7FF6869B76C0(a1, Last, v66, a4 + 24, v67, v68);
v353 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v69, (int)a4 + 24, v70, v71);
sub_7FF6869B76C0(a1, Last, v72, a4 + 24, v73, v74);
v331 = v354 * v353;
sub_7FF6869B7780(a1, Last, (unsigned int)&v331, a4 + 24, v75, v76, v320);
}
break;
case 0x11u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v352 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v49, (int)a4 + 24, v50, v51);
sub_7FF6869B76C0(a1, Last, v52, a4 + 24, v53, v54);
v351 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v55, (int)a4 + 24, v56, v57);
sub_7FF6869B76C0(a1, Last, v58, a4 + 24, v59, v60);
v330 = v351 - v352;
sub_7FF6869B7780(a1, Last, (unsigned int)&v330, a4 + 24, v61, v62, v320);
}
break;
case 0x10u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v350 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v35, (int)a4 + 24, v36, v37);
sub_7FF6869B76C0(a1, Last, v38, a4 + 24, v39, v40);
v349 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v41, (int)a4 + 24, v42, v43);
sub_7FF6869B76C0(a1, Last, v44, a4 + 24, v45, v46);
v329 = v349 + v350;
sub_7FF6869B7780(a1, Last, (unsigned int)&v329, a4 + 24, v47, v48, v320);
}
break;
case 4u:
if ( (unsigned __int64)sub_7FF6869B2A90(a1, Last, v7, (int)a4 + 24, v8, v9) > 1 )
{
v326 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v19, (int)a4 + 24, v20, v21);
sub_7FF6869B76C0(a1, Last, v22, a4 + 24, v23, v24);
v325 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v25, (int)a4 + 24, v26, v27);
sub_7FF6869B76C0(a1, Last, v28, a4 + 24, v29, v30);
sub_7FF6869B77B0(a1, Last, (unsigned int)&v326, a4 + 24, v31, v32, v320);
sub_7FF6869B77B0(a1, Last, (unsigned int)&v325, a4 + 24, v33, v34, v321);
}
break;
default:
if ( n2 <= 4u )
{
if ( n2 == 3 )
{
if ( (unsigned __int8)sub_7FF6869B2AB0(a1, Last, v7, (int)a4 + 24, v8, v9) != 1 )
{
v327 = *(_DWORD *)sub_7FF6869B7720(a1, Last, v14, (int)a4 + 24, v15, v16);
sub_7FF6869B77B0(a1, Last, (unsigned int)&v327, a4 + 24, v17, v18, v320);
}
}
else if ( n2 == 1 )
{
v328 = *(_DWORD *)(v387 + 4);
sub_7FF6869B7780(a1, Last, (unsigned int)&v328, a4 + 24, v8, v9, v320);
}
else if ( n2 == 2
&& (unsigned __int8)sub_7FF6869B2AB0(a1, Last, v7, (int)a4 + 24, v8, v9) != 1 )
{
sub_7FF6869B76C0(a1, Last, v11, a4 + 24, v12, v13);
}
}
break;
}
}
break;
}
}
break;
}
}
}
break;
}
}
}
++*(_QWORD *)(a4 + 240);
return 1;
}
}

v387是opcode,分析case和虚拟机结构体(a4),对于前几条指令,有:

字节码 作用参数个数 字节码参数个数 指令长度 作用
0x1 1 1 2 push arg into stack
0x40 2 0 2 push memory into stack
0x41 2 0 2 mov stack into memory

对于这些字节码,其中的有些并不会将参数写入opcode数组中,而是在进入case后计算出来要带入后续运算的参数,因此将其分为字节码中的参数个数和真正起作用的参数个数,特别地,当字节码参数个数为0时,实际上是一个为0x0的参数,因此指令长度仍为2。

1
2
3
4
5
6
7
8
9
10
11
12
push stack[1], 0x11223344
push stack[2], 0xbb8
mov mem[3000], stack[0] = 0x11223344
push stack[1], 0x40
push stack[2], 0xbb9
mov mem[3001], stack[0] = 0x40
push stack[1], 0x7d1
push stack[2], 0x7d0
push stack[3], 0xbc2
mov mem[3010], stack[1] = 0x7d0
push stack[2], 0xbc3
mov mem[3011], stack[0] = 0x7d1

注意到,虚拟机的stack是一个往下增长的dword结构体,0x1会从索引处往下填写立即数,0x41则会往上回溯两个索引作为参数并将第一个参数加载到内存结构体的第二个索引对应的位置。

对于初步的trace分析,有虚拟机初始在0xBB8和0xBB9位置加载了delta值和轮数,而后在0xBC20xBC9分块加载了输入的明文每个四字对应的在虚拟机内存中的索引的指针0x7D00x7D7,一次加载2个四字(共计8字节),此为分组加密的初始化部分。

接下来加载了后四字的内存指针到栈中后加载了后四字的明文,步入加密流程,mem[3002]为sum:

字节码 作用参数个数 字节码参数个数 指令长度 作用
0x3 1 0 2 mov stack n, stack n-1
0x10 2 0 2 add and push
0x11 2 0 2 sub and push
0x16 2 0 2 shl and push
0x17 2 0 2 shr and push
0x18 2 0 2 xor and push
0x24 2 0 2 cmp whether less than and push
0x52 2 1 2 jnz

编写同构VM脚本:

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
def hexprint(nums, width=11, per_line=16):
format_str = "{:>" + str(width) + "s}"
for i, num in enumerate(nums):
hex_val = hex(num)
print(format_str.format(hex_val), end='')
if (i + 1) % per_line == 0:
print()
if len(nums) % per_line != 0:
print()

def b2dle(byte_array):
return [int.from_bytes(byte_array[i:i+4], byteorder='little', signed=False) for i in range(0, len(byte_array), 4)]

opc = [0x00000001, 0x11223344, 0x00000001, 0x00000BB8, 0x00000041, 0x00000000, 0x00000001, 0x00000040, 0x00000001, 0x00000BB9, 0x00000041, 0x00000000, 0x00000001, 0x000007D1, 0x00000001, 0x000007D0,
0x00000001, 0x00000BC2, 0x00000041, 0x00000000, 0x00000001, 0x00000BC3, 0x00000041, 0x00000000, 0x00000001, 0x00000BC3, 0x00000040, 0x00000000, 0x00000040, 0x00000000, 0x00000001, 0x00000003,
0x00000016, 0x00000000, 0x00000060, 0x00000000, 0x00000001, 0x000007DA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000060, 0x00000000, 0x00000001, 0x00000BC4, 0x00000041, 0x00000000,
0x00000001, 0x00000BC3, 0x00000040, 0x00000000, 0x00000040, 0x00000000, 0x00000001, 0x00000BBA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000060, 0x00000000, 0x00000001, 0x000007DB,
0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x00000BC4, 0x00000040, 0x00000000, 0x00000018, 0x00000000, 0x00000001, 0x00000BC5, 0x00000041, 0x00000000, 0x00000001, 0x00000BC3,
0x00000040, 0x00000000, 0x00000040, 0x00000000, 0x00000001, 0x00000004, 0x00000017, 0x00000000, 0x00000001, 0x000007DC, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x00000BC6,
0x00000041, 0x00000000, 0x00000001, 0x00000BC5, 0x00000040, 0x00000000, 0x00000001, 0x00000BC6, 0x00000040, 0x00000000, 0x00000018, 0x00000000, 0x00000001, 0x00000BC2, 0x00000040, 0x00000000,
0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000060, 0x00000000, 0x00000001, 0x00000BC2, 0x00000040, 0x00000000, 0x00000041, 0x00000000, 0x00000001, 0x00000BBA, 0x2202E040, 0x00000000,
0x00000001, 0x00000BB8, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000060, 0x00000000, 0x75DFEB01, 0x00000BBA, 0x2202DF41, 0x00000000, 0x75DFEB01, 0x00000BC2, 0xFFFFFF40, 0x00000000,
0x00000040, 0x00000000, 0x00000001, 0x00000002, 0x00000016, 0x00000000, 0x00000001, 0x000007DC, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x00000BC7, 0x00000041, 0x00000000,
0x75DFF101, 0x00000BC2, 0x00000040, 0x00000000, 0x75DFEC40, 0x00000000, 0x00000001, 0x00000BBA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x000007DD, 0x00000040, 0x00000000,
0x00000010, 0x00000000, 0x00000001, 0x00000BC7, 0x00000040, 0x00000000, 0x00000018, 0x00000000, 0x00000001, 0x00000BC8, 0x00000041, 0x00000000, 0x00000001, 0x00000BC2, 0x00000040, 0x00000000,
0x00000040, 0x00000000, 0x00000001, 0x00000005, 0x00000017, 0x00000000, 0x00000001, 0x000007DA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x00000BC9, 0x00000041, 0x00000000,
0x00000001, 0x00000BC8, 0x00000040, 0x00000000, 0x00000001, 0x00000BC9, 0x00000040, 0x00000000, 0x00000018, 0x00000000, 0x00000001, 0x00000BC3, 0x00000040, 0x00000000, 0x00000040, 0x00000000,
0x00000010, 0x00000000, 0x00000060, 0x00000000, 0x00000001, 0x00000BC3, 0x00000040, 0x00000000, 0x00000041, 0x00000000, 0x00000001, 0x00000BB9, 0x00000040, 0x00000000, 0x00000001, 0x00000001,
0x00000011, 0x00000000, 0x00000003, 0x00000000, 0x00000001, 0x00000BB9, 0x21F79841, 0x00000000, 0x00000001, 0x00000000, 0x00000024, 0x00000000, 0x00000052, 0x0000000C, 0x00000001, 0x11223344,
0x00000001, 0x00000BB8, 0x00000041, 0x00000000, 0x00000001, 0x00000040, 0x00000001, 0x00000BB9, 0x00000041, 0x00000000, 0x00000001, 0x000007D3, 0x00000001, 0x000007D2, 0x75DFF001, 0x00000BC2,
0x00000041, 0x00000000, 0x00000001, 0x00000BC3, 0x00000041, 0x00000000, 0x00000001, 0x00000BC3, 0x00000040, 0x00000000, 0x00000040, 0x00000000, 0x00000001, 0x00000003, 0x00000016, 0x00000000,
0x00000060, 0x00000000, 0x00000001, 0x000007DA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x75DFEE60, 0x00000000, 0xBC0E2501, 0x00000BC4, 0x2207B441, 0x00000000, 0x00000001, 0x00000BC3,
0x00000040, 0x00000000, 0x2207B440, 0x00000000, 0x00000101, 0x00000BBA, 0x00000040, 0x00000000, 0x75DFEC10, 0x00000000, 0x22027B60, 0x00000000, 0x75DFED01, 0x000007DB, 0x006E0040, 0x00000000,
0x75DFED10, 0x00000000, 0x21F79A01, 0x00000BC4, 0x00000040, 0x00000000, 0x00000018, 0x00000000, 0x72A03101, 0x00000BC5, 0x00000041, 0x00000000, 0x72A03601, 0x00000BC3, 0x00000040, 0x00000000,
0x72A03640, 0x00000000, 0x21F47101, 0x00000004, 0x72A03117, 0x00000000, 0x729F0001, 0x000007DC, 0x00000040, 0x00000000, 0x00000110, 0x00000000, 0x00000001, 0x00000BC6, 0x00000041, 0x00000000,
0x00000001, 0x00000BC5, 0x72A03140, 0x00000000, 0x00000001, 0x00000BC6, 0x00000040, 0x00000000, 0x72A03118, 0x00000000, 0x00000001, 0x00000BC2, 0x72A03140, 0x00000000, 0x0502C040, 0x00000000,
0x00000010, 0x00000000, 0x00000060, 0x00000000, 0x00000001, 0x00000BC2, 0x00000040, 0x00000000, 0x729F7341, 0x00000000, 0x00000001, 0x00000BBA, 0x00000040, 0x00000000, 0x729F0501, 0x00000BB8,
0x00000140, 0x00000000, 0x21F47110, 0x00000000, 0x00000060, 0x00000000, 0x00000001, 0x00000BBA, 0x72A03641, 0x00000000, 0x729F0301, 0x00000BC2, 0x00000040, 0x00000000, 0x00000440, 0x00000000,
0x00000001, 0x00000002, 0x729FD316, 0x00000000, 0x00000101, 0x000007DC, 0x00000040, 0x00000000, 0x729FD310, 0x00000000, 0x00000001, 0x00000BC7, 0x729FD341, 0x00000000, 0x05000001, 0x00000BC2,
0x00000440, 0x00000000, 0x00000040, 0x00000000, 0x00000001, 0x00000BBA, 0x00000040, 0x00000000, 0x729FB310, 0x00000000, 0x07040001, 0x000007DD, 0x00000040, 0x00000000, 0x729F0310, 0x00000000,
0x729F0701, 0x00000BC7, 0x729F0140, 0x00000000, 0x00000018, 0x00000000, 0x00000001, 0x00000BC8, 0x729FD441, 0x00000000, 0x729F0301, 0x00000BC2, 0x00000040, 0x00000000, 0x00000140, 0x00000000,
0x00000001, 0x00000005, 0x00000017, 0x00000000, 0x00000001, 0x000007DA, 0x729F0340, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x00000BC9, 0x00340041, 0x00000000, 0x004C0001, 0x00000BC8,
0x00000140, 0x00000000, 0x729FD301, 0x00000BC9, 0x00000040, 0x00000000, 0x12040018, 0x00000000, 0x00000001, 0x00000BC3, 0x07040040, 0x00000000, 0x729FBA40, 0x00000000, 0x00000010, 0x00000000,
0x00000060, 0x00000000, 0x11040001, 0x00000BC3, 0x729FB940, 0x00000000, 0x729F0041, 0x00000000, 0x00000001, 0x00000BB9, 0x00000040, 0x00000000, 0x00000001, 0x00000001, 0x00000011, 0x00000000,
0x729F0003, 0x00000000, 0x729FB901, 0x00000BB9, 0x00000441, 0x00000000, 0x00000001, 0x00000000, 0x729FB924, 0x00000000, 0x00000052, 0x0000008B, 0x729FB901, 0x11223344, 0x05000001, 0x00000BB8,
0x00000041, 0x00000000, 0x00000001, 0x00000040, 0x00000001, 0x00000BB9, 0x00000041, 0x00000000, 0x729FCF01, 0x000007D5, 0x402C0001, 0x000007D4, 0x00000001, 0x00000BC2, 0x729F0341, 0x00000000,
0x00000001, 0x00000BC3, 0x50000141, 0x00000000, 0x00000001, 0x00000BC3, 0x00000140, 0x00000000, 0x729F0040, 0x00000000, 0x00000001, 0x00000003, 0x00000116, 0x00000000, 0x21F0F560, 0x00000000,
0x729F0001, 0x000007DA, 0x50000140, 0x00000000, 0x00000110, 0x00000000, 0x00000160, 0x00000000, 0x00000001, 0x00000BC4, 0x75DFF041, 0x00000000, 0x729FBA01, 0x00000BC3, 0x50000140, 0x00000000,
0x00000040, 0x00000000, 0x00000001, 0x00000BBA, 0x00000040, 0x00000000, 0x00000110, 0x00000000, 0x50000160, 0x00000000, 0x40000001, 0x000007DB, 0x00000040, 0x00000000, 0x729F0010, 0x00000000,
0x00000001, 0x00000BC4, 0x21F0F140, 0x00000000, 0x00000018, 0x00000000, 0x00000001, 0x00000BC5, 0x00000041, 0x00000000, 0x729F0001, 0x00000BC3, 0x00000040, 0x00000000, 0x21F0F140, 0x00000000,
0x00000001, 0x00000004, 0x729F0017, 0x00000000, 0x00000401, 0x000007DC, 0x402C0040, 0x00000000, 0x00000410, 0x00000000, 0x72A03601, 0x00000BC6, 0x72A03141, 0x00000000, 0x00000001, 0x00000BC5,
0x00000040, 0x00000000, 0x21F45001, 0x00000BC6, 0x729F0040, 0x00000000, 0x02040018, 0x00000000, 0x00000001, 0x00000BC2, 0x729F0040, 0x00000000, 0x50000140, 0x00000000, 0x21F27010, 0x00000000,
0x729F0060, 0x00000000, 0x00000001, 0x00000BC2, 0x00000040, 0x00000000, 0x00000041, 0x00000000, 0x729F0001, 0x00000BBA, 0x00000040, 0x00000000, 0x00000001, 0x00000BB8, 0x21F0F540, 0x00000000,
0x729F0010, 0x00000000, 0x729F0060, 0x00000000, 0x00000101, 0x00000BBA, 0x40000041, 0x00000000, 0x00000101, 0x00000BC2, 0x729FD440, 0x00000000, 0x729FD340, 0x00000000, 0x00000001, 0x00000002,
0x00000016, 0x00000000, 0x21F45001, 0x000007DC, 0x729F0040, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x00000BC7, 0x729F0041, 0x00000000, 0x00000001, 0x00000BC2, 0x729FD340, 0x00000000,
0x40000040, 0x00000000, 0x40000001, 0x00000BBA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x000007DD, 0x21F47840, 0x00000000, 0x729F0010, 0x00000000, 0x50000101, 0x00000BC7,
0x729F0040, 0x00000000, 0x00000018, 0x00000000, 0x00000001, 0x00000BC8, 0x21F47841, 0x00000000, 0x729F0001, 0x00000BC2, 0x50000140, 0x00000000, 0x729F0040, 0x00000000, 0x00000001, 0x00000005,
0x00000017, 0x00000000, 0x00000001, 0x000007DA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000001, 0x00000BC9, 0x00000041, 0x00000000, 0x50000101, 0x00000BC8, 0x21F27040, 0x00000000,
0x729F0001, 0x00000BC9, 0x00000040, 0x00000000, 0x00000018, 0x00000000, 0x75DFF301, 0x00000BC3, 0xBC0E3D40, 0x00000000, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x204A0060, 0x00000000,
0x00000001, 0x00000BC3, 0x729F0040, 0x00000000, 0x00000041, 0x00000000, 0x40000001, 0x00000BB9, 0x00000040, 0x00000000, 0x729FBA01, 0x00000001, 0x729FB911, 0x00000000, 0x00000003, 0x00000000,
0x00000001, 0x00000BB9, 0x21F45041, 0x00000000, 0x729F0001, 0x00000000, 0x00000024, 0x00000000, 0x00000052, 0x0000010A, 0x729F0001, 0x11223344, 0x00000001, 0x00000BB8, 0x729FB941, 0x00000000,
0x40000001, 0x00000040, 0x40000001, 0x00000BB9, 0x00000041, 0x00000000, 0x00000001, 0x000007D7, 0x00000001, 0x000007D6, 0x21F47801, 0x00000BC2, 0x729F0041, 0x00000000, 0x50000101, 0x00000BC3,
0x729F0041, 0x00000000, 0x00000001, 0x00000BC3, 0x00000440, 0x00000000, 0x21F0F540, 0x00000000, 0x729F0001, 0x00000003, 0x402C0016, 0x00000000, 0x00000460, 0x00000000, 0x00000001, 0x000007DA,
0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000060, 0x00000000, 0x00000001, 0x00000BC4, 0x869C2041, 0x00000000, 0x00000001, 0x00000BC3, 0x00000040, 0x00000000, 0x00000440, 0x00000000,
0x002C0001, 0x00000BBA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x729F0060, 0x00000000, 0x00000001, 0x000007DB, 0x40000040, 0x00000000, 0x00000010, 0x00000000, 0x00000101, 0x00000BC4,
0x729F0040, 0x00000000, 0x00000018, 0x00000000, 0x00000101, 0x00000BC5, 0x21F0F541, 0x00000000, 0x729F0001, 0x00000BC3, 0x40000040, 0x00000000, 0x00000140, 0x00000000, 0x00000101, 0x00000004,
0x00000017, 0x00000000, 0x75DFF401, 0x000007DC, 0x729F0040, 0x00000000, 0x40000010, 0x00000000, 0x00000001, 0x00000BC6, 0x00000041, 0x00000000, 0x729FB701, 0x00000BC5, 0x00000140, 0x00000000,
0x00000001, 0x00000BC6, 0x75DFF740, 0x00000000, 0x00000018, 0x00000000, 0x729F0001, 0x00000BC2, 0x00000040, 0x00000000, 0x21F0F140, 0x00000000, 0x00000010, 0x00000000, 0x00000060, 0x00000000,
0x00000001, 0x00000BC2, 0x00015040, 0x00000000, 0x00001041, 0x00000000, 0x01000001, 0x00000BBA, 0x869A0040, 0x00000000, 0x00000001, 0x00000BB8, 0x00027040, 0x00000000, 0x00007010, 0x00000000,
0x00000060, 0x00000000, 0x00000001, 0x00000BBA, 0x00000041, 0x00000000, 0x00000001, 0x00000BC2, 0x89634340, 0x00000000, 0x1F270A40, 0x00000000, 0x869C2001, 0x00000002, 0x00000016, 0x00000000,
0x00000001, 0x000007DC, 0x00000040, 0x00000000, 0x869A0010, 0x00000000, 0x00027001, 0x00000BC7, 0x00000041, 0x00000000, 0x40000001, 0x00000BC2, 0x00000040, 0x00000000, 0x00000040, 0x00000000,
0x729F0001, 0x00000BBA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x21F0F501, 0x000007DD, 0x729F0040, 0x00000000, 0x40000010, 0x00000000, 0x00000001, 0x00000BC7, 0x00000040, 0x00000000,
0x00000018, 0x00000000, 0x75DFF701, 0x00000BC8, 0x00000041, 0x00000000, 0x729FB701, 0x00000BC2, 0x1F828840, 0x00000000, 0x1F700140, 0x00000000, 0x729FB701, 0x00000005, 0x00000117, 0x00000000,
0x00000001, 0x000007DA, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x1F72D101, 0x00000BC9, 0x00000141, 0x00000000, 0x21F0F101, 0x00000BC8, 0x00000040, 0x00000000, 0x00000001, 0x00000BC9,
0x00000040, 0x00000000, 0x1F704A18, 0x00000000, 0x729F6C01, 0x00000BC3, 0x00000040, 0x00000000, 0x00000040, 0x00000000, 0x00000010, 0x00000000, 0x00000060, 0x00000000, 0x1F828801, 0x00000BC3,
0x729F6C40, 0x00000000, 0x1F704841, 0x00000000, 0x75DFF701, 0x00000BB9, 0x75DFF740, 0x00000000, 0x1F828801, 0x00000001, 0x75DFF711, 0x00000000, 0x729FB703, 0x00000000, 0x1F768701, 0x00000BB9,
0x869A1441, 0x00000000, 0x869BD501, 0x00000000, 0x00000024, 0x00000000, 0x75DFF752, 0x00000189, 0x75DFF7FF]

enc = [0x877A62A6, 0x6A55F1F3, 0xAE194847, 0xB1E643E7, 0xA94FE881, 0x9BC8A28A, 0xC4CFAA9F, 0xF1A00CA1]

stack = [0] * 16
mem = [0] * 6000

key = [0xA56BABCD, 0x00000000, 0xFFFFFFFF, 0xABCDEF01]
for i in range(len(key)):
mem[0x7DA+i] = key[i] # 初始化的时候密钥被填入虚拟机内存的第2010~2013个索引

inp = b"12345678123456781234567812345678"
dinp = b2dle(inp)
for i in range(len(dinp)):
mem[0x7D0+i] = dinp[i] # 初始化的时候明文被填入虚拟机内存的第2000~2007个索引

opidx = 0
stackidx = 0

def push(arg):
global stack, stackidx
stack[stackidx] = arg
stackidx += 1

def pop():
global stack, stackidx
stackidx -= 1
return stack[stackidx]

while opidx < len(opc):
if opc[opidx] & 0xFF == 1:
push(opc[opidx+1])
print(f"push stack[{stackidx}], {hex(opc[opidx+1])}")
opidx += 2
elif opc[opidx] & 0xFF == 3:
arg = pop()
push(arg)
push(arg)
print(f"mov stack[{stackidx-1}], stack[{stackidx-2}] = {hex(stack[stackidx-1])}")
opidx += 2
elif opc[opidx] & 0xFF == 0x10:
arg1 = pop()
arg2 = pop()
num = (arg2 + arg1) & 0xFFFFFFFF
print(f"add stack[{stackidx+1}] = {hex(arg2)}, stack[{stackidx}] = {hex(arg1)}\npush stack[{stackidx}], res = {hex(num)}")
push(num)
opidx += 2
elif opc[opidx] & 0xFF == 0x11:
arg1 = pop()
arg2 = pop()
num = (arg2 - arg1) & 0xFFFFFFFF
print(f"sub stack[{stackidx+1}] = {hex(arg2)}, stack[{stackidx}] = {hex(arg1)}\npush stack[{stackidx}], res = {hex(num)}")
push(num)
opidx += 2
elif opc[opidx] & 0xFF == 0x16:
arg1 = pop()
arg2 = pop()
num = (arg2 << arg1) & 0xFFFFFFFF
print(f"shl stack[{stackidx+1}] = {hex(arg2)}, stack[{stackidx}] = {hex(arg1)}\npush stack[{stackidx}], res = {hex(num)}")
push(num)
opidx += 2
elif opc[opidx] & 0xFF == 0x17:
arg1 = pop()
arg2 = pop()
num = (arg2 >> arg1) & 0xFFFFFFFF
print(f"shr stack[{stackidx+1}] = {hex(arg2)}, stack[{stackidx}] = {hex(arg1)}\npush stack[{stackidx}], res = {hex(num)}")
push(num)
opidx += 2
elif opc[opidx] & 0xFF == 0x18:
arg1 = pop()
arg2 = pop()
num = (arg2 ^ arg1) & 0xFFFFFFFF
print(f"xor stack[{stackidx+1}] = {hex(arg2)}, stack[{stackidx}] = {hex(arg1)}\npush stack[{stackidx}], res = {hex(num)}")
push(num)
opidx += 2
elif opc[opidx] & 0xFF == 0x24:
arg1 = pop()
arg2 = pop()
num = 1 if arg1 < arg2 else 0
print(f"lt stack[{stackidx}] = {hex(arg1)}, stack[{stackidx+1}] = {hex(arg2)}\npush stack[{stackidx}], res = {False if num == 0 else True}")
push(num)
opidx += 2
elif opc[opidx] & 0xFF == 0x40:
arg1 = pop()
arg2 = mem[arg1]
push(arg2)
print(f"push stack[{stackidx}], mem[{arg1}] = {hex(arg2)}")
opidx += 2
elif opc[opidx] & 0xFF == 0x41:
arg1 = pop()
arg2 = pop()
mem[arg1] = arg2
print(f"mov mem[{arg1}], stack[{stackidx}] = {hex(arg2)}")
opidx += 2
elif opc[opidx] & 0xFF == 0x52:
arg = pop()
if not arg == 0:
jmpaddr = opc[opidx+1] * 2
print(f"jnz to {hex(jmpaddr)}")
opidx = jmpaddr
else:
opidx += 2
print(f"jnz denied")
elif opc[opidx] & 0xFF == 0x60:
print(f"nop")
opidx += 2
elif opc[opidx] & 0xFF == 0xFF:
print(f"exit")
break
else:
print(f"unknown opc[{opidx}] = {hex(opc[opidx])}")
break
# print(opidx)
# hexprint(stack)
hexprint(mem[0x7D0:0x7D8])
hexprint(mem[0x7DA:0x7DE])
hexprint(mem[0xBB8:0xBBC] + mem[0xBC2:0xBCA])

发现是一个delta为全局变量的魔改TEA,编写同构加解密脚本:

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
def b2dle(byte_array):
return [int.from_bytes(byte_array[i:i+4], byteorder='little', signed=False) for i in range(0, len(byte_array), 4)]

def d2ble(dword_array):
byte_list = bytearray()
for dword in dword_array: byte_list.extend(dword.to_bytes(4, byteorder='little'))
return byte_list

# inp = b"12345678123456781234567812345678"
# dinp = b2dle(inp)
dinp = [0x877A62A6, 0x6A55F1F3, 0xAE194847, 0xB1E643E7, 0xA94FE881, 0x9BC8A28A, 0xC4CFAA9F, 0xF1A00CA1]

key = [0xA56BABCD, 0x00000000, 0xFFFFFFFF, 0xABCDEF01]

delta = 0x11223344
result = [0] * len(dinp)
# ttl = 0
ttl = (0 + 0x40 * delta * len(dinp)//2) & 0xFFFFFFFF
for j in range(len(dinp)//2-1, -1, -1):
m1 = dinp[2*j]
m2 = dinp[2*j+1]
# for j in range(0x40):
# m1 = (m1 + (((m2 << 3) + key[0]) ^ (m2 + ttl + key[1]) ^ ((m2 >> 4) + key[2]))) & 0xFFFFFFFF
# ttl = (ttl + delta) & 0xFFFFFFFF
# m2 = (m2 + (((m1 << 2) + key[2]) ^ (m1 + ttl + key[3]) ^ ((m1 >> 5) + key[0]))) & 0xFFFFFFFF
for i in range(0x40):
m2 = (m2 - (((m1 << 2) + key[2]) ^ (m1 + ttl + key[3]) ^ ((m1 >> 5) + key[0]))) & 0xFFFFFFFF
ttl = (ttl - delta) & 0xFFFFFFFF
m1 = (m1 - (((m2 << 3) + key[0]) ^ (m2 + ttl + key[1]) ^ ((m2 >> 4) + key[2]))) & 0xFFFFFFFF
print(hex(m1), hex(m2))
result[2*j] = m1
result[2*j+1] = m2
enc = d2ble(result)
print(enc)

L3HCTF{9c50d10ba864bedfb37d7efa4e110bf2}

obfuscate

程序中有很多类型的反调试(如ptrace,gdb,rdtsc等),此外还有大量修改了返回地址的混淆(出现在函数中,一个call之后直接call走不返回,后面的代码一般是乱码),其中经过观察发现几个关键函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__int64 __fastcall xor_dec(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
__int64 result; // rax
__int64 i; // [rsp+28h] [rbp-8h]

for ( i = 0; ; ++i )
{
result = a3;
if ( i >= a3 )
break;
*(_BYTE *)(a1 + i) ^= *(_BYTE *)(a2 + i % a4);
}
return result;
}

这个解密函数有很多xref,其中有一些如下:

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
int __fastcall sub_55555555A180(__int64 a1)
{
int n32; // [rsp+Ch] [rbp-B4h]
_BYTE dest[48]; // [rsp+10h] [rbp-B0h] BYREF
__int64 v4; // [rsp+40h] [rbp-80h]
int key3; // [rsp+4Ch] [rbp-74h] BYREF
_BYTE enc3[48]; // [rsp+50h] [rbp-70h] BYREF
int key2; // [rsp+80h] [rbp-40h] BYREF
char enc2[38]; // [rsp+86h] [rbp-3Ah] BYREF
int key1; // [rsp+ACh] [rbp-14h] BYREF
char enc1[8]; // [rsp+B0h] [rbp-10h] BYREF
__int64 v11; // [rsp+B8h] [rbp-8h]

*(_QWORD *)enc1 = 0x61C477DB26D672BDLL;
v11 = 0x41BD3F9C2FD86CACLL;
key1 = 0x41B71EFB;
xor_dec((__int64)enc1, (__int64)&key1, 16, 4);
memcpy(enc2, src_, sizeof(enc2));
key2 = 0x507ED7AB;
xor_dec((__int64)enc2, (__int64)&key2, 38, 4);
memcpy(enc3, src__0, 0x21u);
key3 = 0x46E87CCD;
xor_dec((__int64)enc3, (__int64)&key3, 33, 4);
v4 = a1;
memcpy(dest, enc3, 0x21u);
for ( n32 = 0; n32 < 32; ++n32 )
{
if ( *(unsigned __int8 *)(v4 + n32) != (unsigned __int8)dest[n32] )
{
printf(enc1);
exit(1);
}
}
return printf(enc2);
}

这个函数用于最后的比较结果,密文是1BBBA1F2E97C87218A37FD0A941A81BC401EE3AA732ED83F84B87142CC358B39,此外查询scanf的xref得到一个函数:

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
void __fastcall sub_55555555B1B3(__int64 a1, __int64 a2, __int64 a3, int a4)
{
__int64 v4; // rbp
__int64 v7; // rsi
size_t n32; // rax
int v9; // edx
__int64 v10; // rcx
__int64 v11; // r8
const char *s; // rdi

__isoc99_scanf(a1, a2, a3, a4 ^ 0x43D2469Bu);
v7 = a1 ^ a2;
__asm { rdrand eax }
LOBYTE(v7) = v7 ^ 0x2B;
n32 = strlen(*(const char **)(v4 - 200));
LOWORD(v11) = v11 - 1;
if ( n32 != 32 )
{
printf((const char *)(v4 - 15), v7, (unsigned int)(v9 - 1), v10, v11);
exit(1);
}
__asm { rdrand dx }
s = *(const char **)(v4 - 200);
strlen(s);
sub_55555555ADE5();
__asm { jmp qword ptr [rdx+rdi+50h] }
}

这是用于起始的输入,flag长度为32位,此外在程序中还发现了两个结构完整但是被间接计算混淆的函数:

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
char __fastcall sub_555555555250(__int64 count, __int64 key)
{
_DWORD *v2; // rax
_DWORD *v3; // rax
_DWORD *v4; // rax
_DWORD *v5; // rcx
_DWORD *v6; // rdx
_DWORD *v7; // rsi
_DWORD *v8; // rdi
unsigned int *v9; // rdi
unsigned int *v10; // rax
_DWORD *v11; // rsi
unsigned int *v12; // rcx
unsigned int v13; // edx
int v14; // r8d
unsigned int *v15; // rcx
unsigned int v16; // edx
int *v17; // rax
_DWORD v19[3]; // [rsp+0h] [rbp-70h] BYREF
_DWORD **v24; // [rsp+10h] [rbp-60h]
_QWORD *v25; // [rsp+18h] [rbp-58h]
_DWORD *v26; // [rsp+20h] [rbp-50h]
_DWORD *v27; // [rsp+28h] [rbp-48h]
_DWORD *v28; // [rsp+30h] [rbp-40h]
_DWORD *v29; // [rsp+38h] [rbp-38h]
_DWORD *v30; // [rsp+40h] [rbp-30h]
_DWORD *v31; // [rsp+48h] [rbp-28h]
_DWORD *v32; // [rsp+50h] [rbp-20h]
__int64 count_1; // [rsp+58h] [rbp-18h]
__int64 key_1; // [rsp+60h] [rbp-10h]

count_1 = count;
key_1 = key;
v24 = (_DWORD **)&v19[-4];
v25 = &v19[-4];
v26 = &v19[-4];
v27 = &v19[-4];
v28 = &v19[-4];
v29 = &v19[-4];
v30 = &v19[-4];
v31 = &v19[-4];
v32 = &v19[-4];
*(_QWORD *)&v19[-4] = count;
v19[1] = HIDWORD(key);
v19[0] = 0;
while ( *v29 < 4u )
{
v2 = v30;
v26[*v29] = 0;
*v2 = 0;
while ( *v30 < 4u )
{
v26[*v29] = *(unsigned __int8 *)(*v25 + (unsigned int)(*v30 + 4 * *v29)) + (v26[*v29] << 8);
++*v30;
}
++*v29;
}
v3 = v29;
**v24 = 0xB7E15163;
*v3 = 1;
while ( *v29 < 0x1Au )
{
(*v24)[*v29] = (*v24)[*v29 - 1] - 0x61C88647;
++*v29;
}
v4 = v31;
v5 = v32;
v6 = v27;
v7 = v28;
v8 = v29;
*v30 = 0;
*v8 = 0;
*v7 = 0;
*v6 = 0;
*v5 = 78;
*v4 = 0;
while ( *v31 < *v32 )
{
v9 = v30;
v10 = v28;
v11 = v26;
v12 = v27;
v13 = ((unsigned int)(*v27 + (*v24)[*v29] + *v28) >> 29) | (8 * (*v27 + (*v24)[*v29] + *v28));
(*v24)[*v29] = v13;
*v12 = v13;
v14 = (*v12 + v11[*v9] + *v10) << (*v12 + *v10);
v15 = v29;
v16 = ((*v10 + *v27 + v11[*v9]) >> (32 - (*v10 + *v27))) | v14;
v11[*v9] = v16;
*v10 = v16;
v17 = v30;
*v15 = (*v15 + 1) % 0x1A;
*v17 = ((unsigned __int8)*v17 + 1) & 3;
++*v31;
}
return 1;
}

此为KSA函数,用密钥WelcometoL3HCTF!生成了26个dword的sbox,加密函数如下:

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
int *__fastcall sub_555555555E80(_DWORD *a1, __int64 a2, _DWORD *a3)
{
_DWORD *v3; // rax
_DWORD *index; // rdi
_QWORD *sbox; // rsi
_DWORD *v6; // rcx
int v7; // r8d
_DWORD *v8; // rcx
int **v9; // rax
int *v10; // rcx
int *result; // rax
_DWORD *v12; // [rsp+0h] [rbp-40h] BYREF
int **v13; // [rsp+8h] [rbp-38h]
_DWORD *v14; // [rsp+10h] [rbp-30h]
_DWORD *v15; // [rsp+18h] [rbp-28h]
_DWORD *v16; // [rsp+20h] [rbp-20h]
_DWORD *v17; // [rsp+28h] [rbp-18h]
__int64 message_1; // [rsp+30h] [rbp-10h]
_DWORD *v19; // [rsp+38h] [rbp-8h]

v17 = a1;
v18 = a2;
v19 = a3;
v13 = &v12 - 2;
v14 = &v12 - 2;
v15 = &v12 - 2;
v16 = &v12 - 2;
*(&v12 - 2) = a1;
v12 = a3;
LODWORD(v12) = **(&v12 - 2) + *a3;
*((_DWORD *)&v12 - 4) = (*(&v12 - 2))[1] + v12[1];
*((_DWORD *)&v12 - 4) = 1;
while ( *v16 <= 0xCu )
{
v3 = v14;
index = v16;
sbox = v12;
v6 = v15;
*v14 = *(_DWORD *)(*(_QWORD *)v12 + 4LL * (unsigned int)(2 * *v16)) + __ROL4__(*v15 ^ *v14, *v15);
v7 = (*v3 ^ *v6) << *v3;
v8 = v15;
*v15 = (((unsigned int)(*v15 ^ *v3) >> (32 - *v3)) | v7) + *(_DWORD *)(*sbox + 4LL * (unsigned int)(2 * *index + 1));
*v3 ^= *v8;
++*v16;
}
v9 = v13;
v10 = v15;
**v13 = *v14;
result = *v9;
result[1] = *v10;
return result;
}

经过观察发现程序中只有这一个加密,因此逆这个加密就行,经过大量动调+合理猜测同构出加密并编写出解密脚本:

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
def b2dle(byte_array):
return [int.from_bytes(byte_array[i:i+4], byteorder='little', signed=False) for i in range(0, len(byte_array), 4)]

def d2ble(dword_array):
byte_list = bytearray()
for dword in dword_array: byte_list.extend(dword.to_bytes(4, byteorder='little'))
return byte_list

sbox = [0x122F2C9C, 0xE3BCCAE7, 0xD0FFC0F2, 0xD9A12544, 0x8A27992F,
0x55B1B935, 0x9110B161, 0x92811564, 0x5CE9B359, 0x77C79A51,
0x4265527A, 0x8AB57C4B, 0x11529FA4, 0x9D9F63FF, 0xA970B936,
0xC8EABA0D, 0x9A0EB4AA, 0xB0BC6E7F, 0x9784B100, 0x70DCD3AE,
0x6057A44E, 0x89187658, 0xE00098A8, 0x45773540, 0xF9374F1A,
0x913FA548]

def ROL4(x, shift):
return ((x << shift) | (x >> (32 - shift))) & 0xFFFFFFFF

def ROR4(x, shift):
return ((x >> shift) | (x << (32 - shift))) & 0xFFFFFFFF

inp = b"09876543"
m = b2dle(inp)
num = [(m[0] + sbox[0]) & 0xFFFFFFFF, (m[1] + sbox[1]) & 0xFFFFFFFF]
print(num)
for i in range(1, 13):
num[0] = (sbox[2*i] + ROL4(num[0] ^ num[1], num[1] & 31)) & 0xFFFFFFFF
num[1] = (sbox[2*i+1] + ROL4(num[0] ^ num[1], num[0] & 31)) & 0xFFFFFFFF
num[0] = (num[0] ^ num[1]) & 0xFFFFFFFF
print(d2ble(num).hex())
for i in range(12, 0, -1):
num[0] = (num[0] ^ num[1]) & 0xFFFFFFFF
num[1] = (ROR4((num[1] - sbox[2*i+1]) & 0xFFFFFFFF, num[0] & 31) ^ num[0]) & 0xFFFFFFFF
num[0] = (ROR4((num[0] - sbox[2*i]) & 0xFFFFFFFF, num[1] & 31) ^ num[1]) & 0xFFFFFFFF
print(num)
num = [(num[0] - sbox[0]) & 0xFFFFFFFF, (num[1] - sbox[1]) & 0xFFFFFFFF]
m = d2ble(num)
print(m)

cipher = bytearray.fromhex("1BBBA1F2E97C87218A37FD0A941A81BC401EE3AA732ED83F84B87142CC358B39")
denc = b2dle(cipher)
dres = []
for j in range(len(denc)//2):
num = [denc[2*j],denc[2*j+1]]
for i in range(12, 0, -1):
num[0] = (num[0] ^ num[1]) & 0xFFFFFFFF
num[1] = (ROR4((num[1] - sbox[2*i+1]) & 0xFFFFFFFF, num[0] & 31) ^ num[0]) & 0xFFFFFFFF
num[0] = (ROR4((num[0] - sbox[2*i]) & 0xFFFFFFFF, num[1] & 31) ^ num[1]) & 0xFFFFFFFF
num = [(num[0] - sbox[0]) & 0xFFFFFFFF, (num[1] - sbox[1]) & 0xFFFFFFFF]
dres.append(num[0])
dres.append(num[1])
print(d2ble((dres)))

L3HCTF{5fd277be39046905ef6348ba89131922}

snake

go语言,有一个反调,先对比符号表,讲所有debug相关打上断点,然后逐步调试,有一个函数sub_555980中有0x23轮循环,启动一个负责运行一大堆虚函数表的函数sub_5628C0,其中最后一轮会进入一个用两个if来触发fatal panic的函数sub_69D1C0,将上面的那个if jz改jnz,能进入主程序逻辑sub_69D220,继续深入后来到贪吃蛇逐步执行函数sub_699EA0:

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
__int64 __fastcall main_logic_start___()
{
__int64 v0; // rax
_QWORD *v1; // rbx
__int128 v2; // xmm15
__int64 v3; // rax
__int64 v4; // rdx
__int64 result; // rax
__int64 v6; // rax
char v7; // [rsp+2Bh] [rbp-55h] BYREF
__int64 v8; // [rsp+38h] [rbp-48h] BYREF
__int64 v9; // [rsp+40h] [rbp-40h]
__int64 v10; // [rsp+48h] [rbp-38h]
__int64 v11; // [rsp+50h] [rbp-30h]
char *v12; // [rsp+58h] [rbp-28h]
__int64 v13; // [rsp+60h] [rbp-20h]
__int64 v14; // [rsp+68h] [rbp-18h]
__int64 v15; // [rsp+70h] [rbp-10h]
__int64 *v16; // [rsp+78h] [rbp-8h]
__int64 v17; // [rsp+90h] [rbp+10h]
_QWORD *i; // [rsp+98h] [rbp+18h]

v17 = v0;
for ( i = v1; ; v1 = i )
{
v10 = *v1;
v9 = v1[1];
v3 = (*(__int64 (**)(void))(*(_QWORD *)v0 + 56LL))();
v14 = *((_QWORD *)&v2 + 1);
v15 = v10;
v16 = &v8;
v13 = v9;
v11 = v3;
v12 = &v7;
result = sub_564E60(0, 3, v4, 0, 0);
if ( result >= 0 )
break;
if ( (*(unsigned __int8 (**)(void))(*(_QWORD *)v17 + 64LL))() )
{
v6 = (*(__int64 (**)(void))(*(_QWORD *)v17 + 40LL))();
if ( v6 )
{
(*(void (**)(void))(v6 + 24))();
runtime_convTstring();
runtime_panic();
}
}
(*(void (**)(void))(*(_QWORD *)v17 + 48LL))();
LABEL_2:
v0 = v17;
}
if ( !result )
{
(*(void (**)(void))(*(_QWORD *)v17 + 32LL))();
goto LABEL_2;
}
if ( result != 1 )
{
(*(void (**)(void))(*(_QWORD *)v17 + 24LL))();
goto LABEL_2;
}
return result;
}

其中sub_564E60作用未知,sub_57D900则是错误退出,动态调试发现在564E60下断点时会进入57D900,此外v17+40LL指向的函数sub_69BAC0 return的sub_698D00似乎是程序的核心函数之一:

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
_UNKNOWN **__fastcall main_logic_snake__(__int64 a1, __int64 a2, __int64 a3, __int64 n2_7, __int64 *a5)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS NUMPAD "+" TO EXPAND]

n2_22 = n2_25;
v6 = sub_690360();
if ( v6 )
{
v156 = (*(__int64 (**)(void))(v6 + 24))();
v12 = (__int64 *)runtime_newobject(a1, a2);
v12[1] = 1;
if ( dword_7EAA50 )
{
v12 = (__int64 *)runtime_gcWriteBarrier1();
v13 = v156;
*v14 = v156;
}
else
{
v13 = v156;
}
*v12 = v13;
return &off_703B98;
}
else
{
v7 = n2_25 - sub_69B820();
n10_3 = v7 + ((unsigned __int64)v7 >> 63);
n10_12 = sub_6889E0();
v9 = ((__int64 (*)(void))runtime_slicebytetostring)();
v157 = v9;
n10_7 = n10_12;
n2 = v7 / 2;
for ( n10_13 = 0; n10_12 > n10_13; n10_13 = n10_3 )
{
n2_21 = n2;
v16 = *(unsigned __int8 *)(v9 + n10_13);
if ( *(unsigned __int8 *)(v9 + n10_13) >= 0x80u )
{
v18 = runtime_decoderune();
n2 = n2_21;
v16 = v18;
n10_14 = n10_12;
}
else
{
n10_14 = n10_13 + 1;
}
n10_3 = n10_14;
if ( n2 >= 0 && n2 < n2_0 && ::n2_1 > 1 )
{
v19 = n2 + n2_0;
if ( qword_7A5078 <= (unsigned __int64)(n2 + n2_0) )
runtime_panicIndex(v19, v16, n10_14, qword_7A5078);
v20 = qword_7A5070;
v21 = 3 * v19;
*(_DWORD *)(qword_7A5070 + 8 * v21) = v16;
*(_QWORD *)(v20 + 8 * v21 + 8) = 8;
*(_QWORD *)(v20 + 8 * v21 + 16) = 1;
}
n2 = sub_68A720() + n2_21;
v9 = v157;
n10_12 = n10_7;
}
v142 = 0;
v143 = 0;
n2_1 = 2;
n94 = 94;
v24 = 0;
n9 = 9;
v26 = &v142;
i_1 = 0;
while ( n2_1 != 3 )
{
n2_2 = n2_1;
n94_2 = n94 ^ (v24 * n2_1);
n94_3 = n94_2;
v151 = v24;
switch ( n2_2 )
{
case 0LL:
i_2 = i_1 + 1;
if ( n9 < i_1 + 1 )
{
runtime_growslice();
v24 = v151;
i_2 = i_1 + 1;
v26 = v32;
n9 = n9_1;
n94_2 = n94_3;
}
*((_BYTE *)v26 + i_2 - 1) = 10;
n5 = 5;
break;
case 1LL:
i_2 = i_1 + 1;
if ( n9 < i_1 + 1 )
{
runtime_growslice();
v24 = v151;
i_2 = i_1 + 1;
v26 = v35;
n9 = n9_2;
n94_2 = n94_3;
}
*((_BYTE *)v26 + i_2 - 1) = 21;
n5 = 4;
break;
case 2LL:
i_2 = i_1 + 1;
if ( n9 < i_1 + 1 )
{
runtime_growslice();
v24 = v151;
i_2 = i_1 + 1;
v26 = v37;
n9 = n9_3;
n94_2 = n94_3;
}
*((_BYTE *)v26 + i_2 - 1) = 37;
n5 = 9;
break;
case 4LL:
i_2 = i_1 + 1;
if ( n9 < i_1 + 1 )
{
runtime_growslice();
v24 = v151;
i_2 = i_1 + 1;
v26 = v39;
n9 = n9_4;
n94_2 = n94_3;
}
*((_BYTE *)v26 + i_2 - 1) = 119;
n5 = 6;
break;
case 5LL:
i_2 = i_1 + 1;
if ( n9 < i_1 + 1 )
{
runtime_growslice();
v24 = v151;
i_2 = i_1 + 1;
v26 = v41;
n9 = n9_5;
n94_2 = n94_3;
}
*((_BYTE *)v26 + i_2 - 1) = 51;
n5 = 7;
break;
case 6LL:
for ( i = 0; i < i_1; ++i )
*((_BYTE *)v26 + i) ^= (unsigned __int8)n94_2 ^ (unsigned __int8)i;
n5 = 3;
i_2 = i_1;
break;
case 7LL:
i_2 = i_1 + 1;
if ( n9 < i_1 + 1 )
{
runtime_growslice();
v24 = v151;
i_2 = i_1 + 1;
v26 = v44;
n9 = n9_6;
n94_2 = n94_3;
}
*((_BYTE *)v26 + i_2 - 1) = 33;
n5 = 8;
break;
case 8LL:
i_2 = i_1 + 1;
if ( n9 < i_1 + 1 )
{
runtime_growslice();
v24 = v151;
i_2 = i_1 + 1;
v26 = v46;
n9 = n9_7;
n94_2 = n94_3;
}
*((_BYTE *)v26 + i_2 - 1) = 46;
n5 = 1;
break;
case 9LL:
i_2 = i_1 + 1;
if ( n9 < i_1 + 1 )
{
runtime_growslice();
v24 = v151;
i_2 = i_1 + 1;
v26 = v48;
n9 = n9_8;
n94_2 = n94_3;
}
*((_BYTE *)v26 + i_2 - 1) = 117;
n5 = 0;
break;
default:
n5 = n2_2;
i_2 = i_1;
break;
}
++v24;
i_1 = i_2;
n94_1 = n94_2;
n2_1 = n5;
n94 = n94_1;
}
((void (*)(void))runtime_slicebytetostring)();
n10_15 = sub_6889E0();
v51 = ((__int64 (*)(void))runtime_slicebytetostring)();
v157 = v51;
n10_3 = n10_15;
n10_16 = 0;
n2_3 = 2;
while ( 1 )
{
n2_4 = n2_3;
if ( n10_15 <= n10_16 )
break;
v54 = *(unsigned __int8 *)(v51 + n10_16);
if ( *(unsigned __int8 *)(v51 + n10_16) >= 0x80u )
{
v56 = runtime_decoderune();
n2_3 = n2_4;
v54 = v56;
n10_17 = n10_15;
}
else
{
n10_17 = n10_16 + 1;
}
n10_7 = n10_17;
if ( n2_3 >= 0 && n2_3 < n2_0 && ::n2_1 > 2 )
{
v57 = n2_3 + 2 * n2_0;
if ( qword_7A5078 <= v57 )
runtime_panicIndex(n10_17, v54, n2_3, qword_7A5078);
v58 = qword_7A5070;
v59 = 3 * v57;
*(_DWORD *)(qword_7A5070 + 8 * v59) = v54;
*(_QWORD *)(v58 + 8 * v59 + 8) = 8;
*(_QWORD *)(v58 + 8 * v59 + 16) = 1;
}
n2_3 = n2_4 + sub_68A720();
v51 = v157;
n10_15 = n10_3;
n10_16 = n10_7;
}
n10 = 10;
v61 = sub_64D1A0();
v155 = v61;
n10_1 = 10;
n2_5 = n2_4;
for ( n10_4 = 0; n10 > n10_4; n10_4 = n10_3 )
{
n2_4 = n2_5;
v64 = *(unsigned __int8 *)(v61 + n10_4);
if ( *(unsigned __int8 *)(v61 + n10_4) >= 0x80u )
{
v66 = runtime_decoderune();
n2_5 = n2_4;
v64 = v66;
n10_2 = n10;
}
else
{
n10_2 = n10_4 + 1;
}
n10_3 = n10_2;
if ( n2_5 >= 0 && n2_5 < n2_0 && ::n2_1 > 2 )
{
v67 = n2_5 + 2 * n2_0;
if ( qword_7A5078 <= v67 )
runtime_panicIndex(v67, v64, n10_2, qword_7A5078);
v68 = qword_7A5070;
v69 = 3 * v67;
*(_DWORD *)(qword_7A5070 + 8 * v69) = v64;
*(_QWORD *)(v68 + 8 * v69 + 8) = 8;
*(_QWORD *)(v68 + 8 * v69 + 16) = 1;
}
n2_5 = sub_68A720() + n2_4;
v61 = v155;
n10 = n10_1;
}
Use_WASD_to_move_press_ESC_to_exit[0] = 0x2064ED94C44ECB56LL;
Use_WASD_to_move_press_ESC_to_exit[1] = 0x6158CFB11513023LL;
Use_WASD_to_move_press_ESC_to_exit[2] = 0x677753C8D84DFB13LL;
Use_WASD_to_move_press_ESC_to_exit[3] = 0xE99D00EA857B0163LL;
Use_WASD_to_move_press_ESC_to_exit[4] = 0x7652484911E8C40CLL;
Use_WASD_to_move_press_ESC_to_exit[5] = 0xDD76584BFCF3F616LL;
v133[0] = 0x122C;
*(_QWORD *)&v133[1] = 0x2A1E011B0707041FLL;
v134 = 0x1D050108280C0B1ALL;
v135 = 0x1C2A2E20190D200BLL;
v136 = 0x2023112F080E040FLL;
v137 = 0x121423291F221214LL;
v138 = 0x1B102119132C032BLL;
for ( n25 = 0; n25 < 25; ++n25 )
{
key = LOBYTE(v133[n25]);
key2 = HIBYTE(v133[n25]);
v73 = (unsigned int)(n25 * 2) + ((unsigned int)key ^ (unsigned int)key2);
if ( key >= 0x30 )
runtime_panicIndex(key2, v73, key, 48);
v74 = *((_BYTE *)Use_WASD_to_move_press_ESC_to_exit + key) + n25 * 2 + (key ^ key2) + 30;
if ( key2 >= 0x30 )
runtime_panicIndex(key2, v73, key, 48);
*((_BYTE *)Use_WASD_to_move_press_ESC_to_exit + key) = *((_BYTE *)Use_WASD_to_move_press_ESC_to_exit + key2)
+ n25 * 2
+ (key ^ key2)
+ 30;
*((_BYTE *)Use_WASD_to_move_press_ESC_to_exit + key2) = v74;
}
v75 = ((__int64 (*)(void))runtime_slicebytetostring)();
n10_18 = sub_6889E0();
v150 = v75;
n10_5 = n10_18;
v78 = ((__int64 (*)(void))runtime_slicebytetostring)();
v157 = v78;
n10_3 = n10_5;
n2_9 = n2_22;
n2_6 = n2_22 - v150 - 2;
for ( n10_8 = 0; n10_5 > n10_8; n10_8 = n10_7 )
{
n2_23 = n2_6;
v82 = *(unsigned __int8 *)(n10_8 + v78);
if ( *(unsigned __int8 *)(n10_8 + v78) >= 0x80u )
{
v84 = runtime_decoderune();
n2_6 = n2_23;
n2_9 = n2_22;
v82 = v84;
n10_6 = n10_5;
}
else
{
n10_6 = n10_8 + 1;
}
n10_7 = n10_6;
if ( n2_6 >= 0 && n2_6 < n2_0 && ::n2_1 > 2 )
{
v85 = n2_6 + 2 * n2_0;
if ( qword_7A5078 <= v85 )
runtime_panicIndex(n2_9, v82, n2_6, qword_7A5078);
v86 = qword_7A5070;
v87 = 3 * v85;
*(_DWORD *)(qword_7A5070 + 8 * v87) = v82;
*(_QWORD *)(v86 + 8 * v87 + 8) = 8;
*(_QWORD *)(v86 + 8 * v87 + 16) = 1;
}
n2_6 = n2_23 + sub_68A720();
v78 = v157;
n10_5 = n10_3;
n2_9 = n2_22;
}
for ( n2_8 = 0; n2_9 >= n2_8; ++n2_8 )
{
v89 = n2_8 < 0;
if ( n2_8 >= 0 )
{
if ( n2_8 < n2_0 )
{
if ( ::n2_1 > 3 )
{
v90 = n2_8 + 3 * n2_0;
if ( qword_7A5078 <= v90 )
runtime_panicIndex(n2_9, v90, n2_7, qword_7A5078);
v91 = qword_7A5070 + 24 * v90;
*(_DWORD *)v91 = 45;
*(_QWORD *)(v91 + 8) = 8;
*(_QWORD *)(v91 + 16) = 1;
v89 = n2_8 < 0;
}
else
{
v89 = n2_8 < 0;
}
}
else
{
v89 = n2_8 < 0;
}
}
if ( !v89 && n2_8 < n2_0 && n2_7 >= 0 && ::n2_1 > n2_7 )
{
v92 = n2_8 + n2_7 * n2_0;
if ( qword_7A5078 <= v92 )
runtime_panicIndex(n2_9, v92, n2_7, qword_7A5078);
v93 = qword_7A5070 + 24 * v92;
*(_DWORD *)v93 = 45;
*(_QWORD *)(v93 + 8) = 8;
*(_QWORD *)(v93 + 16) = 1;
}
}
for ( n2_10 = 0; n2_7 >= n2_10; ++n2_10 )
{
if ( n2_0 > 0 && n2_10 >= 0 && ::n2_1 > n2_10 )
{
v95 = n2_10 * n2_0;
if ( qword_7A5078 <= (unsigned __int64)(n2_10 * n2_0) )
runtime_panicIndex(n2_9, v95, n2_7, qword_7A5078);
v96 = qword_7A5070 + 24 * v95;
*(_DWORD *)v96 = 124;
*(_QWORD *)(v96 + 8) = 8;
*(_QWORD *)(v96 + 16) = 1;
}
if ( n2_9 >= 0 && n2_9 < n2_0 && n2_10 >= 0 && ::n2_1 > n2_10 )
{
v97 = n2_9 + n2_10 * n2_0;
if ( qword_7A5078 <= v97 )
runtime_panicIndex(n2_9, v97, n2_7, qword_7A5078);
v98 = qword_7A5070 + 24 * v97;
*(_DWORD *)v98 = 124;
*(_QWORD *)(v98 + 8) = 8;
*(_QWORD *)(v98 + 16) = 1;
}
}
v99 = *(_QWORD *)(a1 + 8);
if ( !v99 )
runtime_panicIndex(n2_9, a1, n2_7, 0);
v100 = 16 * (v99 - 1);
v101 = *(__int64 **)a1;
n2_19 = *(_QWORD *)(*(_QWORD *)a1 + v100);
n2_20 = *(_QWORD *)(*(_QWORD *)a1 + v100 + 8);
if ( n2_9 > n2_19 && n2_7 > n2_20 && n2_19 > 0 && n2_20 > 3 )
{
while ( v99 > 0 )
{
n2_11 = *v101;
if ( *v101 >= 0 && n2_0 > n2_11 )
{
n2_9 = v101[1];
if ( n2_9 >= 0 && ::n2_1 > n2_9 )
{
v106 = n2_0 * n2_9;
v107 = v106 + n2_11;
if ( qword_7A5078 <= v107 )
runtime_panicIndex(v106, a1, v107, qword_7A5078);
n2_9 = qword_7A5070 + 24 * v107;
*(_DWORD *)n2_9 = 42;
*(_QWORD *)(n2_9 + 8) = 8;
*(_QWORD *)(n2_9 + 16) = 1;
}
}
v101 += 2;
--v99;
}
v108 = *(_QWORD *)(a1 + 8);
v109 = v108 - 1;
if ( !v108 )
runtime_panicIndex(n2_9, a1, v109, 0);
v110 = 16 * v109;
n2_12 = *(_QWORD *)(*(_QWORD *)a1 + v110);
n2_13 = *(_QWORD *)(*(_QWORD *)a1 + v110 + 8);
if ( n2_12 >= 0 && n2_0 > n2_12 && n2_13 >= 0 && ::n2_1 > n2_13 )
{
v113 = n2_13 * n2_0 + n2_12;
if ( qword_7A5078 <= v113 )
runtime_panicIndex(n2_9, n2_12, n2_13, qword_7A5078);
v114 = qword_7A5070 + 24 * v113;
*(_DWORD *)v114 = 43;
*(_QWORD *)(v114 + 8) = 2;
*(_QWORD *)(v114 + 16) = 1;
}
n2_15 = *a5;
if ( *a5 >= 0 && n2_0 > n2_15 )
{
n2_14 = a5[1];
if ( n2_14 >= 0 && ::n2_1 > n2_14 )
{
if ( qword_7A5078 <= (unsigned __int64)(n2_15 + n2_14 * n2_0) )
runtime_panicIndex(n2_9, n2_14 * n2_0, n2_14, qword_7A5078);
v117 = qword_7A5070 + 24 * (n2_15 + n2_14 * n2_0);
*(_DWORD *)v117 = 64;
*(_QWORD *)(v117 + 8) = 4;
*(_QWORD *)(v117 + 16) = 1;
}
}
}
else
{
you_are_dead[0] = 0x867FD350;
*(_QWORD *)&you_are_dead[1] = 0x354BD87344587730LL;
you_are_dead_1 = 0xEB01D8B264B96984LL;
for ( n20 = 0; n20 < 20; ++n20 )
*((_BYTE *)you_are_dead + n20) ^= byte_6D7BA9[n20];
v118 = ((__int64 (*)(void))runtime_slicebytetostring)();
n10_19 = sub_6889E0();
v152 = v118;
n10_9 = n10_19;
v121 = ((__int64 (*)(void))runtime_slicebytetostring)();
v157 = v121;
n10_3 = n10_9;
n2_18 = (n2_22 - v152) / 2;
n2_16 = n2_7;
for ( n10_10 = 0; n10_9 > n10_10; n10_10 = n10_7 )
{
n2_24 = n2_18;
v125 = *(unsigned __int8 *)(n10_10 + v121);
if ( *(unsigned __int8 *)(n10_10 + v121) >= 0x80u )
{
v127 = runtime_decoderune();
n2_18 = n2_24;
n2_16 = n2_7;
v125 = v127;
n10_11 = n10_9;
}
else
{
n10_11 = n10_10 + 1;
}
n10_7 = n10_11;
v128 = n2_16 + (n2_16 >> 63);
if ( n2_18 >= 0 && n2_18 < n2_0 )
{
n2_17 = v128 >> 1;
if ( n2_17 >= 0 && ::n2_1 > n2_17 )
{
v130 = n2_18 + n2_0 * n2_17;
if ( qword_7A5078 <= v130 )
runtime_panicIndex(v125, v130, n2_18, qword_7A5078);
v131 = qword_7A5070;
v132 = 3 * v130;
*(_DWORD *)(qword_7A5070 + 8 * v132) = v125;
*(_QWORD *)(v131 + 8 * v132 + 8) = 2;
*(_QWORD *)(v131 + 8 * v132 + 16) = 1;
}
}
n2_18 = n2_24 + sub_68A720();
v121 = v157;
n10_9 = n10_3;
n2_16 = n2_7;
}
runtime_chansend1();
}
return (_UNKNOWN **)main_logic_snake_print();
}
}

其中的文本自解密得到的就是关卡中的文本(包括提示、score字符串和dead提示等),最后return的sub_6900A0 return的sub_6909A0中的syscall_Syscall6则用于打印:

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
_UNKNOWN **__fastcall main_logic_snake_print_(__int64 a1, __int16 a2, __int64 a3, __int64 a4, __int16 a5, __int16 a6)
{
__int64 v6; // rax
__int64 v7; // rbx
__int16 v8; // r10
__int64 v9; // rcx
__int64 v12; // [rsp+20h] [rbp+8h]

LOWORD(dword_7EA818) = a6 - a2 + 1;
HIWORD(dword_7EA818) = v8 - a5 + 1;
word_7EA9F0 = a2;
word_7EA9F2 = a5;
word_7EA9F4 = a6;
word_7EA9F6 = v8;
if ( !a4 )
LABEL_10:
runtime_panicIndex();
v12 = v6;
if ( syscall__ptr_LazyProc_Find() )
{
runtime_gopanic();
goto LABEL_10;
}
if ( syscall_Syscall6(v7, dword_7EA818, (unsigned int)dword_7EA818, v12, dword_7EA814, &word_7EA9F0) )
return 0;
if ( v9 )
runtime_convT64();
return &off_703B38;
}

由于打印时会打印当前得分,因此可以由此寻找score存储的位置,但是进入之后发现score值0已经被硬编码在字符串中,因此需要关注score数据是如何被整合的,在sub_69BAC0中找到游戏逻辑:

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
_UNKNOWN **__fastcall main_logic_snake_()
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS NUMPAD "+" TO EXPAND]

v69 = v0;
map_size = *(_QWORD *)(v0 + 8);
map_size_1 = map_size;
*(_QWORD *)(map_size + 16) = 50;
*(_QWORD *)(map_size + 24) = 20;
sub_162B80();
v2 = sub_162B00();
map_size_2 = map_size_1;
v4 = *(_QWORD *)(map_size_1 + 64);
if ( v4 )
{
if ( v2 - v4 > 80 )
{
sub_21C160();
return (_UNKNOWN **)unknown_libname_41();
}
*(_QWORD *)(map_size_1 + 64) = v2;
}
else
{
*(_QWORD *)(map_size_1 + 64) = v2;
}
snake_Struct_4 = *(__int64 **)map_size_2;
snake_Struct_2 = snake_Struct_4;
if ( !snake_Struct_4[1] )
{
v6 = (_QWORD *)*snake_Struct_4;
v7 = *(_QWORD *)(map_size_2 + 24);
if ( !snake_Struct_4[2] )
{
v66 = *(_QWORD *)(map_size_2 + 24);
runtime_growslice();
snake_Struct_4 = snake_Struct_2;
snake_Struct_2[2] = v8;
if ( dword_36AA50 )
{
v6 = (_QWORD *)runtime_gcWriteBarrier2();
*v9 = v6;
v9[1] = *snake_Struct_4;
}
*snake_Struct_4 = (__int64)v6;
map_size_2 = map_size_1;
v7 = v66;
}
snake_Struct_4[1] = 1;
*v6 = 5;
v6[1] = v7 - 2;
v10 = snake_Struct_4[1] + 1;
v11 = *snake_Struct_4;
v12 = *(_QWORD *)(map_size_2 + 24);
if ( snake_Struct_4[2] < v10 )
{
v66 = *(_QWORD *)(map_size_2 + 24);
runtime_growslice();
snake_Struct_4 = snake_Struct_2;
snake_Struct_2[2] = v13;
if ( dword_36AA50 )
{
v11 = runtime_gcWriteBarrier2();
*v14 = v11;
v14[1] = *snake_Struct_4;
}
*snake_Struct_4 = v11;
map_size_2 = map_size_1;
v12 = v66;
}
snake_Struct_4[1] = v10;
v15 = 16 * (v10 - 1);
*(_QWORD *)(v11 + v15) = 5;
*(_QWORD *)(v11 + v15 + 8) = v12 - 3;
snake_Struct_4[4] = 1;
}
snake_Struct_4[3] = *(_QWORD *)(*(_QWORD *)v69 + 16LL);
v16 = sub_104694(sbox);
v18 = *(_QWORD *)(map_size_2 + 64);
for ( n256 = 0; n256 < 256; ++n256 )
sbox[n256] = n256;
idx_1 = *(_QWORD *)(map_size_2 + 32);
idx = 0;
v23 = 0;
v24 = 0;
while ( idx < 256 )
{
v27 = (unsigned __int8)sbox[idx];
if ( idx_1 >= 0x100 )
runtime_panicIndex(v24, map_size_2, snake_Struct, 256);
idx2 = (__int64)(v27 + idx_1 + (unsigned __int8)sbox[idx_1]) % 256;
if ( idx2 >= 0x100 )
runtime_panicIndex(v24, map_size_2, snake_Struct, 256);
sbox[idx] = sbox[idx2];
sbox[idx2] = v27;
chk = (v18 + v24) % 256;
if ( chk >= 0x100 )
runtime_panicIndex(v24, map_size_2, snake_Struct, 256);
v30 = *(_QWORD *)(map_size_2 + 16);
if ( v30 == 1 )
runtime_panicdivide();
v31 = v16;
snake_Struct_1 = snake_Struct;
v33 = (unsigned __int8)sbox[(unsigned __int8)sbox[chk]] % (v30 - 1);
v34 = v18 + v33 - ((v18 + v33 + ((unsigned __int64)((v18 + v33 + 1) >> 63) >> 56) + 1) & 0xFFFFFFFFFFFFFF00LL);
if ( v34 + 1 >= 0x100 )
runtime_panicIndex(snake_Struct_1, map_size_2, v33, 256);
n4 = *(_QWORD *)(map_size_2 + 24);
if ( n4 == 4 )
runtime_panicdivide();
++idx;
v25 = v33 + 1;
v26 = (unsigned __int8)sbox[(unsigned __int8)sbox[v34 + 1]] % (n4 - 4) + 4;
v16 = v31;
snake_Struct = snake_Struct_1;
idx_1 = idx2;
v23 = v25;
v24 = v26;
}
v36 = *(_QWORD *)(map_size_2 + 64);
if ( v36 - *(_QWORD *)(map_size_2 + 72) > 800 )
{
*(_QWORD *)(map_size_2 + 72) = v36;
**(_QWORD **)(map_size_2 + 8) = v23;
*(_QWORD *)(*(_QWORD *)(map_size_2 + 8) + 8LL) = v24;
}
v37 = snake_Struct[1];
if ( !v37 )
runtime_panicIndex(v24, map_size_2, snake_Struct, 0);
v38 = 16 * (v37 - 1);
inp = snake_Struct[3];
snake_head_x = *(_QWORD *)(*snake_Struct + v38);
snake_head_y = *(_QWORD *)(*snake_Struct + v38 + 8);
if ( inp > 2 )
{
if ( inp == 3 )
{
--snake_head_y;
}
else if ( inp == 4 )
{
++snake_head_y;
}
}
else if ( inp == 1 )
{
++snake_head_x;
}
else if ( inp == 2 )
{
--snake_head_x;
}
if ( *(_QWORD *)(map_size_2 + 16) > snake_head_x
|| *(_QWORD *)(map_size_2 + 24) > snake_head_y
|| snake_head_x > 0
|| snake_head_y > 3 )
{
food_coord = *(_QWORD **)(map_size_2 + 8);
if ( *food_coord == snake_head_x && food_coord[1] == snake_head_y )
{
++snake_Struct[4];
n0x100_3 = *(_QWORD *)(map_size_2 + 32) + 1LL;
*(_QWORD *)(map_size_2 + 32) = n0x100_3;
for ( n256_2 = 0; n256_2 < 256; ++n256_2 )
sbox[n256_2] = n256_2;
for ( n256_3 = 0; n256_3 < 256; ++n256_3 )
{
v60 = (unsigned __int8)sbox[n256_3];
if ( n0x100_3 >= 0x100 )
runtime_panicIndex(v24, map_size_2, snake_Struct, 256);
n0x100_4 = (__int64)(v60 + n0x100_3 + (unsigned __int8)sbox[n0x100_3]) % 256;
if ( n0x100_4 >= 0x100 )
runtime_panicIndex(v24, map_size_2, snake_Struct, 256);
sbox[n256_3] = sbox[n0x100_4];
sbox[n0x100_4] = v60;
n0x100_3 = n0x100_4;
}
for ( i = 0; *(_QWORD *)(map_size_2 + 48) > i; ++i )
*(_BYTE *)(*(_QWORD *)(map_size_2 + 40) + i) = sbox[*(unsigned __int8 *)(*(_QWORD *)(map_size_2 + 40) + i)];
}
n3_1 = snake_head_y;
snake_head_x_1 = snake_head_x;
v45 = snake_Struct[1];
v46 = *snake_Struct;
v47 = snake_Struct[2];
if ( snake_Struct[4] <= (signed __int64)v45 )
{
if ( !v45 )
runtime_panicSliceB();
v54 = v47 - 1;
v55 = ((-(__int64)v54 >> 63) & 0x10) + v46;
if ( v45 > v54 )
{
runtime_growslice();
snake_Struct = snake_Struct_2;
map_size_2 = map_size_1;
snake_head_y = n3_1;
snake_head_x = snake_head_x_1;
v55 = v56;
}
v57 = 16 * (v45 - 1);
*(_QWORD *)(v55 + v57) = snake_head_x;
*(_QWORD *)(v55 + v57 + 8) = snake_head_y;
snake_Struct[1] = v45;
snake_Struct[2] = v54;
if ( dword_36AA50 )
{
runtime_gcWriteBarrier2();
*v58 = v55;
v58[1] = *snake_Struct;
}
*snake_Struct = v55;
}
else
{
v48 = v45 + 1;
if ( v47 < v48 )
{
runtime_growslice();
snake_Struct_3 = snake_Struct_2;
snake_Struct_2[2] = v51;
if ( dword_36AA50 )
{
v49 = runtime_gcWriteBarrier2();
*v52 = v49;
v52[1] = *snake_Struct_3;
}
*snake_Struct_3 = v49;
snake_Struct = snake_Struct_3;
map_size_2 = map_size_1;
snake_head_y = n3_1;
snake_head_x = snake_head_x_1;
v46 = v49;
}
snake_Struct[1] = v48;
v53 = 16 * (v48 - 1);
*(_QWORD *)(v46 + v53) = snake_head_x;
*(_QWORD *)(v46 + v53 + 8) = snake_head_y;
}
}
return main_logic_snake__(
(__int64)snake_Struct,
map_size_2 + 32,
(__int64)snake_Struct,
*(_QWORD *)(map_size_2 + 24),
*(__int64 **)(map_size_2 + 8));
}

创建了一个贪吃蛇的结构体,其中包含蛇的坐标子结构体、食物坐标、地图大小、得分等,尝试直接改得分发现没用,因此可以间接修改,将源代码中这一行:

1
if ( *food_coord == snake_head_x && food_coord[1] == snake_head_y )

修改为:

1
if ( *food_coord != snake_head_x && food_coord[1] != snake_head_y )

此时每前进一步都能加分,为了更稳定,可以修改:

1
2
3
4
5
6
if ( v6 )
{
(*(void (**)(void))(v6 + 24))();
runtime_convTstring();
runtime_panic();
}

这里的if为jo(溢出才跳转),从而删掉panic逻辑,此时只要在调试状态下不撞墙,哪怕撞到自身,只要能达到100分就会弹出flag.

L3HCTF{ad4d5916-9697-4219-af06-014959c2f4c9}