古剑山三解

1签到题

DIE查壳

IDA打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // ebx
unsigned int v4; // eax
_DWORD v6[11]; // [rsp+20h] [rbp-60h]
int v7; // [rsp+4Ch] [rbp-34h] BYREF
char Destination[48]; // [rsp+50h] [rbp-30h] BYREF
char flag_do_you_find_it_?__[36]; // [rsp+80h] [rbp+0h] BYREF
int v10; // [rsp+A4h] [rbp+24h]
int *v11; // [rsp+A8h] [rbp+28h]
int v12; // [rsp+B4h] [rbp+34h]
char *Source; // [rsp+B8h] [rbp+38h]
int n32; // [rsp+C4h] [rbp+44h]
char *Str; // [rsp+C8h] [rbp+48h]
int v16; // [rsp+D4h] [rbp+54h]
int v17; // [rsp+D8h] [rbp+58h]
unsigned int i; // [rsp+DCh] [rbp+5Ch]

_main();
Str = (char *)malloc(0x21u);
strcpy(flag_do_you_find_it_?__, "flag{do_you_find_it_?}");
printf("plz input:");
scanf("%s", Str);
n32 = strlen(Str);
if ( n32 != 32 )
printf("Wrong..");
putchar(10);
Source = (char *)first(Str);
strcpy(Destination, Source);
v3 = strlen(flag_do_you_find_it_?__);
v4 = strlen(Destination);
crypt(Destination, v4, flag_do_you_find_it_?__, v3);
v7 = 0;
v12 = -1872737962;
v6[0] = -56045301;
v6[1] = 1126325548;
v6[2] = 1037697210;
v6[3] = 2123048962;
v6[4] = 1640073719;
v6[5] = -454381817;
v6[6] = -2146442625;
v6[7] = -691840689;
v6[8] = 1448341866;
v6[9] = 586039113;
v6[10] = -1321770811;
v17 = 1;
v16 = 0;
for ( i = 0; i < strlen(Destination); i += 4 )
{
v11 = &v7;
LOBYTE(v7) = Destination[i];
BYTE1(v7) = Destination[i + 1];
BYTE2(v7) = Destination[i + 2];
HIBYTE(v7) = Destination[i + 3];
v7 ^= v12;
v10 = v7;
if ( v7 > 0 )
v7 ^= 0x22222222u;
if ( v6[v16] != v7 )
{
v17 = 0;
printf("Wrong");
break;
}
++v16;
}
if ( v17 == 1 )
printf("Success!");
system("pause");
return 0;
}
```看第一个first
```c
_BYTE *__fastcall first(const char *Str)
{
_BYTE *v2; // [rsp+28h] [rbp-28h]
int v3; // [rsp+34h] [rbp-1Ch]
int v4; // [rsp+44h] [rbp-Ch]
int v5; // [rsp+48h] [rbp-8h]
int v6; // [rsp+4Ch] [rbp-4h]

v3 = strlen(Str);
if ( v3 % 3 )
v6 = 4 * (v3 / 3 + 1);
else
v6 = 4 * (v3 / 3);
v2 = malloc(v6 + 1LL);
v2[v6] = 0;
v5 = 0;
v4 = 0;
while ( v6 - 2 > v5 )
{
v2[v5] = aAbcdefghijklmn[(unsigned __int8)Str[v4] >> 2];
v2[v5 + 1] = aAbcdefghijklmn[(16 * (Str[v4] & 3)) | ((unsigned __int8)Str[v4 + 1] >> 4)];
v2[v5 + 2] = aAbcdefghijklmn[(4 * (Str[v4 + 1] & 0xF)) | ((unsigned __int8)Str[v4 + 2] >> 6)];
v2[v5 + 3] = aAbcdefghijklmn[Str[v4 + 2] & 0x3F];
v4 += 3;
v5 += 4;
}
if ( v3 % 3 == 1 )
{
v2[v5 - 2] = 61;
v2[v5 - 1] = 61;
}
else if ( v3 % 3 == 2 )
{
v2[v5 - 1] = 61;
}
return v2;
}

