您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
used to modify wasm
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.sleazyfork.org/scripts/456876/1130174/wasm%20parsere.js
// ==UserScript== // @name wasm parsere // @version 1.0 // @description used to modify wasm // @author bismuth k // ==/UserScript== const OP = {"unreachable":0,"nop":1,"block":2,"loop":3,"if":4,"else":5,"end":11,"br":12,"br_if":13,"br_table":13,"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":75,"ne":76,"lt":77,"gt":78,"le":79,"ge":80,"abd":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,"abd":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) } regex(match, allOccurences) { let ret = [], rets = []; search: for (let n = this.lexer.index; n < this.lexer.packet.length - match.length; n++) { this.lexer.index = n; ret = []; for (let p = 0; p < match.length; p++) { if (match[p] === '*') this.lexer.vu(); else if (match[p] === '+') ret.push(this.lexer.vu()); else if (this.lexer.u8() !== match[p]) continue search; } if (allOccurences) rets.push(ret); else { this.lexer.index = n; return ret; } } return rets.length? rets: false; } 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.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.type) { case 'func': this.sections[2].body.push({ name: options.name, type: "func", index: this.sections[1].body.length }); this.sections[1].body.push({ param: options.params, return: options.returns }); this.adjustImports++; return this.sections[2].body.length - 1; break; default: throw new Error('oops, not supported yet'); break; } } 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)); bin.push(...section[n].contents); } 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(); let len, before; for (let n = 0; n < localLength; n++) { this.lexer.vu(); this.lexer.u8(); } while(this.lexer.has()) { let op; switch(op = this.lexer.u8()) { case OP.block: case OP.loop: case OP.if: case OP.memory.size: case OP.memory.grow: 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: this.lexer.vu(); break; case OP.f32.const: this.lexer.f32(); break; case OP.f64.const: this.lexer.f64(); break; case OP.global.get: case OP.global.set: 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: this.lexer.vu(); this.lexer.vu(); break; case OP.call_indirect: this.lexer.vu(); this.lexer.u8(); break; case OP.br_table: len = this.lexer.vu(); for (let n = 0; n < len+1; n++) this.lexer.vu(); break; case OP.call: len = this.lexer.index; before = this.lexer.vu(); this.lexer.index = len; this.lexer.replaceVu(this.getAdjusted(before)); break; default: if (op > 255) throw new Error('oops, you did something wrong'); break; } } return this.lexer.packet; } } 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 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) { 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); } 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; } }