Skip to content

Commit

Permalink
Fixed issues pointed out by namazso
Browse files Browse the repository at this point in the history
(https://www.unknowncheats.me/forum/2369780-post10.html)

- DeviceObject no longer leaked
- Unload was added (Still unsure about this)
- EPROCESS are no longer leaked
- Buffers size from userspace are validated
- Dereferenced pointers from userspace are sanitized
  • Loading branch information
EquiFox committed Feb 16, 2019
1 parent 0d63a2f commit 7c7d8a4
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 66 deletions.
80 changes: 54 additions & 26 deletions KsDumperDriver/Driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,65 @@ NTSTATUS CopyVirtualMemory(PEPROCESS targetProcess, PVOID sourceAddress, PVOID t

NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status;
ULONG BytesIO = 0;
NTSTATUS status;
ULONG bytesIO = 0;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG ControlCode = stack->Parameters.DeviceIoControl.IoControlCode;
ULONG controlCode = stack->Parameters.DeviceIoControl.IoControlCode;

if (ControlCode == IO_COPY_MEMORY)
if (controlCode == IO_COPY_MEMORY)
{
PKERNEL_COPY_MEMORY_OPERATION request = (PKERNEL_COPY_MEMORY_OPERATION)Irp->AssociatedIrp.SystemBuffer;
PEPROCESS targetProcess;
if (stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(KERNEL_COPY_MEMORY_OPERATION))
{
PKERNEL_COPY_MEMORY_OPERATION request = (PKERNEL_COPY_MEMORY_OPERATION)Irp->AssociatedIrp.SystemBuffer;
PEPROCESS targetProcess;

if (NT_SUCCESS(PsLookupProcessByProcessId(request->targetProcessId, &targetProcess)))
if (NT_SUCCESS(PsLookupProcessByProcessId(request->targetProcessId, &targetProcess)))
{
CopyVirtualMemory(targetProcess, request->targetAddress, request->bufferAddress, request->bufferSize);
ObDereferenceObject(targetProcess);
}

status = STATUS_SUCCESS;
bytesIO = sizeof(KERNEL_COPY_MEMORY_OPERATION);
}
else
{
CopyVirtualMemory(targetProcess, request->targetAddress, request->bufferAddress, request->bufferSize);
status = STATUS_INFO_LENGTH_MISMATCH;
bytesIO = 0;
}

Status = STATUS_SUCCESS;
BytesIO = sizeof(KERNEL_COPY_MEMORY_OPERATION);
}
else if (ControlCode == IO_GET_PROCESS_LIST)
else if (controlCode == IO_GET_PROCESS_LIST)
{
PKERNEL_PROCESS_LIST_OPERATION request = (PKERNEL_PROCESS_LIST_OPERATION)Irp->AssociatedIrp.SystemBuffer;
if (stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(KERNEL_PROCESS_LIST_OPERATION) &&
stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KERNEL_PROCESS_LIST_OPERATION))
{
PKERNEL_PROCESS_LIST_OPERATION request = (PKERNEL_PROCESS_LIST_OPERATION)Irp->AssociatedIrp.SystemBuffer;

GetProcessList(request->bufferAddress, request->bufferSize, &request->bufferSize, &request->processCount);
GetProcessList(request->bufferAddress, request->bufferSize, &request->bufferSize, &request->processCount);

Status = STATUS_SUCCESS;
BytesIO = sizeof(KERNEL_PROCESS_LIST_OPERATION);
status = STATUS_SUCCESS;
bytesIO = sizeof(KERNEL_PROCESS_LIST_OPERATION);
}
else
{
status = STATUS_INFO_LENGTH_MISMATCH;
bytesIO = 0;
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
BytesIO = 0;
status = STATUS_INVALID_PARAMETER;
bytesIO = 0;
}

Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesIO;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = bytesIO;
IoCompleteRequest(Irp, IO_NO_INCREMENT);

return Status;
return status;
}

NTSTATUS UnsupportedDispatch(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
NTSTATUS UnsupportedDispatch(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);

Expand All @@ -63,23 +81,32 @@ NTSTATUS UnsupportedDispatch(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ s
return Irp->IoStatus.Status;
}

NTSTATUS CreateDispatch(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
NTSTATUS CreateDispatch(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);

IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}

NTSTATUS CloseDispatch(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
NTSTATUS CloseDispatch(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);

IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}

NTSTATUS DriverInitialize(_In_ struct _DRIVER_OBJECT *DriverObject, _In_ PUNICODE_STRING RegistryPath)
void Unload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING deviceName;

RtlInitUnicodeString(&deviceName, L"\\Device\\KsDumper");
IoDeleteSymbolicLink(&deviceName);
IoDeleteDevice(DriverObject->DeviceObject);
}

NTSTATUS DriverInitialize(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
UNICODE_STRING deviceName, symLink;
Expand All @@ -100,6 +127,7 @@ NTSTATUS DriverInitialize(_In_ struct _DRIVER_OBJECT *DriverObject, _In_ PUNIC

if (!NT_SUCCESS(status))
{
IoDeleteDevice(deviceObject);
return status;
}
deviceObject->Flags |= DO_BUFFERED_IO;
Expand All @@ -110,7 +138,7 @@ NTSTATUS DriverInitialize(_In_ struct _DRIVER_OBJECT *DriverObject, _In_ PUNIC
DriverObject->MajorFunction[IRP_MJ_CREATE] = &CreateDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = &CloseDispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &IoControl;
DriverObject->DriverUnload = NULL;
DriverObject->DriverUnload = &Unload;
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

return status;
Expand Down
2 changes: 2 additions & 0 deletions KsDumperDriver/KsDumperDriver.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,13 @@
<ItemGroup>
<ClCompile Include="ProcessLister.c" />
<ClCompile Include="Driver.c" />
<ClCompile Include="Utility.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="UserModeBridge.h" />
<ClInclude Include="ProcessLister.h" />
<ClInclude Include="NTUndocumented.h" />
<ClInclude Include="Utility.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
Expand Down
6 changes: 6 additions & 0 deletions KsDumperDriver/KsDumperDriver.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<ClCompile Include="Driver.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utility.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ProcessLister.h">
Expand All @@ -32,5 +35,8 @@
<ClInclude Include="NTUndocumented.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utility.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
22 changes: 22 additions & 0 deletions KsDumperDriver/NTUndocumented.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ typedef enum _SYSTEM_INFORMATION_CLASS
SystemProcessInformation = 5
} SYSTEM_INFORMATION_CLASS;

typedef enum _MEMORY_INFORMATION_CLASS
{
MemoryBasicInformation,
MemoryWorkingSetInformation,
MemoryMappedFilenameInformation,
MemoryRegionInformation,
MemoryWorkingSetExInformation

} MEMORY_INFORMATION_CLASS;


typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
INT32 AllocationProtect;
SIZE_T RegionSize;
INT32 State;
INT32 Protect;
INT32 Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

NTKERNELAPI NTSTATUS IoCreateDriver(IN PUNICODE_STRING DriverName, OPTIONAL IN PDRIVER_INITIALIZE InitializationFunction);

NTKERNELAPI VOID KeStackAttachProcess(__inout struct _KPROCESS * PROCESS, __out PRKAPC_STATE ApcState);
Expand All @@ -22,6 +43,7 @@ NTKERNELAPI VOID KeUnstackDetachProcess(__in PRKAPC_STATE ApcState);
NTKERNELAPI NTSTATUS NTAPI MmCopyVirtualMemory(IN PEPROCESS FromProcess, IN PVOID FromAddress, IN PEPROCESS ToProcess, OUT PVOID ToAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T NumberOfBytesCopied);

NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL);
NTSYSAPI NTSTATUS NTAPI ZwQueryVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN MEMORY_INFORMATION_CLASS MemoryInformationClass, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength OPTIONAL);

NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(IN HANDLE ProcessId, OUT PEPROCESS *Process);
NTKERNELAPI PVOID PsGetProcessSectionBaseAddress(__in PEPROCESS Process);
Expand Down
81 changes: 41 additions & 40 deletions KsDumperDriver/ProcessLister.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "NTUndocumented.h"
#include "ProcessLister.h"
#include "Utility.h"

static PSYSTEM_PROCESS_INFORMATION GetRawProcessList()
{
Expand All @@ -12,26 +13,13 @@ static PSYSTEM_PROCESS_INFORMATION GetRawProcessList()

if (bufferPtr != NULL)
{
ZwQuerySystemInformation(SystemProcessInformation, bufferPtr, bufferSize, NULL);
ZwQuerySystemInformation(SystemProcessInformation, bufferPtr, bufferSize, &bufferSize);
}
}
return (PSYSTEM_PROCESS_INFORMATION)bufferPtr;
}

