[聚合文章] IE10对象的内存布局及创建

JavaScript 2017-12-03 23 阅读

前言

在利用 uaf 漏洞时,为了达到任意内存读写,需要在内存中喷射布局 js 的对象,这里我研究几个主要的对象在内存中的布局以及创建过程。

环境

系统: win7 32bit SP1
浏览器: IE10

Array

下面的脚本喷射了很多的 array 对象,附加后运行:

<html>
<head>
<script language="javascript">
    alert("Start");
    var a = new Array(); 
    for (var i = 0; i < 0x10000; ++i) {
        a[i] = new Array(0x1000/4);
        for (var j = 0; j < a[i].length; ++j)
            a[i][j] = 0x111;        
    } 
    alert("Done");
</script> 
</head> 
<body> 
</body> 
</html>
 

喷射完后可以使用 vmmap 查看内存状态,可以看到喷射的大块的内存,随意选择一个地址,查看地址内容:

0:013> dd 21c60000
21c60000  00000000 00001010 00000000 00000000
21c60010  00000000 00000400 00000400 00000000
21c60020  00000223 00000223 00000223 00000223
21c60030  00000223 00000223 00000223 00000223
21c60040  00000223 00000223 00000223 00000223
21c60050  00000223 00000223 00000223 00000223
21c60060  00000223 00000223 00000223 00000223
21c60070  00000223 00000223 00000223 00000223
 

0x21c600040x1010 是数组长度 0x1000 加上数组头长度 0x1021c60014 处的两个 0x400 可能就是数组长度 0x1000/4 ,但我们设置的 0x111 却变成了 0x223 ,这次我们改变脚本中的一些参数再次调试:

<html>
<head>
<script language="javascript">
    alert("Start");
    var a = new Array(); 
    for (var i = 0; i < 0x10000; ++i) {
        a[i] = new Array(0x1240/4);
        for (var j = 0; j < a[i].length; ++j)
            a[i][j] = 0x100;        
    } 
    alert("Done");
</script> 
</head> 
<body> 
</body> 
</html>
 

这次得到的结果:

0:005> dd 21c60000
21c60000  00000000 00001250 00000000 00000000
21c60010  00000000 00000490 00000490 00000000
21c60020  00000201 00000201 00000201 00000201
21c60030  00000201 00000201 00000201 00000201
21c60040  00000201 00000201 00000201 00000201
21c60050  00000201 00000201 00000201 00000201
21c60060  00000201 00000201 00000201 00000201
21c60070  00000201 00000201 00000201 00000201
 

这次的结果证实了判断,而且数字存储的方式是 原数*2+1 ,那如果数字溢出的话会怎么样呢,再次修改脚本:

<html>
<head>
<script language="javascript">
    alert("Start");
    var a = new Array(); 
    for (var i = 0; i < 0x10000; ++i) {
        a[i] = new Array(0x1240/4);
        a[i][0] = 0x7fffffff;
        a[i][1] = -2;
        a[i][2] = 1.2345;
        a[i][3] = document.createElement("div");        
    } 
    alert("Done");
</script> 
</head> 
<body> 
</body> 
</html>
 

得到结果如下:

0:005> dd 21c60000
21c60000  00000000 00001250 00000000 00000000
21c60010  00000000 00000490 00000490 00000000
21c60020  02849070 fffffffd 02849080 21d1ec30
21c60030  00000000 00000000 00000000 00000000
21c60040  00000000 00000000 00000000 00000000
21c60050  00000000 00000000 00000000 00000000
0:005> ln poi(02849070)
(610b5ff8)   jscript9!Js::JavascriptNumber::`vftable'   |  (610b6130)   jscript9!Js::BufferStringBuilder::WritableString::`vftable'
Exact matches:
    jscript9!Js::JavascriptNumber::`vftable' = <no type information>
0:005> ln poi(02849080)
(610b5ff8)   jscript9!Js::JavascriptNumber::`vftable'   |  (610b6130)   jscript9!Js::BufferStringBuilder::WritableString::`vftable'
Exact matches:
    jscript9!Js::JavascriptNumber::`vftable' = <no type information>
0:005> ln poi(21d1ec30)
(610b2ad0)   jscript9!Js::CustomExternalObject::`vftable'   |  (610b2c18)   jscript9!Js::PropertyString::`vftable'
Exact matches:
    jscript9!Js::CustomExternalObject::`vftable' = <no type information>
    jscript9!Projection::ArrayObjectInstance::`vftable' = <no type information>
 