很明显是base64的加密
下面的

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
__int64 __fastcall crypt(__int64 p_Destination, unsigned int a2, __int64 flag_do_you_find_it_?_, unsigned int a4)
{
__int64 result; // rax
_BYTE v5[271]; // [rsp+20h] [rbp-60h] BYREF
char v6; // [rsp+12Fh] [rbp+AFh]
int v7; // [rsp+130h] [rbp+B0h]
unsigned int i; // [rsp+134h] [rbp+B4h]
int v9; // [rsp+138h] [rbp+B8h]
int v10; // [rsp+13Ch] [rbp+BCh]

init1(v5, flag_do_you_find_it_?_, a4);
v10 = 0;
v9 = 0;
v7 = 0;
for ( i = 0; ; ++i )
{
result = i;
if ( i >= a2 )
break;
v10 = (unsigned __int8)(v10 + 1);
v9 = (unsigned __int8)(v5[v10] + v9);
v6 = v5[v10];
v5[v10] = v5[v9];
v5[v9] = v6;
v7 = (unsigned __int8)(v5[v10] + v5[v9]);
*(_BYTE *)(p_Destination + i) = *(_BYTE *)(i + p_Destination) ^ v5[v7];
}
return result;
}

标准的RC4加密
那么写解密脚本是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
import itertools
import base64

