From 7f2d987dada25a2875e755a816f57e17792fa9eb Mon Sep 17 00:00:00 2001 From: dajiaohuang Date: Tue, 20 Oct 2026 00:49:51 +0800 Subject: [PATCH] Fix replay tool output buffer sizing and usage instructions replay.cpp allocated a fixed 0x2000 byte output buffer, but each payload record's outbuffer_length is passed unmodified to DeviceIoControl as nOutBufferSize. The target harness (kafl.targets windows_x86_64) uses a 0x10000 byte output buffer, so replaying a record produced for an IOCTL that returns more than 8 KiB makes the kernel write past the replay buffer. Size the output buffer from the record's outbuffer_length instead, growing it only when a larger record is replayed, and zero the allocated region before each IOCTL. The documented build/run steps could not work either: replay.cpp uses CreateFileW/DeviceIoControl, i.e. it is a Windows binary, yet the guide compiled it with a placeholder command and ran ./replay on the Linux host, and referenced an undefined $kAFL variable. Build it with the MinGW-w64 C++ cross-compiler and run it inside the Windows guest. --- docs/installation/README.md | 16 +++++++++++----- docs/installation/replay.cpp | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/installation/README.md b/docs/installation/README.md index 9bf189e..64502dd 100644 --- a/docs/installation/README.md +++ b/docs/installation/README.md @@ -113,14 +113,20 @@ kafl gui -w work # 7. How to reproduce bugs ---------------------------------- -kAFL includes a replay utility to rerun a specific payload against your driver: +kAFL includes a replay utility to rerun a specific payload against your driver. +`replay.cpp` uses the Windows API (`CreateFileW`, `DeviceIoControl`), therefore it has to be +built as a Windows binary and executed inside the Windows guest, not on the Linux host: ```bash -# Build and run the replay tool -cd $kAFL/docs/installation -[you compiler] replay.cpp -o replay +# Install the MinGW-w64 C++ cross-compiler +sudo apt-get install g++-mingw-w64-x86-64 +# Build the replay tool on the host +cd ~/kAFL/docs/installation +x86_64-w64-mingw32-g++ replay.cpp -o replay.exe -static + +# Copy replay.exe into the guest, then run it there # Usage: -./replay +replay.exe ``` ![Fuzz Success](fuzzing.png?raw=true) diff --git a/docs/installation/replay.cpp b/docs/installation/replay.cpp index bb63094..ddc21d0 100644 --- a/docs/installation/replay.cpp +++ b/docs/installation/replay.cpp @@ -7,6 +7,7 @@ char* payload = NULL; char* output = NULL; +DWORD outputSize = 0; DWORD byteRead = NULL; uint32_t u32(unsigned char* data) { @@ -42,6 +43,11 @@ int wmain(int argc, wchar_t* argv[]) { payload = (char*)VirtualAlloc(NULL, ((dFileSize + 0x1000 - 1) / 0x1000) * 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); output = (char*)VirtualAlloc(NULL, BUF_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (payload == NULL || output == NULL) { + printf("Buffer alloc fail..\n"); + return 0; + } + outputSize = BUF_SIZE; if (!ReadFile(hFile, payload, (DWORD)fileSize.QuadPart, &byteRead, NULL) || byteRead != fileSize.QuadPart) { printf("File read fail..\n"); @@ -67,11 +73,21 @@ int wmain(int argc, wchar_t* argv[]) { char* input = &payload[start + 16]; + if (outbuffer_length > outputSize) { + VirtualFree(output, 0, MEM_RELEASE); + output = (char*)VirtualAlloc(NULL, outbuffer_length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (output == NULL) { + printf("Output buffer alloc fail..\n"); + return 0; + } + outputSize = outbuffer_length; + } + memset(output, 0, outputSize); + NTSTATUS res = DeviceIoControl(hDriver, ioctl_code, input, inbuffer_length, output, outbuffer_length, &byteRead, 0); printf("IOCTL: %lx, inputLen: %lx, outputLen: %lx success: %d\n", ioctl_code & 0xffffffff, inbuffer_length & 0xffffffff, outbuffer_length & 0xffffffff, res); start = start + inbuffer_length + 16; - memset(output, 0, BUF_SIZE); } system("pause");