主要是v8对象基础的概念。
0x01 v8是什么
简而言之,v8就是js的解释器。
V8由很多子模块构成,其中,有几个最重要的模块:
- Parser:负责将JavaScript源码转换为Abstract Syntax Tree (AST)
- Ignition:interpreter,即解释器,负责将AST转换为Bytecode,解释执行Bytecode;同时收集TurboFan优化编译所需的信息,比如函数参数的类型
- TurboFan:compiler,即编译器,利用Ignitio所收集的类型信息,将Bytecode转换为优化的汇编代码
- Orinoco:garbage collector,垃圾回收模块,负责将程序不再需要的内存空间回收
Parser、Ignition、Turbofan协作将JS源码最终编译成汇编代码
0x02 v8 中JS对象结构
在下面的代码中定义了a,b两个对象,下面在调试中观察下里面的数据和结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function Foo1 () {} var a = new Foo1(); var b = new Foo1(); a.name = 'name-a'; a.text = 'aaa'; b.name = 'name-b'; b.text = 'bbb'; a[1] = "a-1"; a[2] = "a-2"; %DebugPrint(a); //d8中用来打印object内存信息 %DebugPrint(b); //d8中用来打印object内存信息 %SystemBreak(); //d8中用来中断,调试 |
2.1 使用谷歌浏览器观察
首先先在谷歌开发工具中键入上面的代码,然后在Memory中拍摄快照
我们大致可以看出来,对于a它有两个属性,分别是name
和text
,这两个属性直接保存在对象结构中。还有两个字符串”a-1”和”a-2”,他们作为元素
,保存在了elements中。
因此暂时可以猜测,对象中保存的数据有两种形式: 一种是不需要索引的,称为属性
, 另一种是需要索引的,称为元素
2.2 在ubuntu中编译v8观察
让我们单独看a打印出来的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | DebugPrint: 0x1c6808148b91: [JS_OBJECT_TYPE] - map: 0x1c68083074fd <Map(HOLEY_ELEMENTS)> [FastProperties] - prototype: 0x1c6808148b0d <Object map = 0x1c68083074ad> - elements: 0x1c6808148c81 <FixedArray[19]> [HOLEY_ELEMENTS] - properties: 0x1c6808042229 <FixedArray[0]> - All own properties (excluding elements): { 0x1c68080447d5: [String] in ReadOnlySpace: #name: 0x1c68082d2591 <String[6]: #name-a> (const data field 0), location: in-object //name属性 0x1c68082d25a5: [String] in OldSpace: #text: 0x1c68082d25b5 <String[3]: #aaa> (const data field 1), location: in-object //text属性 } - elements: 0x1c6808148c81 <FixedArray[19]> { 0: 0x1c6808042429 <the_hole> //element中的元素 1: 0x1c68082d25e9 <String[3]: #a-1> 2: 0x1c68082d25f9 <String[3]: #a-2> 3-18: 0x1c6808042429 <the_hole> } 0x1c68083074fd: [Map] - type: JS_OBJECT_TYPE //实例类型 - instance size: 52 //实例大小 - inobject properties: 10 //对象内属性存储空间(包含未使用的slots) - elements kind: HOLEY_ELEMENTS - unused property fields: 8 //未使用的属性slot数 - enum length: invalid - stable_map //对象当前处于快速模式(dictionary_map:字典模式) - back pointer: 0x1c68083074d5 <Map(HOLEY_ELEMENTS)> - prototype_validity cell: 0x1c68082d2939 <Cell value= 0> - instance descriptors (own) #2: 0x1c6808148c59 <DescriptorArray[2]> - prototype: 0x1c6808148b0d <Object map = 0x1c68083074ad> - constructor: 0x1c68082d2835 <JSFunction Foo1 (sfi = 0x1c68082d26ad)> - dependent code: 0x1c68080421b5 <Other heap object (WEAK_FIXED_ARRAY_TYPE)> - construction counter: 5 |
在v8中打印出的结构更确认了我们上面的猜测,并且更多看到了一些东西。比如map。
还有一些其它的
prototype prototype
elements 对象元素
length 元素个数
properties 属性
结构图如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | elements ----> +------------------------+ | MAP +<---------+ +------------------------+ | | element 1 | | +------------------------+ | | element 2 | | | ...... | | | element n | | ArrayObject ---->-------------------------+ | | map | | +------------------------+ | | prototype | | +------------------------+ | | elements | | | +----------+ +------------------------+ | length | +------------------------+ | properties | +------------------------+ |
0x03 v8环境搭建
3.1代理配置
首先在本地的小飞机中,选项设置-》本地代理设置-》开启本地代理-》选择端口
配置git代理,后面的ip采用自己宿主机的,端口采用上一步设置的端口,虚拟机配置采用nat模式
1 | git config --global http.proxy http://192.168.235.1:1080 |
配置环境变量,进行全局代理
1 2 | export http_proxy="http://192.168.235.1:1080" export https_proxy=$http_proxy |
下载工具,并设置环境变量(注意此处环境变量的路径与你下载的路径是否相同
1 2 3 4 5 6 | git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git echo 'export PATH=$PATH:"$HOME/depot_tools"' >> ~/.bashrc git clone https://github.com/ninja-build/ninja.git cd ninja && ./configure.py --bootstrap && cd .. echo 'export PATH=$PATH:"$HOME/ninja"' >> ~/.bashrc |
编译v8
.
1 | fetch v8 && cd v8 |
1 2 3 4 5 6 7 8 9 | gclient sync #更新 git reset --hard [commit hash with vulnerability] #切换版本 tools/dev/v8gen.py x64.debug ninja -C out.gn/x64.debug [d8] #d8参数表示只编译d8 #debug->release编译release版本 |
启动
1 2 3 4 5 6 7 | ./out.gn/x64.release/d8 #启动d8交互shell ./out.gn/x64.release/d8 test.js #运行test.js ./out.gn/x64.debug/d8 ./out.gn/x64.debug/shell ./out.gn/x64.debug/d8 test.js |
调试工具,这个gdbinit如果没有的话需要从网上自行下载
1 2 | echo 'source /home/w4rd3n/v8/tools/gdbinit' >> ~/.gdbinit echo 'source /home/w4rd3n/v8/tools/gdb-v8-support.py' >> ~/.gdbinit |