您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
used to modify wasm
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://updategreasyfork.deno.dev/scripts/455550/1414617/wasm%20parser.js
// ==UserScript== // @name wasm parser // @version 1.0 // @description used to modify wasm // @author bismuth // ==/UserScript== const OP = { "unreachable": 0, "nop": 1, "block": 2, "loop": 3, "if": 4, "else": 5, "end": 11, "br": 12, "br_if": 13, "br_table": 14, "return": 15, "call": 16, "call_indirect": 17, "drop": 26, "select": 27, "local": { "get": 32, "set": 33, "tee": 34 }, "global": { "get": 35, "set": 36 }, "i32": { "load": 40, "load8_s": 44, "load8_u": 45, "load16_s": 46, "load16_u": 47, "store": 54, "store8": 58, "store16": 59, "const": 65, "eqz": 69, "eq": 70, "ne": 71, "lt_s": 72, "lt_u": 73, "gt_s": 74, "gt_u": 75, "le_s": 76, "le_u": 77, "ge_s": 78, "ge_u": 79, "clz": 103, "ctz": 104, "popcnt": 105, "add": 106, "sub": 107, "mul": 108, "div_s": 109, "div_u": 110, "rem_s": 111, "rem_u": 112, "and": 113, "or": 114, "xor": 115, "shl": 116, "shr_s": 117, "shr_u": 118, "rotl": 119, "rotr": 120, "wrap_i64": 167, "wrap_f32_s": 168, "wrap_f32_u": 169, "wrap_f64_s": 170, "wrap_f64_u": 171, "reinterpret_f32": 188 }, "i64": { "load": 41, "load8_s": 48, "load8_u": 49, "load16_s": 50, "load16_u": 51, "load32_s": 52, "load32_u": 53, "store": 55, "store8": 60, "store16": 61, "store32": 62, "const": 66, "eqz": 80, "eq": 81, "ne": 82, "lt_s": 83, "lt_u": 84, "gt_s": 85, "gt_u": 86, "le_s": 87, "le_u": 88, "ge_s": 89, "ge_u": 90, "clz": 121, "ctz": 122, "popcnt": 123, "add": 124, "sub": 125, "mul": 126, "div_s": 127, "div_u": 128, "rem_s": 129, "rem_u": 130, "and": 131, "or": 132, "xor": 133, "shl": 134, "shr_s": 135, "shr_u": 136, "rotl": 137, "rotr": 138, "extend_i32_s": 172, "extend_i32_u": 173, "trunc_f32_s": 174, "trunc_f32_u": 175, "trunc_f64_s": 176, "trunc_f64_u": 177, "reinterpret_f64": 189 }, "f32": { "load": 42, "store": 56, "const": 67, "eq": 91, "ne": 92, "lt": 93, "gt": 95, "le": 94, "ge": 96, "abs": 139, "neg": 140, "ceil": 141, "floor": 142, "trunc": 143, "nearest": 144, "sqrt": 145, "add": 146, "sub": 147, "mul": 148, "div": 149, "min": 150, "max": 151, "copysign": 152, "convert_i32_s": 178, "convert_i32_u": 179, "convert_i64_s": 180, "convert_i64_u": 181, "demote_f64": 182, "reinterpret_i32": 190 }, "f64": { "load": 43, "store": 57, "const": 68, "eq": 97, "ne": 98, "lt": 99, "gt": 100, "le": 101, "ge": 102, "abs": 153, "neg": 154, "ceil": 155, "floor": 156, "trunc": 157, "nearest": 158, "sqrt": 159, "add": 160, "sub": 161, "mul": 162, "div": 163, "min": 164, "max": 165, "copysign": 166, "convert_i32_s": 183, "convert_i32_u": 184, "convert_i64_s": 185, "convert_i64_u": 186, "promote_f32": 187, "reinterpret_i64": 191 }, "memory": { "size": 63, "grow": 64 } }; class WASMSection { constructor(desc,length) { this.section = desc; this.body = new Array(length); } } class WASMParser { constructor(bin) { this.lexer = new Reader(new Uint8Array(bin)); this.sections = new Array(13); this.adjustImports = 0; this.importFuncCount = 0; this.parseWASM(); } read(bin) { this.lexer.packet = new Uint8Array(bin) } loadFunc(index) { this.lexer.set(this.sections[10].body[index - this.importFuncCount]); const localLength = this.lexer.vu(); for (let n = 0; n < localLength; n++) { this.lexer.vu(); this.lexer.u8(); } return; } set(index, val = this.lexer.packet) { this.sections[10].body[index - this.importFuncCount] = val; } getAdjusted(index) { if (index < this.importFuncCount) return index; return index + this.adjustImports; } addImportEntry(options) { const map = ['f64','f32','i64','i32']; switch(options.kind) { case 'func': this.sections[2].body.push({ name: options.name, type: "func", index: this.sections[1].body.length, isNew: true }); this.sections[1].body.push({ param: options.params, return: options.returns, isNew: true }); this.adjustImports++; return this.sections[2].body.length - 1; case 'global': this.sections[6].body.push({ type: options.type, mutable: options.mutable, value: options.mutable, isNew: true }); return this.sections[6].body.length - 1; default: throw new Error('oops, not supported yet'); } } reindex() { let section = this.sections[10].body; let length = section.length; for (let n = 0; n < length; n++) this.sections[10].body[n] = this.parseFunction(section[n]); section = this.sections[9].body; length = section.length; for (let n = 0; n < length; n++) { const l = section[n].funcs.length; for (let p = 0; p < l; p++) this.sections[9].body[n].funcs[p] = this.getAdjusted(section[n].funcs[p]); } section = this.sections[7].body; length = section.length; for (let n = 0; n < length; n++) this.sections[7].body[n].index = this.getAdjusted(section[n].index); this.adjustImports = 0; } compile() { const bin = [0, 97, 115, 109, 1, 0, 0, 0]; for (let n = 0; n < 12; n++) { if (!this.sections[n]) continue; const section = this[`compileSection0x${n.toString(16)}`](); bin.push(n); bin.push(...Writer.vu(section.length)); for (const byte of section) bin.push(byte); } return new Uint8Array(bin); } compileSection0x1() { const map = ['f64','f32','i64','i32']; const section = this.sections[1].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) { bin.push(0x60); bin.push(...Writer.vu(section[n].param.length)); for (const param of section[n].param) bin.push(map.indexOf(param) + 0x7C); bin.push(...Writer.vu(section[n].return.length)); for (const param of section[n].return) bin.push(map.indexOf(param) + 0x7C); } return bin; } compileSection0x2() { const map = ['func','table','mem','global']; const section = this.sections[2].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) { const nameSplit = section[n].name.split('.'); for (const part of nameSplit) bin.push(...Writer.stringLEN(part)); bin.push(map.indexOf(section[n].type)); bin.push(...Writer.vu(section[n].index)); //console.log(bin); } return bin; } compileSection0x3() { const section = this.sections[3].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) bin.push(...Writer.vu(section[n])); return bin; } compileSection0x4() { const section = this.sections[4].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) for (let p = 0; p < 4; p++) bin.push(...Writer.vu(section[n][p])); return bin; } compileSection0x5() { const section = this.sections[5].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) { bin.push(...Writer.vu(section[n].type)); bin.push(...Writer.vu(section[n].limit[0])); bin.push(...Writer.vu(section[n].limit[1])); } return bin; } compileSection0x6() { const map = ['f64','f32','i64','i32']; const section = this.sections[6].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) { bin.push(map.indexOf(section[n].type) + 0x7C); bin.push(section[n].mutable); for (const expr of section[n].expr) bin.push(...Writer.vu(expr)); bin.push(11); } return bin; } compileSection0x7() { const map = ['func','table','mem','global']; const section = this.sections[7].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) { bin.push(...Writer.stringLEN(section[n].name)); bin.push(map.indexOf(section[n].type)); bin.push(...Writer.vu(section[n].index)); } return bin; } compileSection0x8() { const section = this.sections[8].body; const length = 1; const bin = [1]; bin.push(...Writer.vu(section)); return bin; } compileSection0x9() { const section = this.sections[9].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) { bin.push(section[n].type, section[n].expr[0]); bin.push(...Writer.vi(section[n].expr[1]),11); bin.push(...Writer.vu(section[n].funcs.length)); for (const funcIdx of section[n].funcs) bin.push(...Writer.vu(funcIdx)); } return bin; } compileSection0xa() { const section = this.sections[10].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) { //section[n] = this.parseFunction(section[n]); bin.push(...Writer.vu(section[n].length)); for (const byte of section[n]) bin.push(byte); } return bin; } compileSection0xb() { const section = this.sections[11].body; const length = section.length; const bin = Writer.vu(length); for (let n = 0; n < length; n++) { bin.push(section[n].type,section[n].expr[0]); bin.push(...Writer.vi(section[n].expr[1]),11); bin.push(...Writer.vu(section[n].contents.length)); for (const byte of section[n].contents) bin.push(byte); } return bin; } parseWASM() { this.lexer.index = 8; while (this.lexer.has()) { const id = this.lexer.u8(); if (id > 12) return; this[`parseSection0x${id.toString(16)}`](); } this.importFuncCount = this.sections[2].body.filter(({type}) => type === 'func').length; } parseSection0x1() { const map = ['f64','f32','i64','i32']; const rawLength = this.lexer.vu(); const section = new WASMSection('functypes', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) { const type = { param: [], return: [] } if (this.lexer.u8() !== 0x60) break; let len = this.lexer.vu(); for (let n = 0; n < len; n++) type.param.push(map[this.lexer.u8()-0x7C]); len = this.lexer.vu(); for (let n = 0; n < len; n++) type.return.push(map[this.lexer.u8()-0x7C]); section.body[n] = type; } return (this.sections[1] = section); } parseSection0x2() { const map = ['func','table','mem','global']; this.lexer.vu(); const section = new WASMSection('imports', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) section.body[n] = { name: this.lexer.stringLEN() + '.' + this.lexer.stringLEN(), type: map[this.lexer.u8()], index: this.lexer.vu() }; return (this.sections[2] = section); } parseSection0x3() { this.lexer.vu(); const section = new WASMSection('functions', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) section.body[n] = this.lexer.vu(); return (this.sections[3] = section); } parseSection0x4() { this.lexer.vu(); const section = new WASMSection('tables', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) section.body[n] = [this.lexer.vu(), this.lexer.vu(), this.lexer.vu(), this.lexer.vu()]; //incomplete return (this.sections[4] = section); } parseSection0x5() { this.lexer.vu(); const section = new WASMSection('mem', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) section.body[n] = { type: this.lexer.vu(), limit: [this.lexer.vu(), this.lexer.vu()] } return (this.sections[5] = section); } parseSection0x6() { const map = ['f64','f32','i64','i32']; this.lexer.vu(); const section = new WASMSection('globals', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) { section.body[n] = { type: map[this.lexer.u8()-0x7C], mutable: this.lexer.u8(), expr: [] } section.body[n].expr.push(this.lexer.ru8()); switch(this.lexer.u8()) { case OP.i32.const: case OP.i64.const: section.body[n].expr.push(this.lexer.vu()); break; case OP.f32.const: section.body[n].expr.push(this.f32()); break; case OP.f64.const: section.body[n].expr.push(this.f64()); break; } this.lexer.u8(); } return (this.sections[6] = section); } parseSection0x7() { const map = ['func','table','mem','global']; this.lexer.vu(); const section = new WASMSection('exports', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) { const name = this.lexer.stringLEN(); const type = map[this.lexer.u8()]; const index = this.lexer.vu(); section.body[n] = { name, type, index }; } return (this.sections[7] = section); } parseSection0x8() { this.lexer.vu(); const section = new WASMSection('start', this.lexer.vu()); section.body = this.vu(); return (this.sections[8] = section); } parseSection0x9() { this.lexer.vu(); const section = new WASMSection('elements', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) { section.body[n] = { type: this.lexer.u8() }; //NEED TO ACCOUNT FOR DIFFERENT TYPES section.body[n].expr = [this.lexer.u8(),this.lexer.vu()]; this.lexer.u8(); const repeat = this.lexer.vu(); section.body[n].funcs = []; for (let p = 0; p < repeat; p++) section.body[n].funcs.push(this.lexer.vu()); } return (this.sections[9] = section); } parseSection0xa() { this.lexer.vu(); const section = new WASMSection('code', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) { const len = this.lexer.vu(); section.body[n] = this.lexer.packet.slice(this.lexer.index, this.lexer.index += len); } return (this.sections[10] = section); } parseSection0xb() { this.lexer.vu(); const t = this.lexer.index; const section = new WASMSection('data', this.lexer.vu()); for (let n = 0; n < section.body.length; n++) { section.body[n] = { type: this.lexer.u8(), expr: [this.lexer.u8(),this.lexer.vu()] }; this.lexer.u8(); const len = this.lexer.vu(); section.body[n].contents = this.lexer.packet.slice(this.lexer.index, this.lexer.index += len); } return (this.sections[11] = section); } parseFunction(func) { this.lexer.set(func); const localLength = this.lexer.vu(); for (let n = 0; n < localLength; n++) { this.lexer.vu(); this.lexer.u8(); } while(this.lexer.has()) { const before = this.lexer.index; const instr = this.parseInstruction(); if (instr.op === OP.call) { this.lexer.index = before + 1; this.lexer.replaceVu(this.getAdjusted(instr.immediates[0])); } } return this.lexer.packet; } parseInstruction() { let len; const op = this.lexer.u8(); const immediates = []; switch(op) { case OP.block: case OP.loop: case OP.if: case OP.memory.size: case OP.memory.grow: immediates.push(this.lexer.u8()); break; case OP.br: case OP.br_if: case OP.local.get: case OP.local.set: case OP.local.tee: case OP.i32.const: case OP.i64.const: immediates.push(this.lexer.vu()); break; case OP.f32.const: immediates.push(this.lexer.f32()); break; case OP.f64.const: immediates.push(this.lexer.f64()); break; case OP.global.get: case OP.global.set: immediates.push(this.lexer.vu()); break; //adjust global index later case OP.i32.load: case OP.i32.load8_s: case OP.i32.load8_u: case OP.i32.load16_s: case OP.i32.load16_u: case OP.i64.load: case OP.i64.load8_s: case OP.i64.load8_u: case OP.i64.load16_s: case OP.i64.load16_u: case OP.i64.load32_s: case OP.i64.load32_u: case OP.f32.load: case OP.f64.load: case OP.i32.store: case OP.i32.store8: case OP.i32.store16: case OP.i64.store: case OP.i64.store8: case OP.i64.store16: case OP.i64.store32: case OP.f32.store: case OP.f64.store: immediates.push(this.lexer.vu(),this.lexer.vu()); break; case OP.call_indirect: immediates.push(this.lexer.vu(),this.lexer.u8()); break; case OP.br_table: len = this.lexer.vu(); immediates.push(len); for (let n = 0; n < len+1; n++) immediates.push(this.lexer.vu()); break; case OP.call: immediates.push(this.lexer.vu()); break; default: break; } return {op, immediates} } regex(func, instrRegex, cb = (sIndex,eIndex,instrs) => {}, all=true) { this.lexer.set(this.sections[10].body[func - this.importFuncCount]); const todos = []; let exprBlob = []; const localLength = this.lexer.vu(); for (let n = 0; n < localLength; n++) { this.lexer.vu(); this.lexer.u8(); } let startIndex = this.lexer.index, regexPos = 0; while(startIndex < this.lexer.packet.length) { if (regexPos === 0) { exprBlob = []; startIndex = this.lexer.index; } const currIndex = this.lexer.index; const instr = this.parseInstruction(); exprBlob.push(instr); if (instr.op === instrRegex[regexPos][0]) { let good = true; for (let n = 1; n < instrRegex[regexPos].length; n++) if (instrRegex[regexPos][n] !== instr.immediates[n-1] && instrRegex[regexPos][n] !== '*') good = false; if (good) regexPos++; else { regexPos = 0; this.lexer.index = startIndex; this.parseInstruction(); continue; } } else { regexPos = 0; this.lexer.index = startIndex; this.parseInstruction(); continue; } if (regexPos === instrRegex.length) { todos.push([startIndex, this.lexer.index, [...exprBlob]]); if (!all) break; regexPos = 0; } } for (const [si, ci, eb] of todos) { cb(si, ci, eb); } return this.lexer.packet; } inject(code, index = this.lexer.index) { return this.lexer.inject(code, index); } remove(code, index = this.lexer.index) { return this.lexer.remove(code, index); } } class Writer { static vu(num) { const ret = []; while (num >= 128) { ret.push((num & 127) | 128); num >>= 7; } ret.push(num); return ret; } static vi(num) { const ret = []; while (num >= 128) { ret.push((num & 127) | 128); num >>= 7; } if (num < 0x40) ret.push(num); else { ret.push(num | 0x80); ret.push(num<0?1:0); } return ret; } static f32(num) { return [...new Uint8Array(new Float32Array([num]).buffer)]; } static stringLEN(str) { str = new TextEncoder().encode(str); if (str.length > 127) throw new Error('Unsupported string length: don\'t use a string that long (max 127 byte length)'); return [str.length, ...str]; } } class Reader { constructor(packet) { this.packet = packet; this.index = 0; const buffer = new ArrayBuffer(8); this._u8 = new Uint8Array(buffer); this._f32 = new Float32Array(buffer); this._f64 = new Float64Array(buffer); } inject(code, index = this.index) { this.index = index; const newBuf = new Uint8Array(code.length + this.packet.length); newBuf.set(this.packet.slice(0,this.index),0); newBuf.set(code,this.index); newBuf.set(this.packet.slice(this.index),(this.index+code.length)); return (this.packet = newBuf); } remove(index1, index2 = this.index) { this.index = index2; const newBuf = new Uint8Array(index1 - index2 + this.packet.length); newBuf.set(this.packet.slice(0,index1),0); newBuf.set(this.packet.slice(index2,this.packet.length),index1); return (this.packet = newBuf); } replaceVu(replace) { const before = this.index, old = this.vu(), now = this.index; replace = Writer.vu(replace); if (replace.length === now - before) this.packet.set(replace, before); else { const newBuf = new Uint8Array(this.packet.length-now+before+replace.length); newBuf.set(this.packet.slice(0,before),0); newBuf.set(replace,before); newBuf.set(this.packet.slice(now),(this.index=before+replace.length)); this.packet = newBuf; } } has() { return this.index < this.packet.length } set(packet) { this.packet = packet; this.index = 0; } ru8() { return this.packet[this.index] } u8() { return this.packet[this.index++] } f32() { this._u8.set(this.packet.slice(this.index, this.index += 4)); return this._f32[0]; } f64() { this._u8.set(this.packet.slice(this.index, this.index += 8)); return this._f64[0]; } vu() { let out = 0, at = 0; while (this.packet[this.index] & 0x80) { out |= (this.u8() & 0x7f) << at; at += 7; } out |= this.u8() << at; return out; } stringLEN() { const len = this.u8(); const ret = new TextDecoder().decode(this.packet.slice(this.index, this.index += len)); return ret; } }