> 文章列表 > 阿里云CTF2023 字节码跳动 wp (javascript字节码)

阿里云CTF2023 字节码跳动 wp (javascript字节码)

阿里云CTF2023 字节码跳动 wp (javascript字节码)

本题主要考察javascript字节码的翻译。
V8 是 Google 开发的开源 JavaScript 引擎。 Chrome、Node.js和许多其他应用程序都在使用 V8。
如果只发布V8引擎编译后的字节码,就可以保护源码。
但为了保证大家能够把题目做出来,题目所提供的字节码中有详细的调试信息。

下面这篇文章非常详细,讲了变量声明、条件分支、循环、函数声明、类等最基本语法对应的字节码。
https://tw.coderbridge.com/series/817c07dc8e1c46f2b0a604b3b4e195c1
下面这个链接可以当v8的javascript字节码阅读官方文档来用。
https://github.com/v8/v8/blob/d84e9496d23cf1dc776ae32199d81accfabaafb5/src/interpreter/interpreter-generator.cc

其中,与汇编的区别主要在于acc寄存器。大部分的指令都围绕acc寄存器(比如lda系列指令的目标寄存器为acc,以及大部分的算术运算指令中acc默认为操作数之一),可以认为是具有特殊地位的rax。
另一个主要区别是constant pool,可以认为是把data段拆散了放在函数辖区内(在出题人不主动使用相关编译选项以提供constant pool的情况下,尚不清楚相关机理)。

解题思路