def rc4_init(key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
return S
def rc4_keystream(S, length):
i = 0
j = 0
keystream = []
for _ in range(length):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
keystream.append(k)
return keystream
def main():
v12 = -1872737962
v6 = [
-56045301,
1126325548,
1037697210,
2123048962,
1640073719,
-454381817,
-2146442625,
-691840689,
1448341866,
586039113,
-1321770811
]
v12_u = v12 & 0xFFFFFFFF
v6_u = [x & 0xFFFFFFFF for x in v6]
candidates = []
for v in v6_u:
X1 = v
X2 = v ^ 0x22222222
D1 = X1 ^ v12_u
D2 = X2 ^ v12_u
bytes1 = bytes([D1 & 0xFF, (D1 >> 8) & 0xFF, (D1 >> 16) & 0xFF, (D1 >> 24) & 0xFF])
bytes2 = bytes([D2 & 0xFF, (D2 >> 8) & 0xFF, (D2 >> 16) & 0xFF, (D2 >> 24) & 0xFF])
candidates.append((bytes1, bytes2))
key_str = "flag{do_you_find_it_?}"
key_bytes = key_str.encode()
choices = list(itertools.product([0, 1], repeat=len(candidates)))
for choice in choices:
E = b''
for i, idx in enumerate(choice):
E += candidates[i][idx]
S_box = rc4_init(key_bytes)
keystream = rc4_keystream(S_box, len(E))
plain = bytes([E[i] ^ keystream[i] for i in range(len(E))])
try:
decoded = base64.b64decode(plain)
if len(decoded) == 32:
try:
decoded_str = decoded.decode('ascii')
if decoded_str.isprintable():
print("Found valid input:", decoded_str)
return
except UnicodeDecodeError:
continue
except Exception:
continue
print("No valid input found.")
if __name__ == '__main__':
main()

helloworld

DIE查壳

IDA打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
int __cdecl main(int argc, const char **argv, const char **envp)
{
const char *v3; // ebx
unsigned int Seed; // eax
int n100; // esi
Stream *Stream; // eax
unsigned int v7; // edi
unsigned int v8; // ecx
unsigned int v9; // esi
int v10; // eax
char *v11; // edx
unsigned int v12; // eax
unsigned int v13; // ecx
unsigned int n3; // eax
unsigned int v15; // eax
unsigned int v16; // eax
unsigned int v17; // eax
char v18; // al
char v19; // dl
char v20; // dl
char v21; // dl
int v22; // eax
int v24; // [esp-4h] [ebp-A8h]
unsigned int v25; // [esp+14h] [ebp-90h]
unsigned int v26; // [esp+1Ch] [ebp-88h]
char Buffer[100]; // [esp+20h] [ebp-84h] BYREF
char abcdefghijklmnopqrstuvwxyz_[28]; // [esp+84h] [ebp-20h] BYREF

v3 = (const char *)malloc(0x64u);
Seed = time64(0);
srand(Seed);
for ( n100 = 0; n100 < 100; ++n100 )
v3[n100] = rand() % 255;
strcpy(abcdefghijklmnopqrstuvwxyz_, "abcdefghijklmnopqrstuvwxyz");
Stream = _acrt_iob_func(0);
fgets(Buffer, 100, Stream);
v7 = 0;
v26 = 0;
v8 = strlen(Buffer);
if ( v8 )
{
v9 = v25;
v10 = 1 - (_DWORD)Buffer;
do
{
v11 = &Buffer[v7];
if ( (unsigned int)&Buffer[v7 + v10] < v8 )
{
v12 = (unsigned __int8)*v11;
v13 = v12 & 0xF;
n3 = v12 >> 4;
if ( n3 == 3 )
v9 = v11[1] & 0x1F;
v15 = n3 - 1;
if ( !v15 )
{
if ( v13 >= strlen(v3) )
goto LABEL_24;
v21 = v3[v13];
if ( (unsigned __int8)(v21 - 97) > 0x19u )
goto LABEL_24;
v20 = v21 - 32;
goto LABEL_23;
}
v16 = v15 - 1;
if ( v16 )
{
v17 = v16 - 1;
if ( v17 )
{
if ( v17 == 1 && v13 < strlen(v3) )
v3[v13] = v18;
}
else if ( v13 < strlen(v3) && v9 < strlen(abcdefghijklmnopqrstuvwxyz_) )
{
v3[v13] = abcdefghijklmnopqrstuvwxyz_[v9];
}
goto LABEL_24;
}
if ( v13 < strlen(v3) )
{
v19 = v3[v13];
if ( (unsigned __int8)(v19 - 65) <= 0x19u )
{
v20 = v19 + 32;
LABEL_23:
v3[v13] = v20;
}
}
}
LABEL_24:
v26 += 2;
v7 = v26;
v8 = strlen(Buffer);
v10 = 1 - (_DWORD)Buffer;
}
while ( v26 < v8 );
}
v22 = sub_4011CE(sub_401348);
std::ostream::operator<<(v22, v24);
return 0;
}

很简单的逻辑最后的v22就是输出而已.那么根据这个得到脚本

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
def generate_payload():
# Target: "HelloWorld"
# Ops:
# 1: ToUpper (target_idx)
# 3: Replace (target_idx, alpha_idx)
# 4: Truncate (target_idx)

alphabet = "abcdefghijklmnopqrstuvwxyz"
target_str = "HelloWorld"

payload = bytearray()

for i, char in enumerate(target_str):
lower_char = char.lower()
alpha_idx = alphabet.find(lower_char)

# Opcode 3: Replace
# c1 = (3 << 4) | i
# c2: such that c2 & 0x1F == alpha_idx
# Let's use printable characters for c2 if possible (0x40 + idx)
c1_replace = (3 << 4) | i
c2_replace = 0x40 | alpha_idx

payload.append(c1_replace)
payload.append(c2_replace)

# If uppercase needed
if char.isupper():
# Opcode 1: ToUpper
# c1 = (1 << 4) | i
# c2: irrelevant
c1_upper = (1 << 4) | i
c2_upper = 0x41 # 'A' dummy
payload.append(c1_upper)
payload.append(c2_upper)

# Truncate at len(target_str) (which is 10)
# Opcode 4: Truncate
idx_truncate = len(target_str)
c1_trunc = (4 << 4) | idx_truncate
c2_trunc = 0x41 # Dummy
payload.append(c1_trunc)
payload.append(c2_trunc)

return payload


payload = generate_payload()
print(f"Hex Payload: {payload.hex()}")
print(f"Length: {len(payload)}")

# Check for 0x0A (newline) or 0x00 (null)
if 0x0A in payload:
print("Contains newline!")
if 0x00 in payload:
print("Contains null!")

# Print formatted hex for user
hex_str = "".join([f"\\x{b:02x}" for b in payload])
print(f"Escaped String: {hex_str}")

得到hex序列.

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
from pwn import remote

HOST = ""##靶机
PORT = ##


def build_payload() -> bytes:
hex_bytes = [
0x30, 0x07, 0x31, 0x04, 0x32, 0x0B, 0x33, 0x0B,
0x34, 0x0E, 0x35, 0x16, 0x36, 0x0E, 0x37, 0x11,
0x38, 0x0B, 0x39, 0x03, 0x10, 0x41, 0x15, 0x41,
0x4A, 0x41,
]
return bytes(hex_bytes)


def exploit():
payload = build_payload()

io = remote(HOST, PORT)

_ = io.recv(timeout=1)

io.sendline(payload)

io.interactive()


if __name__ == "__main__":
exploit()

3veryre

DIE查壳

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
void __cdecl __noreturn sub_401030(int a1, int a2)
{
unsigned int n0x201; // eax
int v3; // ecx
int v4; // eax
int v5; // eax
int v6; // eax
int v7; // eax
int v8; // eax
int v9; // eax
unsigned int v10; // eax
unsigned int v11; // eax
unsigned int v12; // esi
int v13; // eax
int v14; // eax
unsigned int v15; // esi
int v16; // esi
int v17; // eax
int v18; // esi
int v19; // [esp+Ch] [ebp-4h] BYREF

sub_401390();
dword_40AC60 = 0;
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
LABEL_2:
while ( 1 )
{
n0x201 = *(_DWORD *)(a1 + 4 * dword_40AC60);
v3 = ++dword_40AC60;
if ( n0x201 > 0x201 )
break;
if ( n0x201 == 513 )
{
v19 = sub_4013E0();
v7 = sub_4013E0();
sub_4013A0(v19 - v7);
}
else
{
switch ( n0x201 )
{
case 0x101u:
v19 = sub_4013E0();
v4 = sub_4013E0();
sub_4013A0(v19 + v4);
break;
case 0x102u:
v19 = sub_4013E0();
v5 = sub_4013E0();
sub_4013A0(v19 & v5);
break;
case 0x103u:
sub_401370();
case 0x104u:
v6 = *(_DWORD *)(a1 + 4 * v3);
dword_40AC60 = v3 + 1;
sub_4013A0(v6);
break;
case 0x105u:
printf("Enter integer: ");
scanf("%d", &v19);
fflush((FILE *)&Stream);
sub_4013A0(v19);
break;
default:
continue;
}
}
}
if ( n0x201 > 0x305 )
break;
if ( n0x201 == 773 )
{
v13 = sub_4013E0();
gets(a2 + v13);
}
else if ( n0x201 > 0x301 )
{
v10 = n0x201 - 770;
if ( v10 )
{
v11 = v10 - 1;
if ( v11 )
{
if ( v11 == 1 )
{
v19 = *(_DWORD *)(sub_4013E0() + a2);
sub_4013A0(v19);
}
}
else
{
v12 = *(_DWORD *)(a1 + 4 * v3);
dword_40AC60 = v3 + 1;
if ( !sub_4013E0() )
dword_40AC60 = v12 >> 2;
}
}
else
{
v19 = sub_4013E0();
sub_4013A0(~v19);
}
}
else if ( n0x201 == 769 )
{
v19 = sub_4013E0() + 1;
sub_4013A0(v19);
}
else
{
switch ( n0x201 )
{
case 0x202u:
v19 = sub_4013E0();
v8 = sub_4013E0();
sub_4013A0(v19 | v8);
break;
case 0x203u:
dword_40AC60 = *(_DWORD *)(a1 + 4 * v3) >> 2;
break;
case 0x204u:
sub_4013E0();
break;
case 0x205u:
v9 = sub_4013E0();
printf("%d\n", v9);
break;
default:
continue;
}
}
}
if ( n0x201 > 0x504 )
break;
if ( n0x201 == 1284 )
{
v19 = *(unsigned __int8 *)(sub_4013E0() + a2);
sub_4013A0(v19);
}
else
{
switch ( n0x201 )
{
case 0x401u:
v19 = sub_4013E0() - 1;
sub_4013A0(v19);
break;
case 0x402u:
v19 = sub_4013E0();
v14 = sub_4013E0();
sub_4013A0(v19 ^ v14);
break;
case 0x403u:
v15 = *(_DWORD *)(a1 + 4 * v3);
dword_40AC60 = v3 + 1;
if ( sub_4013E0() )
dword_40AC60 = v15 >> 2;
break;
case 0x404u:
v16 = sub_4013E0();
*(_DWORD *)(v16 + a2) = sub_4013E0();
break;
case 0x405u:
v17 = sub_4013E0();
puts((const char *)(a2 + v17));
break;
default:
goto LABEL_2;
}
}
}
if ( n0x201 == 1540 )
{
v18 = sub_4013E0();
*(_BYTE *)(v18 + a2) = sub_4013E0();
}
}
}```
主要的加密逻辑
```python
import struct

