v8环境搭建看这里
现在的v8采用的是Ignition(JIT生成) + TurboFan(优化)
v8调试
安装pwngdb
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
将v8/tools/目录下的gdbinit和gdb-v8-support.py添加到~/.gdbinit
source /path/to/v8/tools/gdbinit
source /path/to/v8/tools/gdb-v8-support.py
之后就可以使用%DebugPrint(x)来输出调试信息,使用%SystemBreak()来对程序下断点。
但是js本身是没有%这种语法的,执行时要加上--allow-natives-syntax
写个脚本测试下
$ cat ./example/test.js
arr = [1, 2, 3]
%DebugPrint(a);
%SystemBreak();
$ ./d8 --allow-natives-syntax ./example/test.js
DebugPrint: 0x7900010bdfd: [JSArray]
- map: 0x07900024e0b5 <Map[16](PACKED_SMI_ELEMENTS)> [FastProperties]
- prototype: 0x07900024e2f9 <JSArray[0]>
- elements: 0x07900025a7bd <FixedArray[3]> [PACKED_SMI_ELEMENTS (COW)]
- length: 3
- properties: 0x0790000022a9 <FixedArray[0]>
- All own properties (excluding elements): {
0x79000006e61: [String] in ReadOnlySpace: #length: 0x079000204285 <AccessorInfo name= 0x079000006e61 <String[6]: #length>, data= 0x0790000022e1 <undefined>> (const accessor descriptor), location: descriptor
}
- elements: 0x07900025a7bd <FixedArray[3]> {
0: 1
1: 2
2: 3
}
0x7900024e0b5: [Map] in OldSpace
- type: JS_ARRAY_TYPE
- instance size: 16
- inobject properties: 0
- elements kind: PACKED_SMI_ELEMENTS
- unused property fields: 0
- enum length: invalid
- back pointer: 0x0790000022e1 <undefined>
- prototype_validity cell: 0x079000003875 <Cell value= 1>
- instance descriptors #1: 0x07900024e865 <DescriptorArray[1]>
- transitions #1: 0x07900024e881 <TransitionArray[4]>Transition array #1:
0x079000007d55 <Symbol: (elements_transition_symbol)>: (transition to HOLEY_SMI_ELEMENTS) -> 0x07900024e899 <Map[16](HOLEY_SMI_ELEMENTS)>
- prototype: 0x07900024e2f9 <JSArray[0]>
- constructor: 0x07900024e021 <JSFunction Array (sfi = 0x7900021d455)>
- dependent code: 0x0790000022b9 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
- construction counter: 0
可以看出打印出了数组大小,内容以及数据类型等相关信息,数组成员被存储为了SMI(small integer)类型
使用GDB调试
$ gdb d8
pwndbg> r --allow-natives-syntax ./example/test.js
[New Thread 0x7f7491b4a700 (LWP 2571)]
DebugPrint: 0x1e840010be29: [JSArray]
- map: 0x1e840024e0b5 <Map[16](PACKED_SMI_ELEMENTS)> [FastProperties]
- prototype: 0x1e840024e2f9 <JSArray[0]>
- elements: 0x1e840025a7bd <FixedArray[3]> [PACKED_SMI_ELEMENTS (COW)]
- length: 3
- properties: 0x1e84000022a9 <FixedArray[0]>
- All own properties (excluding elements): {
0x1e8400006e61: [String] in ReadOnlySpace: #length: 0x1e8400204285 <AccessorInfo name= 0x1e8400006e61 <String[6]: #length>, data= 0x1e84000022e1 <undefined>> (const accessor descriptor), location: descriptor
}
- elements: 0x1e840025a7bd <FixedArray[3]> {
0: 1
1: 2
2: 3
}
0x1e840024e0b5: [Map] in OldSpace
- type: JS_ARRAY_TYPE
- instance size: 16
- inobject properties: 0
- elements kind: PACKED_SMI_ELEMENTS
- unused property fields: 0
- enum length: invalid
- back pointer: 0x1e84000022e1 <undefined>
- prototype_validity cell: 0x1e8400003875 <Cell value= 1>
- instance descriptors #1: 0x1e840024e865 <DescriptorArray[1]>
- transitions #1: 0x1e840024e881 <TransitionArray[4]>Transition array #1:
0x1e8400007d55 <Symbol: (elements_transition_symbol)>: (transition to HOLEY_SMI_ELEMENTS) -> 0x1e840024e899 <Map[16](HOLEY_SMI_ELEMENTS)>
- prototype: 0x1e840024e2f9 <JSArray[0]>
- constructor: 0x1e840024e021 <JSFunction Array (sfi = 0x1e840021d455)>
- dependent code: 0x1e84000022b9 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
- construction counter: 0
pwndbg> job 0x1e840010be29
0x1e840010be29: [JSArray]
- map: 0x1e840024e0b5 <Map[16](PACKED_SMI_ELEMENTS)> [FastProperties]
- prototype: 0x1e840024e2f9 <JSArray[0]>
- elements: 0x1e840025a7bd <FixedArray[3]> [PACKED_SMI_ELEMENTS (COW)]
- length: 3
- properties: 0x1e84000022a9 <FixedArray[0]>
- All own properties (excluding elements): {
0x1e8400006e61: [String] in ReadOnlySpace: #length: 0x1e8400204285 <AccessorInfo name= 0x1e8400006e61 <String[6]: #length>, data= 0x1e84000022e1 <undefined>> (const accessor descriptor), location: descriptor
}
- elements: 0x1e840025a7bd <FixedArray[3]> {
0: 1
1: 2
2: 3
}
pwndbg> job 0x1e840025a7bd
0x1e840025a7bd: [FixedArray] in OldSpace
- map: 0x1e84000021e1 <Map(FIXED_ARRAY_TYPE)>
- length: 3
0: 1
1: 2
2: 3
pwndbg> x/8gx 0x1e840010be29-1
0x1e840010be28: 0x000022a90024e0b5 0x000000060025a7bd
0x1e840010be38: 0xbeadbeefbeadbeef 0xbeadbeefbeadbeef
0x1e840010be48: 0xbeadbeefbeadbeef 0xbeadbeefbeadbeef
0x1e840010be58: 0xbeadbeefbeadbeef 0xbeadbeefbeadbeef
pwndbg> x/8gx 0x1e840025a7bd-1
0x1e840025a7bc: 0x00000006000021e1 0x0000000400000002
0x1e840025a7cc: 0x000024d100000006 0x0025a7bd00000000
0x1e840025a7dc: 0x0000000400002169 0x0025a7290025a7d1
0x1e840025a7ec: 0x0000002e0000320d 0x00003f790025a7dd
job命令可以查看js object的内存分布。但是job命令的地址是真实地址+1
在v8中地址进行了压缩,只保存低32bit,高位地址都一样
可以看出在0x1e840010be29-1就是存储的arr这个数组的信息,依次分别是map|properties|elements|length
- map: 0x1e840024e0b5
- elements: 0x1e840025a7bd
- length: 3
- properties: 0x1e84000022a9
0x1e840010be28: 0x000022a9|0024e0b5 0x00000006|0025a7bd
这里的length乘了2,后面存储的数组元素也乘了2,应该是v8的特性吧
在elements-1即0x1e840025a7bc出可以看出存储的分别是map|length|arr
- map: 0x1e84000021e1 <Map(FIXED_ARRAY_TYPE)>
- length: 3
0: 1
1: 2
2: 3
0x1e840025a7bc: 0x00000006|000021e1 0x00000004|00000002
0x1e840025a7cc: 0x000024d1|00000006
上边有两个length,第一个是申请的长度,第二个是已使用的长度
存储double类型时按64bit的长度存储,存储的是真实值不会像integer一样乘2