接上篇的继续 反编译 vmp 来进行学习
抖音的不太一样的点在于 他的vmp代码是分散的
好几段代码都是vmp的 然后指令对应的操作还不一样 就很蛋疼…
而且 指令对应的操作也是if else 还有三元表达式形式的 不太好找位置
第一步 看vmp代码结构
484e4f4a403f524300033604d6dbeab10000045d18187b
他通过一系列操作把这个长字符串转成了操作指令集
for (var g = []; ;) try {
var m = i[r++];
// i 就是上面的长字符串处理后的结果
if (m < 37) if (m < 18) if (m < 7) m < 3 ? p[++d] = 0 === m || null : 3 === m ? (c = i[r++], p[++d] = c << 24 >> 24) : (c = ((c = ((c = i[r++]) << 8) + i[r++]) << 8) + i[r++], p[++d] = (c << 8) + i[r++]); else if (m < 13) 7 === m ? (c = (i[r] << 8) + i[r + 1], r += 2, p[++d] = o[c]) : p[++d] = void 0; else if (m < 14) p[++d] = {}; else if (14 === m) c = (i[r] << 8) + i[r + 1], r += 2, s = o[c], u = p[d--], p[d][s] = u; else {
for (s = i[r++], u = i[r++], b = v; s > 0; --s) b = b.p;
p[++d] = b[u]
} else if (m < 28) if (m < 20) 18 === m ? (c = (i[r] << 8) + i[r + 1], r += 2, s = o[c], p[d] = p[d][s]) : (s = p[d--], p[d] = p[d][s]); else if (m < 22) {
for (s = i[r++], u = i[r++], b = v; s > 0; --s) b = b.p;
b[u] = p[d--]
} else if (22 === m) s = p[d--], u = p[d--], b = p[d--], u[s] = b; else {
for (s = i[r++], u = i[r++], b = v, b = v; s > 0; --s) b = b.p;
p[++d] = b, p[++d] = u
} else m < 33 ? 28 === m ? (s = p[d--], p[d] %= s) : p[d] = -p[d] : m < 35 ? (s = p[d--], b = (u = p[d--])[s]++, p[++d] = b) : 35 === m ? (s = p[d--], p[d] = p[d] == s) : (s = p[d--], p[d] = p[d] != s); else if (m < 58) m < 51 ? m < 39 ? 37 === m ? (s = p[d--], p[d] = p[d] === s) : (s = p[d--], p[d] = p[d] !== s) : m < 44 ? (s = p[d--], p[d] = p[d] < s) : 44 === m ? (s = p[d--], p[d] = p[d] >> s) : p[d] = !p[d] : m < 53 ? 51 === m ? (c = (c = (i[r] << 8) + i[r + 1]) << 16 >> 16, r += 2, p[d] ? --d : r += c) : (c = (c = (i[r] << 8) + i[r + 1]) << 16 >> 16, r += 2, p[d] ? r += c : --d) : m < 54 ? (s = p[d--], (u = p[d--])[s] = p[d]) : 54 === m ? (s = p[d--], p[d] = p[d] in s) : p[d] = void 0; else if (m < 68) if (m < 64) 58 === m ? p[d] = typeof p[d] : (c = i[r++], s = p[d--], (u = function e() {
var r = e._v;
return (0, e._u)(r[0], arguments, r[1], r[2], this)
})._v = [s, c, v], u._u = e, p[++d] = u); else {
if (m < 66) throw s = p[d--];
if (66 === m) {
for (s = p[d--], u = null; b = g.pop();) if (2 === b[0] || 3 === b[0]) {
u = b;
break
}
if (u) r = u[2], u[0] = 0, g.push(u); else {
if (!h) return s;
r = h[1], f = h[2], v = h[3], g = h[4], p[++d] = s, h = h[0]
}
} else d -= c = i[r++], u = p.slice(d + 1, d + c + 1), s = p[d--], b = p[d--], s._u === e ? (s = s._v, h = [h, r, f, v, g], r = s[0], null == b && (b = function () {
return this
}()), f = b, (v = [u].concat(u)).length = Math.min(s[1], c) + 1, v.p = s[2], g = []) : (l = s.apply(b, u), p[++d] = l)
} else if (m < 71) if (68 === m) {
for (c = i[r++], b = [void 0], l = c; l > 0; --l) b[l] = p[d--];
u = p[d--], l = new (s = Function.bind.apply(u, b)), p[++d] = l
} else r += 2 + (c = (c = (i[r] << 8) + i[r + 1]) << 16 >> 16); else m < 73 ? (c = (c = (i[r] << 8) + i[r + 1]) << 16 >> 16, r += 2, (s = p[d--]) || (r += c)) : 73 === m ? --d : (s = p[d], p[++d] = s)
} catch (e) {
for (; (c = g.pop()) && !c[0];) ;
if (!c) {
e:for (; h;) {
for (s = h[4]; c = s.pop();) if (c[0]) break e;
h = h[0]
}
if (!h) throw e;
r = h[1], f = h[2], v = h[3], g = h[4], h = h[0]
}
1 === (s = c[0]) ? (r = c[2], c[0] = 0, g.push(c), p[++d] = e) : 2 === s ? (r = c[2], c[0] = 0, g.push(c)) : (r = c[3], c[0] = 2, g.push(c), p[++d] = e)
首先要简化 他那一大堆 if else 变成 switch case 方便后续的操作
变成这样就好了 方便后续的操作
第二步 看一些关键的变量
解释都在代码里了
var c, s, u, b, l, d = -1, p = [], h = null, v = [t];
// 这些变量分别代表了不同的含义 比如 栈 函数变量 函数入参 寄存器 等
// 需要注意反编译过程中的 变量作用域问题
for (s = Math.min(t.length, n), u = 0; u < s; ++u) v.push(t[u]);
v.p = a;
第三步 开始反编译
反编译函数
这是源代码中定义函数的地方
i = r[f++];// i 是函数入参数量
l = o[p--];// l是函数起点指令下标
console.log('newFunc',now,l,i);
(n = function e() {
var f = e._v;
return (0, e._u)(f[0], arguments, f[1], f[2], this);
})._v = [l, i, h];
n._u = e;
o[++p] = n;
console.log(p)
反编译成这样
i = r[f++];
l = o[p--];
let body63 = [];
// (n = function e() {
// var f = e._v;
// return (0, e._u)(f[0], arguments, f[1], f[2], this);
// })._v = [l, i, h];
// if (now === 1192)debugger
console.log('newFunc', l , i, h.idx, p+1)
let func63 = types.identifier('func' + +l)
// if (s == 1582){
let hCopy = h.slice();
let args = types.identifier('arguments');
args.idx = h.idx+1
e(l, args, i, h, this,body63, -1) // 自己处理了一些东西
// h = hCopy.slice();
let v61 = types.functionDeclaration(func63, [], types.blockStatement(body63))
body.push(v61)
// func63._u = e;
func63._v = [l, i, h];
o[++p] = func63;
反编译判断
i = (i = (r[f] << 8) + r[f + 1]) << 16 >> 16;
f += 2;
if (o[p]) {
f += i; // 跳过一部分指令
} else {
--p;
}
i = (i = (r[f] << 8) + r[f + 1]) << 16 >> 16;
f += 2;
let body52 = [];
// 这种不是函数的反编译 需要处理好作用域问题 否则会报错
e(f, h, c, b, a,body52, i-2-1, false, o,p)
body.push(types.ifStatement(o[p], types.blockStatement(body52)))
最终结果
var tmp2248 = {};
var tmp2249 = X["apply"](true, []);
var tmp2250 = func618["apply"](true, [tmp2248, tmp2249]);
var tmp2251 = {};
var tmp2252 = {};
var tmp2253 = navigator["platform"];
tmp2252["platform"] = tmp2253;
var tmp2254 = func618["apply"](true, [tmp2250, tmp2251, tmp2252]);
tmp2018 = tmp2254;
var tmp2255 = func1198["apply"](true, [tmp2254]);
tmp2019 = tmp2255;
var tmp2256 = func1086["apply"](true, [tmp2255]);
tmp2020 = tmp2256;
var tmp2257 = tmp2256["length"];
tmp2021 = tmp2257;
var tmp2258 = 255;
var tmp2259 = tmp2257 & tmp2258;
tmp2023 = tmp2259;
var tmp2260 = 8;
var tmp2261 = tmp2257 >> tmp2260;
var tmp2262 = 255;
var tmp2263 = tmp2261 & tmp2262;
tmp2027 = tmp2263;
var tmp2264 = "";
tmp2028 = tmp2264;
var tmp2265 = func1086["apply"](true, [tmp2264]);
tmp2029 = tmp2265;
var tmp2266 = tmp2265["length"];
tmp2030 = tmp2266;
var tmp2267 = 255;
var tmp2268 = tmp2266 & tmp2267;
tmp2032 = tmp2268;
var tmp2269 = 8;
var tmp2270 = tmp2266 >> tmp2269;
var tmp2271 = 255;
var tmp2272 = tmp2270 & tmp2271;
tmp2036 = tmp2272;
var tmp2273 = tmp2100 ^ tmp2112;
var tmp2274 = tmp2273 ^ tmp2139;
var tmp2275 = tmp2274 ^ tmp2152;
var tmp2276 = tmp2275 ^ tmp2168;
var tmp2277 = tmp2276 ^ tmp2180;
var tmp2278 = tmp2277 ^ tmp2184;
var tmp2279 = tmp2278 ^ tmp2188;
var tmp2280 = tmp2279 ^ tmp2116;
var tmp2281 = tmp2280 ^ tmp2143;
var tmp2282 = tmp2281 ^ tmp2156;
var tmp2283 = tmp2282 ^ tmp2172;
var tmp2284 = tmp2283 ^ tmp2182;
var tmp2285 = tmp2284 ^ tmp2186;
var tmp2286 = tmp2285 ^ tmp2190;
var tmp2287 = tmp2286 ^ tmp2120;
var tmp2288 = tmp2287 ^ tmp2147;
var tmp2289 = tmp2288 ^ tmp2160;
var tmp2290 = tmp2289 ^ tmp2176;
var tmp2291 = tmp2290 ^ tmp2122;
var tmp2292 = tmp2291 ^ tmp2149;
var tmp2293 = tmp2292 ^ tmp2164;
var tmp2294 = tmp2293 ^ tmp2178;
var tmp2295 = tmp2294 ^ tmp2194;
var tmp2296 = tmp2295 ^ tmp2198;
var tmp2297 = tmp2296 ^ tmp2202;
var tmp2298 = tmp2297 ^ tmp2204;
var tmp2299 = tmp2298 ^ tmp377;
var tmp2300 = tmp2299 ^ tmp2210;
var tmp2301 = tmp2300 ^ tmp2217;
var tmp2302 = tmp2301 ^ tmp2128;
var tmp2303 = tmp2302 ^ tmp2135;
var tmp2304 = tmp2303 ^ tmp2222;
var tmp2305 = tmp2304 ^ tmp2226;
var tmp2306 = tmp2305 ^ tmp2230;
var tmp2307 = tmp2306 ^ tmp2232;
var tmp2308 = tmp2307 ^ tmp2235;
var tmp2309 = tmp2308 ^ tmp2239;
var tmp2310 = tmp2309 ^ tmp2243;
var tmp2311 = tmp2310 ^ tmp2247;
var tmp2312 = tmp2311 ^ tmp2259;
var tmp2313 = tmp2312 ^ tmp2263;
var tmp2314 = tmp2313 ^ tmp2268;
var tmp2315 = tmp2314 ^ tmp2272;
tmp2079 = tmp2315;
var tmp2316 = [tmp2100, tmp2112, tmp2222, tmp2139, tmp2152, tmp2168, tmp2239, tmp2180, tmp2184, tmp2226, tmp2188, tmp2116, tmp2143, tmp2230, tmp2232, tmp2156, tmp2172, tmp2235, tmp2182, tmp2186, tmp2190, tmp2120, tmp2147, tmp2160, tmp2247, tmp2176, tmp2122, tmp2149, tmp2164, tmp2178, tmp2194, tmp2198, tmp2243, tmp2202, tmp2204, tmp377, tmp2210, tmp2217, tmp2128, tmp2135, tmp2259, tmp2263, tmp2268, tmp2272];
var tmp2317 = tmp2316["concat"];
var tmp2318 = func120["apply"](true, [tmp2256]);
var tmp2319 = func120["apply"](true, [tmp2265]);
var tmp2320 = [tmp2315];
var tmp2321 = tmp2317["apply"](tmp2316, [tmp2318, tmp2319, tmp2320]);
tmp2085 = tmp2321;
var tmp2322 = func1382["apply"](true, [tmp2099]);
var tmp2323 = func1538["apply"](true, [tmp2108]);
tmp2322 += tmp2323;
var tmp2324 = String["fromCharCode"];
var tmp2325 = 121;
var tmp2326 = tmp2324["apply"](String, [tmp2325]);
var tmp2327 = String["fromCharCode"];
var tmp2328 = tmp2327["apply"];
var tmp2329 = tmp2328["apply"](tmp2327, [true, tmp2321]);
var tmp2330 = ee["apply"](true, [tmp2326, tmp2329]);
tmp2322 += tmp2330;
tmp2086 = tmp2322;
var tmp2331 = "s4";
var tmp2332 = re["apply"](true, [tmp2322, tmp2331]);
return tmp2332;
大概就是这样 一共三千多行 可以很明白的看到他的执行逻辑了
总结
他的麻烦点就是变量作用域问题 其他的按部就班的按照他的代码逻辑去改成ast节点的操作就行了