第十五届全国大学生信息安全竞赛创新实践能力赛CISCN

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