Crane => Blog

猫系代码少年Crane

0%

腾讯极客挑战赛-码上种树

作为一名凑热闹选手,去看了看种树比赛

前面两道题没有留记录,只记得是比较简单的js执行

第三题

base64解码,格式化一下,整理成这样的代码

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
(function(a, b) {
var _0x23fc5a = function(_0x2858d9) {
while (--_0x2858d9) {
a['push'](a['shift']());
}
};
_0x23fc5a(++b);
}(['A5473788'], 0x196));

var _0x23fc = function(a, b) {
a = a - 0x0;
var _0x23fc5a = ['A5473788'][a];
return _0x23fc5a;
};

window["A5473788"] = function(ret) {
var ans = 0x30d3f;
for (var i = 0x30d3f; i > 0; i--) {
var t = 0x0;
for (var j = 0x0; j < i; j++) {
t += ret['a'][0];
}
t % ret['a'][2] == ret['a'][1] && i < ans && (ans = i);
}
return ans;
};

可以看出来是找x*a[0]≡a[1] mod ret[2]中x的最小正整数解,他用的是一种循环的方法,但是这种同余方程可以用扩展欧几里得算法求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def run(a):
global x, y
x, y = 1, 0
def exgcd(a, b):
global x, y
if b == 0:
x, y = 1, 0
return a
d = exgcd(b, a % b)
x, y = y, x
y -= (a // b) * x
return d
a, b, m = a[0],a[1],a[2]
d = exgcd(a, m)
res = b-a
if res % d != 0:
ans = 0x30d3f
else:
ans = x*res//d
t=m//d
ans=(ans%t+t)%t+1
if(ans > 0x30d3f):
ans = 0x30d3f
return str(ans)

第四题

把jsfuck稍微处理一下,得到下面的代码

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
window.A593C8B8 = async (_) =>
(($, _, __, ___, ____) => {
let _____ = (function* () {
while ([]){
let a = [(_, __) => _ + __, (_, __) => _ - __, (_, __) => _ * __]
console.log(___,____)
yield a[++__ % (3)]["bind"](0, ___, ____);
}
})();

let calc = function (_____, ______, _______) {
____ = _____;
___ = ______["next"]()["value"]();
console.log(___)
__ == _["a"]["length"] && _______(-___);
};

return new Promise((__) =>
_["a"]["forEach"]((___) => {
console.log(___)
$["setTimeout"]((____) => calc(___, _____, __), ___)
}
)
);
})(window, _, 0, 0, 0);

可以看出来他先用setTimeout做了个排序,然后按顺序做加减乘法,python代码如下

1
2
3
4
5
6
7
8
9
10
11
def run(a):
a.sort()
last = -a[0]
for i in range(1,len(a)):
if i % 3 == 1:
last = last * a[i]
elif i % 3 == 2:
last = last + a[i]
elif i % 3 == 0:
last = last - a[i]
return str(-last)

第五题

上来一个wasm,反编译一下wasm2c q5.wasm -o q5.c

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
static u32 w2c_Run(u32 w2c_p0, u32 w2c_p1) {
u32 w2c_l2 = 0, w2c_l3 = 0, w2c_l4 = 0, w2c_l5 = 0, w2c_l6 = 0, w2c_l7 = 0;
FUNC_PROLOGUE;
u32 w2c_i0, w2c_i1, w2c_i2;
w2c_i0 = w2c_p0;
w2c_l2 = w2c_i0;
w2c_i0 = w2c_p1;
w2c_i1 = 1u;
w2c_i0 -= w2c_i1;
w2c_l4 = w2c_i0;
if (w2c_i0) {
w2c_L1:
w2c_i0 = w2c_l2;
w2c_l3 = w2c_i0;
w2c_i0 = 0u;
w2c_l6 = w2c_i0;
w2c_i0 = 10u;
w2c_l7 = w2c_i0;
w2c_L2:
w2c_i0 = w2c_l3;
w2c_i1 = 10u;
w2c_i0 = REM_U(w2c_i0, w2c_i1);
w2c_l5 = w2c_i0;
w2c_i0 = w2c_l3;
w2c_i1 = 10u;
w2c_i0 = DIV_U(w2c_i0, w2c_i1);
w2c_l3 = w2c_i0;
w2c_i0 = w2c_l5;
w2c_i1 = w2c_l6;
w2c_i0 = (*Z_MathZ_maxZ_iii)(w2c_i0, w2c_i1);
w2c_l6 = w2c_i0;
w2c_i0 = w2c_l5;
w2c_i1 = w2c_l7;
w2c_i0 = (*Z_MathZ_minZ_iii)(w2c_i0, w2c_i1);
w2c_l7 = w2c_i0;
w2c_i0 = w2c_l3;
w2c_i1 = 0u;
w2c_i0 = w2c_i0 > w2c_i1;
if (w2c_i0) {goto w2c_L2;}
w2c_i0 = w2c_l2;
w2c_i1 = w2c_l6;
w2c_i2 = w2c_l7;
w2c_i1 *= w2c_i2;
w2c_i0 += w2c_i1;
w2c_l2 = w2c_i0;
w2c_i0 = w2c_l4;
w2c_i1 = 1u;
w2c_i0 -= w2c_i1;
w2c_l4 = w2c_i0;
if (w2c_i0) {goto w2c_L1;}
}
w2c_i0 = w2c_l2;
FUNC_EPILOGUE;
return w2c_i0;
}

把一些临时代码都删掉,优化一下,可以得到。。。我没存,只剩下了这个python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def run(a):
p1 = a[0]
p2 = a[1]
p2 = p2 - 1
while p2 > 0:
i1 = p1
i2 = 0
i3 = 10
while i1 > 0:
i4 = i1 % 10
i1 = i1 // 10
i2 = max(i4,i2)
i3 = min(i4,i3)
p1 = i2*i3+p1
p2 = p2-1
if(i3 == 0):
break
return str(p1)

这里可以优化一下的就是,当i3等于0的时候就已经是结果了

第六题

是一个叫__TENCENT_CHAOS_VM栈虚拟机,第一次运行可以生成window[‘CA1807EB’]这个函数,也是一个虚拟机,然后在把数据给window[‘CA1807EB’]跑得到最终结果

缩小一下规模,看一下他是怎么运行window['CA1807EB']({a:[1,1,1,1,1,1,1,1,1,1,1,1]})

在循环的地方打一个log,输出一下栈的情况

1
2
3
4
5
6
for (var p = 0; !p; ){
t = f++;
p = u[e[t]]();
console.log("ip:",f,"op:",e[t]);
console.log(r);
}

观察一下之后,发现他在拼接字符串,然后有几个循环,做了几个乘法取模再加法

所以在一写关键操作的地方继续打log

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
function() {
t1 = r[r.length - 2]
t2 = r.pop()
r[r.length - 1] = t1 % t2;
console.log("mod",t1,t2,"=",r[r.length - 1])
},
function() {
var n = e[f++];
if(r[r.length - 1]){
f = n;
console.log("jmp",f)
}
},
function() {
t1 = r[r.length - 2]
t2 = r.pop()
r[r.length - 1] = t1 >= t2;
console.log("if",t1,t2,">=",r[r.length - 1])
},
function() {
t1 = r[r.length - 2]
t2 = r.pop()
r[r.length - 1] = t1 * t2;
console.log("mul",t1,t2,"=",r[r.length - 1])
},
function() {
var n = e[f++],
t = n ? r.slice(-n) : [];
r.length -= n;
var o = r.pop();
r.push(o[0][o[1]].apply(o[0], t));
console.log("apply",o[1],t);
},
function() {
t1 = r[r.length - 2]
t2 = r.pop()
r[r.length - 1] = t1 + t2;
console.log("add",t1,t2,"=",r[r.length - 1])
},

得到下面的记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apply BigInt [ 0 ]
apply BigInt [ 1 ]
if 0 1 >= false
jmp 123
apply BigInt [ '1661594' ]
mul 1n 1661594n = 1661594n
apply BigInt [ '1125899906842597' ]
mod 1661594n 1125899906842597n = 1661594n
add 0 1 = 1
if 1 1 >= true
if 0 1 >= false
jmp 272
apply BigInt [ '2477627' ]
mul 1661594n 2477627n = 4116810157438n
apply BigInt [ '1125899906842597' ]
mod 4116810157438n 1125899906842597n = 4116810157438n
add 0 1 = 1
if 1 1 >= true
add 0n 4116810157438n = 4116810157438n
apply BigInt [ '1125899906842597' ]
mod 4116810157438n 1125899906842597n = 4116810157438n
apply BigInt [ 1 ]
...

最终整理出,先各自乘方两两相乘最终相加的这么一个逻辑,用python进行实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def run(a):
d = [
2984158, 5661305,
5256230, 6741738,
6336549, 5845217,
3784624, 1491299,
2847395, 1943349,
1387618, 1185107
]
m = 1125899906842597
t = [0]*12
for i in range(12):
t[i] = pow(d[i],a[i],m)
# print(t[i])
ans = 0
for i in range(6):
ans = ((t[i*2] * t[i*2+1]) % m + ans) % m
# print(ans)
return str(ans)

结果刚跑了1w发现d换了,手动调整了一下,结果2w的时候又换了,无奈把提取数据的部分又自动化了一下

让js自己打log,然后传给python

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
import sys
import os
import re
import json
import requests as req

def run(a,d):
m = 1125899906842597
t = [0]*12
for i in range(12):
t[i] = pow(d[i],a[i],m)
# print(t[i])
ans = 0
for i in range(6):
ans = ((t[i*2] * t[i*2+1]) % m + ans) % m
# print(ans)
return str(ans)

def parseJs(js):
print("js:",js)
res = req.get("http://159.75.70.9:8080/"+js+".js")
f = open("q6_2.js","w")
f.write('''
window = global
global.window = global
data = []
''')
t = res.text
t = t.replace('apply(o[0],t))','apply(o[0],t));data.push(t[0])')
f.write(t)
f.write(f'''
ans = window["{js}"]({{a:[1,1,1,1,1,1,1,1,1,1,1,1]}})
data.pop()
console.log(data.filter(x => x != 0 && x != 1 && x!= '1125899906842597').map(x=>parseInt(x)))
''')
f.close()
data = os.popen('node q6_2.js').read()
data = eval(data)
return data

s = req.session()
lastJs = ""
d = []
while True:
ret = s.get("http://159.75.70.9:8081/pull?u=***")
ret = json.loads(ret.text)
a = ret["a"]
if(lastJs == ret["c"]):
ans = run(a,d)
ret = s.get("http://159.75.70.9:8081/push?t="+ret["t"]+"&a="+ans)
print(ret.text)
else:
d = parseJs(ret["c"])
lastJs = ret["c"]

后面的题

实际上我做出第6题的时候比赛就快结束了,结果200w+1又是个VM,实在是看不下去了