Tento skript by neměl být instalován přímo. Jedná se o knihovnu, kterou by měly jiné skripty využívat pomocí meta příkazu // @require https://update.greatest.deepsurf.us/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;
- }
- }