ruzzy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Ruzzy

Ruzzy

Ruzzy is a coverage-guided fuzzer for Ruby built on libFuzzer. It enables fuzzing both pure Ruby code and Ruby C extensions with sanitizer support for detecting memory corruption and undefined behavior.
Ruzzy是一款基于libFuzzer构建的、针对Ruby的覆盖率引导模糊测试工具。它支持对纯Ruby代码和Ruby C扩展进行模糊测试,同时集成了sanitizer以检测内存损坏和未定义行为。

When to Use

适用场景

Ruzzy is currently the only production-ready coverage-guided fuzzer for Ruby.
Choose Ruzzy when:
  • Fuzzing Ruby applications or libraries
  • Testing Ruby C extensions for memory safety issues
  • You need coverage-guided fuzzing for Ruby code
  • Working with Ruby gems that have native extensions
Ruzzy是目前唯一一款可用于生产环境的、针对Ruby的覆盖率引导模糊测试工具。
选择Ruzzy的场景:
  • 对Ruby应用或库进行模糊测试
  • 测试Ruby C扩展的内存安全性问题
  • 需要为Ruby代码提供覆盖率引导的模糊测试
  • 处理包含原生扩展的Ruby gem

Quick Start

快速开始

Set up environment:
bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
Test with the included toy example:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby -e 'require "ruzzy"; Ruzzy.dummy'
This should quickly find a crash demonstrating that Ruzzy is working correctly.
设置环境:
bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
使用内置的示例进行测试:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby -e 'require "ruzzy"; Ruzzy.dummy'
该命令应能快速发现崩溃问题,证明Ruzzy正常工作。

Installation

安装

Platform Support

平台支持

Ruzzy supports Linux x86-64 and AArch64/ARM64. For macOS or Windows, use the Dockerfile or development environment.
Ruzzy支持Linux x86-64和AArch64/ARM64架构。对于macOS或Windows系统,请使用Dockerfile开发环境

Prerequisites

前置要求

  • Linux x86-64 or AArch64/ARM64
  • Recent version of clang (tested back to 14.0.0, latest release recommended)
  • Ruby with gem installed
  • Linux x86-64或AArch64/ARM64架构
  • 较新版本的clang(测试支持至14.0.0,推荐使用最新版本)
  • 已安装gem的Ruby环境

Installation Command

安装命令

Install Ruzzy with clang compiler flags:
bash
MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
    gem install ruzzy
Environment variables explained:
  • MAKE
    : Overrides make to respect subsequent environment variables
  • CC
    ,
    CXX
    ,
    LDSHARED
    ,
    LDSHAREDXX
    : Ensure proper clang binaries are used for latest features
使用clang编译器标志安装Ruzzy:
bash
MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
    gem install ruzzy
环境变量说明:
  • MAKE
    :覆盖默认make命令,使其遵循后续环境变量设置
  • CC
    CXX
    LDSHARED
    LDSHAREDXX
    :确保使用正确的clang二进制文件以支持最新特性

Troubleshooting Installation

安装故障排除

If installation fails, enable debug output:
bash
RUZZY_DEBUG=1 gem install --verbose ruzzy
如果安装失败,启用调试输出:
bash
RUZZY_DEBUG=1 gem install --verbose ruzzy

Verification

验证安装

Verify installation by running the toy example (see Quick Start section).
通过运行快速开始部分的示例来验证安装是否成功。

Writing a Harness

编写测试Harness

Fuzzing Pure Ruby Code

对纯Ruby代码进行模糊测试

Pure Ruby fuzzing requires two scripts due to Ruby interpreter implementation details.
Tracer script (
test_tracer.rb
):
ruby
undefined
由于Ruby解释器的实现细节,对纯Ruby代码进行模糊测试需要两个脚本。
追踪脚本(
test_tracer.rb
):
ruby
undefined

frozen_string_literal: true

frozen_string_literal: true

require 'ruzzy'
Ruzzy.trace('test_harness.rb')

**Harness script (`test_harness.rb`):**

