2024矩阵杯线上初赛-jvm

jvm

quick js 逆向

第一次接触。

首先在程序中找到相关信息,包括quick js 的版本。

image.png

在 github 中找到相关的源码版本, 下载下来本地编译

修改一下debug相关,使程序dump出 字节码:

1

修改 quickjs.c

image.png

然后找到

1
JS_ReadFunctionTag

函数

image.png

尾部添加 dump函数,即可

image.png

编写 Lu1u.c 文件,从二进制文件中提取bytecode. 修改qjsc_hello 和 qjsc_hello_size 即可。

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
/* File generated automatically by the QuickJS compiler. */

#include "quickjs-libc.h"

const uint32_t qjsc_hello_size = 3881;

const uint8_t qjsc_hello[3881] = {

};

static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContextRaw(rt);
if (!ctx)
return NULL;
JS_AddIntrinsicBaseObjects(ctx);
JS_AddIntrinsicBigInt(ctx);
return ctx;
}

int main(int argc, char **argv)
{
JSRuntime *rt; //js运行时
JSContext *ctx; //上下文
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0);
js_std_loop(ctx);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return 0;
}

提取方法,在main函数中会被引用:

image.png

编译:

1
2
3
gcc Lu1u.c libquickjs.a -lm -ldl -lpthread -o test


然后运行,即可打印出相关的Opcode.

1

这题用js实现了一个虚拟机,并且一些Opcode指令可能被替换,只能根据程序逻辑和一些符号来猜测。

替换的指令:

1
2
3
4
add 替换成 div
xor 替换成 and

......

最终的比较数据:

image.png

image.png

image.png

解读完opcode的代码后,解析相应代码

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
"""
1 getReg

2 getReg

8: REG[r1] = REG[r1] << REG[r2]

"""

opcodes = [1, 1, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 16, 1, 1, 1, 1, 2, 0, 0, 0, 8, 2, 3, 1, 17, 3, 2, 15
, 2, 3, 3, 16, 2, 1, 2, 1, 2, 0, 0, 0, 1, 3, 1, 2, 12, 1, 256, 13, 0, 0, 0, 18, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0
, 0, 0, 15, 2, 1, 0, 3, 1, 2, 15, 2, 2, 0, 3, 1, 2, 1, 2, 0, 0, 0, 256, 17, 1, 2, 15, 2, 1, 1, 15, 3, 1, 0, 16
, 1, 0, 2, 16, 1, 1, 3, 1, 2, 0, 0, 0, 1, 3, 0, 2, 12, 0, 256, 13, 0, 0, 0, 71, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0
, 0, 0, 1, 2, 0, 0, 0, 0, 1, 3, 0, 0, 0, 1, 3, 1, 3, 1, 3, 0, 0, 0, 256, 17, 1, 3, 15, 3, 1, 1, 3, 2, 3, 1, 3
, 0, 0, 0, 256, 17, 2, 3, 15, 3, 1, 1, 15, 4, 1, 2, 16, 1, 2, 3, 16, 1, 1, 4, 3, 3, 4, 1, 4, 0, 0, 0, 256, 17
, 3, 4, 15, 4, 0, 0, 11, 4, 3, 16, 0, 0, 4, 1, 4, 0, 0, 0, 1, 3, 0, 4, 12, 0, 27, 13, 0, 0, 0, 145, 0]


"""
1, 1 , getreg 1
0, 0, 0, 0, 累加
save reg 1

mov eax,0

1, 2, 0, 0, 0, 0,
mov ebx,0
1, 3, 0, 0, 0, 0,
mov ecx,0
16, 1, 1,1,
REG[rindx]=buff[idx]

1, 2, 0, 0, 0, 8,
mov ebx,8
2, 3,1,
17, 3, 2,
ModReg

15 , 2, 3, 3,
16, 2, 1, 2,

1, 2, 0, 0, 0, 1,
3, 1, 2,
12, 1, 256,
13, 0, 0, 0, 18,
jne 18???

1, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0,
15, 2, 1, 0,
3, 1, 2,
15, 2, 2, 0,
3, 1, 2,
1, 2, 0, 0, 0, 256,
17, 1, 2,
15, 2, 1, 1,
15, 3, 1, 0,
16, 1, 0, 2,
16, 1, 1, 3,

1, 2, 0, 0, 0, 1,
3, 0, 2,
12, 0, 256,
13, 0, 0, 0, 71,
1, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0,
1, 2, 0, 0, 0, 0,
1, 3, 0, 0, 0, 1,
3, 1, 3,
1, 3, 0, 0, 0, 256,
17, 1, 3,
15, 3, 1, 1,
3, 2, 3,
1, 3, 0, 0, 0, 256,
17, 2, 3,
15, 3, 1, 1,
15, 4, 1, 2,
16, 1, 2, 3,
16, 1, 1, 4,
3, 3, 4,
1, 4, 0, 0, 0, 256,
17, 3, 4,
15, 4, 0, 0,
11, 4, 3,
16, 0, 0, 4,
1, 4, 0, 0, 0, 1,
3, 0, 4,
12, 0, 27,
13, 0, 0, 0, 145,
0

"""

