Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for full linux memory dumps (fix #219) #225

Merged
merged 5 commits into from
Feb 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions linux_mode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,23 @@ The second tab will detect once the first tab has finished executing the `cpu` c
Once the second tab indicates that snapshotting is complete, the target VM can be terminated.

```console
In the Qemu tab, press Ctrl+C, run the `cpu` command
Detected cpu registers dumped to regs.json
In the QEMU tab, press Ctrl+C, run the `cpu` command
Detected cpu registers dumped to 'regs.json'
Connecting to Qemu monitor at localhost:55555
Connected
Instructing Qemu to dump physical memory to file raw
Instructing Qemu to dump physical memory into 'mem.elf'
Done
Converting elf file 'mem.elf' to raw file 'raw'
The current binary doesn't have a section header
The current binary doesn't have a section header
Done
Converting raw file raw to dump file /wtf/targets/linux_crash_test/state/mem.dmp
Converting raw file 'raw' to dump file '/wtf/targets/linux_crash_test/state/mem.dmp'
Done
mv regs.json /wtf/targets/linux_crash_test/state/regs.json
mv symbol-store.json /wtf/targets/linux_crash_test/state/symbol-store.json
mv 'regs.json' '/wtf/targets/linux_crash_test/state/regs.json'
mv 'symbol-store.json' '/wtf/targets/linux_crash_test/state/symbol-store.json'
Snapshotting complete

Breakpoint 1, 0x0000555555555189 in do_crash_test ()
Breakpoint 1, 0x00005555555551e9 in do_crash_test ()
(gdb)
```

Expand All @@ -177,7 +181,7 @@ user@pc:/wtf/targets/linux_crash_test$ ../../src/build/wtf master --name linux_c
Run the fuzzee and note that crashes are found quickly.

```console
user@pc:/wtf/targets/linux_crash_test$ ../../src/build/wtf fuzz --backend=bochscpu --name linux_crash_test
user@pc:/wtf/targets/linux_crash_test$ ../../src/build/wtf fuzz --name linux_crash_test
Setting @fptw to 0xff'ff.
The debugger instance is loaded with 16 items
Setting debug register status to zero.
Expand Down
49 changes: 48 additions & 1 deletion linux_mode/qemu_snapshot/gdb_fuzzbkpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import struct
import subprocess
import pathlib
import lief

currentdir = pathlib.Path(inspect.getfile(inspect.currentframe()))
currentdir = currentdir.absolute().parent
Expand All @@ -26,6 +27,7 @@
pwn.context.arch = "amd64"

SYMSTORE_FILENAME = pathlib.Path("symbol-store.json")
ELF_FILENAME = pathlib.Path("mem.elf")
RAW_FILENAME = pathlib.Path("raw")
DMP_FILENAME = pathlib.Path("mem.dmp")
REGS_JSON_FILENAME = pathlib.Path("regs.json")
Expand All @@ -43,6 +45,37 @@ class dump_file:
BMP_EXPECTED_SIGNATURE = b"SDMP"
BMP_EXPECTED_VALID_DUMP = b"DUMP"

def convert_elf_to_raw():
print(f"Converting elf file '{ELF_FILENAME}' to raw file '{RAW_FILENAME}'")

core = lief.parse(ELF_FILENAME)

def is_load_segment(s):
return s.type == lief.ELF.Segment.TYPE.LOAD

segments = filter(is_load_segment, core.segments)

elf_file = ELF_FILENAME.open("rb")
raw_file = RAW_FILENAME.open("wb")

pos = 0
for s in segments:
pad_len = s.physical_address - pos
for _ in range(pad_len // dump_file.PAGE_SIZE):
raw_file.write(b"\0" * dump_file.PAGE_SIZE)
pos += dump_file.PAGE_SIZE

elf_file.seek(s.file_offset)
for _ in range(s.physical_size // dump_file.PAGE_SIZE):
raw_file.write(elf_file.read(dump_file.PAGE_SIZE))
pos += dump_file.PAGE_SIZE

elf_file.close()
raw_file.close()

ELF_FILENAME.unlink()
print("Done")

def convert_raw_to_dmp(out_filename: pathlib.Path):
dump_size = RAW_FILENAME.stat().st_size
pages_count = int(dump_size / dump_file.PAGE_SIZE)
Expand Down Expand Up @@ -147,6 +180,19 @@ def write_phys_mem_file_to_disk():
qemu_monitor.wait_ready(s)
print("Done")

def dump_guest_memory():
print(
f"Connecting to Qemu monitor at {qemu_monitor.HOSTNAME}:{qemu_monitor.PORT}"
)
s = qemu_monitor.setup_sock()
print("Connected")
qemu_monitor.wait_ready(s)

print(f"Instructing Qemu to dump physical memory into '{ELF_FILENAME}'")
s.send(f"dump-guest-memory {ELF_FILENAME}\n".encode())
qemu_monitor.wait_ready(s)
print("Done")


class kernel:
@staticmethod
Expand Down Expand Up @@ -325,7 +371,8 @@ def wait_for_cpu_regs_dump():

wait_for_cpu_regs_dump()

qemu_monitor.write_phys_mem_file_to_disk()
qemu_monitor.dump_guest_memory()
dump_file.convert_elf_to_raw()

out_filename = self.target_dir / "state" / DMP_FILENAME
dump_file.convert_raw_to_dmp(out_filename)
Expand Down
2 changes: 1 addition & 1 deletion linux_mode/qemu_snapshot/target_vm/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ download_prereqs() {

sudo apt-get install -y libglib2.0-dev libpixman-1-dev python3-pip cmake

pip3 install pwntools
pip3 install pwntools lief

# If there isn't a bookworm script for debootstrap (like in Ubuntu 18.04), copy
# over the bullseye script as it is the same
Expand Down