class VMInterpreter:
def __init__(self):
self.ip = 0 # 指令指针
self.stack = []
self.memory = bytearray(1024) # 数据内存
self.code = [] # 字节码指令

# 初始化内存数据(从你提供的hex数据)
self.init_memory()

def init_memory(self):
# 初始化内存区域的数据
initial_data = bytes([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6C, 0x4D, 0x10, 0x05, 0x13, 0x13,
0x0E, 0x51, 0x5B, 0x29, 0x45, 0x5E, 0x44, 0x42, 0x47, 0x53, 0x5B, 0x7A,
0x47, 0x51, 0x16, 0x4C, 0x45, 0x58, 0x58, 0x2F, 0x12, 0x29, 0x43, 0x12,
0x47, 0x03, 0x0F, 0x29, 0x46, 0x51, 0x11, 0x15, 0x45, 0x00, 0x0F, 0x2E,
0x15, 0x0B, 0x47, 0x15, 0x44, 0x02, 0x11, 0x00
])
self.memory[:len(initial_data)] = initial_data

def push(self, value):
"""模拟 sub_4013A0 - 压栈操作"""
self.stack.append(value)

def pop(self):
"""模拟 sub_4013E0 - 弹栈操作"""
if not self.stack:
raise Exception("Stack underflow")
return self.stack.pop()

