{"id":13838478,"url":"https://github.com/awslabs/snapchange","last_synced_at":"2025-07-10T21:33:01.325Z","repository":{"id":163517825,"uuid":"636439179","full_name":"awslabs/snapchange","owner":"awslabs","description":"Lightweight fuzzing of a memory snapshot using KVM","archived":false,"fork":false,"pushed_at":"2024-04-11T13:05:34.000Z","size":881,"stargazers_count":436,"open_issues_count":2,"forks_count":27,"subscribers_count":12,"default_branch":"main","last_synced_at":"2024-08-05T15:07:41.440Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/awslabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-05-04T21:13:40.000Z","updated_at":"2024-07-16T09:16:22.000Z","dependencies_parsed_at":"2023-12-21T00:30:00.408Z","dependency_job_id":"f86e9963-6741-475f-a792-0161fe03763e","html_url":"https://github.com/awslabs/snapchange","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awslabs%2Fsnapchange","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awslabs%2Fsnapchange/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awslabs%2Fsnapchange/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awslabs%2Fsnapchange/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/awslabs","download_url":"https://codeload.github.com/awslabs/snapchange/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225657492,"owners_count":17503558,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T15:01:58.879Z","updated_at":"2024-11-21T01:31:07.322Z","avatar_url":"https://github.com/awslabs.png","language":"Rust","readme":"# Snapchange\n\nLightweight fuzzing of a memory snapshot using KVM\n\nSnapchange provides the ability to load a raw memory dump and register state into a\nKVM virtual machine (VM) for execution. At a point in execution, this VM can be reset to its initial\nstate by resetting the dirty pages found by KVM or pages manually dirtied by a\nfuzzer.\n\n## Quick Links:\n\n* [Cookbook](./docs/COOKBOOK.md) provides examples [fuzz](./docs/COOKBOOK.md#fuzz-commands), [trace](./docs/COOKBOOK.md#trace-commands), [coverage](./docs/COOKBOOK.md#coverage-commands), [minimize](./docs/COOKBOOK.md#minimize-commands), and [project](./docs/COOKBOOK.md#project-commands) command line utilities\n* [Taking a snapshot with QEMU](./qemu_snapshot/README.md)\n* [Architecture](./docs/ARCHITECTURE.md)\n* [Fuzzer Lifecycle](./docs/FUZZ_FUNCTION_LIFECYCLE.md)\n\n## Tutorials\n\n* [Tutorial 1 - Basic Usage](./examples/01_getpid/README.md)\n* [Tutorial 2 - `LibTIFF` with ASAN](./examples/02_libtiff/README.md)\n* [Tutorial 3 - `FFmpeg` with custom mutator](./examples/03_ffmpeg_custom_mutator/README.md)\n* [Tutorial 4 - Syscall fuzzer](./examples/04_syscall_fuzzer/README.md)\n* [Tutorial 5 - Redqueen](./examples/05_redqueen/README.md)\n\n# Aspirations\n\n* Replay a physical memory and register state snapshot using KVM\n* Parallel execution across multiple cores\n* Provide a set of introspection features to the guest VM\n* Real-time coverage state via breakpoint coverage\n* Real-time performance metrics of fuzzer components\n* Provide fuzzing utilities such as single-step debug tracing, testcase minimization, and testcase coverage\n* Input abstraction to allow custom mutation and generation strategies\n\n# Example:\n\n#### Create a target fuzzer from the fuzzer template\n\n```console\n$ cp -r -L fuzzer_template your_new_fuzzer\n```\n\n#### Modify `your_new_fuzzer/create_snapshot.sh` to take a snapshot of your target\n\n#### Update `src/fuzzer.rs` to inject mutated data into the guest VM\n\n```rust\n#[derive(Default)]\npub struct TemplateFuzzer;\n\nimpl Fuzzer for TemplateFuzzer {\n    // The type of Input being fuzzed. Used to know how to generate and mutate useful inputs.\n    type Input = Vec\u003cu8\u003e;\n    // The starting address of the snapshot\n    const START_ADDRESS: u64 = 0x402363;\n    // The maximum length of mutated input to generate\n    const MAX_INPUT_LENGTH: usize = 100;\n\n    fn set_input(\u0026mut self, input: \u0026Self::Input, fuzzvm: \u0026mut FuzzVm\u003cSelf\u003e) -\u003e Result\u003c()\u003e {\n        // Write the mutated input into the data buffer in the guest VM\n        fuzzvm.write_bytes_dirty(VirtAddr(0x402004), CR3, \u0026input)?;\n        Ok(())\n    }\n\n    fn reset_breakpoints(\u0026self) -\u003e Option\u003c\u0026[BreakpointLookup]\u003e {\n        Some(\u0026[\n            // Reset when the VM hits example1!main+0x123\n            BreakpointLookup::SymbolOffset(\"example1!main\", 0x123)\n        ])\n    }\n}\n```\n\n#### Start fuzzing with 16 cores\n\n```console\n$ cargo run -r -- fuzz -c 16\n```\n\n\n# Implementation\n\nQuick usage of terms for this README:\n\n* Hypervisor: The target agnostic code executing the snapshot in KVM\n* Fuzzer:     The target specific code used to modify and monitor the guest for a target\n              specific fuzz case\n\nThe hypervisor begins by mapping the physical memory file for each core requested. In\nthis way, each core has its own, unique copy of memory. The hypervisor then creates the\nKVM guest and gives the guest this backing memory. This guest's register state is then\ninitialized with the given register state and execution of the guest is launched. The\nhypervisor waits until the guest exits. Each exit is handled by the hyperisor and some\nare passed to the fuzzer for target specific mutation, modification, or introspection. If\nthe handler of the exit signifies that the guest should be reset, the hyperisor exits the\nrun loop and resets the guest back to the original snapshot state and restarts the run\nloop again.\n\nCoverage of the guest is generated by using coverage breakpoints.  A separate file with a \nlist of addresses to breakpoint can be given to the hypervisor. If any of these addresses \nare hit, the address will be added to the coverage database and the instruction for that \naddress will be restored. In this way, the breakpoint will not be triggered again.\n\n# Project directory\n\nSnapchange leverages target specific project directories for configuration. This directory\nis where input and output files and directories are placed. The following file\nextensions/directories are used as inputs:\n\n* `.physmem`    - The file containing the raw, physical memory file\n* Register file (one of the following)\n    - `.regs` - JSON register file containing the [register state](./docs/REGISTER.md)\n    - `.qemuregs` - Output from `info registers` from `qemu`\n\nThe full list of files and their uses in the project directory can be found [here](./docs/PROJECT_DIRECTORY.md)\n\n# Debugging Trace\n\nA full example of the debugging single-step trace can be found [here](./docs/DEBUG_TRACE.md).\n\n```\nITERATION 604 0x00007ffff7ecb0d5 0x11115000 | libc-2.31.so!__GI___getpid+0x5 (0x7ffff7ecb0d5)              \n    syscall \n    [0f, 05]\nITERATION 605 0xffffffff83a00000 0x11115000 | entry_SYSCALL_64+0x0 (0xffffffff83a00000)                    \n    swapgs \n    [0f, 01, f8]\nITERATION 606 0xffffffff83a00003 0x11115000 | entry_SYSCALL_64+0x3 (0xffffffff83a00003)                    \n    mov qword ptr gs:[0xa014], rsp \n    [None:0x0+0xa014=0xa014]] \n    RSP:0x7fffffffeb78 -\u003e \u001bexample1!main+0x19 (0x55555555514e)\u001b-\u003e 0xff8458b48f44589\n    [65, 48, 89, 24, 25, 14, a0, 00, 00]\nITERATION 607 0xffffffff83a0000c 0x11115000 | entry_SYSCALL_64+0xc (0xffffffff83a0000c)                    \n    nop \n    [66, 90]\nITERATION 608 0xffffffff83a0000e 0x11115000 | entry_SYSCALL_64+0xe (0xffffffff83a0000e)                    \n    mov rsp, cr3 \n    RSP:0x7fffffffeb78 -\u003e example1!main+0x19 (0x55555555514e) -\u003e 0xff8458b48f44589\n    CR3:0x11115000\n    [0f, 20, dc]\n```\n\n# Snapshots\n\nInformation about obtaining a snapshot via `VirtualBox` or `QEMU` are below:\n\n* [VirtualBox](./docs/VIRTUALBOX_SNAPSHOT.md)\n* [QEMU](./qemu_snapshot/README.md)\n\nThe examples include a `make_example.sh` (like [example 1](./examples/01_getpid/make_example.sh)) script which goes a full snapshot from scratch. These\nexamples can be used as a template for other targets for reproducible snapshots.\n\n# Documentation and clippy\n\n```\nmake all\ncargo doc --open\n```\n\n# Where to begin reading?\n\nThe [HACKING](./HACKING.md) provides a few higher level locations in the code base to start\nunderstanding the system.\n\n## Security\n\nSee [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.\n\n## License\n\nThis project is licensed under the Apache-2.0 License.\n","funding_links":[],"categories":["Rust","Application Security"],"sub_categories":["API Fuzzing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawslabs%2Fsnapchange","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fawslabs%2Fsnapchange","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawslabs%2Fsnapchange/lists"}