[
  {
    "path": "README.md",
    "content": "# kernel-read-write-using-ioctl\nsimple driver to read and write to a process's memory using IOCTL as communication\n\ndriver can be mapped with kdmapper\n\nusermode example is auto bhop for csgo\n\nNOTE: disable security check when compiling driver if mapping with kdmapper\n\n![disable security check picture](https://github.com/beans42/kernel-read-write-using-ioctl/blob/master/security_check.png)\n"
  },
  {
    "path": "driver src/driver.cpp",
    "content": "#include <ntifs.h>\n\nextern \"C\" { //undocumented windows internal functions (exported by ntoskrnl)\n\tNTKERNELAPI NTSTATUS IoCreateDriver(PUNICODE_STRING DriverName, PDRIVER_INITIALIZE InitializationFunction);\n\tNTKERNELAPI NTSTATUS MmCopyVirtualMemory(PEPROCESS SourceProcess, PVOID SourceAddress, PEPROCESS TargetProcess, PVOID TargetAddress, SIZE_T BufferSize, KPROCESSOR_MODE PreviousMode, PSIZE_T ReturnSize);\n}\n\nconstexpr 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\nconstexpr ULONG read_code  = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x776, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for reading memory\nconstexpr ULONG write_code = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x777, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for writing memory\n\nstruct info_t { //message type that will be passed between user program and driver\n\tHANDLE target_pid = 0; //process id of process we want to read from / write to\n\tvoid*  target_address = 0x0; //address in the target proces we want to read from / write to\n\tvoid*  buffer_address = 0x0; //address in our usermode process to copy to (read mode) / read from (write mode)\n\tSIZE_T size = 0; //size of memory to copy between our usermode process and target process\n\tSIZE_T return_size = 0; //number of bytes successfully read / written\n};\n\nNTSTATUS ctl_io(PDEVICE_OBJECT device_obj, PIRP irp) {\n\tUNREFERENCED_PARAMETER(device_obj);\n\t\n\tstatic PEPROCESS s_target_process;\n\n\tirp->IoStatus.Information = sizeof(info_t);\n\tauto stack = IoGetCurrentIrpStackLocation(irp);\n\tauto buffer = (info_t*)irp->AssociatedIrp.SystemBuffer;\n\n\tif (stack) { //add error checking\n\t\tif (buffer && sizeof(*buffer) >= sizeof(info_t)) {\n\t\t\tconst auto ctl_code = stack->Parameters.DeviceIoControl.IoControlCode;\n\n\t\t\tif (ctl_code == init_code) //if control code is find process, find the target process by its id and put it into g_target_process\n\t\t\t\tPsLookupProcessByProcessId(buffer->target_pid, &s_target_process);\n\n\t\t\telse if (ctl_code == read_code) //if control code is read, copy target process memory to our process\n\t\t\t\tMmCopyVirtualMemory(s_target_process, buffer->target_address, PsGetCurrentProcess(), buffer->buffer_address, buffer->size, KernelMode, &buffer->return_size);\n\n\t\t\telse if (ctl_code == write_code) //if control code is write, copy our process memory to target process memory\n\t\t\t\tMmCopyVirtualMemory(PsGetCurrentProcess(), buffer->buffer_address, s_target_process, buffer->target_address, buffer->size, KernelMode, &buffer->return_size);\n\t\t}\n\t}\n\n\tIoCompleteRequest(irp, IO_NO_INCREMENT);\n\treturn STATUS_SUCCESS;\n}\n\nNTSTATUS unsupported_io(PDEVICE_OBJECT device_obj, PIRP irp) {\n\tUNREFERENCED_PARAMETER(device_obj);\n\t\n\tirp->IoStatus.Status = STATUS_NOT_SUPPORTED;\n\tIoCompleteRequest(irp, IO_NO_INCREMENT);\n\treturn irp->IoStatus.Status;\n}\n\nNTSTATUS create_io(PDEVICE_OBJECT device_obj, PIRP irp) {\n\tUNREFERENCED_PARAMETER(device_obj);\n\n\tIoCompleteRequest(irp, IO_NO_INCREMENT);\n\treturn irp->IoStatus.Status;\n}\n\nNTSTATUS close_io(PDEVICE_OBJECT device_obj, PIRP irp) {\n\tUNREFERENCED_PARAMETER(device_obj);\n\t\n\tIoCompleteRequest(irp, IO_NO_INCREMENT);\n\treturn irp->IoStatus.Status;\n}\n\nNTSTATUS real_main(PDRIVER_OBJECT driver_obj, PUNICODE_STRING registery_path) {\n\tUNREFERENCED_PARAMETER(registery_path);\n\t\n\tUNICODE_STRING dev_name, sym_link;\n\tPDEVICE_OBJECT dev_obj;\n\n\tRtlInitUnicodeString(&dev_name, L\"\\\\Device\\\\cartidriver\"); //die lit\n\tauto status = IoCreateDevice(driver_obj, 0, &dev_name, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &dev_obj);\n\tif (status != STATUS_SUCCESS) return status;\n\n\tRtlInitUnicodeString(&sym_link, L\"\\\\DosDevices\\\\cartidriver\");\n\tstatus = IoCreateSymbolicLink(&sym_link, &dev_name);\n\tif (status != STATUS_SUCCESS) return status;\n\n\tSetFlag(dev_obj->Flags, DO_BUFFERED_IO); //set DO_BUFFERED_IO bit to 1\n\n\tfor (int t = 0; t <= IRP_MJ_MAXIMUM_FUNCTION; t++) //set all MajorFunction's to unsupported\n\t\tdriver_obj->MajorFunction[t] = unsupported_io;\n\n\t//then set supported functions to appropriate handlers\n\tdriver_obj->MajorFunction[IRP_MJ_CREATE] = create_io; //link our io create function\n\tdriver_obj->MajorFunction[IRP_MJ_CLOSE] = close_io; //link our io close function\n\tdriver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ctl_io; //link our control code handler\n\tdriver_obj->DriverUnload = NULL; //add later\n\n\tClearFlag(dev_obj->Flags, DO_DEVICE_INITIALIZING); //set DO_DEVICE_INITIALIZING bit to 0 (we are done initializing)\n\treturn status;\n}\n\nextern \"C\" NTSTATUS DriverEntry(PDRIVER_OBJECT driver_obj, PUNICODE_STRING registery_path) {\n\tUNREFERENCED_PARAMETER(driver_obj);\n\tUNREFERENCED_PARAMETER(registery_path);\n\n\tUNICODE_STRING  drv_name;\n\tRtlInitUnicodeString(&drv_name, L\"\\\\Driver\\\\cartidriver\");\n\tIoCreateDriver(&drv_name, &real_main); //so it's kdmapper-able\n\n\treturn STATUS_SUCCESS;\n}\n"
  },
  {
    "path": "usermode example/driver.hpp",
    "content": "#pragma once\n#include <Windows.h>\n\nconstexpr 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\nconstexpr DWORD read_code  = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x776, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for reading memory\nconstexpr DWORD write_code = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x777, METHOD_BUFFERED, FILE_SPECIAL_ACCESS); //custom io control code for writing memory\n\nclass driver_manager {\n\tHANDLE m_driver_handle = nullptr; //handle to our driver\n\n    struct info_t { //message type that will be passed between user program and driver\n        UINT64 target_pid = 0; //process id of process we want to read from / write to\n        UINT64 target_address = 0x0; //address in the target proces we want to read from / write to\n        UINT64 buffer_address = 0x0; //address in our usermode process to copy to (read mode) / read from (write mode)\n        UINT64 size = 0; //size of memory to copy between our usermode process and target process\n        UINT64 return_size = 0; //number of bytes successfully read / written\n    };\n\npublic:\n    driver_manager(const char* driver_name, DWORD target_process_id) {\n\t\tm_driver_handle = CreateFileA(driver_name, GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); //get a handle to our driver\n        attach_to_process(target_process_id); //tell driver to find the process with this id and put it into g_target_process\n\t}\n\n    void attach_to_process(DWORD process_id) {\n        info_t io_info;\n        \n        io_info.target_pid = process_id;\n\n        DeviceIoControl(m_driver_handle, init_code, &io_info, sizeof(io_info), &io_info, sizeof(io_info), nullptr, nullptr);\n    }\n\n    template<typename T> T RPM(const UINT64 address) {\n        info_t io_info;\n        T read_data;\n\n        io_info.target_address = address;\n        io_info.buffer_address = (UINT64)&read_data;\n        io_info.size = sizeof(T);\n\n        DeviceIoControl(m_driver_handle, read_code, &io_info, sizeof(io_info), &io_info, sizeof(io_info), nullptr, nullptr);\n        if (io_info.return_size != sizeof(T))\n            throw 0xBEEF; //partial read\n        return read_data;\n    }\n\n    template<typename T> bool WPM(const UINT64 address, const T buffer) {\n        info_t io_info;\n\n        io_info.target_address = address;\n        io_info.buffer_address = (UINT64)&buffer;\n        io_info.size = sizeof(T);\n\n        DeviceIoControl(m_driver_handle, write_code, &io_info, sizeof(io_info), &io_info, sizeof(io_info), nullptr, nullptr);\n        return io_info.return_size == sizeof(T);\n    }\n};\n"
  },
  {
    "path": "usermode example/main.cpp",
    "content": "#include \"driver.hpp\"\n#include <TlHelp32.h>\n\nconstexpr uintptr_t dwLocalPlayer = 0xD2FB94;\nconstexpr uintptr_t dwForceJump = 0x51ED760;\nconstexpr uintptr_t m_fFlags = 0x104;\nconstexpr uintptr_t FL_ONGROUND = 1 << 0;\n\nauto get_module(const char* module_name, DWORD process_id) {\n\tHANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, process_id);\n\tif (hSnap != INVALID_HANDLE_VALUE) {\n\t\tMODULEENTRY32 modEntry;\n\t\tmodEntry.dwSize = sizeof(modEntry);\n\t\tif (Module32First(hSnap, &modEntry)) {\n\t\t\tdo {\n\t\t\t\tif (!strcmp(modEntry.szModule, module_name)) {\n\t\t\t\t\tCloseHandle(hSnap);\n\t\t\t\t\treturn modEntry;\n\t\t\t\t}\n\t\t\t} while (Module32Next(hSnap, &modEntry));\n\t\t}\n\t}\n}\n\nint main() {\n\tauto hwnd = FindWindowA(NULL, \"Counter-Strike: Global Offensive\");\n\tDWORD process_id; GetWindowThreadProcessId(hwnd, &process_id);\n\tauto client = get_module(\"client_panorama.dll\", process_id);\n\tauto client_base = (uintptr_t)client.modBaseAddr;\n\n\tauto driver = new driver_manager(\"\\\\\\\\.\\\\cartidriver\", process_id);\n\n\twhile (true) {\n\t\tauto local_player = driver->RPM<uintptr_t>(client_base + dwLocalPlayer);\n\t\tif (!local_player) continue;\n\t\tauto flags = driver->RPM<DWORD>(local_player + m_fFlags);\n\t\tif (flags & FL_ONGROUND)\n\t\t\tif (GetAsyncKeyState(VK_SPACE) >> 15)\n\t\t\t\tdriver->WPM<DWORD>(client_base + dwForceJump, 6);\n\t\tSleep(5);\n\t}\n}\n"
  }
]