```ruby
require 'ruzzy'
Ruzzy.trace('test_harness.rb')

**测试Harness脚本(`test_harness.rb`):**

```ruby

frozen_string_literal: true

frozen_string_literal: true

require 'ruzzy'
def fuzzing_target(input)

Your code to fuzz here

if input.length == 4 if input[0] == 'F' if input[1] == 'U' if input[2] == 'Z' if input[3] == 'Z' raise end end end end end end
test_one_input = lambda do |data| fuzzing_target(data) return 0 end
Ruzzy.fuzz(test_one_input)

Run with:

```bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby test_tracer.rb
require 'ruzzy'
def fuzzing_target(input)

此处放置待模糊测试的代码

if input.length == 4 if input[0] == 'F' if input[1] == 'U' if input[2] == 'Z' if input[3] == 'Z' raise end end end end end end
test_one_input = lambda do |data| fuzzing_target(data) return 0 end
Ruzzy.fuzz(test_one_input)

运行命令:

```bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby test_tracer.rb

Fuzzing Ruby C Extensions

对Ruby C扩展进行模糊测试

C extensions can be fuzzed with a single harness file, no tracer needed.
Example harness for msgpack (
fuzz_msgpack.rb
):
ruby
undefined
对C扩展进行模糊测试只需一个Harness文件,无需追踪脚本。
针对msgpack的示例Harness(
fuzz_msgpack.rb
):
ruby
undefined

frozen_string_literal: true

frozen_string_literal: true

require 'msgpack' require 'ruzzy'
test_one_input = lambda do |data| begin MessagePack.unpack(data) rescue Exception # We're looking for memory corruption, not Ruby exceptions end return 0 end
Ruzzy.fuzz(test_one_input)

Run with:

```bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby fuzz_msgpack.rb
require 'msgpack' require 'ruzzy'
test_one_input = lambda do |data| begin MessagePack.unpack(data) rescue Exception # 我们关注的是内存损坏,而非Ruby异常 end return 0 end
Ruzzy.fuzz(test_one_input)

运行命令:

```bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby fuzz_msgpack.rb

Harness Rules

Harness编写规则

DoDon't
Catch Ruby exceptions if testing C extensionsLet Ruby exceptions crash the fuzzer
Return 0 from test_one_input lambdaReturn other values
Keep harness deterministicUse randomness or time-based logic
Use tracer script for pure RubySkip tracer for pure Ruby code
See Also: For detailed harness writing techniques, patterns for handling complex inputs, and advanced strategies, see the fuzz-harness-writing technique skill.
建议做法禁止做法
测试C扩展时捕获Ruby异常让Ruby异常导致模糊测试工具崩溃
从test_one_input lambda返回0返回其他值
保持Harness的确定性使用随机性或基于时间的逻辑
对纯Ruby代码使用追踪脚本对纯Ruby代码跳过追踪脚本
另请参阅: 有关编写高效Harness的详细技巧、处理复杂输入的模式以及高级策略,请查看fuzz-harness-writing技术文档。

Compilation

编译

Installing Gems with Sanitizers

安装带Sanitizer的Gem

When installing Ruby gems with C extensions for fuzzing, compile with sanitizer flags:
bash
MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
CFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
CXXFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
    gem install <gem-name>
当安装用于模糊测试的、包含C扩展的Ruby gem时,需使用sanitizer标志进行编译:
bash
MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
CFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
CXXFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
    gem install <gem-name>

Build Flags

构建标志

FlagPurpose
-fsanitize=address,fuzzer-no-link
Enable AddressSanitizer and fuzzer instrumentation
-fno-omit-frame-pointer
Improve stack trace quality
-fno-common
Better compatibility with sanitizers
-fPIC
Position-independent code for shared libraries
-g
Include debug symbols
标志用途
-fsanitize=address,fuzzer-no-link
启用AddressSanitizer和模糊测试工具插桩
-fno-omit-frame-pointer
提升栈跟踪的质量
-fno-common
提升与sanitizer的兼容性
-fPIC
为共享库生成位置无关代码
-g
包含调试符号

