V8调试环境搭建

  1. 平台
  2. 搭建步骤
  3. 搭建Turbolizer
  4. V8的GDB支持
  5. Patch V8
  6. Recommended

准备写点关于V8的文章,这一篇主要介绍如何搭建环境和推荐一些阅读资料。

平台

  • Ubuntu 18.04.02 x64

搭建步骤

以下步骤是我从安装完虚拟机开始执行的。

  1. 更换源

    $ sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    $ sudo gedit /etc/apt/sources.list
    deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
    
    deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
    
    deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
    
    deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
    
    deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
  2. 更新apt

    $ sudo apt update
  3. 安装依赖

    $ sudo apt-get install binutils python2.7 perl socat git build-essential gdb gdbserver pkg-config curl re2c
    $ sudo ln -s /usr/bin/python2.7 /usr/bin/python
  4. 设置代理

    1. git代理

      $ gedit ~/.gitconfig
      [http]
          proxy = socks5://ip:1080
      [https]
          proxy = socks5://ip:1080
    2. 环境变量代理

      $ gedit ~/.bashrc
      export http_proxy=http://ip:1080
      #注意不能使用https
      export https_proxy=http://ip:1080
    3. 配置boto代理(gclient不能直接使用socks代理)

      $ gedit ~/.boto_proxy
      [Boto]
      proxy = ip
      proxy_port = 1080
      $ echo "export NO_AUTH_BOTO_CONFIG=$HOME/.boto_proxy" >> ~/.bashrc
      $ source ~/.bashrc
      
  5. 安装GDB插件

    $ git clone https://github.com/scwuaptx/peda.git ~/peda
    $ git clone https://github.com/pwndbg/pwndbg.git ~/pwndbg && pushd ~/pwndbg && ~/pwndbg/setup.sh && popd
    
  6. 获取并配置depop_tool

    $ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git ~/depot_tools
    $ echo "export PATH=$PATH:$HOME/depot_tools" >> ~/.bashrc && source ~/.bashrc
    
  7. 获取并配置ninja

    $ git clone https://github.com/ninja-build/ninja.git ~/ninja
    $ pushd ninja && ./configure.py --bootstrap && popd
    $ echo "export PATH=$PATH:$HOME/ninja" >> ~/.bashrc && source ~/.bashrc
    
  8. 增加swap空间

    编译时如果swap空间不够会造成编译失败

    #查看swap空间
    free -m 
    #创建swap文件
    $ sudo mkdir /swap && cd /swap
    #这里设定为4个G的大小
    $ sudo dd if=/dev/zero of=swapfile bs=1024 count=4000000
    $ sudo mkswap -f swapfile
    #使文件生效
    $ sudo swapon swapfile
    #再次查看就可看到已经扩容成功
    
    #将该配置写入/etc/fstab,在文件后面追加内容
    /swap/swapfile /swap swap defaults 0 0
    
    #如果需要卸载swap文件,执行以下命令并删除配置内容就行了
    #$ sudo swapoff swapfile 
    
    