ip = 0


while opcodes[ip] != 0:

ccode = opcodes[ip]
if ccode == 1:
reg = opcodes[ip + 1]
data = sum(opcodes[ip+2:ip+6])
# print('REG[reg:%d]=%d'% (reg, data))
print('mov REG[reg:%d],%d'% (reg, data))
ip += 6
if ccode == 2:

# print("REG[reg:%d] = REG[reg:%d]"%(opcodes[ip + 2], opcodes[ip + 1]))
print("mov REG[reg:%d], REG[reg:%d]"%(opcodes[ip + 2], opcodes[ip + 1]))
ip += 3
if ccode == 3:
print("add REG[reg:%d], REG[reg:%d]"%(opcodes[ip + 1], opcodes[ip + 2]))
ip += 3
if ccode == 4:
print("sub REG[reg:%d], REG[reg:%d]"%(opcodes[ip + 2], opcodes[ip + 1]))
ip += 3
if ccode == 11:
print("xor REG[reg:%d],REG[reg:%d]"%(opcodes[ip + 2], opcodes[ip + 1]))
ip += 3

if ccode == 12:
print("cmp REG[reg:%d], %d"%(opcodes[ip + 1], opcodes[ip + 2]))
ip += 3
if ccode == 13:
print("jne %d"%sum(opcodes[ip+1:ip+6]))
ip += 5
if ccode == 15:
print("REG[dataIdx:%d]=buf[bufIdx:%d]=REG[regid:%d]"%(opcodes[ip + 3], opcodes[ip + 2],opcodes[ip + 1]))
ip += 4

if ccode == 16:
print("REG[regid:%d]=REG[dataIdx:%d]=buf[bufIdx:%d]"%(opcodes[ip + 3], opcodes[ip + 2],opcodes[ip + 1]))
ip += 4
if ccode == 17:
# print("modREG REG[reg:%d]-=REG[reg:%d]"%(opcodes[ip + 2], opcodes[ip + 1]))
print("mod REG[reg:%d],REG[reg:%d]"%(opcodes[ip + 1], opcodes[ip + 2]))
ip += 3

稍微解析一下得到:

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
mov REG[reg:1],0
mov REG[reg:2],0
mov REG[reg:3],0
REG[regid:1]=REG[dataIdx:1]=buf[bufIdx:1]
mov REG[reg:2],8
mov REG[reg:1], REG[reg:3]
mod REG[reg:3],REG[reg:2]
REG[dataIdx:3]=buf[bufIdx:3]=REG[regid:2]
REG[regid:2]=REG[dataIdx:1]=buf[bufIdx:2]
mov REG[reg:2],1
add REG[reg:1], REG[reg:2]
cmp REG[reg:1], 256
jne 19
mov REG[reg:0],0
mov REG[reg:1],0
REG[dataIdx:0]=buf[bufIdx:1]=REG[regid:2]
add REG[reg:1], REG[reg:2]
REG[dataIdx:0]=buf[bufIdx:2]=REG[regid:2]
add REG[reg:1], REG[reg:2]
mov REG[reg:2],256
mod REG[reg:1],REG[reg:2]
REG[dataIdx:1]=buf[bufIdx:1]=REG[regid:2]
REG[dataIdx:0]=buf[bufIdx:1]=REG[regid:3]
REG[regid:2]=REG[dataIdx:0]=buf[bufIdx:1]
REG[regid:3]=REG[dataIdx:1]=buf[bufIdx:1]
mov REG[reg:2],1
add REG[reg:0], REG[reg:2]
cmp REG[reg:0], 256
jne 72
mov REG[reg:0],0
mov REG[reg:1],0
mov REG[reg:2],0
mov REG[reg:3],1
add REG[reg:1], REG[reg:3]
mov REG[reg:3],256
mod REG[reg:1],REG[reg:3]
REG[dataIdx:1]=buf[bufIdx:1]=REG[regid:3]
add REG[reg:2], REG[reg:3]
mov REG[reg:3],256
mod REG[reg:2],REG[reg:3]
REG[dataIdx:1]=buf[bufIdx:1]=REG[regid:3]
REG[dataIdx:2]=buf[bufIdx:1]=REG[regid:4]
REG[regid:3]=REG[dataIdx:2]=buf[bufIdx:1]
REG[regid:4]=REG[dataIdx:1]=buf[bufIdx:1]
add REG[reg:3], REG[reg:4]
mov REG[reg:4],256
mod REG[reg:3],REG[reg:4]
REG[dataIdx:0]=buf[bufIdx:0]=REG[regid:4]
xor REG[reg:3],REG[reg:4]
REG[regid:4]=REG[dataIdx:0]=buf[bufIdx:0]
mov REG[reg:4],1
add REG[reg:0], REG[reg:4]
cmp REG[reg:0], 27
jne 145