def load_bytecode(self, bytecode_data):
"""加载字节码数据"""
# 将字节数据解析为DWORD数组
self.code = []
for i in range(0, len(bytecode_data), 4):
if i + 4 <= len(bytecode_data):
value = struct.unpack('<I', bytecode_data[i:i+4])[0]
self.code.append(value)

def execute(self):
"""执行字节码"""
while self.ip < len(self.code):
opcode = self.code[self.ip]
self.ip += 1

# 解码指令
if opcode == 0x101: # ADD
b = self.pop()
a = self.pop()
self.push(a + b)

elif opcode == 0x102: # AND
b = self.pop()
a = self.pop()
self.push(a & b)

elif opcode == 0x103: # 特殊操作(未知)
# sub_401370() - 需要具体实现
pass

elif opcode == 0x104: # PUSH IMMEDIATE
if self.ip < len(self.code):
value = self.code[self.ip]
self.ip += 1
self.push(value)

elif opcode == 0x105: # INPUT
user_input = int(input("Enter integer: "))
self.push(user_input)

elif opcode == 0x201: # SUB
b = self.pop()
a = self.pop()
self.push(a - b)

elif opcode == 0x202: # OR
b = self.pop()
a = self.pop()
self.push(a | b)

elif opcode == 0x203: # JMP
if self.ip < len(self.code):
self.ip = self.code[self.ip] // 4