9. 获取V8并编译

   ```bash
   #命令使用过程中很可能会因为环境问题或者网络问题中断,如果中断就将当前目录文件全部删除并重试。
   #rm .gclient* && rm -rf v8
   #如果发现不是网络问题请对照上面的配置步骤查看是否环境出了问题(主要看依赖和代理配置)。
   $ fetch v8
   $ cd v8 && gclient sync
   $ tools/dev/v8gen.py x64.debug
   $ ninja -C out.gn/x64.debug
  1. 启动

    $ ./out/x64.debug/d8 
    $ ./out/x64.debug/shell 
    

搭建Turbolizer

Turbolizer是一个基于HTML的分析工具,能够可视化Turbofan pipeline各个阶段优化产生的代码。工具可在v8/tools/turbolizer中找到。

切换到turbolizer目录之后,搭建步骤:

$ npm i #有可能比较慢,如果有cnpm可执行 $ cnpm install
$ npm run-script build #sudo cnpm run-script build
#也可以部署到其他目录
$ npm run deploy -- /www/turbolizer
#在当前目录或者是部署的目标目录开启一个http服务,然后去访问就可以使用工具了。
$ python -m SimpleHTTPServer 8000

如果搭建失败可能是因为分支的问题,切换到master分支或者是其他分支再试试。

部署的时候出现以下输出是正常的:

$ sudo cnpm run-script build
[sudo] password for qwq: 

> turbolizer@0.1.0 build /home/qwq/Documents/Browser/v8/tools/turbolizer
> rollup -c


src/turbo-visualizer.ts → build/turbolizer.js...
(!) /home/qwq/Documents/Browser/v8/tools/turbolizer/src/graphmultiview.ts(98,29): semantic error TS2345 Argument of type 'GraphView' is not assignable to parameter of type 'PhaseView'.
  Types of property 'detachSelection' are incompatible.
    Type '() => Set<unknown>' is not assignable to type '() => Set<string>'.
      Type 'Set<unknown>' is not assignable to type 'Set<string>'.
        Type 'unknown' is not assignable to type 'string'.
(!) /home/qwq/Documents/Browser/v8/tools/turbolizer/src/graphmultiview.ts(100,29): semantic error TS2345 Argument of type 'ScheduleView' is not assignable to parameter of type 'PhaseView'.
  Types of property 'detachSelection' are incompatible.
    Type '() => Set<unknown>' is not assignable to type '() => Set<string>'.
      Type 'Set<unknown>' is not assignable to type 'Set<string>'.
(!) /home/qwq/Documents/Browser/v8/tools/turbolizer/src/graphmultiview.ts(102,29): semantic error TS2345 Argument of type 'SequenceView' is not assignable to parameter of type 'PhaseView'.
  Types of property 'detachSelection' are incompatible.
    Type '() => Set<unknown>' is not assignable to type '() => Set<string>'.
      Type 'Set<unknown>' is not assignable to type 'Set<string>'.
(!) /home/qwq/Documents/Browser/v8/tools/turbolizer/src/code-view.ts(176,9): semantic error TS2304 Cannot find name 'PR'.
(!) /home/qwq/Documents/Browser/v8/tools/turbolizer/src/text-view.ts(149,57): semantic error TS2345 Argument of type 'unknown' is not assignable to parameter of type 'string'.
(!) /home/qwq/Documents/Browser/v8/tools/turbolizer/src/graph-view.ts(371,3): semantic error TS2416 Property 'detachSelection' in type 'GraphView' is not assignable to the same property in base type 'PhaseView'.
  Type '() => Set<unknown>' is not assignable to type '() => Set<string>'.
    Type 'Set<unknown>' is not assignable to type 'Set<string>'.
      Type 'unknown' is not assignable to type 'string'.
(!) /home/qwq/Documents/Browser/v8/tools/turbolizer/src/schedule-view.ts(33,3): semantic error TS2416 Property 'detachSelection' in type 'ScheduleView' is not assignable to the same property in base type 'TextView'.
  Type '() => Set<unknown>' is not assignable to type '() => Set<string>'.
    Type 'Set<unknown>' is not assignable to type 'Set<string>'.
      Type 'unknown' is not assignable to type 'string'.
(!) /home/qwq/Documents/Browser/v8/tools/turbolizer/src/sequence-view.ts(33,3): semantic error TS2416 Property 'detachSelection' in type 'SequenceView' is not assignable to the same property in base type 'TextView'.
  Type '() => Set<unknown>' is not assignable to type '() => Set<string>'.
    Type 'Set<unknown>' is not assignable to type 'Set<string>'.
      Type 'unknown' is not assignable to type 'string'.
(!) Circular dependency: src/edge.ts -> src/node.ts -> src/edge.ts
created build/turbolizer.js in 6.5s

最好使用Chrome去访问并使用该工具。

V8的GDB支持

在tools目录下有两个文件:

v8/tools/gdbinit
v8/tools/gdb-v8-support.py

只需要在~/.gdbinit中source这两个文件就可以了,需要注意的是这些调试命令只能在debug版本的d8中才会生效,release不行,缺少导出符号。

关于gdb命令的使用都可以直接查看这两个文件的内容,里面有关于命令的注释。

另外,开启--allow-natives-syntax时可以使用的native syntax:https://gist.github.com/totherik/3a4432f26eea1224ceeb

Patch V8

假如有如下patch文件内容:

diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index b027d36..ef1002f 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1668,6 +1668,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
                           Builtins::kArrayPrototypeCopyWithin, 2, false);
     SimpleInstallFunction(isolate_, proto, "fill",
                           Builtins::kArrayPrototypeFill, 1, false);
+    SimpleInstallFunction(isolate_, proto, "oob",
+                          Builtins::kArrayOob,2,false);
     SimpleInstallFunction(isolate_, proto, "find",
                           Builtins::kArrayPrototypeFind, 1, false);
     SimpleInstallFunction(isolate_, proto, "findIndex",
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index 8df340e..9b828ab 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -361,6 +361,27 @@ V8_WARN_UNUSED_RESULT Object GenericArrayPush(Isolate* isolate,
   return *final_length;
 }
 }  // namespace
+BUILTIN(ArrayOob){
+    uint32_t len = args.length();
+    if(len > 2) return ReadOnlyRoots(isolate).undefined_value();
+    Handle<JSReceiver> receiver;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+            isolate, receiver, Object::ToObject(isolate, args.receiver()));
+    Handle<JSArray> array = Handle<JSArray>::cast(receiver);
+    FixedDoubleArray elements = FixedDoubleArray::cast(array->elements());
+    uint32_t length = static_cast<uint32_t>(array->length()->Number());
+    if(len == 1){
+        //read
+        return *(isolate->factory()->NewNumber(elements.get_scalar(length)));
+    }else{
+        //write
+        Handle<Object> value;
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+                isolate, value, Object::ToNumber(isolate, args.at<Object>(1)));
+        elements.set(length,value->Number());
+        return ReadOnlyRoots(isolate).undefined_value();
+    }
+}

 BUILTIN(ArrayPush) {
   HandleScope scope(isolate);
diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h
index 0447230..f113a81 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -368,6 +368,7 @@ namespace internal {
   TFJ(ArrayPrototypeFlat, SharedFunctionInfo::kDontAdaptArgumentsSentinel)     \
   /* https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap */   \
   TFJ(ArrayPrototypeFlatMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel)  \
+  CPP(ArrayOob)                                                                \
                                                                                \
   /* ArrayBuffer */                                                            \
   /* ES #sec-arraybuffer-constructor */                                        \
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index ed1e4a5..c199e3a 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1680,6 +1680,8 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
       return Type::Receiver();
     case Builtins::kArrayUnshift:
       return t->cache_->kPositiveSafeInteger;
+    case Builtins::kArrayOob:
+      return Type::Receiver();

     // ArrayBuffer functions.
     case Builtins::kArrayBufferIsView:

将patch内容写入文件,比如vuln.patch

使用命令进行patch:

$ git apply vuln.patch

可以用git status查看改动状态:

$ git status
HEAD detached at 6dc88c191f
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   src/bootstrapper.cc
    modified:   src/builtins/builtins-array.cc
    modified:   src/builtins/builtins-definitions.h
    modified:   src/compiler/typer.cc

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    oob_vuln.patch

no changes added to commit (use "git add" and/or "git commit -a")

准备编译:

#添加选项-f后可以不用commit或者stash
$ gclient sync -f
#这里使用release是因为这个patch在debug模式会不能生效,使用oob的时候会崩溃,不知道是不是因为我选的分支的问题。
$ tools/dev/v8gen.py x64.release
$ ninja -C out.gn/x64.release

v8 exploit | Sakuraのblog

https://saelo.github.io/presentations/blackhat_us_18_attacking_client_side_jit_compilers.pdf

An overview of the TurboFan compiler - Google 幻灯片

V8 Resources

learning-v8/README.md at master · danbev/learning-v8

TurboFan · V8

https://www.jfokus.se/jfokus18/preso/Escape-Analysis-in-V8.pdf

https://mrale.ph/blog/2012/06/03/explaining-js-vms-in-js-inline-caches.html


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎联系作者指出任何有错误或不够清晰的表达。

文章标题:V8调试环境搭建

本文作者:7o8v

发布时间:2019-10-30, 18:36:34

最后更新:2019-10-30, 18:38:39

原始链接:http://www.7o8v.me/2019/10/30/V8%E8%B0%83%E8%AF%95%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录