DataView
是一个可以从 ArrayBuffer
对象中读写多种数值类型的底层接口,在读写时不用考虑平台字节序问题。
示例代码:
<html> <body> <script> var array_buffer = new ArrayBuffer(0x10); var data_view = new DataView(array_buffer, 0, array_buffer.byteLength); </script> </body> </html>
测试平台是 win10 x64 Edge
在windbg里搜索 DataView
:
0:025> x chakra!Js::*DataView 00007ff8`37235938 chakra!Js::JavascriptLibrary::CreateDataView = <no type information> 00007ff8`37349190 chakra!Js::DataView::DataView = <no type information> 00007ff8`375c4318 chakra!Js::BuiltInPropertyRecords::DataView = <no type information>
DataView::DataView
就是 DataView
的构造函数,下断点调试示例代码。
0:025> g Breakpoint 2 hit chakra!Js::DataView::DataView: 00007ff8`37349190 488bc4 mov rax,rsp 0:008> gu chakra!Js::JavascriptLibrary::CreateDataView+0x4f: 00007ff8`37235987 4883c430 add rsp,30h 0:008> dq da28f16180 l10 000000da`28f16180 00007ff8`374d48c0 000000da`28ed0100 000000da`28f16190 00000000`00000000 00000000`00000000 000000da`28f161a0 00000000`00000010 000000da`28f93640 000000da`28f161b0 00000000`00000000 000000da`331ebff0 000000da`28f161c0 00000000`00000000 00000000`00000000 000000da`28f161d0 00000000`00000000 00000000`00000000 000000da`28f161e0 00000000`00000000 00000000`00000000 000000da`28f161f0 00000000`00000000 00000000`00000000 0:008> ln 00007ff8`374d48c0 (00007ff8`374d48c0) chakra!Js::DataView::`vftable' | (00007ff8`374d4be8) chakra!Js::ProjectionArrayBuffer::`vftable' Exact matches: chakra!Js::DataView::`vftable' = <no type information>
确实得到了一个 DataView
对象,偏移 0x20
处为 ArrayBuffer
的长度 0x10
,偏移 0x28
处为 ArrayBuffer
对象的地址:
0:008> dq poi(da28f16180+0x28) l10 000000da`28f93640 00007ff8`3742d1e0 000000da`28ed2040 000000da`28f93650 00000000`00000000 00000000`00000000 000000da`28f93660 000000da`28e35f00 00000000`00000000 000000da`28f93670 000000da`331ebff0 00000000`00000010 000000da`28f93680 000000da`28f92981 00000000`00000000 000000da`28f93690 00000000`00000000 00000000`00000000 000000da`28f936a0 00000000`00000000 00000000`00000000 000000da`28f936b0 00000000`00000000 00000000`00000000 0:008> ln poi(poi(da28f16180+0x28)) (00007ff8`3742d1e0) chakra!Js::JavascriptArrayBuffer::`vftable' | (00007ff8`3742d4f0) chakra!Js::ArrayObject::`vftable' Exact matches: chakra!Js::JavascriptArrayBuffer::`vftable' = <no type information>
现在修改代码,添加对 dataview
的操作:
<html> <body> <script> var array_buffer = new ArrayBuffer(0x10); var data_view = new DataView(array_buffer, 0, array_buffer.byteLength); data_view.setInt32(0,12,true); </script> </body> </html>
这次 dataview
如下:
0:011> dq 000000da`28f176c0 l10 000000da`28f176c0 00007ff8`374d48c0 000000da`29278900 000000da`28f176d0 00000000`00000000 00000000`00000000 000000da`28f176e0 00000000`00000010 000000da`28f93600 000000da`28f176f0 00000000`00000000 000000da`33523ff0 000000da`28f17700 000000da`29269a80 000000da`28f17840 000000da`28f17710 000000da`28f17780 000000da`28ef8200 000000da`28f17720 00000000`00000000 00000000`00000000 000000da`28f17730 00000000`00000000 00000000`00000000
ArrayBuffer
:
0:011> dq 000000da`28f93600 l10 000000da`28f93600 00007ff8`3742d1e0 000000da`29278980 000000da`28f93610 00000000`00000000 00000000`00000000 000000da`28f93620 000000da`28e35080 00000000`00000000 000000da`28f93630 000000da`33523ff0 00000000`00000010 000000da`28f93640 00007ff8`374391d8 3d26f15c`00000619 000000da`28f93650 00000018`00000000 00610072`00720061 000000da`28f93660 00750062`005f0079 00720065`00660066 000000da`28f93670 00000000`00000000 00000000`00000000
ArrayBuffer
对象偏移 0x30
处其实为缓冲区地址,对应到 DataView
对象偏移 0x38
处,在用 setInt32
设置值后缓冲区内容:
0:011> db 000000da`33523ff0 l10 000000da`33523ff0 0c 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:011> dq 000000da`33523ff0 l2 000000da`33523ff0 00000000`0000000c 00000000`00000000
可以看到,用 setInt32
以小端序模式填入值 0xc
,用 getInt32
可以读出来:
> data_view.getInt32(0).toString(16) "c000000"
不加 true
为默认字节序,得到结果如下:
> data_view.setInt32(0,12); undefined > data_view.getInt32(0).toString(16) "c" > data_view.getInt32(1).toString(16) "c00"
DataView
的成员函数还可以用如下方式调用,加 call
的话要带上 this
,也就是 data_view
:
data_view.setUint32.call(data_view, 0, 12, true);
DataView
可以用来做地址读写,只要能够利用漏洞修改 DataView
对象的长度字段和缓冲区地址字段即可。
修改代码为:
<html> <body> <script> var array_buffer = new ArrayBuffer(0x10); var data_view = new DataView(array_buffer, 0, array_buffer.byteLength); alert("change memory"); data_view.setInt32(0x12345678, 0xffffffff, true); alert("Done"); </script> </body> </html>
DataView
对象:
0000004c`f7abbe40 00007ff8374d48c0 chakra!Js::DataView::`vftable' 0000004c`f7abbe48 0000004cf7ad4040 0000004c`f7abbe50 0000000000000000 0000004c`f7abbe58 0000000000000000 0000004c`f7abbe60 0000000000000010 0000004c`f7abbe68 0000004cf7b50ec0 0000004c`f7abbe70 0000000000000000 0000004c`f7abbe78 00000044f3f55b90 0000004c`f7abbe80 0000004cf7b6e340 0000004c`f7abbe88 0000004cf7abbfc0
ArrayBuffer
对象:
0000004c`f7b50ec0 00007ff83742d1e0 chakra!Js::JavascriptArrayBuffer::`vftable' 0000004c`f7b50ec8 0000004cf7ad40c0 0000004c`f7b50ed0 0000000000000000 0000004c`f7b50ed8 0000000000000000 0000004c`f7b50ee0 0000004cf72f5360 0000004c`f7b50ee8 0000000000000000 0000004c`f7b50ef0 00000044f3f55b90 0000004c`f7b50ef8 0000000000000010 0000004c`f7b50f00 0000000000000001
缓冲区:
00000044`f3f55b90 0000000000000000 0000000000000000
在弹窗后 break
下来修改长度字段和缓冲区地址:
0:022> dq 0000004c`f7abbe40 l1 0000004c`f7abbe40 00007ff8`374d48c0 0:022> dq 0000004c`f7abbe40+0x20 l1 0000004c`f7abbe60 00000000`00000010 0:022> ed 0000004c`f7abbe40+0x20 ffffffff 0:022> dq 0000004c`f7abbe40+0x20 l1 0000004c`f7abbe60 00000000`ffffffff 0:022> dq 0000004c`f7abbe40+0x38 l1 0000004c`f7abbe78 00000044`f3f55b90 0:022> ed 0000004c`f7abbe40+0x38 00000000 0:022> dq 0000004c`f7abbe40+0x38 l1 0000004c`f7abbe78 00000044`00000000
修改后的对象:
0000004c`f7abbe40 00007ff8374d48c0 chakra!Js::DataView::`vftable' 0000004c`f7abbe48 0000004cf7ad4040 0000004c`f7abbe50 0000000000000000 0000004c`f7abbe58 0000000000000000 0000004c`f7abbe60 00000000ffffffff 0000004c`f7abbe68 0000004cf7b50ec0 0000004c`f7abbe70 0000000000000000 0000004c`f7abbe78 0000004400000000 0000004c`f7abbe80 0000004cf7b6e340 0000004c`f7abbe88 0000004cf7abbfc0
现在长度变成了 0x00000000ffffffff
,缓冲区地址 0x000000ef00000000
。现在可以读写的范围为 [0x000000ef00000000, 0x000000efffffffff]
。
如果 0x000000ef12345678
地址可写,那么就会写入 0xffffffff
。
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。