可以看到,对于溢出的数, Array 采用 JavascriptNumber 对象的方式存储,而 -2 则直接存储。 Array 这样存储的主要目的就是为了区分地址和数据。

21c6000421c60014 两处地址下写入断点,看看数组是如何被创建的:

0:005> ba w4 21c60000+4
0:005> ba w4 21c60000+14
0:005> g
Breakpoint 0 hit
eax=21c60000 ebx=124f7b60 ecx=124f7b70 edx=21c60010 esi=21c60000 edi=00001250
eip=610ea743 esp=032eba18 ebp=032eba28 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Recycler::LargeAlloc+0xa1:
610ea743 8b4514          mov     eax,dword ptr [ebp+14h] ss:0023:032eba3c=00000000
 

先断在了中,这时 21c60004 已经被写入了数组的长度 0x1250 ,跳出这个函数:

0:007> gu
eax=21c60010 ebx=00000000 ecx=00000000 edx=21c60010 esi=025070e8 edi=00000490
eip=610b9a59 esp=032eba40 ebp=032eba44 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Recycler::AllocZero+0x91:
610b9a59 c70000000000    mov     dword ptr [eax],0    ds:0023:21c60010=00000000
 

再跳出一次:

0:007> gu
eax=21c60010 ebx=00000000 ecx=00000000 edx=21c60010 esi=21b8e8e0 edi=00000490
eip=61164571 esp=032eba50 ebp=032eba84 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Js::JavascriptArray::DirectSetItem_Full+0x3ed:
61164571 8b4de8          mov     ecx,dword ptr [ebp-18h] ss:0023:032eba6c=00000490
0:007> p
eax=21c60010 ebx=00000000 ecx=00000490 edx=21c60010 esi=21b8e8e0 edi=00000490
eip=61164574 esp=032eba50 ebp=032eba84 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Js::JavascriptArray::DirectSetItem_Full+0x3f0:
61164574 c70000000000    mov     dword ptr [eax],0    ds:0023:21c60010=00000000
0:007> p
eax=21c60010 ebx=00000000 ecx=00000490 edx=21c60010 esi=21b8e8e0 edi=00000490
eip=6116457a esp=032eba50 ebp=032eba84 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Js::JavascriptArray::DirectSetItem_Full+0x3f6:
6116457a 897804          mov     dword ptr [eax+4],edi ds:0023:21c60014=00000000
0:007> 
eax=21c60010 ebx=00000000 ecx=00000490 edx=21c60010 esi=21b8e8e0 edi=00000490
eip=6116457d esp=032eba50 ebp=032eba84 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Js::JavascriptArray::DirectSetItem_Full+0x3f9:
6116457d 894808          mov     dword ptr [eax+8],ecx ds:0023:21c60018=00000000
0:007> 
eax=21c60010 ebx=00000000 ecx=00000490 edx=21c60010 esi=21b8e8e0 edi=00000490
eip=61164580 esp=032eba50 ebp=032eba84 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Js::JavascriptArray::DirectSetItem_Full+0x3fc:
61164580 c7400c00000000  mov     dword ptr [eax+0Ch],0 ds:0023:21c6001c=00000000
0:007> 
eax=21c60010 ebx=00000000 ecx=00000490 edx=21c60010 esi=21b8e8e0 edi=00000490
eip=61164587 esp=032eba50 ebp=032eba84 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Js::JavascriptArray::DirectSetItem_Full+0x403:
61164587 8bd0            mov     edx,eax
0:007> 
eax=21c60010 ebx=00000000 ecx=00000490 edx=21c60010 esi=21b8e8e0 edi=00000490
eip=61164589 esp=032eba50 ebp=032eba84 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
jscript9!Js::JavascriptArray::DirectSetItem_Full+0x405:
61164589 894614          mov     dword ptr [esi+14h],eax ds:0023:21b8e8f4=610be460
 