先在题目提供的filechecker_bytecode.txt中搜[generated,从海量函数中找到三个可疑函数:

  • main 25264行
  • aaa 25334行,constant pool中有一个极为可疑的常量,
    3edd7925cd6e04ab44f25bef57bc53bd20b74b8c11f893090fdcdfddad0709100100fe6a9230333234fbae
  • ccc 25505行,
    没有调用任何其他函数,返回值为布尔类型,函数过程出现了异或和与运算,以及大量jump。

原文译文对照

main的原文:

[generated bytecode for function: main (0x3711a3bdfd81 <SharedFunctionInfo main>)]
Bytecode length: 69
Parameter count 1
Register count 4
Frame size 32
OSR nesting level: 0
Bytecode Age: 01207 S> 0x3711a3be0a56 @    0 : 21 00 00          LdaGlobal [0], [0]0x3711a3be0a59 @    3 : c2                Star1 1215 E> 0x3711a3be0a5a @    4 : 2d f9 01 02       LdaNamedProperty r1, [1], [2]0x3711a3be0a5e @    8 : c2                Star1 0x3711a3be0a5f @    9 : 0d 02             LdaSmi [2]1219 E> 0x3711a3be0a61 @   11 : 2f f9 04          LdaKeyedProperty r1, [4]0x3711a3be0a64 @   14 : c3                Star0 1270 S> 0x3711a3be0a65 @   15 : 96 23             JumpIfToBooleanFalse [35] (0x3711a3be0a88 @ 50)0x3711a3be0a67 @   17 : 17 03             LdaImmutableCurrentContextSlot [3]0x3711a3be0a69 @   19 : c2                Star1 1279 E> 0x3711a3be0a6a @   20 : 61 f9 fa 06       CallUndefinedReceiver1 r1, r0, [6]0x3711a3be0a6e @   24 : c2                Star1 0x3711a3be0a6f @   25 : 11                LdaTrue 1286 E> 0x3711a3be0a70 @   26 : 6a f9 08          TestEqual r1, [8]0x3711a3be0a73 @   29 : 98 15             JumpIfFalse [21] (0x3711a3be0a88 @ 50)1305 S> 0x3711a3be0a75 @   31 : 21 02 09          LdaGlobal [2], [9]0x3711a3be0a78 @   34 : c1                Star2 1313 E> 0x3711a3be0a79 @   35 : 2d f8 03 0b       LdaNamedProperty r2, [3], [11]0x3711a3be0a7d @   39 : c2                Star1 0x3711a3be0a7e @   40 : 13 04             LdaConstant [4]0x3711a3be0a80 @   42 : c0                Star3 1313 E> 0x3711a3be0a81 @   43 : 5d f9 f8 f7 0d    CallProperty1 r1, r2, r3, [13]0x3711a3be0a86 @   48 : 89 13             Jump [19] (0x3711a3be0a99 @ 67)1349 S> 0x3711a3be0a88 @   50 : 21 02 09          LdaGlobal [2], [9]0x3711a3be0a8b @   53 : c1                Star2 1357 E> 0x3711a3be0a8c @   54 : 2d f8 03 0b       LdaNamedProperty r2, [3], [11]0x3711a3be0a90 @   58 : c2                Star1 0x3711a3be0a91 @   59 : 13 05             LdaConstant [5]0x3711a3be0a93 @   61 : c0                Star3 1357 E> 0x3711a3be0a94 @   62 : 5d f9 f8 f7 0f    CallProperty1 r1, r2, r3, [15]0x3711a3be0a99 @   67 : 0e                LdaUndefined 1378 S> 0x3711a3be0a9a @   68 : a8                Return 
Constant pool (size = 6)
0x3711a3be09e1: [FixedArray] in OldSpace- map: 0x2546cb1c12c1 <Map>- length: 60: 0x39ea5930f9e9 <String[7]: #process>1: 0x20e3b754b6d9 <String[4]: #argv>2: 0x26784b2e1619 <String[7]: #console>3: 0x0ef123a28e69 <String[3]: #log>4: 0x3711a3be0961 <String[6]: #Right!>5: 0x3711a3be0979 <String[6]: #Wrong!>
Handler Table (size = 0)
Source Position Table (size = 31)
0x3711a3be0aa1 <ByteArray[31]>

main的指令翻译如下:

acc = global.process
r1 = acc
acc = global.process.argv
r1 = acc
(now r1 = global.process.argv)
acc = 2
acc = r1[acc], 即acc = global.process.argv[2]
r0 = acc
(now r0 = global.process.argv[2])
如果r0的值转为boolean后为false,则跳转到wrong。意思应该是判空。
acc = 某外部函数
r1 = acc
调用r1,参数个数为1,参数放在r0,即调用某外部函数(global.process.argv[2])
r1 = acc
acc = True
acc如果不为true,则跳转到wrong。意思是某外部函数要返回true。
r2 = console
r1 = console.log
r3 = 'Right!'
console.log(r3)
jmp ret
console.log('Wrong!')
ret

可见main函数的关键是这个外部函数。

aaa函数原文:

[generated bytecode for function: aaa (0x3711a3bdfd31 <SharedFunctionInfo aaa>)]
Bytecode length: 91
Parameter count 2
Register count 7
Frame size 56
OSR nesting level: 0
Bytecode Age: 0757 S> 0x3711a3be0cde @    0 : 21 00 00          LdaGlobal [0], [0]0x3711a3be0ce1 @    3 : c0                Star3 768 E> 0x3711a3be0ce2 @    4 : 2d f7 01 02       LdaNamedProperty r3, [1], [2]0x3711a3be0ce6 @    8 : c0                Star3 0x3711a3be0ce7 @    9 : 0b f7             Ldar r3757 E> 0x3711a3be0ce9 @   11 : 68 f7 03 01 04    Construct r3, a0-a0, [4]0x3711a3be0cee @   16 : c3                Star0 792 S> 0x3711a3be0cef @   17 : 2d fa 02 06       LdaNamedProperty r0, [2], [6]0x3711a3be0cf3 @   21 : c0                Star3 0x3711a3be0cf4 @   22 : 0d 2b             LdaSmi [43]799 E> 0x3711a3be0cf6 @   24 : 6a f7 08          TestEqual r3, [8]0x3711a3be0cf9 @   27 : 97 04             JumpIfTrue [4] (0x3711a3be0cfd @ 31)806 S> 0x3711a3be0cfb @   29 : 12                LdaFalse 819 S> 0x3711a3be0cfc @   30 : a8                Return 835 S> 0x3711a3be0cfd @   31 : 21 00 00          LdaGlobal [0], [0]0x3711a3be0d00 @   34 : c0                Star3 846 E> 0x3711a3be0d01 @   35 : 2d f7 03 09       LdaNamedProperty r3, [3], [9]0x3711a3be0d05 @   39 : c0                Star3 0x3711a3be0d06 @   40 : 0d 2b             LdaSmi [43]0x3711a3be0d08 @   42 : bf                Star4 0x3711a3be0d09 @   43 : 0b f7             Ldar r3835 E> 0x3711a3be0d0b @   45 : 68 f7 f6 01 0b    Construct r3, r4-r4, [11]0x3711a3be0d10 @   50 : c2                Star1 942 S> 0x3711a3be0d11 @   51 : 21 00 00          LdaGlobal [0], [0]0x3711a3be0d14 @   54 : bf                Star4 949 E> 0x3711a3be0d15 @   55 : 2d f6 01 02       LdaNamedProperty r4, [1], [2]0x3711a3be0d19 @   59 : c0                Star3 0x3711a3be0d1a @   60 : 13 04             LdaConstant [4]0x3711a3be0d1c @   62 : be                Star5 0x3711a3be0d1d @   63 : 13 05             LdaConstant [5]0x3711a3be0d1f @   65 : bd                Star6 949 E> 0x3711a3be0d20 @   66 : 5e f7 f6 f5 f4 0d CallProperty2 r3, r4, r5, r6, [13]0x3711a3be0d26 @   72 : c1                Star2 1056 S> 0x3711a3be0d27 @   73 : 17 02             LdaImmutableCurrentContextSlot [2]0x3711a3be0d29 @   75 : c0                Star3 0x3711a3be0d2a @   76 : 19 fa f6          Mov r0, r40x3711a3be0d2d @   79 : 19 f9 f5          Mov r1, r50x3711a3be0d30 @   82 : 19 f8 f4          Mov r2, r61063 E> 0x3711a3be0d33 @   85 : 5f f7 f6 03 0f    CallUndefinedReceiver r3, r4-r6, [15]1087 S> 0x3711a3be0d38 @   90 : a8                Return 
Constant pool (size = 6)
0x3711a3be0c69: [FixedArray] in OldSpace- map: 0x2546cb1c12c1 <Map>- length: 60: 0x3adf78836561 <String[6]: #Buffer>1: 0x2546cb1c4999 <String[4]: #from>2: 0x2546cb1c4d41 <String[6]: #length>3: 0x3adf78836c31 <String[5]: #alloc>4: 0x3711a3be0bb1 <String[86]: #3edd7925cd6e04ab44f25bef57bc53bd20b74b8c11f893090fdcdfddad0709100100fe6a9230333234fbae>5: 0x3adf78838741 <String[3]: #hex>
Handler Table (size = 0)
Source Position Table (size = 38)
0x3711a3be0d41 <ByteArray[38]>

aaa函数翻译如下:

r3 = Buffer
r3 = Buffer.from
acc = Buffer.from
r0 = new Buffer.from(a0),猜测此处的a0就是main传进来的用户输入。姑且称为buf。
r3 = buf.length
判断buf.length是否为43,如果不为则直接返回false。
r3 = Buffer
r3 = Buffer.alloc
r4 = 43
acc = Buffer.alloc
r1 = new Buffer.alloc(43)
r4 = Buffer
r3 = Buffer.from
r5 = 3edd7925cd6e04ab44f25bef57bc53bd20b74b8c11f893090fdcdfddad0709100100fe6a9230333234fbae
r6 = hex
r2 = Buffer.from(r5, 'hex')
r3 = 外部函数
r4 = r0 (用户输入,长度43)
r5 = r1 (空置buffer,长度43)
r6 = r2(内置常量,长度86)
return 外部函数(r4, r5, r6)

有理由怀疑aaa函数中的外部函数是ccc。
ccc函数原文:

[generated bytecode for function: ccc (0x3711a3bdfce1 <SharedFunctionInfo ccc>)]
Bytecode length: 188
Parameter count 4
Register count 4
Frame size 32
OSR nesting level: 0
Bytecode Age: 0173 S> 0x3711a3be1216 @    0 : 00 0d aa 00       LdaSmi.Wide [170]0x3711a3be121a @    4 : c3                Star0 188 S> 0x3711a3be121b @    5 : 0c                LdaZero 189 E> 0x3711a3be121c @    6 : 23 00 00          StaGlobal [0], [0]194 S> 0x3711a3be121f @    9 : 21 00 02          LdaGlobal [0], [2]0x3711a3be1222 @   12 : c1                Star2 0x3711a3be1223 @   13 : 0d 13             LdaSmi [19]194 E> 0x3711a3be1225 @   15 : 6c f8 04          TestLessThan r2, [4]0x3711a3be1228 @   18 : 98 2a             JumpIfFalse [42] (0x3711a3be1252 @ 60)274 S> 0x3711a3be122a @   20 : 21 00 02          LdaGlobal [0], [2]273 E> 0x3711a3be122d @   23 : 2f 03 06          LdaKeyedProperty a0, [6]265 E> 0x3711a3be1230 @   26 : 38 fa 08          Add r0, [8]277 E> 0x3711a3be1233 @   29 : 44 33 09          AddSmi [51], [9]285 E> 0x3711a3be1236 @   32 : 00 4c ff 00 05 00 BitwiseAndSmi.Wide [255], [5]0x3711a3be123c @   38 : c3                Star0 305 S> 0x3711a3be123d @   39 : 21 00 02          LdaGlobal [0], [2]0x3711a3be1240 @   42 : c0                Star3 0x3711a3be1241 @   43 : 0b fa             Ldar r0308 E> 0x3711a3be1243 @   45 : 34 04 f7 0a       StaKeyedProperty a1, r3, [10]200 S> 0x3711a3be1247 @   49 : 21 00 02          LdaGlobal [0], [2]0x3711a3be124a @   52 : 50 0c             Inc [12]200 E> 0x3711a3be124c @   54 : 23 00 00          StaGlobal [0], [0]183 E> 0x3711a3be124f @   57 : 88 30 00          JumpLoop [48], [0] (0x3711a3be121f @ 9)337 S> 0x3711a3be1252 @   60 : 0d 55             LdaSmi [85]0x3711a3be1254 @   62 : c2                Star1 352 S> 0x3711a3be1255 @   63 : 0d 13             LdaSmi [19]353 E> 0x3711a3be1257 @   65 : 23 00 00          StaGlobal [0], [0]359 S> 0x3711a3be125a @   68 : 21 00 02          LdaGlobal [0], [2]0x3711a3be125d @   71 : c1                Star2 0x3711a3be125e @   72 : 0d 2b             LdaSmi [43]359 E> 0x3711a3be1260 @   74 : 6c f8 0d          TestLessThan r2, [13]0x3711a3be1263 @   77 : 98 34             JumpIfFalse [52] (0x3711a3be1297 @ 129)383 S> 0x3711a3be1265 @   79 : 21 00 02          LdaGlobal [0], [2]0x3711a3be1268 @   82 : c0                Star3 403 E> 0x3711a3be1269 @   83 : 21 00 02          LdaGlobal [0], [2]402 E> 0x3711a3be126c @   86 : 2f 03 10          LdaKeyedProperty a0, [16]394 E> 0x3711a3be126f @   89 : 38 f9 0f          Add r1, [15]407 E> 0x3711a3be1272 @   92 : 00 4c ff 00 0e 00 BitwiseAndSmi.Wide [255], [14]386 E> 0x3711a3be1278 @   98 : 34 04 f7 12       StaKeyedProperty a1, r3, [18]442 S> 0x3711a3be127c @  102 : 21 00 02          LdaGlobal [0], [2]441 E> 0x3711a3be127f @  105 : 2f 04 16          LdaKeyedProperty a1, [22]436 E> 0x3711a3be1282 @  108 : 3f f9 15          BitwiseXor r1, [21]446 E> 0x3711a3be1285 @  111 : 00 4c ff 00 14 00 BitwiseAndSmi.Wide [255], [20]0x3711a3be128b @  117 : c2                Star1 365 S> 0x3711a3be128c @  118 : 21 00 02          LdaGlobal [0], [2]0x3711a3be128f @  121 : 50 18             Inc [24]365 E> 0x3711a3be1291 @  123 : 23 00 00          StaGlobal [0], [0]347 E> 0x3711a3be1294 @  126 : 88 3a 00          JumpLoop [58], [0] (0x3711a3be125a @ 68)531 S> 0x3711a3be1297 @  129 : 00 0d 9f 00       LdaSmi.Wide [159]540 E> 0x3711a3be129b @  133 : 6a f9 19          TestEqual r1, [25]0x3711a3be129e @  136 : 98 32             JumpIfFalse [50] (0x3711a3be12d0 @ 186)563 S> 0x3711a3be12a0 @  138 : 0c                LdaZero 564 E> 0x3711a3be12a1 @  139 : 23 00 00          StaGlobal [0], [0]569 S> 0x3711a3be12a4 @  142 : 21 00 02          LdaGlobal [0], [2]0x3711a3be12a7 @  145 : c1                Star2 0x3711a3be12a8 @  146 : 0d 2b             LdaSmi [43]569 E> 0x3711a3be12aa @  148 : 6c f8 1a          TestLessThan r2, [26]0x3711a3be12ad @  151 : 98 21             JumpIfFalse [33] (0x3711a3be12ce @ 184)604 S> 0x3711a3be12af @  153 : 21 00 02          LdaGlobal [0], [2]603 E> 0x3711a3be12b2 @  156 : 2f 05 1b          LdaKeyedProperty a2, [27]0x3711a3be12b5 @  159 : c1                Star2 614 E> 0x3711a3be12b6 @  160 : 21 00 02          LdaGlobal [0], [2]613 E> 0x3711a3be12b9 @  163 : 2f 04 1d          LdaKeyedProperty a1, [29]607 E> 0x3711a3be12bc @  166 : 6a f8 1f          TestEqual r2, [31]0x3711a3be12bf @  169 : 97 04             JumpIfTrue [4] (0x3711a3be12c3 @ 173)636 S> 0x3711a3be12c1 @  171 : 12                LdaFalse 649 S> 0x3711a3be12c2 @  172 : a8                Return 575 S> 0x3711a3be12c3 @  173 : 21 00 02          LdaGlobal [0], [2]0x3711a3be12c6 @  176 : 50 20             Inc [32]575 E> 0x3711a3be12c8 @  178 : 23 00 00          StaGlobal [0], [0]558 E> 0x3711a3be12cb @  181 : 88 27 00          JumpLoop [39], [0] (0x3711a3be12a4 @ 142)682 S> 0x3711a3be12ce @  184 : 11                LdaTrue 694 S> 0x3711a3be12cf @  185 : a8                Return 705 S> 0x3711a3be12d0 @  186 : 12                LdaFalse 718 S> 0x3711a3be12d1 @  187 : a8                Return 
Constant pool (size = 1)
0x3711a3be11c9: [FixedArray] in OldSpace- map: 0x2546cb1c12c1 <Map>- length: 10: 0x2546cb1c9159 <String[1]: #i>
Handler Table (size = 0)
Source Position Table (size = 119)
0x3711a3be12d9 <ByteArray[119]>

ccc函数翻译:

r0 = 170
i = 0
{循环体开始
r2 = i
判断r2 < 19
acc = a0[i]
acc += r0
acc += 51
acc &= 0xff
r0 = acc
r3 = i
acc = r0
a1[r3] = acc,即a1[i] = r0
i += 1
}循环体结束label_19轮循环过后:
r1 = 85
i = 19
{循环体开始
r2 = i
判断r2 < 43
r3 = i
acc = a0[i]
acc += r1
acc &= 0xff
a1[r3] = acc,即a1[i] = acc
acc = a1[i]
acc ^= r1
acc &= 0xff
r1 = acc
i += 1
}循环体结束label_43轮循环过后:
判断r1 == 159,如果不等,则return false
i = 0
{循环体开始
r2 = i
判断r2 < 43,如果超过,则return true
r2 = a2[i]
acc = a1[i]
判断是否相等,不相等则return false
i += 1
}循环体结束

解题脚本

mid = '3edd7925cd6e04ab44f25bef57bc53bd20b74b8c11f893090fdcdfddad0709100100fe6a9230333234fbae'
# print(len(mid))flag = ''
r0 = 170
for i in range(19):dst = int(mid[2 * i:2 * i + 2], 16)# print('dst:', dst, hex(dst))for ch in range(128):acc = chacc += r0acc += 51acc &= 0xff# print(ch, hex(ch))if acc == dst:flag += chr(ch)r0 = accbreak
print(r0)
print(flag)r1 = 85
for i in range(19, 43):dst = int(mid[2 * i:2 * i + 2], 16)# print('dst:', dst, hex(dst))for ch in range(128):acc = chacc += r1acc &= 0xffif acc == dst:flag += chr(ch)r1 = ((acc ^ r1) & 0xff)break
print(r1)
print(flag)