指令虚拟化

这篇文章解决什么问题

VM(Virtual Machine,虚拟机)类题目是逆向中常见的代码保护方式。出题人会把原本的逻辑转换成一套自定义字节码,再由解释器循环读取并执行。静态分析时,我们看到的往往不是直接的业务逻辑,而是“取 opcode → 分发 → 执行 handler”的解释器结构。

这篇文章先从一个最小 VM 示例入手,再说明如何定义指令集、实现解释器,以及逆向时应该如何还原 VM 的真实逻辑。

认识虚拟机

虚拟机本质上是用软件模拟一套执行环境。我们可以自定义一套指令,例如 0x01 表示把立即数放入虚拟寄存器,0x02 表示输出寄存器中的字符。程序运行时,解释器根据当前 eip 读取 opcode,再跳转到对应的 handler 执行。

在代码保护中,虚拟化会把原本直接执行的机器码转换成自定义字节码。这样一来,逆向者不能只看普通反编译结果,而需要先理解这套 VM 的指令集和解释器。

VM 执行流程

VM 的主程序通常是一个循环:不断读取 opcode,执行 opcode 对应的 handler,最后更新虚拟 eip

最小示例

原始程序:

1
2
3
4
5
6
7
#include <stdio.h>

int main() {
printf("Hello!
");
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
32
33
#include <stdio.h>

int main() {
int eip = 0;
int eax = 0;

char code[] = {
0x01, 0x48, 0x02,
0x01, 0x65, 0x02,
0x01, 0x6c, 0x02,
0x01, 0x6f, 0x02,
0x01, 0x21, 0x02,
0x01, 0x0a, 0x02,
0xff
};

while (1) {
switch (code[eip]) {
case 0x01:
eax = code[eip + 1];
eip += 2;
break;
case 0x02:
printf("%c", eax);
eip += 1;
break;
case 0xff:
return 0;
default:
return -1;
}
}
}

这个例子里:

  • 0x01 imm:把立即数 imm 放入虚拟寄存器 eax
  • 0x02:输出 eax 中保存的字符
  • 0xff:结束 VM 执行

所以逆向 VM 的第一步,不是急着找 flag,而是先把每个 opcode 的含义整理出来。

正向实现:

想要对抗指令虚拟化,首先要搞清楚用于保护的虚拟机是如何实现的
要想实现虚拟机,需要完成两个目标:
1.定义一套指令集
2.实现对应的解释器

结构体的定义:

真实赛题的VM通常会实现一个类似如下的结构体,用于保存虚拟机状态:

1
2
3
4
5
6
7
8
typedef struct
{
unsigned int r1; //虚拟寄存器r1
unsigned int r2; //虚拟寄存器r2
unsigned int eip; //指向正在解释的opcode地址
unsigned char mem[256]; //虚拟内存
unsigned char code[1024]; //存放自定义机器码
}

书写机器码:

假定希望实现的语句如下:

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

typedef struct
{
unsigned int r1; //虚拟寄存器r1
unsigned int r2; //虚拟寄存器r2
unsigned int eip; //指向正在解释的opcode地址
unsigned char mem[256]; //虚拟内存
unsigned char code[1024]; //存放自定义机器码
};
int main() {
char input[60];
char target[] = "Y0u'd_BetteR_N0t_be_S0me0Ne_Who_always_sh0ws_0ff";
scanf("%59s", input);
for (int i = 0; i < strlen(target); i++)
{
input[i] ^= 0x21;
}

if (!memcmp(input, target, 60))
printf("yes\n");
else
printf("No\n");

}

我们定义:

opcode 指令格式 指令长度 指令含义
0x10 0x10 操作数 2 r1=操作数
0x11 0x11 操作数 2 r2=操作数
0x20 0x20 操作数1 操作数2 3 mem[操作数1]=操作数2
0x30 0x30 1 mem[r1]^=r2
0x40 0x40 1 接收输入到&mem[0]
0x50 0x50 操作数1 操作数2 3 返回memcmp(&mem[0],&mem[操作数1],操作数2)

根据我们定义的指令对其进行拆分和重构,可以得到如下代码:

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
#include<stdio.h>
int main() {
unsigned char code[] = {
0x20,0x10,0x59,
0x20,0x10,0x30,
0x20,0x10,0x75,
0x20,0x10,0x27,
0x20,0x10,0x64,
0x20,0x10,0x5f,
0x20,0x10,0x42,
0x20,0x10,0x65,
0x20,0x10,0x74,
0x20,0x10,0x74,
0x20,0x10,0x65,
0x20,0x10,0x52,
0x20,0x10,0x5f,
0x20,0x10,0x4e,
0x20,0x10,0x30,
0x20,0x10,0x74,
0x20,0x10,0x5f,
0x20,0x10,0x62,
0x20,0x10,0x65,
0x20,0x10,0x5f,
0x20,0x10,0x53,
0x20,0x10,0x30,
0x20,0x10,0x6d,
0x20,0x10,0x65,
0x20,0x10,0x30,
0x20,0x10,0x4e,
0x20,0x10,0x65,
0x20,0x10,0x5f,
0x20,0x10,0x57,
0x20,0x10,0x68,
0x20,0x10,0x6f,
0x20,0x10,0x5f,
0x20,0x10,0x61,
0x20,0x10,0x6c,
0x20,0x10,0x77,
0x20,0x10,0x61,
0x20,0x10,0x79,
0x20,0x10,0x73,
0x20,0x10,0x5f,
0x20,0x10,0x73,
0x20,0x10,0x68,
0x20,0x10,0x30,
0x20,0x10,0x77,
0x20,0x10,0x73,
0x20,0x10,0x5f,
0x20,0x10,0x30,
0x20,0x10,0x66,
0x20,0x10,0x66,

0x40,

0x11,0x21,0x10,0x00,0x30,0x11,0x21,0x10,0x01,0x30,0x11,0x21,0x10,0x02,0x30,0x11,0x21,0x10,0x03,0x30,0x11,0x21,0x10,0x04,0x30,0x11,0x21,0x10,0x05,0x30,0x11,0x21,0x10,0x06,0x30,0x11,0x21,0x10,0x07,0x30,0x11,0x21,0x10,0x08,0x30,0x11,0x21,0x10,0x09,0x30,0x11,0x21,0x10,0x0a,0x30,0x11,0x21,0x10,0x0b,0x30,0x11,0x21,0x10,0x0c,0x30,0x11,0x21,0x10,0x0d,0x30,0x11,0x21,0x10,0x0e,0x30,0x11,0x21,0x10,0x0f,0x30,0x11,0x21,0x10,0x10,0x30,0x11,0x21,0x10,0x11,0x30,0x11,0x21,0x10,0x12,0x30,0x11,0x21,0x10,0x13,0x30,0x11,0x21,0x10,0x14,0x30,0x11,0x21,0x10,0x15,0x30,0x11,0x21,0x10,0x16,0x30,0x11,0x21,0x10,0x17,0x30,0x11,0x21,0x10,0x18,0x30,0x11,0x21,0x10,0x19,0x30,0x11,0x21,0x10,0x1a,0x30,0x11,0x21,0x10,0x1b,0x30,0x11,0x21,0x10,0x1c,0x30,0x11,0x21,0x10,0x1d,0x30,0x11,0x21,0x10,0x1e,0x30,0x11,0x21,0x10,0x1f,0x30,0x11,0x21,0x10,0x20,0x30,0x11,0x21,0x10,0x21,0x30,0x11,0x21,0x10,0x22,0x30,0x11,0x21,0x10,0x23,0x30,0x11,0x21,0x10,0x24,0x30,0x11,0x21,0x10,0x25,0x30,0x11,0x21,0x10,0x26,0x30,0x11,0x21,0x10,0x27,0x30,0x11,0x21,0x10,0x28,0x30,0x11,0x21,0x10,0x29,0x30,0x11,0x21,0x10,0x2a,0x30,0x11,0x21,0x10,0x2b,0x30,0x11,0x21,0x10,0x2c,0x30,0x11,0x21,0x10,0x2d,0x30,0x11,0x21,0x10,0x2e,0x30,0x11,0x21,0x10,0x2f,0x30,0x11,0x21,0x10,0x30,0x30,0x11,0x21,0x10,0x31,0x30,0x11,0x21,0x10,0x32,0x30,0x11,0x21,0x10,0x33,0x30,0x11,0x21,0x10,0x34,0x30,0x11,0x21,0x10,0x35,0x30,0x11,0x21,0x10,0x36,0x30,0x11,0x21,0x10,0x37,0x30,0x11,0x21,0x10,0x38,0x30,0x11,0x21,0x10,0x39,0x30,0x11,0x21,0x10,0x3a,0x30,0x50,0x10,59};

初始化虚拟机:

在实际虚拟机运行之前,需要先对VM结构体进行初始化:

1
2
3
4
5
VM* vm_new() {
VM* vm = (VM*)malloc(sizeof(VM));
memset(vm, 0, sizeof(VM));
memcpy(vm->code, code, sizeof(code));
return vm;

解释器编写:

现在就可以来实现每条指令的handle以及dispatcher了:

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 vm_run(VM* vm) {
char opcode;
char operand_1, operand_2;

while (1) {
opcode = vm->code[vm->eip];
switch (opcode) {
case 0x10:
operand_1 = vm->code[vm->eip + 1];
vm->r1 = operand_1;
vm->eip += 2;
break;
case 0x11:
operand_1 = vm->code[vm->eip + 1];
vm->r2 = operand_1;
case 0x20:
operand_1 = vm->code[vm->eip + 1];
operand_2 = vm->code[vm->eip + 2];
vm->mem[operand_1] = operand_2;
vm->eip += 3;
break;
case 0x30:
vm->mem[vm->r1] ^= vm->r2;
vm->eip += 1;
break;
case 0x40:
scanf("%59s", &vm->mem[0]);
case 0x50:
operand_1 = vm->code[vm->eip + 1];
operand_2 = vm->code[vm->eip + 2];
return memcmp(&vm->mem[0], &vm->mem[operand_1], operand_2);

}
}
}

启动:

于是main函数可以这样写 :

1
2
3
4
5
6
7
8
int main()
{
VM* vm=vm_new();
if(!vm_run(vm))
printf("Yes\n");
else
printf("No\n");
}

解题步骤:

遇到VM类的赛题,我们一般按照如下的步骤来解题:

1.分析VM结构:

结构体大小
有哪些字段

2.分析指令集:

指令长度是否可变
 每种指令的构成
 每种指令的含义
 VM的退出条件

3.编写python版解释器,输出伪汇编代码

4.阅读伪代码,分析程序流程,写出去虚拟化的原始代码

5.书写解题脚本

本例的python解释器如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
code=b' \x10Y \x100 \x10u \x10\' \x10d \x10_ \x10B \x10e \x10t \x10t \x10e \x10R \x10_ \x10N \x100 \x10t \x10_ \x10b \x10e \x10_ \x10S \x100 \x10m \x10e \x100 \x10N \x10e \x10_ \x10W \x10h \x10o \x10_ \x10a \x10l \x10w \x10a \x10y \x10s \x10_ \x10s \x10h \x100 \x10w \x10s \x10_ \x100 \x10f \x10f@\x11!\x10\x000\x11!\x10\x010\x11!\x10\x020\x11!\x10\x030\x11!\x10\x040\x11!\x10\x050\x11!\x10\x060\x11!\x10\x070\x11!\x10\x080\x11!\x10\t0\x11!\x10\n0\x11!\x10\x0b0\x11!\x10\x0c0\x11!\x10\r0\x11!\x10\x0e0\x11!\x10\x0f0\x11!\x10\x100\x11!\x10\x110\x11!\x10\x120\x11!\x10\x130\x11!\x10\x140\x11!\x10\x150\x11!\x10\x160\x11!\x10\x170\x11!\x10\x180\x11!\x10\x190\x11!\x10\x1a0\x11!\x10\x1b0\x11!\x10\x1c0\x11!\x10\x1d0\x11!\x10\x1e0\x11!\x10\x1f0\x11!\x10 0\x11!\x10!0\x11!\x10"0\x11!\x10#0\x11!\x10$0\x11!\x10%0\x11!\x10&0\x11!\x10\'0\x11!\x10(0\x11!\x10)0\x11!\x10*0\x11!\x10+0\x11!\x10,0\x11!\x10-0\x11!\x10.0\x11!\x10/0\x11!\x1000\x11!\x1010\x11!\x1020\x11!\x1030\x11!\x1040\x11!\x1050\x11!\x1060\x11!\x1070\x11!\x1080\x11!\x1090\x11!\x10:0P\x10;'



r1=0

r2=0

eip=0

mem=[0]*256



while True:

    opcode=code[eip]

    print(hex(eip)[2:].rjust(2,'0'),end='   ')

    if opcode==0x20:

        op1=code[eip+1]

        op2=code[eip+2]

        mem[op1]=op2

        print(f"mov [{hex(op1)}],{hex(op2)}")

        eip+=3

    elif opcode ==0x10:

        r2=code[eip+1]

        print(f"mov r1,{hex(r1)}")

        eip+=2



    elif opcode ==0x11:

        r2=code[eip+1]

        print(f"mov r2,{hex(r2)}")

        eip+=2

    elif opcode ==0x30:

        mem[r1] ^=r2

        print("xor [{hex(r1)}],{hex(r2)}")

        eip+=1

    elif opcode==0x40:

        #flag=input()

        flag="12345".ljust(59,'\0')

        for i in range(59):

            mem[i]=ord(flag[i])

        eip+=1

    elif opcode==0x50:

        op1=code[eip+1]

        op2=code[eip+2]

        print(f"{mem[0:0+op2]} to {mem[op1:op1+op2]}")

        print(mem[0:0+op2] == mem[op1:op1+op2])

        exit()



    else:

        raise RuntimeError(f"unknown opcode: {hex(opcode)}")

# 00   mov [0x10],0x59

# 03   mov [0x10],0x30

# 06   mov [0x10],0x75

# 09   mov [0x10],0x27

# 0c   mov [0x10],0x64

# 0f   mov [0x10],0x5f

# 12   mov [0x10],0x42

# 15   mov [0x10],0x65

# 18   mov [0x10],0x74

# 1b   mov [0x10],0x74

# 1e   mov [0x10],0x65

# 21   mov [0x10],0x52

# 24   mov [0x10],0x5f

# 27   mov [0x10],0x4e

# 2a   mov [0x10],0x30

# 2d   mov [0x10],0x74

# 30   mov [0x10],0x5f

# 33   mov [0x10],0x62

# 36   mov [0x10],0x65

# 39   mov [0x10],0x5f

# 3c   mov [0x10],0x53

# 3f   mov [0x10],0x30

# 42   mov [0x10],0x6d

# 45   mov [0x10],0x65

# 48   mov [0x10],0x30

# 4b   mov [0x10],0x4e

# 4e   mov [0x10],0x65

# 51   mov [0x10],0x5f

# 54   mov [0x10],0x57

# 57   mov [0x10],0x68

# 5a   mov [0x10],0x6f

# 5d   mov [0x10],0x5f

# 60   mov [0x10],0x61

# 63   mov [0x10],0x6c

# 66   mov [0x10],0x77

# 69   mov [0x10],0x61

# 6c   mov [0x10],0x79

# 6f   mov [0x10],0x73

# 72   mov [0x10],0x5f

# 75   mov [0x10],0x73

# 78   mov [0x10],0x68

# 7b   mov [0x10],0x30

# 7e   mov [0x10],0x77

# 81   mov [0x10],0x73

# 84   mov [0x10],0x5f

# 87   mov [0x10],0x30

# 8a   mov [0x10],0x66

# 8d   mov [0x10],0x66

# 90   91   mov r2,0x21

# 93   mov r1,0x0

# 95   xor [{hex(r1)}],{hex(r2)}

# 96   mov r2,0x21

# 98   mov r1,0x0

# 9a   xor [{hex(r1)}],{hex(r2)}

# 9b   mov r2,0x21

# 9d   mov r1,0x0

# 9f   xor [{hex(r1)}],{hex(r2)}

# a0   mov r2,0x21

# a2   mov r1,0x0

# a4   xor [{hex(r1)}],{hex(r2)}

# a5   mov r2,0x21

# a7   mov r1,0x0

# a9   xor [{hex(r1)}],{hex(r2)}

# aa   mov r2,0x21

# ac   mov r1,0x0

# ae   xor [{hex(r1)}],{hex(r2)}

# af   mov r2,0x21

# b1   mov r1,0x0

# b3   xor [{hex(r1)}],{hex(r2)}

# b4   mov r2,0x21

# b6   mov r1,0x0

# b8   xor [{hex(r1)}],{hex(r2)}

# b9   mov r2,0x21

# bb   mov r1,0x0

# bd   xor [{hex(r1)}],{hex(r2)}

# be   mov r2,0x21

# c0   mov r1,0x0

# c2   xor [{hex(r1)}],{hex(r2)}

# c3   mov r2,0x21

# c5   mov r1,0x0

# c7   xor [{hex(r1)}],{hex(r2)}

# c8   mov r2,0x21

# ca   mov r1,0x0

# cc   xor [{hex(r1)}],{hex(r2)}

# cd   mov r2,0x21

# cf   mov r1,0x0

# d1   xor [{hex(r1)}],{hex(r2)}

# d2   mov r2,0x21

# d4   mov r1,0x0

# d6   xor [{hex(r1)}],{hex(r2)}

# d7   mov r2,0x21

# d9   mov r1,0x0

# db   xor [{hex(r1)}],{hex(r2)}

# dc   mov r2,0x21

# de   mov r1,0x0

# e0   xor [{hex(r1)}],{hex(r2)}

# e1   mov r2,0x21

# e3   mov r1,0x0

# e5   xor [{hex(r1)}],{hex(r2)}

# e6   mov r2,0x21

# e8   mov r1,0x0

# ea   xor [{hex(r1)}],{hex(r2)}

# eb   mov r2,0x21

# ed   mov r1,0x0

# ef   xor [{hex(r1)}],{hex(r2)}

# f0   mov r2,0x21

# f2   mov r1,0x0

# f4   xor [{hex(r1)}],{hex(r2)}

# f5   mov r2,0x21

# f7   mov r1,0x0

# f9   xor [{hex(r1)}],{hex(r2)}

# fa   mov r2,0x21

# fc   mov r1,0x0

# fe   xor [{hex(r1)}],{hex(r2)}

# ff   mov r2,0x21

# 101   mov r1,0x0

# 103   xor [{hex(r1)}],{hex(r2)}

# 104   mov r2,0x21

# 106   mov r1,0x0

# 108   xor [{hex(r1)}],{hex(r2)}

# 109   mov r2,0x21

# 10b   mov r1,0x0

# 10d   xor [{hex(r1)}],{hex(r2)}

# 10e   mov r2,0x21

# 110   mov r1,0x0

# 112   xor [{hex(r1)}],{hex(r2)}

# 113   mov r2,0x21

# 115   mov r1,0x0

# 117   xor [{hex(r1)}],{hex(r2)}

# 118   mov r2,0x21

# 11a   mov r1,0x0

# 11c   xor [{hex(r1)}],{hex(r2)}

# 11d   mov r2,0x21

# 11f   mov r1,0x0

# 121   xor [{hex(r1)}],{hex(r2)}

# 122   mov r2,0x21

# 124   mov r1,0x0

# 126   xor [{hex(r1)}],{hex(r2)}

# 127   mov r2,0x21

# 129   mov r1,0x0

# 12b   xor [{hex(r1)}],{hex(r2)}

# 12c   mov r2,0x21

# 12e   mov r1,0x0

# 130   xor [{hex(r1)}],{hex(r2)}

# 131   mov r2,0x21

# 133   mov r1,0x0

# 135   xor [{hex(r1)}],{hex(r2)}

# 136   mov r2,0x21

# 138   mov r1,0x0

# 13a   xor [{hex(r1)}],{hex(r2)}

# 13b   mov r2,0x21

# 13d   mov r1,0x0

# 13f   xor [{hex(r1)}],{hex(r2)}

# 140   mov r2,0x21

# 142   mov r1,0x0

# 144   xor [{hex(r1)}],{hex(r2)}

# 145   mov r2,0x21

# 147   mov r1,0x0

# 149   xor [{hex(r1)}],{hex(r2)}

# 14a   mov r2,0x21

# 14c   mov r1,0x0

# 14e   xor [{hex(r1)}],{hex(r2)}

# 14f   mov r2,0x21

# 151   mov r1,0x0

# 153   xor [{hex(r1)}],{hex(r2)}

# 154   mov r2,0x21

# 156   mov r1,0x0

# 158   xor [{hex(r1)}],{hex(r2)}

# 159   mov r2,0x21

# 15b   mov r1,0x0

# 15d   xor [{hex(r1)}],{hex(r2)}

# 15e   mov r2,0x21

# 160   mov r1,0x0

# 162   xor [{hex(r1)}],{hex(r2)}

# 163   mov r2,0x21

# 165   mov r1,0x0

# 167   xor [{hex(r1)}],{hex(r2)}

# 168   mov r2,0x21

# 16a   mov r1,0x0

# 16c   xor [{hex(r1)}],{hex(r2)}

# 16d   mov r2,0x21

# 16f   mov r1,0x0

# 171   xor [{hex(r1)}],{hex(r2)}

# 172   mov r2,0x21

# 174   mov r1,0x0

# 176   xor [{hex(r1)}],{hex(r2)}

# 177   mov r2,0x21

# 179   mov r1,0x0

# 17b   xor [{hex(r1)}],{hex(r2)}

# 17c   mov r2,0x21

# 17e   mov r1,0x0

# 180   xor [{hex(r1)}],{hex(r2)}

# 181   mov r2,0x21

# 183   mov r1,0x0

# 185   xor [{hex(r1)}],{hex(r2)}

# 186   mov r2,0x21

# 188   mov r1,0x0

# 18a   xor [{hex(r1)}],{hex(r2)}

# 18b   mov r2,0x21

# 18d   mov r1,0x0

# 18f   xor [{hex(r1)}],{hex(r2)}

# 190   mov r2,0x21

# 192   mov r1,0x0

# 194   xor [{hex(r1)}],{hex(r2)}

# 195   mov r2,0x21

# 197   mov r1,0x0

# 199   xor [{hex(r1)}],{hex(r2)}

# 19a   mov r2,0x21

# 19c   mov r1,0x0

# 19e   xor [{hex(r1)}],{hex(r2)}

# 19f   mov r2,0x21

# 1a1   mov r1,0x0

# 1a3   xor [{hex(r1)}],{hex(r2)}

# 1a4   mov r2,0x21

# 1a6   mov r1,0x0

# 1a8   xor [{hex(r1)}],{hex(r2)}

# 1a9   mov r2,0x21

# 1ab   mov r1,0x0

# 1ad   xor [{hex(r1)}],{hex(r2)}

# 1ae   mov r2,0x21

# 1b0   mov r1,0x0

# 1b2   xor [{hex(r1)}],{hex(r2)}

# 1b3   mov r2,0x21

# 1b5   mov r1,0x0

# 1b7   xor [{hex(r1)}],{hex(r2)}

# 1b8   [10, 50, 51, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] to [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

#其实逆向逻辑也就是如下:

raw=[0x59,0x30,0x75,0x27,0x64,0x5f,0x42,0x65,0x74,0x74,0x65,0x52,0x5f,0x4e,0x30,0x74,0x5f,0x62,0x65,0x5f,0x53,0x30,0x6d,0x65,0x30,0x4e,0x65,0x5f,0x57,0x68,0x6f,0x5f,0x61,0x6c,0x77,0x61,0x79,0x73,0x5f,0x73,0x68,0x30,0x77,0x73,0x5f,0x30,0x66,0x66]

flag=''

for i in range(len(raw)):

    flag+=chr(raw[i]^0x21)

print(flag)