继续单步可以看到设置 21c60014 的过程,最后一句把我们创建的数组的地址放到了 [esi+14h] ,这里是一个对象:

0:007> ln poi(esi)
(610b2f78)   jscript9!Js::JavascriptArray::`vftable'   |  (610b30e0)   jscript9!Js::JavascriptError::`vftable'
Exact matches:
    jscript9!Js::JavascriptArray::`vftable' = <no type information>
 

在全部喷射完后再次查看这里的地址,

0:005> dd 21b8e8e0
21b8e8e0  610b2f78 02839a60 00000000 00000003 <=
21b8e8f0  00000490 21c60010 21c60010 00000000 
21b8e900  610b2f78 02839a60 00000000 00000003 <=
21b8e910  00000490 21c62010 21c62010 00000000 
21b8e920  610b2f78 02839a60 00000000 00000003 <=
21b8e930  00000490 21c64010 21c64010 00000000
21b8e940  610b2f78 02839a60 00000000 00000003 <=
21b8e950  00000490 21c66010 21c66010 00000000
 

这里可以明显的看到一个对象的大小是 0x20 ,存储了数组的大小和地址等信息。

LargeHeapBlock

测试脚本:

<html>
<head>
<script language="javascript">
    alert("Start");
    var a = new Array(); 
    for (var i = 0; i < 0x100; ++i) {
        a[i] = new Array(0x1000/4);
        a[i][0] = 0x7fffffff;
        a[i][1] = -2;
        a[i][2] = 1.2345;
        a[i][3] = document.createElement("div");        
    } 
    alert("Done");
</script> 
</head> 
<body> 
</body> 
</html>
 

windbg 中搜索与 largeheapblock 有关的函数可以搜索到很多,这里选择两个看上去和内存分配有关的下断点:

0:005> bl
 3 e 610ea785     0001 (0001)  0:**** jscript9!HeapInfo::AddLargeHeapBlock
 4 e 612737af     0001 (0001)  0:**** jscript9!LargeHeapBlock::Alloc
 

这里开启堆页调试,在 AddLargeHeapBlock 断下后到函数返回后:

0:007> gu
eax=0187ffa8 ebx=09f18fa8 ecx=071e4470 edx=071e0620 esi=071e0370 edi=00001250
eip=610ea708 esp=0548b8b0 ebp=0548b8c0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!Recycler::LargeAlloc+0x66:
610ea708 8bd8            mov     ebx,eax
0:007> !heap -p -a @eax
    address 0187ffa8 found in
    _DPH_HEAP_ROOT @ 1861000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 1861cc8:          187ffa8               54 -          187f000             2000
          jscript9!LargeHeapBlock::`vftable'
    6bef8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    ...
 
