Bu script direkt olarak kurulamaz. Başka scriptler için bir kütüphanedir ve meta yönergeleri içerir // @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;
- }
- }