Running Campaigns

运行测试任务

Environment Setup

环境设置

Before running any fuzzing campaign, set ASAN_OPTIONS:
bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
Options explained:
  1. allocator_may_return_null=1
    : Skip common low-impact allocation failures (DoS)
  2. detect_leaks=0
    : Ruby interpreter leaks data, ignore these for now
  3. use_sigaltstack=0
    : Ruby recommends disabling sigaltstack with ASan
在运行任何模糊测试任务前,设置ASAN_OPTIONS:
bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
选项说明:
  1. allocator_may_return_null=1
    :跳过常见的低影响分配失败(拒绝服务类问题)
  2. detect_leaks=0
    :Ruby解释器存在数据泄漏,暂时忽略此类问题
  3. use_sigaltstack=0
    :Ruby官方建议在使用ASan时禁用sigaltstack

Basic Run

基础运行

bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb
Note:
LD_PRELOAD
is required for sanitizer injection. Unlike
ASAN_OPTIONS
, do not export it as it may interfere with other programs.
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb
注意:
LD_PRELOAD
是注入sanitizer所必需的。与
ASAN_OPTIONS
不同,请勿导出该变量,否则可能会干扰其他程序。

With Corpus

使用语料库

bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb /path/to/corpus
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb /path/to/corpus

Passing libFuzzer Options

传递libFuzzer选项

All libFuzzer options can be passed as arguments:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb /path/to/corpus -max_len=1024 -timeout=10
See libFuzzer options for full reference.
所有libFuzzer选项均可作为参数传递:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb /path/to/corpus -max_len=1024 -timeout=10
有关完整选项列表,请参阅libFuzzer文档

Reproducing Crashes

复现崩溃

Re-run a crash case by passing the crash file:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb ./crash-253420c1158bc6382093d409ce2e9cff5806e980
通过传递崩溃文件来重新运行崩溃案例:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb ./crash-253420c1158bc6382093d409ce2e9cff5806e980

Interpreting Output

输出解读

OutputMeaning
INFO: Running with entropic power schedule
Fuzzing campaign started
ERROR: AddressSanitizer: heap-use-after-free
Memory corruption detected
SUMMARY: libFuzzer: fuzz target exited
Ruby exception occurred
artifact_prefix='./'; Test unit written to ./crash-*
Crash input saved
Base64: ...
Base64 encoding of crash input
输出内容含义
INFO: Running with entropic power schedule
模糊测试任务已启动
ERROR: AddressSanitizer: heap-use-after-free
检测到内存损坏
SUMMARY: libFuzzer: fuzz target exited
发生Ruby异常
artifact_prefix='./'; Test unit written to ./crash-*
已保存崩溃输入
Base64: ...
崩溃输入的Base64编码

Sanitizer Integration

Sanitizer集成

AddressSanitizer (ASan)

AddressSanitizer (ASan)

Ruzzy includes a pre-compiled AddressSanitizer library:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb
Use ASan for detecting:
  • Heap buffer overflows
  • Stack buffer overflows
  • Use-after-free
  • Double-free
  • Memory leaks (disabled by default in Ruzzy)
Ruzzy包含预编译的AddressSanitizer库:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby harness.rb
使用ASan可检测:
  • 堆缓冲区溢出
  • 栈缓冲区溢出
  • 释放后使用
  • 重复释放
  • 内存泄漏(Ruzzy中默认禁用)

UndefinedBehaviorSanitizer (UBSan)

UndefinedBehaviorSanitizer (UBSan)

Ruzzy also includes UBSan:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::UBSAN_PATH') \
    ruby harness.rb
Use UBSan for detecting:
  • Signed integer overflow
  • Null pointer dereferences
  • Misaligned memory access
  • Division by zero
Ruzzy同样集成了UBSan:
bash
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::UBSAN_PATH') \
    ruby harness.rb
使用UBSan可检测:
  • 有符号整数溢出
  • 空指针解引用
  • 内存访问未对齐
  • 除零错误

