
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 게스트를 생성하고 이 백킹 메모리를 게스트에 제공합니다. 이 게스트의 레지스터 상태는 그런 다음 주어진 레지스터 상태로 초기화되고 게스트 실행이 시작됩니다. 하이퍼바이저는 게스트가 종료(exit)할 때까지 대기합니다. 각 종료는 하이퍼바이저가 처리하며 일부는 대상별 변형, 수정 또는 인트로스펙션을 위해 퍼저에 전달됩니다. 종료 핸들러가 게스트를 리셋해야 한다고 표시하면 하이퍼바이저는 실행 루프를 종료하고 게스트를 원래 스냅샷 상태로 되돌린 다음 실행 루프를 다시 시작합니다.
게스트의 커버리지는 커버리지 브레이크포인트를 사용하여 생성됩니다. 브레이크포인트를 지정할 주소 목록이 포함된 별도의 파일을 하이퍼바이저에 제공할 수 있습니다. 이 주소들 중 하나라도 적중되면 그 주소가 커버리지 데이터베이스에 추가되고 해당 주소의 명령어가 복원됩니다. 이렇게 하면 브레이크포인트가 다시 트리거되지 않습니다.
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 라이선스에 따라 라이선스가 부여됩니다.