V8 调试手册¶
这篇笔记只保留 V8 漏洞分析最常用的环境、命令和调试步骤。
V8 环境搭建¶
两条构建线:x64.debug(调试)和 x64.release_with_symbol(复现)。
1) 安装 depot_tools¶
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git ~/depot_tools
echo 'export PATH="$HOME/depot_tools:$PATH"' >> ~/.bashrc
source ~/.bashrc
gclient
建议把 depot_tools 放在 PATH 前面,避免系统自带 gn/ninja 混入。
2) 拉取 V8 源码¶
Linux 额外依赖:
3) 代理开关(可选)¶
网络较慢可在 ~/.bashrc 添加:
proxy_on() {
export http_proxy=http://127.0.0.1:xxx
export https_proxy=$http_proxy
git config --global http.proxy $http_proxy
git config --global https.proxy $http_proxy
}
proxy_off() {
unset http_proxy
unset https_proxy
git config --global --unset http.proxy
git config --global --unset https.proxy
}
4) 切到指定版本/漏洞版本(可选)¶
5) 调试构建:x64.debug¶
6) 复现构建:x64.release_with_symbol¶
gn gen out/x64.release_with_symbol --args='
is_debug=false
is_component_build=true
symbol_level=2
target_cpu="x64"
v8_enable_backtrace=true
v8_enable_disassembler=true
v8_enable_object_print=true
v8_enable_verify_heap=true
treat_warnings_as_errors=false
'
ninja -C out/x64.release_with_symbol d8
验证版本:
gdbinit_v8 脚本¶
gdbinit_v8 对应仓库里的 tools/gdbinit,用于给 gdb 注入 V8 专用命令。
1) 获取并加载¶
2) 启动方式¶
3) 常用命令¶
job <tagged_ptr>:打印对象jlh <local_handle>/jh <internal_handle>:打印 handle 指向对象jco [pc]:打印 PC 对应 Code 对象jca [pc] [n]:打印附近反汇编jst/jstc:打印 JS 栈jtt <map>:打印 map transition tree
4) 常用配合¶
- JS 里
%DebugPrint(obj)拿地址 %SystemBreak()停住进程- gdb 里
job <地址>
最常用启动参数¶
./out.gn/x64.debug/d8 poc.js \
--allow-natives-syntax \
--print-bytecode \
--print-bytecode-filter=trigger \
--trace-opt \
--trace-deopt \
--trace-ic \
>stdout.v8dump 2>stderr.v8dump
| 参数 | 作用 |
|---|---|
--allow-natives-syntax |
打开 %DebugPrint、%OptimizeFunctionOnNextCall |
--print-bytecode |
打印 Ignition bytecode |
--print-bytecode-filter=trigger |
只打印目标函数 |
--trace-opt |
优化编译日志 |
--trace-deopt |
反优化原因 |
--trace-ic |
IC 状态迁移 |
常用命令模板¶
1) 只看 bytecode¶
2) 看优化和 deopt¶
3) 看 TurboFan 图¶
mkdir -p turbo
./out.gn/x64.debug/d8 poc.js \
--trace-turbo \
--trace-turbo-path=./turbo \
--trace-turbo-filter=trigger
4) 提升复现稳定性¶
flag 名称可能随版本变化,先用 ./out.gn/x64.debug/d8 --help 校对。
gdb 常用操作¶
常见断点:
(gdb) rbreak Builtins_
(gdb) b v8::internal::Runtime_ThrowReferenceError
(gdb) b v8::internal::BytecodeGenerator::ControlScopeForBreakable::Execute
建议先 rbreak 缩小范围,再保留关键断点。
调试时常用 % 内建¶
%DebugPrint(obj);
%SystemBreak();
%PrepareFunctionForOptimization(f);
%OptimizeFunctionOnNextCall(f);
做 type confusion 时,配合 x/gx 校对“语义字段”和“内存偏移”。
漏洞分析流程¶
第一步:最小化 PoC¶
保留最短可稳定触发版本。
第二步:先看 bytecode¶
bytecode 已异常先不看汇编;bytecode 正常再看优化图/反汇编。
第三步:确认是否依赖优化态¶
同一份 PoC 对比“未优化/已优化”,判断问题类型:
- 前端语义生成问题
- IC handler 选择问题
- 优化阶段错误折叠/错误假设
第四步:关键对象都 DebugPrint¶
至少打印 receiver、lookup_start_object、返回值对象。
第五步:对照 patch¶
先定位 patch 落点,再确认本地断点是否命中同一路径。
速查¶
# 0) gdbinit_v8
cp tools/gdbinit ~/.gdbinit_v8
echo 'source ~/.gdbinit_v8' >> ~/.gdbinit
# 1) 字节码
./out.gn/x64.debug/d8 poc.js --print-bytecode --print-bytecode-filter=trigger
# 2) 优化/反优化
./out.gn/x64.debug/d8 poc.js --allow-natives-syntax --trace-opt --trace-deopt
# 3) IC 迁移
./out.gn/x64.debug/d8 poc.js --trace-ic
# 4) TurboFan 图
./out.gn/x64.debug/d8 poc.js --trace-turbo --trace-turbo-path=./turbo --trace-turbo-filter=trigger
# 5) gdb
gdb --args ./out.gn/x64.debug/d8 poc.js --allow-natives-syntax