elif opcode == 0x204: # POP
self.pop()

elif opcode == 0x205: # PRINT INT
value = self.pop()
print(f"Output: {value}")

elif opcode == 0x301: # INC
value = self.pop()
self.push(value + 1)

elif opcode == 0x302: # NOT
value = self.pop()
self.push(~value)

elif opcode == 0x303: # JZ (Jump if Zero)
if self.ip < len(self.code):
target = self.code[self.ip]
self.ip += 1
if self.pop() == 0:
self.ip = target // 4

elif opcode == 0x304: # LOAD INT from memory
addr = self.pop()
if addr < len(self.memory) - 3:
value = struct.unpack('<I', self.memory[addr:addr+4])[0]
self.push(value)

elif opcode == 0x305: # GETS (输入字符串)
addr = self.pop()
user_input = input("Enter string: ")
input_bytes = user_input.encode() + b'\x00'
self.memory[addr:addr+len(input_bytes)] = input_bytes

elif opcode == 0x401: # DEC
value = self.pop()
self.push(value - 1)

elif opcode == 0x402: # XOR
b = self.pop()
a = self.pop()
self.push(a ^ b)

elif opcode == 0x403: # JNZ (Jump if Not Zero)
if self.ip < len(self.code):
target = self.code[self.ip]
self.ip += 1
if self.pop() != 0:
self.ip = target // 4

elif opcode == 0x404: # STORE INT to memory
value = self.pop()
addr = self.pop()
if addr <= len(self.memory) - 4:
self.memory[addr:addr+4] = struct.pack('<I', value)

elif opcode == 0x405: # PUTS (输出字符串)
addr = self.pop()
# 找到以null结尾的字符串
end = addr
while end < len(self.memory) and self.memory[end] != 0:
end += 1
string_data = self.memory[addr:end]
try:
print(f"String: {string_data.decode('ascii', errors='replace')}")
except:
print(f"Hex: {string_data.hex()}")

elif opcode == 0x504: # LOAD BYTE from memory
addr = self.pop()
if addr < len(self.memory):
value = self.memory[addr]
self.push(value)

elif opcode == 0x604: # STORE BYTE to memory
value = self.pop() & 0xFF
addr = self.pop()
if addr < len(self.memory):
self.memory[addr] = value

else:
print(f"Unknown opcode: 0x{opcode:04x} at IP: {self.ip-1}")
break

def decode_bytecode():
"""解密字节码的主要函数"""
vm = VMInterpreter()

# 从你提供的hex数据加载字节码
bytecode_hex = """
04 01 00 00 18 01 00 00 05 03 00 00 04 01 00 00
00 00 00 00 04 01 00 00 00 00 00 00 04 04 00 00
04 01 00 00 2F 00 00 00 04 01 00 00 00 00 00 00
04 03 00 00 01 02 00 00 03 03 00 00 D4 00 00 00
04 01 00 00 18 00 00 00 04 01 00 00 00 00 00 00
04 03 00 00 01 01 00 00 04 05 00 00 04 01 00 00
10 00 00 00 04 01 00 00 00 00 00 00 04 03 00 00
04 01 00 00 07 00 00 00 02 01 00 00 01 01 00 00
04 05 00 00 02 04 00 00 04 01 00 00 18 01 00 00
04 01 00 00 00 00 00 00 04 03 00 00 01 01 00 00
04 05 00 00 01 02 00 00 03 04 00 00 D4 00 00 00
04 01 00 00 00 00 00 00 04 03 00 00 01 03 00 00
04 01 00 00 00 00 00 00 04 04 00 00 03 02 00 00
20 00 00 00 04 01 00 00 2F 00 00 00 04 01 00 00
00 00 00 00 04 03 00 00 01 02 00 00 03 04 00 00
04 01 00 00 04 01 00 00 18 02 00 00 05 04 00 00
03 01 00 00 04 01 00 00 1C 02 00 00 05 04 00 00
03 01 00 00
"""

