
KVMを使用したメモリスナップショットの軽量ファジング
KVM を使用したメモリスナップショットの軽量ファジング
Snapchange は、生のメモリダンプとレジスタ状態を KVM 仮想マシン (VM) にロードして実行する機能を提供します。実行中の任意の時点で、この VM は、KVM によって検出されたダーティページ、またはファザーによって手動でダーティ化されたページをリセットすることにより、初期状態にリセットできます。
LibTIFFFFmpeg$ cp -r -L fuzzer_template your_new_fuzzer
your_new_fuzzer/create_snapshot.sh を変更して、ターゲットのスナップショットを取得するsrc/fuzzer.rs を更新して、変異したデータをゲスト VM に注入する#[derive(Default)]
pub struct TemplateFuzzer;
impl Fuzzer for TemplateFuzzer {
// The type of Input being fuzzed. Used to know how to generate and mutate useful inputs.
type Input = Vec<u8>;
// The starting address of the snapshot
const START_ADDRESS: u64 = 0x402363;
// The maximum length of mutated input to generate
const MAX_INPUT_LENGTH: usize = 100;
fn set_input(&mut self, input: &Self::Input, fuzzvm: &mut FuzzVm<Self>) -> Result<()> {
// Write the mutated input into the data buffer in the guest VM
fuzzvm.write_bytes_dirty(VirtAddr(0x402004), CR3, &input)?;
Ok(())
}
fn reset_breakpoints(&self) -> Option<&[BreakpointLookup]> {
Some(&[
// Reset when the VM hits example1!main+0x123
BreakpointLookup::SymbolOffset("example1!main", 0x123)
])
}
}
$ cargo run -r -- fuzz -c 16
この README で使用される用語の簡単な説明:
ハイパーバイザーは、要求された各コアの物理メモリファイルをマッピングすることから始まります。これにより、各コアは独自のメモリコピーを持つことになります。次に、ハイパーバイザーは KVM ゲストを作成し、このバッキングメモリをゲストに与えます。このゲストのレジスタ状態は、指定されたレジスタ状態で初期化され、ゲストの実行が開始されます。ハイパーバイザーは、ゲストが終了するまで待機します。各終了はハイパーバイザーによって処理され、一部はターゲット固有の変異、変更、またはイントロスペクションのためにファザーに渡されます。終了のハンドラーがゲストをリセットすべきであると示した場合、ハイパーバイザーは実行ループを終了し、ゲストを元のスナップショット状態にリセットして、実行ループを再度開始します。
ゲストのカバレッジは、カバレッジブレークポイントを使用して生成されます。ブレークポイントするアドレスのリストを含む別のファイルをハイパーバイザーに渡すことができます。これらのアドレスのいずれかがヒットした場合、そのアドレスはカバレッジデータベースに追加され、そのアドレスの命令が復元されます。これにより、ブレークポイントは再度トリガーされません。
Snapchange は、構成にターゲット固有のプロジェクトディレクトリを活用します。このディレクトリは、入力ファイルと出力ファイルおよびディレクトリが配置される場所です。次のファイル拡張子/ディレクトリが入力として使用されます:
.physmem - 生の物理メモリファイルを含むファイル.regs - レジスタ状態 を含む JSON レジスタファイル.qemuregs - qemu の info registers からの出力プロジェクトディレクトリ内のファイルとその用途の完全なリストは、ここ にあります。
デバッグ用シングルステップトレースの完全な例は、ここ にあります。
ITERATION 604 0x00007ffff7ecb0d5 0x11115000 | libc-2.31.so!__GI___getpid+0x5 (0x7ffff7ecb0d5)
syscall
[0f, 05]
ITERATION 605 0xffffffff83a00000 0x11115000 | entry_SYSCALL_64+0x0 (0xffffffff83a00000)
swapgs
[0f, 01, f8]
ITERATION 606 0xffffffff83a00003 0x11115000 | entry_SYSCALL_64+0x3 (0xffffffff83a00003)
mov qword ptr gs:[0xa014], rsp
[None:0x0+0xa014=0xa014]]
RSP:0x7fffffffeb78 -> example1!main+0x19 (0x55555555514e)-> 0xff8458b48f44589
[65, 48, 89, 24, 25, 14, a0, 00, 00]
ITERATION 607 0xffffffff83a0000c 0x11115000 | entry_SYSCALL_64+0xc (0xffffffff83a0000c)
nop
[66, 90]
ITERATION 608 0xffffffff83a0000e 0x11115000 | entry_SYSCALL_64+0xe (0xffffffff83a0000e)
mov rsp, cr3
RSP:0x7fffffffeb78 -> example1!main+0x19 (0x55555555514e) -> 0xff8458b48f44589
CR3:0x11115000
[0f, 20, dc]
VirtualBox または QEMU を介してスナップショットを取得する方法については、以下を参照してください:
例には、ゼロから完全なスナップショットを作成する make_example.sh (例 1 など) スクリプトが含まれています。これらの例は、再現可能なスナップショットのための他のターゲットのテンプレートとして使用できます。
make all
cargo doc --open
HACKING には、システムを理解し始めるためのコードベース内のいくつかの高レベルの場所が記載されています。
詳細については、CONTRIBUTING を参照してください。
このプロジェクトは Apache-2.0 License の下でライセンスされています。