0:007> ln poi(eax)
(610b1c7c)   jscript9!LargeHeapBlock::`vftable'   |  (610b1ca0)   jscript9!Segment::`vftable'
Exact matches:
    jscript9!LargeHeapBlock::`vftable' = <no type information>
 

可以看到 AddLargeHeapBlock 分配了 0x54 大小的空间,是一个 LargeHeapBlock 对象。然后我们关闭堆页,在返回后的地址下断点:

0:015> bl
 0 e 61baa708     0001 (0001)  0:**** jscript9!Recycler::LargeAlloc+0x66 ".printf \"new LargeHeapBlock: addr = 0x%p\\n\",eax;g"
0:015> g
...
...
new LargeHeapBlock: addr = 0x01eb4af8
new LargeHeapBlock: addr = 0x01eb4b58
new LargeHeapBlock: addr = 0x01eb4bb8
new LargeHeapBlock: addr = 0x01eb4c18
new LargeHeapBlock: addr = 0x01eb4c78
new LargeHeapBlock: addr = 0x01eb4cd8
new LargeHeapBlock: addr = 0x01eb4d38
new LargeHeapBlock: addr = 0x01eb4d98
 

得到了一系列分配的地址,间隔为 0x60 就是对象大小加上头大小,这些内存如下:

01eb4af8 61b71c7c 00000003 03dac000 00000002 <=
01eb4b08 00000001 00000000 00000004 03dad020
01eb4b18 03dae000 01eb4a98 00000000 00000000
01eb4b28 00000000 00000000 01eaddc0 03dac000
01eb4b38 00000000 00000000 00000000 00000004
01eb4b48 00000000 00000000 77d0590a 8c000000
01eb4b58 61b71c7c 00000003 03dae000 00000002 <=
01eb4b68 00000001 00000000 00000004 03daf020
01eb4b78 03db0000 01eb4af8 00000000 00000000
01eb4b88 00000000 00000000 01eaddc0 03dae000
01eb4b98 00000000 00000000 00000000 00000004
01eb4ba8 00000000 00000000 77d05916 8c000000
01eb4bb8 61b71c7c 00000003 03db0000 00000002 <=
01eb4bc8 00000001 00000000 00000004 03db1020
01eb4bd8 03db2000 01eb4b58 00000000 00000000
01eb4be8 00000000 00000000 01eaddc0 03db0000
01eb4bf8 00000000 00000000 00000000 00000004
01eb4c08 00000000 00000000 77d059e2 8c000000
 

每个对象偏移 0x24 处的地址指向前一个对象。

ArrayBuffer & Int32Array

ArrayBuffer 表示数据的原始缓冲区,能够申请指定大小的内存,但无法直接读取或写入,需要将其传递到类型化数组创建数据化数组, Int32Array 就是一种,比如:

var buf = new ArrayBuffer(30);
var a = new Int32Array(buf);
 

我们来喷射一些 Int32Array 对象:

<html>
<head>
<script language="javascript">
    alert("Start");
    var a = new Array(); 
    for (var i = 0; i < 0x10000; ++i) {
        a[i] = new Int32Array(0x1000/4);
        for (var j = 0; j < a[i].length; ++j)
            a[i][j] = 0x123;
    } 
    alert("Done");
</script> 
</head> 
<body> 
</body> 
</html>
 

喷射完后,内存中的对象:

12690000 323a4d40 010181cd ffeeffee 00000000
12690010 13660010 116c0010 004e0000 12690000
12690020 00000fd0 12690040 13660000 00000000
12690030 00000001 00000000 1365fff0 1365fff0
12690040 b232cd48 080181c5 116b0b18 0886ec48
12690050 00000012 f0e0d0c0 7ea2c967 88000000
12690060 00000123 00000123 00000123 00000123
12690070 00000123 00000123 00000123 00000123
12690080 00000123 00000123 00000123 00000123
12690090 00000123 00000123 00000123 00000123
126900a0 00000123 00000123 00000123 00000123
126900b0 00000123 00000123 00000123 00000123
 

搜索大小为 0x1000 的堆,能够搜索到很多:

0:015> !heap -flt s 100
    _HEAP @ 180000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
      ...
      ...
        1581b530 0201 0201  [00]   1581b538    01000 - (busy)
        1581c538 0201 0201  [00]   1581c540    01000 - (busy)
        1581d540 0201 0201  [00]   1581d548    01000 - (busy)
        1581e548 0201 0201  [00]   1581e550    01000 - (busy)
        1581f550 0201 0201  [00]   1581f558    01000 - (busy)
        15820558 0201 0201  [00]   15820560    01000 - (busy)
        15821560 0201 0201  [00]   15821568    01000 - (busy)
        15822568 0201 0201  [00]   15822570    01000 - (busy)
        15823570 0201 0201  [00]   15823578    01000 - (busy)
        15824578 0201 0201  [00]   15824580    01000 - (busy)
        15825580 0201 0201  [00]   15825588    01000 - (busy)
        15826588 0201 0201  [00]   15826590    01000 - (busy)
        15827590 0201 0201  [00]   15827598    01000 - (busy)
        15828598 0201 0201  [00]   158285a0    01000 - (busy)
        158295a0 0201 0201  [00]   158295a8    01000 - (busy)
        1582a5a8 0201 0201  [00]   1582a5b0    01000 - (busy)
        1582b5b0 0201 0201  [00]   1582b5b8    01000 - (busy)
        1582c5b8 0201 0201  [00]   1582c5c0    01000 - (busy)
        1582d5c0 0201 0201  [00]   1582d5c8    01000 - (busy)
        1582e5c8 0201 0201  [00]   1582e5d0    01000 - (busy)
        1582f5d0 0201 0201  [00]   1582f5d8    01000 - (busy)
        158305d8 0201 0201  [00]   158305e0    01000 - (busy)
        158315e0 0201 0201  [00]   158315e8    01000 - (busy)
        158325e8 0201 0201  [00]   158325f0    01000 - (busy)
        158335f0 0201 0201  [00]   158335f8    01000 - (busy)
        158345f8 0201 0201  [00]   15834600    01000 - (busy)
        15835600 0201 0201  [00]   15835608    01000 - (busy)
        15836608 0201 0201  [00]   15836610    01000 - (busy)
        15837610 0201 0201  [00]   15837618    01000 - (busy)
        15838618 0201 0201  [00]   15838620    01000 - (busy)
        15839620 0201 0201  [00]   15839628    01000 - (busy)
        1583a628 0201 0201  [00]   1583a630    01000 - (busy)
        1583b630 0201 0201  [00]   1583b638    01000 - (busy)
        1583c638 0201 0201  [00]   1583c640    01000 - (busy)
        1583d640 0201 0201  [00]   1583d648    01000 - (busy)
        1583e648 0201 0201  [00]   1583e650    01000 - (busy)
        15840458 0201 0201  [00]   15840460    01000 - (busy)
        15841460 0201 0201  [00]   15841468    01000 - (busy)
        15842468 0201 0201  [00]   15842470    01000 - (busy)
        15843470 0201 0201  [00]   15843478    01000 - (busy)
        15844478 0201 0201  [00]   15844480    01000 - (busy)
        15845480 0201 0201  [00]   15845488    01000 - (busy)
        15846488 0201 0201  [00]   15846490    01000 - (busy)
        15847490 0201 0201  [00]   15847498    01000 - (busy)
        15848498 0201 0201  [00]   158484a0    01000 - (busy)
        158494a0 0201 0201  [00]   158494a8    01000 - (busy)
        1584a4a8 0201 0201  [00]   1584a4b0    01000 - (busy)
        1584b4b0 0201 0201  [00]   1584b4b8    01000 - (busy)
        1584c4b8 0201 0201  [00]   1584c4c0    01000 - (busy)
        1584d4c0 0201 0201  [00]   1584d4c8    01000 - (busy)
        1584e4c8 0201 0201  [00]   1584e4d0    01000 - (busy)
        1584f4d0 0201 0201  [00]   1584f4d8    01000 - (busy)
        158504d8 0201 0201  [00]   158504e0    01000 - (busy)
        158514e0 0201 0201  [00]   158514e8    01000 - (busy)
        158524e8 0201 0201  [00]   158524f0    01000 - (busy)
        158534f0 0201 0201  [00]   158534f8    01000 - (busy)
        158544f8 0201 0201  [00]   15854500    01000 - (busy)
        15855500 0201 0201  [00]   15855508    01000 - (busy)
        ...
0:015> dd 15855508
15855508  00000123 00000123 00000123 00000123
15855518  00000123 00000123 00000123 00000123
15855528  00000123 00000123 00000123 00000123
15855538  00000123 00000123 00000123 00000123
15855548  00000123 00000123 00000123 00000123
15855558  00000123 00000123 00000123 00000123
15855568  00000123 00000123 00000123 00000123
15855578  00000123 00000123 00000123 00000123
 

确实是我们喷射的数据,在堆的头信息处下写入断点,看看这个堆是怎么创建的:

0:015> ba w4 15855500
0:015> g
Breakpoint 0 hit
eax=004e0000 ebx=6045434c ecx=15855500 edx=15855506 esi=0f710b98 edi=004ea840
eip=77a347c2 esp=02b3b7a0 ebp=02b3b7e4 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!RtlpSubSegmentInitialize+0x122:
77a347c2 c60200          mov     byte ptr [edx],0           ds:0023:15855506=00
0:007> k
ChildEBP RetAddr  
02b3b7e4 77a3433d ntdll!RtlpSubSegmentInitialize+0x122
02b3b880 77a22e82 ntdll!RtlpLowFragHeapAllocFromContext+0x882
02b3b8f4 77b59d45 ntdll!RtlAllocateHeap+0x206
02b3b914 61dcfb8b msvcrt!malloc+0x8d
02b3b924 61bb2be4 jscript9!memset+0x349d3
02b3b93c 61d7dac4 jscript9!Js::JavascriptArrayBuffer::Create+0x3c
02b3b968 61d78a20 jscript9!Js::TypedArrayBase::CreateNewInstance+0x1cf
02b3b9e0 61ba6c47 jscript9!Js::TypedArray<int>::NewInstance+0x55
02b3ba0c 61d4bd6b jscript9!Js::InterpreterStackFrame::OP_LoopBodyStart+0x9f
02b3ba24 61b826f0 jscript9!Js::InterpreterStackFrame::OP_ProfiledLoopBodyStart+0x1a
02b3bb04 61b849e0 jscript9!Js::InterpreterStackFrame::Process+0x45a1
02b3bc3c 02430fe9 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x305
 

通过栈回溯发现堆由 malloc 创建,上层是由 jscript9!Js::JavascriptArrayBuffer::Create 调用的,在上层由 jscript9!Js::TypedArray<int>::NewInstance 调用,那么在 TypedArray<int>::NewInstance 下断点就可以看 Int32Array 的创建过程。

0:007> bm /a jscript9!Js::TypedArray<int>::NewInstance
  1: 61d789cb @!"jscript9!Js::TypedArray<int>::NewInstance"
 

这次只创建一个对象:

<html>
<head>
<script language="javascript">
    alert("Start");
    var a = new Int32Array(0x1000/4); 
    for (var i = 0; i < a.length; ++i)
            a[i] = 0x123;
    } 
    alert("Done");
</script> 
</head> 
<body> 
</body> 
</html>
 

断下:

0:016> g
Breakpoint 1 hit
eax=00000002 ebx=02301660 ecx=00000801 edx=02b3b9d8 esi=00000002 edi=02b3bbb8
eip=61d789cb esp=02b3b9cc ebp=02b3ba1c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!Js::TypedArray<int>::NewInstance:
61d789cb 8bff            mov     edi,edi
 

搜索和 jscript9!Js::TypedArray<int> 有关的函数可以找到一个 jscript9!Js::TypedArray<int>::Creat ,看起来是创建对象的函数,下断点:

0:005> bm /a jscript9!Js::TypedArray<int>::Create
  2: 61d09640 @!"jscript9!Js::TypedArray<int>::Create"
0:007> g
Breakpoint 2 hit
eax=00000400 ebx=04a6ae20 ecx=00000000 edx=00000000 esi=0cef0858 edi=00000400
eip=61d09640 esp=02b3b964 ebp=02b3b998 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!Js::TypedArray<int>::Create:
61d09640 8bff            mov     edi,edi
 

单步可以跟到分配内存的地方:

0:007> 
eax=00001000 ebx=04a6ae20 ecx=01e070e8 edx=00000000 esi=0231b000 edi=04a6ae20
eip=61d0967f esp=02b3b950 ebp=02b3b960 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!Js::TypedArray<int>::Create+0x3f:
61d0967f 6a24            push    24h
0:007> 
eax=00001000 ebx=04a6ae20 ecx=01e070e8 edx=00000000 esi=0231b000 edi=04a6ae20
eip=61d09681 esp=02b3b94c ebp=02b3b960 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript9!Js::TypedArray<int>::Create+0x41:
61d09681 e8b5dfe6ff      call    jscript9!Recycler::Alloc (61b7763b)
0:007> p
eax=046a00f0 ebx=04a6ae20 ecx=046a0030 edx=01e0b3a4 esi=0231b000 edi=04a6ae20
eip=61d09686 esp=02b3b950 ebp=02b3b960 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
jscript9!Js::TypedArray<int>::Create+0x46:
61d09686 ffb61c010000    push    dword ptr [esi+11Ch] ds:0023:0231b11c=023098a0
 

TypedArray<int> 对象大小为 0x24 ,返回后的对象已经设置好了:

0:007> gu
eax=046a00f0 ebx=04a6ae20 ecx=17f480a0 edx=00000000 esi=0cef0858 edi=00000400
eip=61d7dae6 esp=02b3b978 ebp=02b3b998 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
jscript9!Js::TypedArrayBase::CreateNewInstance+0x1f1:
61d7dae6 8bf0            mov     esi,eax
0:007> dd 046a00f0 l9
046a00f0  61b738c8 023098a0 00000000 00000003
046a0100  00000004 00000000 00000400 17f480a0
046a0110  04a6ae20
0:007> ln poi(046a00f0)
(61b738c8)   jscript9!Js::TypedArray<int>::`vftable'   |  (61b73a20)   jscript9!Js::TypedArray<unsigned short>::`vftable'
Exact matches:
    jscript9!Js::TypedArray<int>::`vftable' = <no type information>
 

TypedArray<int> 对象尾部的两个地址分别是存放 Int32Array 数据的缓冲区和 ArrayBuffer 对象:

0:007> ln poi(04a6ae20)
(61bb2bf8)   jscript9!Js::JavascriptArrayBuffer::`vftable'   |  (61d7e1c8)   jscript9!Js::CopyOnWriteObject<Js::TypedArray<bool>,Js::NoSpecialProperties>::`vftable'
Exact matches:
    jscript9!Js::JavascriptArrayBuffer::`vftable' = <no type information>
0:007> dd 04a6ae20
04a6ae20  61bb2bf8 02309a20 00000000 00000003
04a6ae30  17f480a0 00001000 00000000 00000000
04a6ae40  04a6ae60 00000000 00000000 00000000
0:007> dd 17f480a0-8
17f48098  79b770df 88000000 00000000 00000000
17f480a8  00000000 00000000 00000000 00000000
17f480b8  00000000 00000000 00000000 00000000
17f480c8  00000000 00000000 00000000 00000000
17f480d8  00000000 00000000 00000000 00000000
 

缓冲区的堆头已经设置好了,继续运行后就填入了数据:

0:005> dd 17f480a0-8
17f48098  79b770df 88000000 00000123 00000123
17f480a8  00000123 00000123 00000123 00000123
17f480b8  00000123 00000123 00000123 00000123
17f480c8  00000123 00000123 00000123 00000123
17f480d8  00000123 00000123 00000123 00000123
17f480e8  00000123 00000123 00000123 00000123
17f480f8  00000123 00000123 00000123 00000123
17f48108  00000123 00000123 00000123 00000123
 

总结一下:

TypedArray<int>:
+0x00: 虚表
+0x18: 数组长度
+0x1c: 缓冲区地址
+0x20: ArrayBuffer对象地址
 
ArrayBuffer:
+0x00: 虚表
+0x10: 缓冲区地址
+0x14: 缓冲区长度
 

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。