static NTSTATUS DriverSleep(int ms)
{
LARGE_INTEGER li;
li.QuadPart = -10000;

for (int i = 0; i < ms; i++)
{
KeDelayExecutionThread(KernelMode, FALSE, &li);
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}

static ULONG CalculateListedProcessListSize(PSYSTEM_PROCESS_INFORMATION rawProcessList)
static ULONG CalculateProcessListOutputSize(PSYSTEM_PROCESS_INFORMATION rawProcessList)
{
int size = 0;

Expand All @@ -43,23 +31,29 @@ static ULONG CalculateListedProcessListSize(PSYSTEM_PROCESS_INFORMATION rawProce
return size;
}

static PLDR_DATA_TABLE_ENTRY GetMainModuleEntry(PPEB64 peb)
static PLDR_DATA_TABLE_ENTRY GetMainModuleDataTableEntry(PPEB64 peb)
{
if (peb->Ldr)
if (SanitizeUserPointer(peb, sizeof(PEB64)))
{
if (!peb->Ldr->Initialized)
if (peb->Ldr)
{
int initLoadCount = 0;

while (!peb->Ldr->Initialized && initLoadCount++ < 4)
if (SanitizeUserPointer(peb->Ldr, sizeof(PEB_LDR_DATA)))
{
DriverSleep(250);
}
}
if (!peb->Ldr->Initialized)
{
int initLoadCount = 0;

if (peb->Ldr->Initialized)
{
return CONTAINING_RECORD(peb->Ldr->InLoadOrderModuleList.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
while (!peb->Ldr->Initialized && initLoadCount++ < 4)
{
DriverSleep(250);
}
}

if (peb->Ldr->Initialized)
{
return CONTAINING_RECORD(peb->Ldr->InLoadOrderModuleList.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
}
}
}
}
return NULL;
Expand All @@ -74,7 +68,7 @@ NTSTATUS GetProcessList(PVOID listedProcessBuffer, INT32 bufferSize, PINT32 requ

if (rawProcessList)
{
int expectedBufferSize = CalculateListedProcessListSize(rawProcessList);
int expectedBufferSize = CalculateProcessListOutputSize(rawProcessList);

if (!listedProcessBuffer || bufferSize < expectedBufferSize)
{
Expand Down Expand Up @@ -102,21 +96,26 @@ NTSTATUS GetProcessList(PVOID listedProcessBuffer, INT32 bufferSize, PINT32 requ
__try
{
mainModuleBase = PsGetProcessSectionBaseAddress(targetProcess);
PPEB64 peb = (PPEB64)PsGetProcessPeb(targetProcess);

if (peb)
if (mainModuleBase)
{
PLDR_DATA_TABLE_ENTRY mainModuleEntry = GetMainModuleEntry(peb);
PPEB64 peb = (PPEB64)PsGetProcessPeb(targetProcess);

if (mainModuleEntry)
if (peb)
{
mainModuleEntryPoint = mainModuleEntry->EntryPoint;
mainModuleImageSize = mainModuleEntry->SizeOfImage;
isWow64 = IS_WOW64_PE(peb->ImageBaseAddress);

mainModuleFileName = ExAllocatePool(NonPagedPool, 256 * sizeof(WCHAR));
RtlZeroMemory(mainModuleFileName, mainModuleEntry->FullDllName.Length + sizeof(WCHAR));
RtlCopyMemory(mainModuleFileName, mainModuleEntry->FullDllName.Buffer, mainModuleEntry->FullDllName.Length);
PLDR_DATA_TABLE_ENTRY mainModuleEntry = GetMainModuleDataTableEntry(peb);
mainModuleEntry = SanitizeUserPointer(mainModuleEntry, sizeof(LDR_DATA_TABLE_ENTRY));

if (mainModuleEntry)
{
mainModuleEntryPoint = mainModuleEntry->EntryPoint;
mainModuleImageSize = mainModuleEntry->SizeOfImage;
isWow64 = IS_WOW64_PE(mainModuleBase);

mainModuleFileName = ExAllocatePool(NonPagedPool, 256 * sizeof(WCHAR));
RtlZeroMemory(mainModuleFileName, 256 * sizeof(WCHAR));
RtlCopyMemory(mainModuleFileName, mainModuleEntry->FullDllName.Buffer, 256 * sizeof(WCHAR));
}
}
}
}
Expand All @@ -130,7 +129,7 @@ NTSTATUS GetProcessList(PVOID listedProcessBuffer, INT32 bufferSize, PINT32 requ
KeUnstackDetachProcess(&state);
}

if (mainModuleBase)
if (mainModuleFileName)
{
RtlCopyMemory(processSummary->MainModuleFileName, mainModuleFileName, 256 * sizeof(WCHAR));
ExFreePool(mainModuleFileName);
Expand All @@ -144,6 +143,8 @@ NTSTATUS GetProcessList(PVOID listedProcessBuffer, INT32 bufferSize, PINT32 requ
processSummary++;
(*processCount)++;
}

ObDereferenceObject(targetProcess);
}

rawProcessList = (PSYSTEM_PROCESS_INFORMATION)(((CHAR*)rawProcessList) + rawProcessList->NextEntryOffset);
Expand Down
35 changes: 35 additions & 0 deletions KsDumperDriver/Utility.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "NTUndocumented.h"
#include "Utility.h"

NTSTATUS DriverSleep(int ms)
{
LARGE_INTEGER li;
li.QuadPart = -10000;

for (int i = 0; i < ms; i++)
{
KeDelayExecutionThread(KernelMode, FALSE, &li);
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}

PVOID SanitizeUserPointer(PVOID pointer, SIZE_T size)
{
MEMORY_BASIC_INFORMATION memInfo;

if (NT_SUCCESS(ZwQueryVirtualMemory(ZwCurrentProcess(), pointer, MemoryBasicInformation, &memInfo, sizeof(MEMORY_BASIC_INFORMATION), NULL)))
{
if (!(((uintptr_t)memInfo.BaseAddress + memInfo.RegionSize) < (((uintptr_t)pointer + size))))
{
if (memInfo.State & MEM_COMMIT || !(memInfo.Protect & (PAGE_GUARD | PAGE_NOACCESS)))
{
if (memInfo.Protect & PAGE_EXECUTE_READWRITE || memInfo.Protect & PAGE_EXECUTE_WRITECOPY || memInfo.Protect & PAGE_READWRITE || memInfo.Protect & PAGE_WRITECOPY)
{
return pointer;
}
}
}
}
return NULL;
}
6 changes: 6 additions & 0 deletions KsDumperDriver/Utility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once
#include <ntddk.h>

NTSTATUS DriverSleep(int ms);

PVOID SanitizeUserPointer(PVOID pointer, SIZE_T size);

0 comments on commit 7c7d8a4

Please sign in to comment.