Repository: beans42/kernel-read-write-using-ioctl Branch: master Commit: 4da9c51f4c46 Files: 4 Total size: 9.1 KB Directory structure: gitextract__zrcyrgw/ ├── README.md ├── driver src/ │ └── driver.cpp └── usermode example/ ├── driver.hpp └── main.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # kernel-read-write-using-ioctl simple driver to read and write to a process's memory using IOCTL as communication driver can be mapped with kdmapper usermode example is auto bhop for csgo NOTE: disable security check when compiling driver if mapping with kdmapper ![disable security check picture](https://github.com/beans42/kernel-read-write-using-ioctl/blob/master/security_check.png) ================================================ FILE: driver src/driver.cpp ================================================ #include extern "C" { //undocumented windows internal functions (exported by ntoskrnl) NTKERNELAPI NTSTATUS IoCreateDriver(PUNICODE_STRING DriverName, PDRIVER_INITIALIZE InitializationFunction); NTKERNELAPI NTSTATUS MmCopyVirtualMemory(PEPROCESS SourceProcess, PVOID SourceAddress, PEPROCESS TargetProcess, PVOID TargetAddress, SIZE_T BufferSize, KPROCESSOR_MODE PreviousMode, PSIZE_T ReturnSize); } constexpr ULONG init_code = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x775, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for setting g_target_process by target process id constexpr ULONG read_code = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x776, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for reading memory constexpr ULONG write_code = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x777, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for writing memory struct info_t { //message type that will be passed between user program and driver HANDLE target_pid = 0; //process id of process we want to read from / write to void* target_address = 0x0; //address in the target proces we want to read from / write to void* buffer_address = 0x0; //address in our usermode process to copy to (read mode) / read from (write mode) SIZE_T size = 0; //size of memory to copy between our usermode process and target process SIZE_T return_size = 0; //number of bytes successfully read / written }; NTSTATUS ctl_io(PDEVICE_OBJECT device_obj, PIRP irp) { UNREFERENCED_PARAMETER(device_obj); static PEPROCESS s_target_process; irp->IoStatus.Information = sizeof(info_t); auto stack = IoGetCurrentIrpStackLocation(irp); auto buffer = (info_t*)irp->AssociatedIrp.SystemBuffer; if (stack) { //add error checking if (buffer && sizeof(*buffer) >= sizeof(info_t)) { const auto ctl_code = stack->Parameters.DeviceIoControl.IoControlCode; if (ctl_code == init_code) //if control code is find process, find the target process by its id and put it into g_target_process PsLookupProcessByProcessId(buffer->target_pid, &s_target_process); else if (ctl_code == read_code) //if control code is read, copy target process memory to our process MmCopyVirtualMemory(s_target_process, buffer->target_address, PsGetCurrentProcess(), buffer->buffer_address, buffer->size, KernelMode, &buffer->return_size); else if (ctl_code == write_code) //if control code is write, copy our process memory to target process memory MmCopyVirtualMemory(PsGetCurrentProcess(), buffer->buffer_address, s_target_process, buffer->target_address, buffer->size, KernelMode, &buffer->return_size); } } IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } NTSTATUS unsupported_io(PDEVICE_OBJECT device_obj, PIRP irp) { UNREFERENCED_PARAMETER(device_obj); irp->IoStatus.Status = STATUS_NOT_SUPPORTED; IoCompleteRequest(irp, IO_NO_INCREMENT); return irp->IoStatus.Status; } NTSTATUS create_io(PDEVICE_OBJECT device_obj, PIRP irp) { UNREFERENCED_PARAMETER(device_obj); IoCompleteRequest(irp, IO_NO_INCREMENT); return irp->IoStatus.Status; } NTSTATUS close_io(PDEVICE_OBJECT device_obj, PIRP irp) { UNREFERENCED_PARAMETER(device_obj); IoCompleteRequest(irp, IO_NO_INCREMENT); return irp->IoStatus.Status; } NTSTATUS real_main(PDRIVER_OBJECT driver_obj, PUNICODE_STRING registery_path) { UNREFERENCED_PARAMETER(registery_path); UNICODE_STRING dev_name, sym_link; PDEVICE_OBJECT dev_obj; RtlInitUnicodeString(&dev_name, L"\\Device\\cartidriver"); //die lit auto status = IoCreateDevice(driver_obj, 0, &dev_name, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &dev_obj); if (status != STATUS_SUCCESS) return status; RtlInitUnicodeString(&sym_link, L"\\DosDevices\\cartidriver"); status = IoCreateSymbolicLink(&sym_link, &dev_name); if (status != STATUS_SUCCESS) return status; SetFlag(dev_obj->Flags, DO_BUFFERED_IO); //set DO_BUFFERED_IO bit to 1 for (int t = 0; t <= IRP_MJ_MAXIMUM_FUNCTION; t++) //set all MajorFunction's to unsupported driver_obj->MajorFunction[t] = unsupported_io; //then set supported functions to appropriate handlers driver_obj->MajorFunction[IRP_MJ_CREATE] = create_io; //link our io create function driver_obj->MajorFunction[IRP_MJ_CLOSE] = close_io; //link our io close function driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ctl_io; //link our control code handler driver_obj->DriverUnload = NULL; //add later ClearFlag(dev_obj->Flags, DO_DEVICE_INITIALIZING); //set DO_DEVICE_INITIALIZING bit to 0 (we are done initializing) return status; } extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT driver_obj, PUNICODE_STRING registery_path) { UNREFERENCED_PARAMETER(driver_obj); UNREFERENCED_PARAMETER(registery_path); UNICODE_STRING drv_name; RtlInitUnicodeString(&drv_name, L"\\Driver\\cartidriver"); IoCreateDriver(&drv_name, &real_main); //so it's kdmapper-able return STATUS_SUCCESS; } ================================================ FILE: usermode example/driver.hpp ================================================ #pragma once #include constexpr DWORD init_code = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x775, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for setting g_target_process by target process id constexpr DWORD read_code = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x776, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for reading memory constexpr DWORD write_code = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x777, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for writing memory class driver_manager { HANDLE m_driver_handle = nullptr; //handle to our driver struct info_t { //message type that will be passed between user program and driver UINT64 target_pid = 0; //process id of process we want to read from / write to UINT64 target_address = 0x0; //address in the target proces we want to read from / write to UINT64 buffer_address = 0x0; //address in our usermode process to copy to (read mode) / read from (write mode) UINT64 size = 0; //size of memory to copy between our usermode process and target process UINT64 return_size = 0; //number of bytes successfully read / written }; public: driver_manager(const char* driver_name, DWORD target_process_id) { m_driver_handle = CreateFileA(driver_name, GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); //get a handle to our driver attach_to_process(target_process_id); //tell driver to find the process with this id and put it into g_target_process } void attach_to_process(DWORD process_id) { info_t io_info; io_info.target_pid = process_id; DeviceIoControl(m_driver_handle, init_code, &io_info, sizeof(io_info), &io_info, sizeof(io_info), nullptr, nullptr); } template T RPM(const UINT64 address) { info_t io_info; T read_data; io_info.target_address = address; io_info.buffer_address = (UINT64)&read_data; io_info.size = sizeof(T); DeviceIoControl(m_driver_handle, read_code, &io_info, sizeof(io_info), &io_info, sizeof(io_info), nullptr, nullptr); if (io_info.return_size != sizeof(T)) throw 0xBEEF; //partial read return read_data; } template bool WPM(const UINT64 address, const T buffer) { info_t io_info; io_info.target_address = address; io_info.buffer_address = (UINT64)&buffer; io_info.size = sizeof(T); DeviceIoControl(m_driver_handle, write_code, &io_info, sizeof(io_info), &io_info, sizeof(io_info), nullptr, nullptr); return io_info.return_size == sizeof(T); } }; ================================================ FILE: usermode example/main.cpp ================================================ #include "driver.hpp" #include constexpr uintptr_t dwLocalPlayer = 0xD2FB94; constexpr uintptr_t dwForceJump = 0x51ED760; constexpr uintptr_t m_fFlags = 0x104; constexpr uintptr_t FL_ONGROUND = 1 << 0; auto get_module(const char* module_name, DWORD process_id) { HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, process_id); if (hSnap != INVALID_HANDLE_VALUE) { MODULEENTRY32 modEntry; modEntry.dwSize = sizeof(modEntry); if (Module32First(hSnap, &modEntry)) { do { if (!strcmp(modEntry.szModule, module_name)) { CloseHandle(hSnap); return modEntry; } } while (Module32Next(hSnap, &modEntry)); } } } int main() { auto hwnd = FindWindowA(NULL, "Counter-Strike: Global Offensive"); DWORD process_id; GetWindowThreadProcessId(hwnd, &process_id); auto client = get_module("client_panorama.dll", process_id); auto client_base = (uintptr_t)client.modBaseAddr; auto driver = new driver_manager("\\\\.\\cartidriver", process_id); while (true) { auto local_player = driver->RPM(client_base + dwLocalPlayer); if (!local_player) continue; auto flags = driver->RPM(local_player + m_fFlags); if (flags & FL_ONGROUND) if (GetAsyncKeyState(VK_SPACE) >> 15) driver->WPM(client_base + dwForceJump, 6); Sleep(5); } }