# 转换hex字符串为字节数据
hex_values = bytecode_hex.replace('\n', ' ').split()
bytecode_bytes = bytes(int(x, 16) for x in hex_values if x)

vm.load_bytecode(bytecode_bytes)

print("开始执行虚拟机字节码...")
print("=" * 50)

try:
vm.execute()
except Exception as e:
print(f"执行错误: {e}")

print("=" * 50)
print("执行完成")
print(f"栈状态: {vm.stack}")
print(f"指令指针: {vm.ip}")

# 输出内存中的关键数据
print("\n内存数据转储:")
for i in range(0, min(256, len(vm.memory)), 16):
hex_str = ' '.join(f'{b:02x}' for b in vm.memory[i:i+16])
ascii_str = ''.join(chr(b) if 32 <= b < 127 else '.' for b in vm.memory[i:i+16])
print(f"{i:04x}: {hex_str:<48} {ascii_str}")

def analyze_verification_logic():
"""分析验证逻辑"""
print("\n验证逻辑分析:")
print("1. 程序读取用户输入并进行一系列运算")
print("2. 包含算术运算(加、减、与、或、异或)")
print("3. 包含内存操作和字符串处理")
print("4. 最终会检查结果并输出OK/Failed")

# 基于内存中的初始数据进行分析
initial_string = "virtualM"
print(f"\n初始字符串: {initial_string}")
print("这可能是验证的关键字符串")

if __name__ == "__main__":
decode_bytecode()
analyze_verification_logic()

打印相应操作
那么解密脚本

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
def extract_flag():
# 内存中的加密数据
encrypted_data = bytes([
0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6C, 0x4D, 0x10, 0x05, 0x13, 0x13,
0x0E, 0x51, 0x5B, 0x29, 0x45, 0x5E, 0x44, 0x42, 0x47, 0x53, 0x5B, 0x7A,
0x47, 0x51, 0x16, 0x4C, 0x45, 0x58, 0x58, 0x2F, 0x12, 0x29, 0x43, 0x12,
0x47, 0x03, 0x0F, 0x29, 0x46, 0x51, 0x11, 0x15, 0x45, 0x00, 0x0F, 0x2E,
0x15, 0x0B, 0x47, 0x15, 0x44, 0x02, 0x11, 0x00
])

# 使用"virtualM"作为XOR密钥进行解密
key = b"virtualM"

decrypted = bytearray()
for i in range(len(encrypted_data)):
decrypted_byte = encrypted_data[i] ^ key[i % len(key)]
decrypted.append(decrypted_byte)

# 转换为字符串
flag = decrypted.decode('ascii', errors='ignore')

# 查找flag模式
import re
flag_pattern = re.search(r'flag\{[^}]+\}', flag)
if flag_pattern:
return flag_pattern.group(0)
else:
# 如果没找到标准格式,返回可打印部分
printable_flag = ''.join(chr(b) if 32 <= b < 127 else '' for b in decrypted)
return printable_flag
# 解密flag
flag = extract_flag()
print(f"解密得到的flag: {flag}")

古剑山三解
https://boke-git-main-huang-chaos-projects.vercel.app/2025/11/29/古剑山三解/
作者
Ined
发布于
2025年11月29日
许可协议