2025-02-14 17:39:30 +00:00

264 lines
6.7 KiB
C

#include <ntifs.h>
#include <minwindef.h>
#include "Undocumented.h"
#define DRIVER_NAME "miieow"
static UNICODE_STRING DriverName;
static UNICODE_STRING DeviceName;
static UNICODE_STRING SymbolicLink;
NTSTATUS
MwCreate(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp);
NTSTATUS
MwClose(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp);
NTSTATUS
MwCtl(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp);
#define MwCtlReadProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#define MwCtlWriteProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#define MwCtlProtectProcessMemory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#define MwCtlGetModuleInfo CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
struct MwVmRequest
{
_In_ DWORD ProcessId;
_In_ PVOID Src;
_In_ SIZE_T Size;
_Out_ PVOID Dst;
};
struct MwVpRequest
{
_In_ DWORD ProcessId;
_In_ PVOID Address;
_In_ ULONG NewProt;
_In_ SIZE_T Size;
_Out_ ULONG* pOldProt;
};
struct MwMiRequest
{
_In_ DWORD ProcessId;
_In_ WCHAR Module[256];
_Out_ PVOID BaseAddr;
_Out_ ULONG Size;
};
NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT pDriverObject, _In_ PUNICODE_STRING pRegistryPath)
{
UNREFERENCED_PARAMETER(pRegistryPath);
NTSTATUS Status = STATUS_SUCCESS;
RtlInitUnicodeString(&DriverName, L"\\Driver\\" DRIVER_NAME);
RtlInitUnicodeString(&DeviceName, L"\\Device\\" DRIVER_NAME);
RtlInitUnicodeString(&SymbolicLink, L"\\DosDevices\\" DRIVER_NAME);
if (pDriverObject == NULL)
{
return IoCreateDriver(&DriverName, &DriverEntry);
}
PDEVICE_OBJECT pDeviceObject = NULL;
Status = IoCreateDevice(pDriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
if (Status != STATUS_SUCCESS)
{
return Status;
}
Status = IoCreateSymbolicLink(&SymbolicLink, &DeviceName);
if (Status != STATUS_SUCCESS)
{
return Status;
}
SetFlag(pDeviceObject->Flags, DO_BUFFERED_IO);
pDriverObject->MajorFunction[IRP_MJ_CREATE] = MwCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = MwClose;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MwCtl;
ClearFlag(pDeviceObject->Flags, DO_DEVICE_INITIALIZING);
return Status;
}
NTSTATUS
MwCopyVirtualMemory(_In_ PEPROCESS pSourceProcess, _In_ PVOID SourceAddress, _In_ PEPROCESS pDestinationProcess, _In_ PVOID DestinationAddress, _In_ SIZE_T Size)
{
NTSTATUS Status;
SIZE_T ReturnSize;
Status = MmCopyVirtualMemory(pSourceProcess, SourceAddress, pDestinationProcess, DestinationAddress, Size, KernelMode, &ReturnSize);
return Status;
}
NTSTATUS
MwCreate(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp)
{
UNREFERENCED_PARAMETER(pDeviceObject);
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return pIrp->IoStatus.Status;
}
NTSTATUS
MwClose(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp)
{
UNREFERENCED_PARAMETER(pDeviceObject);
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return pIrp->IoStatus.Status;
}
NTSTATUS
MwCtl(_In_ PDEVICE_OBJECT pDeviceObject, _In_ PIRP pIrp)
{
UNREFERENCED_PARAMETER(pDeviceObject);
UNREFERENCED_PARAMETER(pIrp);
NTSTATUS Status = STATUS_SUCCESS;
PEPROCESS pTargetProcess = NULL;
pIrp->IoStatus.Information = 0;
PIO_STACK_LOCATION pStackIrp = IoGetCurrentIrpStackLocation(pIrp);
if (pStackIrp == NULL || pIrp->AssociatedIrp.SystemBuffer == NULL)
{
Status = STATUS_UNSUCCESSFUL;
goto Cleanup;
}
const ULONG ControlCode = pStackIrp->Parameters.DeviceIoControl.IoControlCode;
switch (ControlCode)
{
case MwCtlReadProcessMemory:
{
struct MwVmRequest *Request = (struct MwVmRequest *)pIrp->AssociatedIrp.SystemBuffer;
Status = PsLookupProcessByProcessId((HANDLE)Request->ProcessId, &pTargetProcess);
if (Status != STATUS_SUCCESS)
{
goto Cleanup;
}
Status = MwCopyVirtualMemory(pTargetProcess, Request->Src, PsGetCurrentProcess(), Request->Dst, Request->Size);
if (Status != STATUS_SUCCESS)
{
goto Cleanup;
}
pIrp->IoStatus.Information = sizeof(struct MwVmRequest);
break;
}
case MwCtlWriteProcessMemory:
{
struct MwVmRequest* Request = (struct MwVmRequest*)pIrp->AssociatedIrp.SystemBuffer;
Status = PsLookupProcessByProcessId((HANDLE)Request->ProcessId, &pTargetProcess);
if (Status != STATUS_SUCCESS)
{
goto Cleanup;
}
Status = MwCopyVirtualMemory(PsGetCurrentProcess(), Request->Src, pTargetProcess, Request->Dst, Request->Size);
if (Status != STATUS_SUCCESS)
{
goto Cleanup;
}
pIrp->IoStatus.Information = sizeof(struct MwVmRequest);
break;
}
case MwCtlProtectProcessMemory:
{
struct MwVpRequest* Request = (struct MwVpRequest*)pIrp->AssociatedIrp.SystemBuffer;
Status = PsLookupProcessByProcessId((HANDLE)Request->ProcessId, &pTargetProcess);
if (Status != STATUS_SUCCESS)
{
goto Cleanup;
}
// Locals used in usermode address space scope must be stack relative
// due to cr3 being modified. However, the stack is still paged in and
// other normal registers are preserved
PVOID Address = Request->Address;
SIZE_T Size = Request->Size;
ULONG NewProt = Request->NewProt;
ULONG OldProt;
KAPC_STATE state = { 0 };
KeStackAttachProcess(pTargetProcess, &state);
{
Status = ZwProtectVirtualMemory(ZwCurrentProcess(), &Address, &Size, NewProt, &OldProt);
}
KeUnstackDetachProcess(&state);
*Request->pOldProt = OldProt;
pIrp->IoStatus.Information = sizeof(struct MwVpRequest);
break;
}
case MwCtlGetModuleInfo:
{
struct MwMiRequest* pRequest = (struct MwMiRequest*)pIrp->AssociatedIrp.SystemBuffer;
Status = PsLookupProcessByProcessId((HANDLE)pRequest->ProcessId, &pTargetProcess);
if (Status != STATUS_SUCCESS)
{
goto Cleanup;
}
PEB* pPeb = PsGetProcessPeb(pTargetProcess);
UNICODE_STRING TargetModule;
RtlInitUnicodeString(&TargetModule, pRequest->Module);
PVOID ModuleBase = NULL;
ULONG ModuleSize = 0;
{
KAPC_STATE State;
KeStackAttachProcess(pTargetProcess, &State);
{
for (PLIST_ENTRY entry = pPeb->Ldr->InLoadOrderModuleList.Flink; entry != &pPeb->Ldr->InLoadOrderModuleList; entry = entry->Flink)
{
PLDR_DATA_TABLE_ENTRY _entry = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if (RtlCompareUnicodeString(&TargetModule, &_entry->BaseDllName, TRUE) == 0)
{
ModuleBase = _entry->DllBase;
ModuleSize = _entry->SizeOfImage;
}
}
}
KeUnstackDetachProcess(&State);
}
pRequest->BaseAddr = ModuleBase;
pRequest->Size = ModuleSize;
pIrp->IoStatus.Information = sizeof(struct MwMiRequest);
break;
}
default:
{
Status = STATUS_UNSUCCESSFUL;
pIrp->IoStatus.Information = 0;
break;
}
}
Cleanup:
if (pTargetProcess != NULL) ObDereferenceObject(pTargetProcess);
pIrp->IoStatus.Status = Status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return Status;
}