baby_tree
前言
这道题打开是个ast后缀文件,没有遇到过,上网搜了一下,大概了解是抽象语法树,以前没遇到过,先收集资料学习一波
AST在的应用
1、代码语法的检查、代码风格的检查、代码的格式化、代码的高亮、代码错误提示、代码自动补全
2、语法分析器会生成一个抽象语法树(AST)。之后,语义分析器会进行工作并生成一个通过类型检查的 AST,这一步的实现就是依赖于 SwiftSyntax (基于 libSyntax 库开发)
AST产生的原理
生成AST
swiftc -dump-ast main.swift
从Swift到源码
目前还没有能够从Swift AST编译回Swift的方法,那么我们就只能类似于做阅读理解一样,硬读AST,但是这也是有技巧的,寻找规律,才能轻松化解
我这里用notepad.exe打开的源码,然后让其识别为js代码,这样子就会有层次比较明显的父子节点关系
首先是函数初始化
(func_decl range=[re.swift:1:1 - line:14:1] "check(_:_:)" interface type='(String, String) -> Bool' access=internal
首先是一个函数的定义Bool check(String,String),我们先收起这个函数,往下分析
变量赋值
(argument
(integer_literal_expr type='Int' location=re.swift:6:55 range=[re.swift:6:55 - line:6:55] value=3 builtin_initializer=Swift.(file).Int.init(_builtinIntegerLiteral:) initializer=**NULL**))
)))
我们在这题中要注意的是value
主函数根据猜测check的两个参数分别为data和key,结果给result,key为345y,而data是我们输入的flag,现在我们分析收起来的部分,也就是check部分
这里说明函数Bool check(String encoded,String keyValue)
list转换为字符数组
(argument_list
(argument
(member_ref_expr type='String.UTF8View' location=re.swift:2:29 range=[re.swift:2:21 - line:2:29] decl=Swift.(file).String extension.utf8
(declref_expr type='String' location=re.swift:2:21 range=[re.swift:2:21 - line:2:21] decl=re.(file).check(_:_:).encoded@re.swift:1:14 function_ref=unapplied)))
这段代码可以翻译成
encoded.encode('utf8')
从11行到70行的代码类似,其中一个变量是b,另外一个是k,是两个数组,用来存放我们传入的key和data
这里是定义了四个变量,r0,r1,r2,r3,到这里为止程序的意思都是能猜出来的,在98行开始for_each_stmt,程序正式进入算法部分,就要认真分析了。
如何获取算法的计算过程
extension
我们要注意程序中的.extersion后缀 后面存储的是运算符号,比如此处,存储了我们的减号
本题目中出现的.extersion
extersion....
extersion.-
extersion.count //获取flag的长度
extension.subscript
extension.+
extension.^
extension.&
extension.>>
这里应该是个循环,i=0,binary_expr,113-119是对binary_expr的操作,操作为extersion后的减,而减法有两个参数,一个是 extension.count,另外一个是4,所以就是len-4,最后整理出来就是
for i in range(0, count(b)-4)
创建一个tupl元组tuple_expr,tuple=(r0,r1,r2,r3)
后面的操作又是类似的,先是b数组 ,参数是i和value,一共有四个
故我们可以整理得到这条赋值语句为 r0, r1, r2, r3 = ( b[i], b[i+1], b[i+2], b[i+3] )
分析得出b[i+0] = r2^(0xFF& (k[0]+ (r0>>4)) )
同理得出
b[i+1]=r3^(0xFF&(k[1]+(r1>>2)))
b[i+2]=r0^k[2]
b[i+3]=r1^k[3]
k[0], k[1], k[2], k[3] = k[1], k[2], k[3], k[0]
这个是value密文,直接写脚本就行
b=[88 ,35, 88, 225, 7 ,201, 57 ,94 ,77 ,56 ,75 ,168 ,72 ,218 ,64 ,91 ,16 ,
101 ,32 ,207 ,73 ,130,74 ,128,76 ,201,16 ,248,41 ,205,103,84 ,91 ,99 ,79 ,202,22 ,131,63 ,255,20 ,16]
k=[ord('3'),ord('4'),ord('5'),ord('y')]
for i in range (len(b)-4+1):
k[0],k[1],k[2],k[3]=k[1],k[2],k[3],k[0]
for i in range (len(b)-4,-1,-1):
r0 = b[i]
r1 = b[i + 1]
r2 = b[i + 2]
r3 = b[i + 3]
k[3],k[2],k[1],k[0]=k[2],k[1],k[0],k[3]
b[i + 1]=r3^k[3]
b[i + 0]=r2^k[2]
b[i + 2]=r0^((k[0]+(b[i]>>4))&0xff)
b[i + 3]=r1^((k[1]+(b[i+1]>>2))&0xff)
for i in range(len(b)):
print(chr(b[i]),end="")
babycode
这题下载下来是个.mrb后缀的文件,之前没遇到过,搜了一下发现是ruby语言的中间态,然后找到了篇以前ctf出过的ruby题,既然是mruby题,那我们先安装环境
安装mruby
将mruby源码clone到本地并编译,这里我下的最新版mruby,因为.mrb文件用notepad打开后,开头的RITE0300意味着版本很高
根据图片,我们在文件夹内输入命令rake -v就可以完成编译,在bin文件夹里就可以找到我们需要的mruby程序
查看文档,发现可以通过指令参数执行mrb文件,但是我的库文件好像有点问题,跑不起来,只能看字节码,自己翻译了
mruby -v -b babycode.mrb 得到Ruby汇编
mruby 3.1.0 (2022-05-12)
irep 0x55d3b2e1e4d0 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
007 EXEC R2 I(0:0x55d3b2e1e580)
010 TCLASS R2
012 METHOD R3 I(1:0x55d3b2e1ed80)
015 DEF R2 :check
018 SSEND R2 :gets n=0 (0x00)
022 SEND R2 :chomp n=0 (0x00)
026 MOVE R1 R2 ; R1:p
029 MOVE R3 R1 ; R1:p
032 SSEND R2 :check n=1 (0x01)
036 JMPNOT R2 050
040 STRING R3 L(0) ; yes
043 SSEND R2 :puts n=1 (0x01)
047 JMP 052
050 LOADNIL R2
052 RETURN R2
054 STOP
irep 0x55d3b2e1e580 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:0x55d3b2e1e650)
010 RETURN R1
irep 0x55d3b2e1e650 nregs=3 nlocals=1 pools=0 syms=6 reps=4 ilen=55
000 LOADI32 R1 305419896
006 SETCONST XX R1
009 LOADI R1 16
012 SETCONST YY R1
015 LOADSELF R1
017 SCLASS R1
019 METHOD R2 I(0:0x55d3b2e1e790)
022 DEF R1 :encrypt
025 TCLASS R1
027 METHOD R2 I(1:0x55d3b2e1e830)
030 DEF R1 :encrypt
033 SSEND R1 :private n=0 (0x00)
037 TCLASS R1
039 METHOD R2 I(2:0x55d3b2e1eb50)
042 DEF R1 :to_key
045 TCLASS R1
047 METHOD R2 I(3:0x55d3b2e1ec20)
050 DEF R1 :enc_one
053 RETURN R1
irep 0x55d3b2e1e790 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 (0x00)
011 MOVE R4 R5 ; R4:cip
014 MOVE R5 R4 ; R4:cip
017 MOVE R6 R1 ; R1:t
020 MOVE R7 R2 ; R2:p
023 SEND R5 :encrypt n=2 (0x02)
027 RETURN R5
irep 0x55d3b2e1e830 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 (0x01)
011 MOVE R4 R11 ; R4:key
014 ARRAY R5 R5 0 ; R5:c
017 LOADI_0 R6 ; R6:n
019 MOVE R11 R6 ; R6:n
022 MOVE R12 R1 ; R1:t
025 SEND R12 :length n=0 (0x00)
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 (0x00)
047 SEND R11 :to_i n=0 (0x00)
051 LOADI R12 24
054 SEND R11 :<< n=1 (0x01)
058 MOVE R7 R11 ; R7:num1
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 (0x00)
079 SEND R12 :to_i n=0 (0x00)
083 LOADI R13 16
086 SEND R12 :<< n=1 (0x01)
090 ADD R11 R12
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 (0x00)
113 SEND R12 :to_i n=0 (0x00)
117 LOADI R13 8
120 SEND R12 :<< n=1 (0x01)
124 ADD R11 R12
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 (0x00)
147 SEND R12 :to_i n=0 (0x00)
151 ADD R11 R12
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 (0x00)
171 SEND R11 :to_i n=0 (0x00)
175 LOADI R12 24
178 SEND R11 :<< n=1 (0x01)
182 MOVE R8 R11 ; R8:num2
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 (0x00)
203 SEND R12 :to_i n=0 (0x00)
207 LOADI R13 16
210 SEND R12 :<< n=1 (0x01)
214 ADD R11 R12
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 (0x00)
237 SEND R12 :to_i n=0 (0x00)
241 LOADI R13 8
244 SEND R12 :<< n=1 (0x01)
248 ADD R11 R12
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 (0x00)
271 SEND R12 :to_i n=0 (0x00)
275 ADD R11 R12
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 (0x03)
293 AREF R9 R11 0 ; R9:enum1
297 AREF R10 R11 1 ; R10:enum2
301 MOVE R11 R5 ; R5:c
304 MOVE R12 R9 ; R9:enum1
307 SEND R11 :<< n=1 (0x01)
311 MOVE R11 R5 ; R5:c
314 MOVE R12 R10 ; R10:enum2
317 SEND R11 :<< n=1 (0x01)
321 ADDI R6 8 ; R6:n
324 JMP 019
327 MOVE R11 R5 ; R5:c
330 BLOCK R12 I(0:0x55d3b2e1ea80)
333 SENDB R11 :collect n=0 (0x00)
337 STRING R12 L(0) ;
340 SEND R11 :join n=1 (0x01)
344 RETURN R11
irep 0x55d3b2e1ea80 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 (0x02)
014 RETURN R3
irep 0x55d3b2e1eb50 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 (0x01)
014 RETURN R3
irep 0x55d3b2e1ec20 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:0x55d3b2e1ecf0)
027 SENDB R8 :times n=0 (0x00)
031 MOVE R8 R5 ; R5:y
034 MOVE R9 R6 ; R6:z
037 ARRAY R8 R8 2
040 RETURN R8
irep 0x55d3b2e1ecf0 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 (0x01)
018 GETUPVAR R5 6 0
022 LOADI_5 R6
024 SEND R5 :>> n=1 (0x01)
028 SEND R4 :^ n=1 (0x01)
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 (0x01)
057 ADDI R7 1
060 LOADI_3 R8
062 SEND R7 :& n=1 (0x01)
066 GETIDX R6 R7
068 ADD R5 R6
070 SEND R4 :^ n=1 (0x01)
074 ADD R3 R4
076 SETUPVAR R3 5 0
080 LOADL R4 L(0) ; 4294967295
083 SEND R3 :& n=1 (0x01)
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 (0x01)
118 GETUPVAR R5 5 0
122 LOADI_5 R6
124 SEND R5 :>> n=1 (0x01)
128 SEND R4 :^ n=1 (0x01)
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 (0x01)
159 GETIDX R6 R7
161 ADD R5 R6
163 SEND R4 :^ n=1 (0x01)
167 ADD R3 R4
169 SETUPVAR R3 6 0
173 LOADL R4 L(0) ; 4294967295
176 SEND R3 :& n=1 (0x01)
180 SETUPVAR R3 6 0
184 RETURN R3
irep 0x55d3b2e1ed80 nregs=13 nlocals=8 pools=2 syms=7 reps=0 ilen=128
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
008 MOVE R8 R3 ; R3:i
011 MOVE R9 R1 ; R1:p
014 SEND R9 :length n=0 (0x00)
018 LT R8 R9
020 JMPNOT R8 086
024 MOVE R8 R1 ; R1:p
027 MOVE R9 R3 ; R3:i
030 GETIDX R8 R9
032 SEND R8 :ord n=0 (0x00)
036 MOVE R5 R8 ; R5:c
039 MOVE R8 R5 ; R5:c
042 MOVE R9 R4 ; R4:lst_ch
045 SEND R8 :^ n=1 (0x01)
049 MOVE R9 R3 ; R3:i
052 ADDI R9 1
055 SEND R8 :^ n=1 (0x01)
059 SEND R8 :chr n=0 (0x00)
063 MOVE R9 R1 ; R1:p
066 MOVE R10 R3 ; R3:i
069 MOVE R11 R8
072 SETIDX R9 R10 R11
074 MOVE R8 R5 ; R5:c
077 MOVE R4 R8 ; R4:lst_ch
080 ADDI R3 1 ; R3:i
083 JMP 008
086 STRING R6 L(0) ; aaaassssddddffff ; R6:k
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 (0x02)
105 MOVE R7 R8 ; R7:cipher_text
108 MOVE R8 R7 ; R7:cipher_text
111 STRING R9 L(1) ; f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb
114 EQ R8 R9
116 JMPNOT R8 124
120 LOADT R8
122 RETURN R8
124 LOADF R8
126 RETURN R8
ruby字节码文档
找到一份ruby字节码文档,可以对着看,比较乱,可以整理一下
Instruction Name | Operand type | Semantics |
---|---|---|
OP_NOP | - | |
OP_MOVE“ | BB | R(a) = R(b) |
OP_LOADL” | BB | R(a) = Pool(b) |
OP_LOADI“ | BsB | R(a) = mrb_int(b) |
OP_LOADI_0’ | B | R(a) = 0 |
OP_LOADI_1’ | B | R(a) = 1 |
OP_LOADI_2’ | B | R(a) = 2 |
OP_LOADI_3’ | B | R(a) = 3 |
OP_LOADSYM” | BB | R(a) = Syms(b) |
OP_LOADNIL’ | B | R(a) = nil |
OP_LOADSELF’ | B | R(a) = self |
OP_LOADT’ | B | R(a) = true |
OP_LOADF’ | B | R(a) = false |
OP_GETGV“ | BB | R(a) = getglobal(Syms(b)) |
OP_SETGV” | BB | setglobal(Syms(b), R(a)) |
OP_GETSV“ | BB | R(a) = Special[b] |
OP_SETSV” | BB | Special = R(a) |
OP_GETIV“ | BB | R(a) = ivget(Syms(b)) |
OP_SETIV” | BB | ivset(Syms(b),R(a)) |
OP_GETCV“ | BB | R(a) = cvget(Syms(b)) |
OP_SETCV” | BB | cvset(Syms(b),R(a)) |
OP_GETCONST“ | BB | R(a) = constget(Syms(b)) |
OP_SETCONST” | BB | constset(Syms(b),R(a)) |
OP_GETMCNST“ | BB | R(a) = R(a)::Syms(b) |
OP_SETMCNST” | BB | R(a+1)::Syms(b) = R(a) |
OP_GETUPVAR’ | BBB | R(a) = uvget(b,c) |
OP_SETUPVAR’ | BBB | uvset(b,c,R(a)) |
OP_JMP | S | pc+=a |
OP_JMPIF’ | SB | if R(b) pc+=a |
OP_JMPNOT’ | SB | if !R(b) pc+=a |
OP_ONERR | sS | rescue_push(pc+a) |
OP_EXCEPT’ | B | R(a) = exc |
OP_RESCUE“ | BB | R(b) = R(a).isa?(R(b)) |
OP_POPERR | B | a.times{rescue_pop()} |
OP_RAISE’ | B | raise(R(a)) |
OP_EPOP | B | A.times{ensure_pop().call} |
OP_SENDV” | BB | R(a) = call(R(a),Syms(b),R(a+1)) |
OP_SENDVB“ | BB | R(a) = call(R(a),Syms(b),R(a+1),&R(a+2)) |
OP_SEND” | BBB | R(a) = call(R(a),Syms(b),R(a+1),…,R(a+c)) |
OP_SENDB“ | BBB | R(a) = call(R(a),Syms(Bx),R(a+1),…,R(a+c),&R(a+c+1)) |
OP_CALL’ | B | R(a) = self.call(frame.argc, frame.argv) |
OP_SUPER’ | BB | R(a) = super(R(a+1),… ,R(a+b+1)) |
OP_ARGARY’ | BS | R(a) = argument array (16=5:1:5:1:4) |
OP_ENTER | W | arg setup according to flags (23=5:5:1:5:5:1:1) |
OP_KARG” | BB | R(a) = kdict # todo |
OP_KARG2“ | BB | R(a) = kdict; kdict.rm(Syms(b)) # todo |
OP_RETURN’ | B | return R(a) (normal) |
OP_RETURN_BLK’ | B | return R(a) (in-block return) |
OP_BREAK’ | B | break R(a) |
OP_BLKPUSH’ | BS | R(a) = block (16=5:1:5:1:4) |
OP_ADD” | BB | R(a) = R(a)+R(a+1) |
OP_ADDI“ | BBB | R(a) = R(a)+mrb_int© |
OP_SUB” | BB | R(a) = R(a)-R(a+1) |
OP_SUBI“ | BB | R(a) = R(a)-C |
OP_MUL” | BB | R(a) = R(a)R(a+1) |
OP_DIV“ | BB | R(a) = R(a)/R(a+1) |
OP_EQ” | BB | R(a) = R(a)==R(a+1) |
OP_LT“ | BB | R(a) = R(a)<R(a+1) |
OP_LE” | BB | R(a) = R(a)<=R(a+1) |
OP_GT“ | BB | R(a) = R |
OP_GE” | BB | R(a) = R(a)>=R(a+1) |
OP_ARRAY’ | BB | R(a) = ary_new(R(a),R(a+1)…R(a+b)) |
OP_ARRAY2“ | BB | R |
OP_ARYCAT’ | B | ary_cat(R(a),R(a+1)) |
OP_ARYPUSH’ | B | ary_push(R(a),R(a+1)) |
OP_AREF’ | BB | R(a) = R(a) |
OP_ASET’ | BB | R(a) = R(a+1) |
OP_APOST’ | BB | R(a),R(A+1)…R(A+C) = R(a)[B…] |
OP_STRING” | BB | R(a) = str_dup(Lit(b)) |
OP_STRCAT’ | B | str_cat(R(a),R(a+1)) |
OP_HASH’ | BB | R(a) = hash_new(R(a),R(a+1)…R(a+b)) |
OP_HASHADD’ | BB | R(a) = hash_push(R(a),R(a+1)…R(a+b)) |
OP_LAMBDA“ | BB | R(a) = lambda(SEQ,OP_L_LAMBDA) |
OP_BLOCK” | BB | R(a) = lambda(SEQ,OP_L_BLOCK) |
OP_METHOD“ | BB | R(a) = lambda(SEQ,OP_L_METHOD) |
OP_RANGE_INC’ | B | R(a) = range_new(R(a),R(a+1),FALSE) |
OP_RANGE_EXC’ | B | R(a) = range_new(R(a),R(a+1),TRUE) |
OP_OCLASS’ | B | R(a) = ::Object |
OP_CLASS” | BB | R(a) = newclass(R(a),Syms(b),R(a+1)) |
OP_MODULE“ | BB | R(a) = newmodule(R(a),Syms(b)) |
OP_EXEC” | BB | R(a) = blockexec(R(a),SEQ) |
OP_DEF“ | BB | R(a).newmethod(Syms(b),R(a+1)) |
OP_ALIAS’ | B | alias_method(R(a),R(a+1),R(a+2)) |
OP_UNDEF” | BB | undef_method(R(a),Syms(b)) |
OP_SCLASS’ | B | R(a) = R(a).singleton_class |
OP_TCLASS’ | B | R(a) = target_class |
OP_ERR’ | B | raise(RuntimeError, Lit(Bx)) |
OP_EXT1 | - | make 1st operand 16bit |
OP_EXT2 | - | make 2nd operand 16bit |
OP_EXT3 | - | make 1st and 2nd operands 16bit |
OP_STOP | - | stop VM |
check函数,也包含逐字节xor操作
irep 0x55d3b2e1ed80 nregs=13 nlocals=8 pools=2 syms=7 reps=0 ilen=128
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
i=0
006 LOADI_0 R4 ; R4:lst_ch
lst_ch=0
008 MOVE R8 R3 ; R3:i
R8=i
011 MOVE R9 R1 ; R1:p
R9=p
014 SEND R9 :length n=0 (0x00)
call length(p)
018 LT R8 R9
if i<length(p)继续执行,否则跳到86行
020 JMPNOT R8 086
024 MOVE R8 R1 ; R1:p
R8=p
027 MOVE R9 R3 ; R3:i
R9=i
030 GETIDX R8 R9
p[i]
032 SEND R8 :ord n=0 (0x00)
call ord(p[i])
036 MOVE R5 R8 ; R5:c
c=ord(p[i])
039 MOVE R8 R5 ; R5:c
R8=c
042 MOVE R9 R4 ; R4:lst_ch
R9=lst_ch
045 SEND R8 :^ n=1 (0x01)
call c^lst_ch
049 MOVE R9 R3 ; R3:i
R9=i
052 ADDI R9 1
R9=i+1
055 SEND R8 :^ n=1 (0x01)
call c^lst_ch^(i+1)
059 SEND R8 :chr n=0 (0x00)
call c^lst_ch^(i+1)
063 MOVE R9 R1 ; R1:p
R9=p
066 MOVE R10 R3 ; R3:i
R10=i
069 MOVE R11 R8
R11=c^lst_ch^(i+1)
072 SETIDX R9 R10 R11
p[i]=c^lst_ch^(i+1)
074 MOVE R8 R5 ; R5:c
R8=c
077 MOVE R4 R8 ; R4:lst_ch
lst_ch=c
080 ADDI R3 1 ; R3:i
R3=i+1
083 JMP 008
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
R9=p
098 MOVE R10 R6 ; R6:k
R10=k
101 SEND R8 :encrypt n=2 (0x02)
call encrypt(p,k)
105 MOVE R7 R8 ; R7:cipher_text
108 MOVE R8 R7 ; R7:cipher_text
111 STRING R9 L(1) ; f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb
114 EQ R8 R9
if !R8==R9 jmp 124
116 JMPNOT R8 124
if
120 LOADT R8
122 RETURN R8
return true
124 LOADF R8
126 RETURN R8
return false
每一行的解释都写在了字节码下面,整理一下
def check(p):
i=0
lst_ch=0
for i in range(len(p)):
c=ord(p[i])
p[i]=c^lst_ch^(i+1)
lst_ch=c
k="aaaassssddddffff"
m=encrypt(p,k)
if m!=f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb:
return false
else:
return true
函数定义及调用
irep 0x55d3b2e1e650 nregs=3 nlocals=1 pools=0 syms=6 reps=4 ilen=55
000 LOADI32 R1 305419896
R1=305419896
006 SETCONST XX R1
XX=305419896
009 LOADI R1 16
R1=16
012 SETCONST YY R1
YY=16
015 LOADSELF R1
017 SCLASS R1
019 METHOD R2 I(0:0x55d3b2e1e790)
022 DEF R1 :encrypt
encrypt=0x55d3b2e1e790
025 TCLASS R1
027 METHOD R2 I(1:0x55d3b2e1e830)
030 DEF R1 :encrypt
encrypt=0x55d3b2e1e830
033 SSEND R1 :private n=0 (0x00)
call encrypt=0x55d3b2e1e830 #八字节循环累加
037 TCLASS R1
039 METHOD R2 I(2:0x55d3b2e1eb50)
042 DEF R1 :to_key
to_key =0x55d3b2e1eb50
045 TCLASS R1
047 METHOD R2 I(3:0x55d3b2e1ec20)
050 DEF R1 :#enc_one
enc_one =0x55d3b2e1ec20
053 RETURN R1
这段好像没什么用,只是把函数名和函数地址对应起来,也就是定义函数,我们把函数地址对应的那块字节码先分析一下
irep 0x55d3b2e1e790 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
R5=CIPHER
007 SEND R5 :new n=0 (0x00)
call R5=new CIPHER()
011 MOVE R4 R5 ; R4:cip
cip=new CIPHER()
014 MOVE R5 R4 ; R4:cip
017 MOVE R6 R1 ; R1:t
020 MOVE R7 R2 ; R2:p
023 SEND R5 :encrypt n=2 (0x02)
call encrypt(t,p)
027 RETURN R5
转成python
def encrypt(t,p):
cip=CIPHER()
return _encrypt(t,p)
对结果进行累加
irep 0x55d3b2e1e830 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
R12=p
007 SSEND R11 :to_key n=1 (0x01)
call to_key(p)
011 MOVE R4 R11 ; R4:key
key=to_key(p)
014 ARRAY R5 R5 0 ; R5:c
R5
017 LOADI_0 R6 ; R6:n
n=0
019 MOVE R11 R6 ; R6:n
R11=n
022 MOVE R12 R1 ; R1:t
R12=t
025 SEND R12 :length n=0 (0x00)
call length(t)
029 LT R11 R12
n<length(t)
031 JMPNOT R11 327
035 MOVE R11 R1 ; R1:t
R11=t
038 MOVE R12 R6 ; R6:n
R12=n
041 GETIDX R11 R12
t[n]
043 SEND R11 :ord n=0 (0x00)
ord(t[n])
047 SEND R11 :to_i n=0 (0x00)
call to_i(ord(t[n]))
051 LOADI R12 24
R12=24
054 SEND R11 :<< n=1 (0x01)
to_i(ord(n[t]))<<24
058 MOVE R7 R11 ; R7:num1
num1=to_i(ord(n[t]))<<24
061 MOVE R11 R7 ; R7:num1
R11=num1
064 MOVE R12 R1 ; R1:t
R12=t
067 MOVE R13 R6 ; R6:n
R13=n
070 ADDI R13 1
R13=n+1
073 GETIDX R12 R13
t[n+1]
075 SEND R12 :ord n=0 (0x00)
ord(t[n+1])
079 SEND R12 :to_i n=0 (0x00)
call to_i(ord(t[n+1]))
083 LOADI R13 16
R13=16
086 SEND R12 :<< n=1 (0x01)
to_i(ord(t[n+1]))<<16
090 ADD R11 R12
num1+= to_i(ord(t[n+1]))<<16
092 MOVE R7 R11 ; R7:num1
095 MOVE R11 R7 ; R7:num1
R11=num1
098 MOVE R12 R1 ; R1:t
R12=t
101 MOVE R13 R6 ; R6:n
R13=n
104 ADDI R13 2
R13=n+2
107 GETIDX R12 R13
t[n+2]
109 SEND R12 :ord n=0 (0x00)
ord(t[n+2])
113 SEND R12 :to_i n=0 (0x00)
to_i(ord(t[n+2]))
117 LOADI R13 8
R13=8
120 SEND R12 :<< n=1 (0x01)
to_i(ord(t[n+2]))<<8
124 ADD R11 R12
num1+= to_i(ord(t[n+2]))<<8
126 MOVE R7 R11 ; R7:num1
129 MOVE R11 R7 ; R7:num1
R11=num1
132 MOVE R12 R1 ; R1:t
R12=t
135 MOVE R13 R6 ; R6:n
R13=n
138 ADDI R13 3
R13=n+3
141 GETIDX R12 R13
t[n+3]
143 SEND R12 :ord n=0 (0x00)
ord(t[n+3])
147 SEND R12 :to_i n=0 (0x00)
to_i(t[n+3])
151 ADD R11 R12
num1+= to_i(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 (0x00)
171 SEND R11 :to_i n=0 (0x00)
175 LOADI R12 24
178 SEND R11 :<< n=1 (0x01)
182 MOVE R8 R11 ; R8:num2
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 (0x00)
203 SEND R12 :to_i n=0 (0x00)
207 LOADI R13 16
210 SEND R12 :<< n=1 (0x01)
214 ADD R11 R12
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 (0x00)
237 SEND R12 :to_i n=0 (0x00)
241 LOADI R13 8
244 SEND R12 :<< n=1 (0x01)
248 ADD R11 R12
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 (0x00)
271 SEND R12 :to_i n=0 (0x00)
275 ADD R11 R12
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 (0x03)
call enc_one(num1,num2,key)
293 AREF R9 R11 0 ; R9:enum1
297 AREF R10 R11 1 ; R10:enum2
301 MOVE R11 R5 ; R5:c
304 MOVE R12 R9 ; R9:enum1
307 SEND R11 :<< n=1 (0x01)
311 MOVE R11 R5 ; R5:c
314 MOVE R12 R10 ; R10:enum2
317 SEND R11 :<< n=1 (0x01)
321 ADDI R6 8 ; R6:n
324 JMP 019
327 MOVE R11 R5 ; R5:c
330 BLOCK R12 I(0:0x55d3b2e1ea80)#下面解析
333 SENDB R11 :collect n=0 (0x00)
337 STRING R12 L(0) ;
340 SEND R11 :join n=1 (0x01)
344 RETURN R11
irep 0x55d3b2e1ea80 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 (0x02)
call sprintf(%.8x)
014 RETURN R3
这段代码比较有规律,分析前面一段就行了,然后我们写python代码
c=[]
for n in range(0,len(t),8):
num1 = int(ord(t[n])) << 24
num1 += (ord(t[n+1])) <<16
num1 += (ord(t[n+2])) <<8
num1 += (ord(t[n+3]))
num2 = (ord(t[n+4])) << 24
num2 += (ord(t[n+5])) <<16
num2 += (ord(t[n+6])) <<8
num2 += (ord(t[n+7]))
enum1,enum2=enc_one(num1,num2,key)
c.append(enum1)
c.append(enum2)
return hex(c)
irep x0x55d3b2e1e580 nregs=3 nlocals=1 pools=0 syms=1 reps=1 ilen=12
000 LOADNIL R1
R1=nil
002 LOADNIL R2
R2=nil
004 CLASS R1 :CIPHER
R1=new CIPHER
007 EXEC R1 I(0:0x55d3b2e1e650)#执行define函数
010 RETURN R1
mruby 3.1.0 (2022-05-12)
irep 0x55d3b2e1e4d0 nregs=5 nlocals=2 pools=1 syms=5 reps=2 ilen=55
local variable names:
R1:p
000 LOADNIL R2
R2=nil
002 LOADNIL R3
R3=nil
004 CLASS R2 :Crypt
R2=new Crypt()
007 EXEC R2 I(0:0x55d3b2e1e580)#实际执行执行define函数
blockexec(R(a),SEQ)
010 TCLASS R2
012 METHOD R3 I(1:0x55d3b2e1ed80)#check
015 DEF R2 :check
018 SSEND R2 :gets n=0 (0x00)
022 SEND R2 :chomp n=0 (0x00)
call check
026 MOVE R1 R2 ; R1:p
029 MOVE R3 R1 ; R1:p
032 SSEND R2 :check n=1 (0x01)
036 JMPNOT R2 050
040 STRING R3 L(0) ; yes
043 SSEND R2 :puts n=1 (0x01)
047 JMP 052
050 LOADNIL R2
052 RETURN R2
054 STOP
这里应该是check成功打印yes,还有最后一段就是
魔改XTEA
irep 0x55d3b2e1ecf0 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 (0x01)
018 GETUPVAR R5 6 0
022 LOADI_5 R6
024 SEND R5 :>> n=1 (0x01)
028 SEND R4 :^ n=1 (0x01)
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 (0x01)
057 ADDI R7 1
060 LOADI_3 R8
062 SEND R7 :& n=1 (0x01)
066 GETIDX R6 R7
068 ADD R5 R6
070 SEND R4 :^ n=1 (0x01)
074 ADD R3 R4
076 SETUPVAR R3 5 0
080 LOADL R4 L(0) ; 4294967295
083 SEND R3 :& n=1 (0x01)
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 (0x01)
118 GETUPVAR R5 5 0
122 LOADI_5 R6
124 SEND R5 :>> n=1 (0x01)
128 SEND R4 :^ n=1 (0x01)
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 (0x01)
159 GETIDX R6 R7
161 ADD R5 R6
163 SEND R4 :^ n=1 (0x01)
167 ADD R3 R4
169 SETUPVAR R3 6 0
173 LOADL R4 L(0) ; 4294967295
176 SEND R3 :& n=1 (0x01)
180 SETUPVAR R3 6 0
184 RETURN R3
这里面有许多指令SETUPVAR、GETUPVAR指令不认识,但是有很明显的XTEA特征,而且魔改了
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x12345678;
for (i=0; i < num_rounds; i++) {
v0 += (((v1 << 3) ^ (v1 >> 5)) + v1) ^ (sum + key[((sum>>11)+1) & 3]);
sum += delta;
v1 += (((v0 << 3) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum+1) & 3]);
}
v[0]=v0; v[1]=v1;
}
所以最后总结一下,整个程序的执行流程就是输入值进行c^lst_ch^(i+1)异或操作,每组八字节中每四个字节进行累加,最后进行XTEA加密
//XTEA
#include<stdio.h>
#include<stdlib.h>
#include <stdint.h>
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x12345678, sum=delta*num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 3) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum+1) & 3]);
sum -= delta;
v0 -= (((v1 << 3) ^ (v1 >> 5)) + v1) ^ (sum + key[((sum>>11)+1) & 3]);
}
v[0]=v0; v[1]=v1;
}
int main(){
uint32_t v[]={0xf469358b,0x7f165145,0x116e127a,0xd6105917,0xbce5225d,0x6d62a714,0xc390c5ed,0x93b22d8b,0x6b102a88,0x13488fdb};
uint32_t k[4]={'aaaa','ssss','dddd','ffff'};
int i;
for(i=0;i<5;i++){
encipher(16,&v[i*2],k);
printf("%08x%08x",v[i*2],v[i*2+1]);
}
}
#67080e02194b500d5c585f0b5e40461511470a08154211560d47491e04031d262771217626242765
然后就是对这串16进制数进行xor操作了
cipher = bytes.fromhex('67080e02194b500d5c585f0b5e40461511470a08154211560d47491e04031d262771217626242765')
cipher = list(cipher)
lst_ch=0
for i in range(len(cipher)):
cipher[i]^=lst_ch ^ (i+1)
lst_ch = cipher[i]
print(bytes(cipher))
#flag{6ad1c70c-daa4-11ec-9d64-0242ac1200}
secreeeeet
这题还没有复现出来,等复现完毕再补上…..
总结
这次国赛虽然题目出得有点恶心,两道阅读题,但是学到了很多,ast和ruby之前很少接触到,这次有了些理解,以后遇到类似的题目就能有点思路。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 767778848@qq.com