发现是rc4 ,但是存在魔改,最后xor的时候,是直接和索引进行xor的。

1
2
3
4
5
mov REG[reg:4],256
mod REG[reg:3],REG[reg:4] # 取模运算,索引放入 REG[reg:3] ecx
REG[dataIdx:0]=buf[bufIdx:0]=REG[regid:4] # 一个取值运算?
xor REG[reg:3],REG[reg:4] # xor REG[reg:3] ^ REG[reg:4]
REG[regid:4]=REG[dataIdx:0]=buf[bufIdx:0]

编写解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

static void rc4_init(unsigned char* p_s, unsigned char* p_key, unsigned int p_key_len)
{
unsigned char t_k[256];
int t_i;
for (t_i = 0; t_i < 256; t_i++)
{
p_s[t_i] = t_i;
t_k[t_i] = p_key[t_i % p_key_len];
}
int t_j = 0;
for (t_i = 0; t_i < 256; t_i++)
{
t_j = (t_j + p_s[t_i] + t_k[t_i]) % 256;
unsigned char t_tmp = p_s[t_i];
p_s[t_i] = p_s[t_j];
p_s[t_j] = t_tmp;
}
}

void rc4_crypt(unsigned char* p_data, unsigned int p_data_len, unsigned char* p_key, unsigned int p_key_len)
{
unsigned char t_s[256];
rc4_init(t_s, p_key, p_key_len);
int t_i = 0, t_j = 0;
unsigned int t_k;
for (t_k = 0; t_k < p_data_len; t_k++)
{
t_i = (t_i + 1) % 256;
t_j = (t_j + t_s[t_i]) % 256;
unsigned char t_tmp = t_s[t_i];
t_s[t_i] = t_s[t_j];
t_s[t_j] = t_tmp;
int t_t = (t_s[t_i] + t_s[t_j]) % 256;
p_data[t_k] ^= t_t;
}
}


int main()
{
unsigned char t_data[] = { 0x20,0xd5,0x95,0xf7,0x32,0x2f,0x74,0x95,0x70,0xf9,0xce,0x59,0xd5,0xde,0x9b,0xc2,0x51,0x12,0xd4,0xf6,0x60,0xbe,0x96,0x33,0x0c,0x45,0x03 };
unsigned char key[8] = { 0xde,0xad,0xbe,0x0f,0x0f,0xbe,0xad,0xde };

rc4_crypt(t_data, 27, key, 8);
printf("加密后的数据:\n");
int t_i;
for (t_i = 0; t_i < 27; t_i++)
printf("%x ", t_data[t_i]);
printf("\n");


return 0;
}
1
2
3
66 6c 61 67 7b 6a 73 33 6e 67 31 6e 37 6c 69 6b 33 6d 31 72 30 75 74 65 72 21 7d

# flag{js3ng1n7lik3m1r0uter!}

2024矩阵杯线上初赛-jvm
https://pwner.top/2024/06/01/2024矩阵杯线上初赛-jvm/
作者
m1n9yu3
发布于
2024年6月1日
许可协议