Common Sanitizer Issues

常见Sanitizer问题

IssueSolution
Ruby interpreter leak warningsUse
ASAN_OPTIONS=detect_leaks=0
Sigaltstack conflictsUse
ASAN_OPTIONS=use_sigaltstack=0
Allocation failure spamUse
ASAN_OPTIONS=allocator_may_return_null=1
LD_PRELOAD interferes with toolsDon't export it; set inline with ruby command
See Also: For detailed sanitizer configuration, common issues, and advanced flags, see the address-sanitizer and undefined-behavior-sanitizer technique skills.
| 问题 | 原因 | 解决方案 | |-------|----------| | Ruby解释器泄漏警告 | Ruby解释器本身存在数据泄漏 | 设置
ASAN_OPTIONS=detect_leaks=0
| | Sigaltstack冲突 | Ruby与ASan的sigaltstack设置不兼容 | 设置
ASAN_OPTIONS=use_sigaltstack=0
| | 分配失败信息泛滥 | 低影响分配失败被频繁报告 | 设置
ASAN_OPTIONS=allocator_may_return_null=1
| | LD_PRELOAD干扰其他工具 | 导出了LD_PRELOAD变量 | 不要导出LD_PRELOAD,仅在运行Ruby命令时内联设置 |
另请参阅: 有关sanitizer的详细配置、常见问题及高级标志,请查看address-sanitizerundefined-behavior-sanitizer技术文档。

Real-World Examples

实际案例

Example: msgpack-ruby

案例:msgpack-ruby

Fuzzing the msgpack MessagePack parser for memory corruption.
Install with sanitizers:
bash
MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
CFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
CXXFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
    gem install msgpack
Harness (
fuzz_msgpack.rb
):
ruby
undefined
对msgpack的MessagePack解析器进行模糊测试以检测内存损坏。
安装带sanitizer的msgpack:
bash
MAKE="make --environment-overrides V=1" \
CC="/path/to/clang" \
CXX="/path/to/clang++" \
LDSHARED="/path/to/clang -shared" \
LDSHAREDXX="/path/to/clang++ -shared" \
CFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
CXXFLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -fno-common -fPIC -g" \
    gem install msgpack
测试Harness(
fuzz_msgpack.rb
):
ruby
undefined

frozen_string_literal: true

frozen_string_literal: true

require 'msgpack' require 'ruzzy'
test_one_input = lambda do |data| begin MessagePack.unpack(data) rescue Exception # We're looking for memory corruption, not Ruby exceptions end return 0 end
Ruzzy.fuzz(test_one_input)

**Run:**

```bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby fuzz_msgpack.rb
require 'msgpack' require 'ruzzy'
test_one_input = lambda do |data| begin MessagePack.unpack(data) rescue Exception # 我们关注的是内存损坏,而非Ruby异常 end return 0 end
Ruzzy.fuzz(test_one_input)

**运行命令:**

```bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby fuzz_msgpack.rb

Example: Pure Ruby Target

案例:纯Ruby目标

Fuzzing pure Ruby code with a custom parser.
Tracer (
test_tracer.rb
):
ruby
undefined
对包含自定义解析器的纯Ruby代码进行模糊测试。
追踪脚本(
test_tracer.rb
):
ruby
undefined

frozen_string_literal: true

frozen_string_literal: true

require 'ruzzy'
Ruzzy.trace('test_harness.rb')

**Harness (`test_harness.rb`):**

```ruby
require 'ruzzy'
Ruzzy.trace('test_harness.rb')

**测试Harness(`test_harness.rb`):**

```ruby

frozen_string_literal: true

frozen_string_literal: true

require 'ruzzy' require_relative 'my_parser'
test_one_input = lambda do |data| begin MyParser.parse(data) rescue StandardError # Expected exceptions from malformed input end return 0 end
Ruzzy.fuzz(test_one_input)

**Run:**

```bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby test_tracer.rb
require 'ruzzy' require_relative 'my_parser'
test_one_input = lambda do |data| begin MyParser.parse(data) rescue StandardError # 格式错误输入导致的预期异常 end return 0 end
Ruzzy.fuzz(test_one_input)

**运行命令:**

```bash
export ASAN_OPTIONS="allocator_may_return_null=1:detect_leaks=0:use_sigaltstack=0"
LD_PRELOAD=$(ruby -e 'require "ruzzy"; print Ruzzy::ASAN_PATH') \
    ruby test_tracer.rb

Troubleshooting

故障排除

ProblemCauseSolution
Installation failsWrong clang version or pathVerify clang path, use clang 14.0.0+
cannot open shared object file
LD_PRELOAD not setSet LD_PRELOAD inline with ruby command
Fuzzer immediately exitsMissing corpus directoryCreate corpus directory or pass as argument
No coverage progressPure Ruby needs tracerUse tracer script for pure Ruby code
Leak detection spamRuby interpreter leaksSet
ASAN_OPTIONS=detect_leaks=0
Installation debug neededCompilation errorsUse
RUZZY_DEBUG=1 gem install --verbose ruzzy
问题原因解决方案
安装失败clang版本错误或路径不正确验证clang路径,使用clang 14.0.0+版本
cannot open shared object file
未设置LD_PRELOAD在运行Ruby命令时内联设置LD_PRELOAD
模糊测试工具立即退出缺少语料库目录创建语料库目录或作为参数传递
覆盖率无进展纯Ruby代码未使用追踪脚本对纯Ruby代码使用追踪脚本
泄漏检测信息泛滥Ruby解释器存在泄漏设置
ASAN_OPTIONS=detect_leaks=0
需要安装调试信息编译错误使用
RUZZY_DEBUG=1 gem install --verbose ruzzy

Related Skills

相关技术

Technique Skills

技术文档

SkillUse Case
fuzz-harness-writingDetailed guidance on writing effective harnesses
address-sanitizerMemory error detection during fuzzing
undefined-behavior-sanitizerDetecting undefined behavior in C extensions
libfuzzerUnderstanding libFuzzer options (Ruzzy is built on libFuzzer)
技术适用场景
fuzz-harness-writing编写高效测试Harness的详细指南
address-sanitizer模糊测试期间的内存错误检测
undefined-behavior-sanitizer检测C扩展中的未定义行为
libfuzzer理解libFuzzer选项(Ruzzy基于libFuzzer构建)

Related Fuzzers

相关模糊测试工具

SkillWhen to Consider
libfuzzerWhen fuzzing Ruby C extension code directly in C/C++
aflppAlternative approach for fuzzing Ruby by instrumenting Ruby interpreter
工具适用场景
libfuzzer直接在C/C++中对Ruby C扩展进行模糊测试时
aflpp通过插桩Ruby解释器对Ruby进行模糊测试的替代方案

Resources

资源

Key External Resources

关键外部资源

Introducing Ruzzy, a coverage-guided Ruby fuzzer Official Trail of Bits blog post announcing Ruzzy, covering motivation, architecture, and initial results.
Ruzzy GitHub Repository Source code, additional examples, and development instructions.
libFuzzer Documentation Since Ruzzy is built on libFuzzer, understanding libFuzzer options and behavior is valuable.
Fuzzing Ruby C extensions Detailed guide on fuzzing C extensions with compilation flags and examples.
Fuzzing pure Ruby code Detailed guide on the tracer pattern required for pure Ruby fuzzing.
Introducing Ruzzy, a coverage-guided Ruby fuzzer Trail of Bits官方博客文章,介绍Ruzzy的开发动机、架构和初始测试结果。
Ruzzy GitHub Repository 源代码、更多示例及开发说明。
libFuzzer Documentation 由于Ruzzy基于libFuzzer构建,了解libFuzzer的选项和行为非常重要。
Fuzzing Ruby C extensions 关于使用编译标志和示例对C扩展进行模糊测试的详细指南。
Fuzzing pure Ruby code 关于对纯Ruby代码进行模糊测试所需的追踪模式的详细指南。