diff --git a/examples/ZydisWinKernel.c b/examples/ZydisWinKernel.c new file mode 100644 index 0000000..6c0e2b2 --- /dev/null +++ b/examples/ZydisWinKernel.c @@ -0,0 +1,185 @@ +/*************************************************************************************************** + + Zyan Disassembler Engine (Zydis) + + Original Author : Matthijs Lavrijsen + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + +***************************************************************************************************/ + +/** + * @file + * @brief Windows kernel mode driver sample. + * + * This is a Windows kernel mode driver. It links against the kernel mode-compatible version of Zydis. + * The driver finds its own entry point and decodes and prints the disassembly of this function. + * To view the log, either attach a kernel debugger or use a tool like Sysinternals DebugView. + */ + +#include +#include +#include +#include +#include "Zydis/Zydis.h" + +/* ============================================================================================== */ +/* Forward declarations */ +/* ============================================================================================== */ + +NTKERNELAPI +PVOID +NTAPI +RtlPcToFileHeader( + _In_ PVOID PcValue, + _Out_ PVOID *BaseOfImage + ); + +NTKERNELAPI +PIMAGE_NT_HEADERS +NTAPI +RtlImageNtHeader( + _In_ PVOID ImageBase + ); + +DRIVER_INITIALIZE +DriverEntry; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#endif + +/* ============================================================================================== */ +/* Helper functions */ +/* ============================================================================================== */ + +VOID +Print( + _In_ PCCH Format, + _In_ ... + ) +{ + CHAR message[512]; + va_list argList; + va_start(argList, Format); + const int n = _vsnprintf_s(message, sizeof(message), sizeof(message) - 1, Format, argList); + message[n] = '\0'; + vDbgPrintExWithPrefix("[ZYDIS] ", DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, message, argList); + va_end(argList); +} + +/* ============================================================================================== */ +/* Entry point */ +/* ============================================================================================== */ + +_Use_decl_annotations_ +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(RegistryPath); + + if (ZydisGetVersion() != ZYDIS_VERSION) + { + Print("Invalid zydis version\n"); + return STATUS_UNKNOWN_REVISION; + } + + // Get the driver's image base and PE headers + ULONG_PTR imageBase; + RtlPcToFileHeader((PVOID)DriverObject->DriverInit, (PVOID*)&imageBase); + if (imageBase == 0) + return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; + PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader((PVOID)imageBase); + if (imageBase == 0) + return STATUS_INVALID_IMAGE_FORMAT; + + // Get the section headers of the INIT section + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders); + PIMAGE_SECTION_HEADER initSection = NULL; + for (ULONG i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i) + { + if (memcmp(section->Name, "INIT", sizeof("INIT") - 1) == 0) + { + initSection = section; + break; + } + section++; + } + if (initSection == NULL) + return STATUS_NOT_FOUND; + + // Get the RVAs of the entry point and import directory. If the import directory lies within the INIT section, + // stop disassembling when its address is reached. Otherwise, disassemble until the end of the INIT section. + const ULONG entryPointRva = (ULONG)((ULONG_PTR)DriverObject->DriverInit - imageBase); + const ULONG importDirRva = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + SIZE_T length = initSection->VirtualAddress + initSection->SizeOfRawData - entryPointRva; + if (importDirRva > entryPointRva && importDirRva > initSection->VirtualAddress && + importDirRva < initSection->VirtualAddress + initSection->SizeOfRawData) + length = importDirRva - entryPointRva; + + Print("Driver image base: 0x%p, size: 0x%X\n", imageBase, ntHeaders->OptionalHeader.SizeOfImage); + Print("Entry point RVA: 0x%X (0x%p)\n", entryPointRva, DriverObject->DriverInit); + + // Initialize Zydis decoder and formatter + ZydisDecoder decoder; +#ifdef _M_AMD64 + if (!ZYDIS_SUCCESS(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64))) +#else + if (!ZYDIS_SUCCESS(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_COMPAT_32, ZYDIS_ADDRESS_WIDTH_32))) +#endif + return STATUS_DRIVER_INTERNAL_ERROR; + + ZydisFormatter formatter; + if (!ZYDIS_SUCCESS(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL))) + return STATUS_DRIVER_INTERNAL_ERROR; + + SIZE_T readOffset = 0; + ZydisDecodedInstruction instruction; + ZydisStatus status; + CHAR printBuffer[128]; + + // Start the decode loop + while ((status = ZydisDecoderDecodeBuffer(&decoder, (PVOID)(imageBase + entryPointRva + readOffset), + length - readOffset, (ULONG_PTR)(imageBase + entryPointRva + readOffset), &instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + NT_ASSERT(ZYDIS_SUCCESS(status)); + if (!ZYDIS_SUCCESS(status)) + { + readOffset++; + continue; + } + + // Format and print the instruction + ZydisFormatterFormatInstruction( + &formatter, &instruction, printBuffer, sizeof(printBuffer)); + Print("+%-4X 0x%-16llX\t\t%s\n", readOffset, instruction.instrAddress, printBuffer); + + readOffset += instruction.length; + } + + // Return an error status so that the driver does not have to be unloaded after running. + return STATUS_UNSUCCESSFUL; +} + +/* ============================================================================================== */