ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

V8 JS-Fuzzer 完全指南:从语料库构建到本地 ClusterFuzz 模糊测试实战

V8 JS-Fuzzer 完全指南:从语料库构建到本地 ClusterFuzz 模糊测试实战 V8 JS-Fuzzer 完全指南从语料库构建到本地 ClusterFuzz 模糊测试实战【免费下载链接】v8The official mirror of the V8 Git repository项目地址: https://gitcode.com/gh_mirrors/v81/v8V8 仓库中的 JS-Fuzzertools/clusterfuzz/js_fuzzer/README.md是一个面向 D8、Chakra、JSC、Spidermonkey 等独立 JavaScript 引擎 shell 的语法级模糊测试工具被 ClusterFuzz 用于在引擎中挖掘解析、编译与执行阶段的内存安全问题。本文以该 README 为核心骨架结合仓库内 run.js、script_mutator.js、runner.js 等源码完整讲解环境搭建、Fuzzing DB 构建、二进制打包以及两种本地执行方案workbench 差分实验与run_locally_against_d8.py崩溃复现读完即可在本地跑起一轮针对d8的模糊测试并拿到可复现的崩溃用例。一、JS-Fuzzer 是什么JS-Fuzzer 是一个用 Node.js 编写、基于 Babel AST 的 JavaScript 模糊测试器。它与传统的“随机字节乱改”不同它从真实世界的大量 JS 测试语料中按概率挑选片段重组、交叉、替换、扭曲生成语法合法、语义刁钻的新程序从而更高效地触发引擎解析器与 JIT 编译器的深层路径。从源码结构看它的核心部件集中在 tools/clusterfuzz/js_fuzzer 目录build_db.js从多引擎测试语料中抽取 AST 片段构建“突变数据库”Fuzzing DBrun.js模糊测试主入口负责解析命令行、加载语料与数据库、调度 mutator 并输出测试用例mutators/一组独立变换器数组、对象、变量、数字、表达式、函数调用、交叉重组、Unicode 转义、内存破坏等runner.js决定每次测试用例由哪些语料文件组合而成exceptions.js对无法解析或性能极差的用例的跳过/软跳过名单。引擎适配通过环境变量APP_NAME实现见 run.jsd8、v8_simple_inspector_fuzzer、v8_foozzie.py对应 V8 引擎ch、js、jsc分别对应 Chakra、Spidermonkey、JavaScriptCore。同时FUZZ_MODE环境变量决定使用哪种 mutator 体系default单引擎、foozzie差分模糊、foozzie_fuzzilli面向 Fuzzilli 语料的差分模糊、wasm仅 wasm-module-builder 用例映射关系定义在 run.js。二、环境准备Node.js 与依赖安装由于 fuzzer 依赖的 Node 版本可能比 ClusterFuzz 生产环境更新的 Babel 生态README 明确说明采用 pkg 打包成自包含二进制。先在本地准备环境安装 Node.js 与 npm在 tools/clusterfuzz/js_fuzzer 目录下执行$ npm install依赖清单见 package.json运行时依赖包括babel/parser、babel/traverse、babel/types、babel/generator、babel/template等 Babel 核心模块以及commander命令行解析、globals内建全局标识符表、tempfile/tempy临时目录开发依赖包括mocha测试框架、sinon桩函数、eslint、prettier以及打包用的pkg ^5.8.1。pkg.assets字段声明了resources/**/*表示 Babel 等资源文件会被一并打入二进制。三、构建 Fuzzing DB突变数据库Fuzzer 运行前必须先构建数据库。数据源是 ClusterFuzz 定期打包的多引擎测试集web_tests.zip数据桶地址为gs://clusterfuzz-data/web_tests.zip下载后解压得到目录树包含v8/、chakra/、spidermonkey/、WebKit/JSTests/、fuzzilli/等语料子目录。构建步骤如下$ mkdir db $ node build_db.js -i /path/to/web_tests -o db chakra v8 spidermonkey WebKit/JSTests fuzzilli $ node validate_db.js -i db -o db/index.json-i指定解压后的 web_tests 根目录-o指定数据库输出目录命令行末尾的chakra v8 spidermonkey WebKit/JSTests fuzzilli是参与构建的语料名对应 corpus.js 中定义的语料解析规则build_db.js 逐文件解析为 AST通过 db.js 的MutateDbWriter把表达式节点按类型如CallExpression、LogicalExpression、UnaryExpression等连同哈希写入输出目录最后写出index.json索引validate_db.js 对数据库做完整性校验并输出可用的index.json。整个构建过程耗时较长。构建完成后可选用 test_db.js 对数据库做冒烟验证$ node test_db.js -i db数据库内部结构可以参考仓库中的期望样例 test_data/db/e2e_expected按CallExpression/、ClassExpression/、NewExpression/、TaggedTemplateExpression/等节点类型分目录存放 JSON 片段顶层是index.json。四、构建 fuzzer 可执行文件依赖与数据库就绪后用 pkg 打包为自包含二进制这一步可跳过 Node 运行时依赖便于部署到 ClusterFuzz 环境$ ./node_modules/.bin/pkg -t node18-linux-x64 .-t指定目标平台三元组README 注明将linux替换为win或macos即可对应平台构建例如node18-win-x64、node18-macos-x64产物在 Linux/macOS 下名为ochang_js_fuzzerWindows 下为ochang_js_fuzzer.exe二进制名称源自 package.json 中的name: ochang_js_fuzzer原始作者为 Oliver Chang见 README。五、打包发布output.zip为方便交付可直接使用打包脚本$ ./package.sh # Linux $ ./package.sh win # Windows $ ./package.sh macos # macOSpackage.sh 内部依次完成按平台调用 pkg → 清空旧产物 → 创建output/目录 → 建立软链接db指向../dbrun指向../ochang_js_fuzzer并额外链接foozzie_launcher.py→ 用zip打包为output.zip。也可以手工执行等价命令注意 Windows 下ochang_js_fuzzer与run都要加.exe后缀$ mkdir output $ cd output $ ln -s ../db db $ ln -s ../ochang_js_fuzzer run $ zip -r /path/output.zip *六、开发与单元测试仓库为 fuzzer 维护了一套基于 mocha 的单元测试覆盖各类 mutator 与回归场景。运行$ npm testnpm test实际执行的是APP_NAMEd8 mocha见 package.json 的scripts字段测试用例位于 test/ 目录如test_mutate_numbers.js、test_mutate_objects.js、test_mutate_function_calls.js、test_differential_fuzz.js、test_memory_corruptions.js、test_normalize.js等输入与期望输出配对存放在 test_data/。当测试期望需要更新时例如调整了 mutator 行为导致输出变化用环境变量重新生成期望文件$ GENERATE1 npm test七、生成异常配置跳过名单语料中总有少量用例“无法解析”或“性能极差”如超大正则、死循环模式继续以它们为输入只会浪费算力。仓库提供脚本自动生成跳过/软跳过名单$ WEB_TESTS/path/to/web_tests OUTPUT/path/to/output/folder ./gen_exceptions.sh该脚本耗时超过 1 小时。gen_exceptions.sh 依次对chakra、v8、spidermonkey、WebKit/JSTests、CrashTests五个语料执行APP_NAMEd8 node run.js -i $WEB_TESTS -o $OUTPUT -z -v -e -c corpus其中-z清零全部突变概率只做解析验证、-v输出详细日志、-e额外按严格模式解析、-c指定逐个文件突变模式最后用 gen_exceptions.js 汇总各语料日志生成 generated/exceptions.js。生成的名单在运行时由 exceptions.js 消费其中SKIPPED_FILES直接排除如d8-os.js、regress-444805.js、/^modules.*\.js/、/^regexp-property-.*\.js/等SKIPPED_DIRECTORIES按目录排除如embenchen、sqlite、v8/test/message、v8/test/debugger等SOFT_SKIPPED_FILES与SOFT_SKIPPED_PATHS则以较低概率选用如binaryen大二进制测试、webgl路径等。八、本地差分模糊测试实验workbenchREADME 提供了一套可本地复现 ClusterFuzz 工作流的实验方案当前仅限差分模糊测试differential fuzzing。先搭建工作目录$ workdir/ $ workdir/app_dir # d8 及运行所需全部文件的打包目录可用符号链接 $ workdir/fuzzer # 存放 ochang_js_fuzzer 可执行文件与 db 目录可用符号链接 $ workdir/input # 语料根目录即 web_tests.zip 解压后的数据 $ workdir/output # 模糊测试输出目录需为空说明app_dir目录应包含带完整运行依赖的d8打包版本即含v8_build_config.json等配置——因为 script_mutator.js 中的loadJSONFromBuild会读取APP_DIR/v8_build_config.json来推断memory_corruption_api、架构等信息fuzzer目录放入打包好的ochang_js_fuzzer与db目录。启动实验NUM_RUNS约为 40000 时对应工作站上 24 小时的模糊测试量$ NUM_RUNS40000 $ python tools/workbench.py $NUM_RUNSworkbench.py 按 CPU 核数启动多进程每个进程先调用tools/fuzz_one.py生成用例再调用tools/run_one.py逐一执行并收集统计最后把各进程的stats.json与failures.json合并去重按失败source去重重复记为dupe汇总写入workdir/output/stats.json与failures.json。随时查看运行统计$ cat workdir/output/stats.json | python -m json.tool汇总字段包括total总用例数、crash、failure、dupe重复失败、timeout。发现失败后可批量构造最小化命令$ MINIMIZER_PATHpath/to/minimizer $ python tools/minimize.py $MINIMIZER_PATHMINIMIZER_PATH应指向 ClusterFuzz 代码库中 minimizer 的本地检出路径tools/minimize.py 会逐条为失败用例生成最小化命令行。九、本地 ClusterFuzz 模拟run_locally_against_d8.py如果不做完整实验只想快速验证 fuzzer 能否在本地d8上砸出崩溃可直接使用 tools/run_locally_against_d8.py 模拟 ClusterFuzz 的“生成→执行→判定→保存”闭环用 fuzzer 生成一批测试用例用d8执行每个用例应用生成的 flags通过信号、退出码或FATAL错误信息检测崩溃把崩溃用例及其 flags 保存到本地目录。基本用法$ python3 tools/run_locally_against_d8.py [options]参数说明下表综合 README 与脚本中 argparse 定义参数说明默认值--num-tests n生成并运行的测试用例总数10000--num-crashes n找到 n 个崩溃后停止10--d8 path被测d8二进制路径脚本目录向上四级仓库根的out/x64.release/d8--crash-dir path崩溃用例保存目录js_fuzzer 目录下workdir/crash/--batch-size n每次调用 fuzzer 生成的用例数100--extra-flags flags始终传给d8的附加 flag如--extra-flags --turbofan --allow-natives-syntax空--jobs n并行d8任务数默认按 CPU 数脚本内为cpu_count / 2README 描述为 CPU 数--fuzzer pathfuzzer 二进制路径workdir/fuzzer/ochang_js_fuzzer--input path语料目录workdir/input--app-dir path含v8_build_config.json的应用目录workdir/app_dir--output-dir path生成的测试用例存放目录workdir/output/generated执行与崩溃判定脚本内部按批生成每批独立目录避免并发冲突生成时注入APP_NAMEd8与APP_DIR环境变量对应 run.js 的引擎推断逻辑随后用d8 --fuzzing [extra-flags] [flags-file 内容] test.js执行单用例 5 秒超时防挂死。崩溃判定覆盖四类信号见 run_locally_against_d8.py返回码为负 → 收到信号打印Signal received: N返回码大于 127 → 疑似信号Likely signalstderr 中出现FATAL→ 引擎内部致命错误stderr 中出现AddressSanitizer→ ASan 报告。命中的用例以crash_序号_原名.js命名保存若 fuzzer 同时产出了对应的flags-N.js由 run.js 为 V8 引擎生成的 flag 文件也会一并拷贝。运行过程中终端会实时刷新Generated: x/y, Crashes: z进度达到--num-tests或--num-crashes阈值即停止。注意脚本在启动前会校验d8与 fuzzer 二进制存在且可执行缺失时直接报错退出。十、源码级纵深核心设计速览1. 突变器管线与概率设置script_mutator.js 的defaultSettings()定义了全部突变概率可用run.js的-s/--setting keyvalue覆盖多次使用可覆盖多项或用-z/--zero_settings全部清零这正是 gen_exceptions 脚本的做法设置项默认值含义MUTATE_ARRAYS/MUTATE_OBJECTS0.1数组/对象字面量突变MUTATE_VARIABLES0.075变量替换MUTATE_NUMBERS0.05数字突变MUTATE_EXPRESSIONS/MUTATE_FUNCTION_CALLS0.1表达式/函数调用替换ADD_VAR_OR_OBJ_MUTATIONS0.1变量或对象注入MUTATE_CROSSOVER_INSERT0.1从数据库交叉插入片段CORRUPT_MEMORY/CORRUPT_MEMORY_VIA_WATCHPOINTS0.1沙箱内存破坏相关沙箱模糊测试开启时生效DIFF_FUZZ_*0.1~0.5差分模糊专用打印、跳过函数、跟踪捕获异常ENABLE_ALLOCATION_TIMEOUT/MUTATE_ALLOCATION_TIMEOUT0.5 / 0.02分配超时注入ENABLE_*_UNICODE_ESCAPE0.05标识符/字符串/正则的 Unicode 转义SCRIPT_MUTATOR_SHUFFLE/SCRIPT_MUTATOR_EXTRA_MUTATIONS0.2打乱 mutator 顺序 / 追加 1~5 个额外 mutatorTRANSFORM_CLOSURES0.2移除匿名无参自调用闭包is_sandbox_fuzzing/is_x64_linuxfalse由构建配置自动推断突变顺序是固定的先移除闭包 → 执行各 mutator可打乱→ 追加内存破坏沙箱模式→ 追加分配超时 → 最后做 Unicode 转义try_catch包装放在易错突变之后避免用例过早抛出。Wasm 模式WasmScriptMutator会调低 crossover/object 概率、调高 number/variable/function-call 概率以保护 wasm-module-builder 结构完整。2. 语料组合策略runner.js 定义了多种 RunnerRandomCorpusRunner从主引擎语料取 40%~80% 输入、其余从其他语料均分每个测试用例由 2~10 个输入组合而成MAX_TEST_INPUTS_PER_TEST 10RandomCorpusRunnerWithFuzzilli额外加入 Fuzzilli 语料默认 RunnerRandomWasmCorpusRunner偏向 V8 wasm 语料SingleCorpusRunner对应-c逐文件模式。多个输入的 AST 会被合并后再突变见mutateInputs从而让交叉突变CrossOverMutator能跨文件复用变量与表达式这是 JS-Fuzzer 生成高价值用例的关键设计。3. 依赖解析与冲突处理resolveDependencies会为每个输入补齐测试框架依赖mjsunit 的mjsunit.js、Spidermonkey 的shell.js、JSTests 的jstest_stubs、Chakra 的chakra_stubs等并在最前面注入stubs.js、最后注入fuzz_library.js沙箱模式再加sandbox_fuzz_library.js。针对 wasm-module-builder 在 V8 与 Chakra 语料中重复定义的问题resolveCollisions会以 V8 版本为准剔除 Chakra 旧版依赖相关测试数据见 test_data/regress/dependency_collision。十一、常见问题与注意事项磁盘空间生成大量用例时若出现ENOSPCrun.js 会打印No space left. Bailing out...并终止注意预留充足空间工作目录权限运行run_locally_against_d8.py前需确认d8与 fuzzer 二进制存在且带可执行权限语料新鲜度Fuzzing DB 与语料直接决定突变质量建议定期同步最新的web_tests.zip并重建数据库差分模糊限制README 明确当前 workbench 实验方案仅支持差分模糊测试其他模式需依赖 ClusterFuzz 完整环境如foozzie_launcher.py测试期望更新修改 mutator 后输出快照变化是正常的用GENERATE1 npm test重新生成期望即可。掌握以上流程后你可以独立完成“下载语料 → 构建 DB → 打包 fuzzer → 本地复现 ClusterFuzz 式崩溃验证”的完整闭环为 V8 及其他 JS 引擎的健壮性测试提供可复现、可最小化的高质量输入。【免费下载链接】v8The official mirror of the V8 Git repository项目地址: https://gitcode.com/gh_mirrors/v81/v8创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表