1103 lines
26 KiB
C
1103 lines
26 KiB
C
/*
|
|
* Process Hacker -
|
|
* KProcessHacker API
|
|
*
|
|
* Copyright (C) 2009-2016 wj32
|
|
*
|
|
* This file is part of Process Hacker.
|
|
*
|
|
* Process Hacker is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Process Hacker is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <ph.h>
|
|
#include <kphuser.h>
|
|
#include <kphuserp.h>
|
|
|
|
HANDLE PhKphHandle = NULL;
|
|
BOOLEAN PhKphVerified;
|
|
KPH_KEY PhKphL1Key;
|
|
|
|
NTSTATUS KphConnect(
|
|
_In_opt_ PWSTR DeviceName
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE kphHandle;
|
|
UNICODE_STRING objectName;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
IO_STATUS_BLOCK isb;
|
|
OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
|
|
|
|
if (PhKphHandle)
|
|
return STATUS_ADDRESS_ALREADY_EXISTS;
|
|
|
|
if (DeviceName)
|
|
RtlInitUnicodeString(&objectName, DeviceName);
|
|
else
|
|
RtlInitUnicodeString(&objectName, KPH_DEVICE_NAME);
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&objectName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = NtOpenFile(
|
|
&kphHandle,
|
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
|
&objectAttributes,
|
|
&isb,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_NON_DIRECTORY_FILE
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
// Protect the handle from being closed.
|
|
|
|
handleFlagInfo.Inherit = FALSE;
|
|
handleFlagInfo.ProtectFromClose = TRUE;
|
|
|
|
NtSetInformationObject(
|
|
kphHandle,
|
|
ObjectHandleFlagInformation,
|
|
&handleFlagInfo,
|
|
sizeof(OBJECT_HANDLE_FLAG_INFORMATION)
|
|
);
|
|
|
|
PhKphHandle = kphHandle;
|
|
PhKphVerified = FALSE;
|
|
PhKphL1Key = 0;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphConnect2(
|
|
_In_opt_ PWSTR DeviceName,
|
|
_In_ PWSTR FileName
|
|
)
|
|
{
|
|
return KphConnect2Ex(DeviceName, FileName, NULL);
|
|
}
|
|
|
|
NTSTATUS KphConnect2Ex(
|
|
_In_opt_ PWSTR DeviceName,
|
|
_In_ PWSTR FileName,
|
|
_In_opt_ PKPH_PARAMETERS Parameters
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
WCHAR fullDeviceName[256];
|
|
PH_FORMAT format[2];
|
|
SC_HANDLE scmHandle;
|
|
SC_HANDLE serviceHandle;
|
|
BOOLEAN started = FALSE;
|
|
BOOLEAN created = FALSE;
|
|
|
|
if (!DeviceName)
|
|
DeviceName = KPH_DEVICE_SHORT_NAME;
|
|
|
|
PhInitFormatS(&format[0], L"\\Device\\");
|
|
PhInitFormatS(&format[1], DeviceName);
|
|
|
|
if (!PhFormatToBuffer(format, 2, fullDeviceName, sizeof(fullDeviceName), NULL))
|
|
return STATUS_NAME_TOO_LONG;
|
|
|
|
// Try to open the device.
|
|
status = KphConnect(fullDeviceName);
|
|
|
|
if (NT_SUCCESS(status) || status == STATUS_ADDRESS_ALREADY_EXISTS)
|
|
return status;
|
|
|
|
if (
|
|
status != STATUS_NO_SUCH_DEVICE &&
|
|
status != STATUS_NO_SUCH_FILE &&
|
|
status != STATUS_OBJECT_NAME_NOT_FOUND &&
|
|
status != STATUS_OBJECT_PATH_NOT_FOUND
|
|
)
|
|
return status;
|
|
|
|
// Load the driver, and try again.
|
|
|
|
// Try to start the service, if it exists.
|
|
|
|
scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
|
|
|
if (scmHandle)
|
|
{
|
|
serviceHandle = OpenService(scmHandle, DeviceName, SERVICE_START);
|
|
|
|
if (serviceHandle)
|
|
{
|
|
if (StartService(serviceHandle, 0, NULL))
|
|
started = TRUE;
|
|
|
|
CloseServiceHandle(serviceHandle);
|
|
}
|
|
|
|
CloseServiceHandle(scmHandle);
|
|
}
|
|
|
|
if (!started && RtlDoesFileExists_U(FileName))
|
|
{
|
|
// Try to create the service.
|
|
|
|
scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
|
|
|
|
if (scmHandle)
|
|
{
|
|
serviceHandle = CreateService(
|
|
scmHandle,
|
|
DeviceName,
|
|
DeviceName,
|
|
SERVICE_ALL_ACCESS,
|
|
SERVICE_KERNEL_DRIVER,
|
|
SERVICE_DEMAND_START,
|
|
SERVICE_ERROR_IGNORE,
|
|
FileName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
L""
|
|
);
|
|
|
|
if (serviceHandle)
|
|
{
|
|
created = TRUE;
|
|
|
|
// Set parameters if the caller supplied them. Note that we fail the entire function
|
|
// if this fails, because failing to set parameters like SecurityLevel may result in
|
|
// security vulnerabilities.
|
|
if (Parameters)
|
|
{
|
|
status = KphSetParameters(DeviceName, Parameters);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
// Delete the service and fail.
|
|
goto CreateAndConnectEnd;
|
|
}
|
|
}
|
|
|
|
if (StartService(serviceHandle, 0, NULL))
|
|
started = TRUE;
|
|
}
|
|
|
|
CloseServiceHandle(scmHandle);
|
|
}
|
|
}
|
|
|
|
if (started)
|
|
{
|
|
// Try to open the device again.
|
|
status = KphConnect(fullDeviceName);
|
|
}
|
|
|
|
CreateAndConnectEnd:
|
|
if (created)
|
|
{
|
|
// "Delete" the service. Since we (may) have a handle to the device, the SCM will delete the
|
|
// service automatically when it is stopped (upon reboot). If we don't have a handle to the
|
|
// device, the service will get deleted immediately, which is a good thing anyway.
|
|
DeleteService(serviceHandle);
|
|
CloseServiceHandle(serviceHandle);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphDisconnect(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
|
|
|
|
if (!PhKphHandle)
|
|
return STATUS_ALREADY_DISCONNECTED;
|
|
|
|
// Unprotect the handle.
|
|
|
|
handleFlagInfo.Inherit = FALSE;
|
|
handleFlagInfo.ProtectFromClose = FALSE;
|
|
|
|
NtSetInformationObject(
|
|
PhKphHandle,
|
|
ObjectHandleFlagInformation,
|
|
&handleFlagInfo,
|
|
sizeof(OBJECT_HANDLE_FLAG_INFORMATION)
|
|
);
|
|
|
|
status = NtClose(PhKphHandle);
|
|
PhKphHandle = NULL;
|
|
PhKphVerified = FALSE;
|
|
PhKphL1Key = 0;
|
|
|
|
return status;
|
|
}
|
|
|
|
BOOLEAN KphIsConnected(
|
|
VOID
|
|
)
|
|
{
|
|
return PhKphHandle != NULL;
|
|
}
|
|
|
|
BOOLEAN KphIsVerified(
|
|
VOID
|
|
)
|
|
{
|
|
return PhKphVerified;
|
|
}
|
|
|
|
NTSTATUS KphSetParameters(
|
|
_In_opt_ PWSTR DeviceName,
|
|
_In_ PKPH_PARAMETERS Parameters
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE parametersKeyHandle = NULL;
|
|
PPH_STRING parametersKeyName;
|
|
ULONG disposition;
|
|
UNICODE_STRING valueName;
|
|
|
|
if (!DeviceName)
|
|
DeviceName = KPH_DEVICE_SHORT_NAME;
|
|
|
|
parametersKeyName = PhConcatStrings(
|
|
3,
|
|
L"System\\CurrentControlSet\\Services\\",
|
|
DeviceName,
|
|
L"\\Parameters"
|
|
);
|
|
status = PhCreateKey(
|
|
¶metersKeyHandle,
|
|
KEY_WRITE | DELETE,
|
|
PH_KEY_LOCAL_MACHINE,
|
|
¶metersKeyName->sr,
|
|
0,
|
|
0,
|
|
&disposition
|
|
);
|
|
PhDereferenceObject(parametersKeyName);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
return status;
|
|
|
|
RtlInitUnicodeString(&valueName, L"SecurityLevel");
|
|
status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_DWORD, &Parameters->SecurityLevel, sizeof(ULONG));
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto SetValuesEnd;
|
|
|
|
if (Parameters->CreateDynamicConfiguration)
|
|
{
|
|
KPH_DYN_CONFIGURATION configuration;
|
|
|
|
RtlInitUnicodeString(&valueName, L"DynamicConfiguration");
|
|
|
|
configuration.Version = KPH_DYN_CONFIGURATION_VERSION;
|
|
configuration.NumberOfPackages = 1;
|
|
|
|
if (NT_SUCCESS(KphInitializeDynamicPackage(&configuration.Packages[0])))
|
|
{
|
|
status = NtSetValueKey(parametersKeyHandle, &valueName, 0, REG_BINARY, &configuration, sizeof(KPH_DYN_CONFIGURATION));
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto SetValuesEnd;
|
|
}
|
|
}
|
|
|
|
// Put more parameters here...
|
|
|
|
SetValuesEnd:
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
// Delete the key if we created it.
|
|
if (disposition == REG_CREATED_NEW_KEY)
|
|
NtDeleteKey(parametersKeyHandle);
|
|
}
|
|
|
|
NtClose(parametersKeyHandle);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphInstall(
|
|
_In_opt_ PWSTR DeviceName,
|
|
_In_ PWSTR FileName
|
|
)
|
|
{
|
|
return KphInstallEx(DeviceName, FileName, NULL);
|
|
}
|
|
|
|
NTSTATUS KphInstallEx(
|
|
_In_opt_ PWSTR DeviceName,
|
|
_In_ PWSTR FileName,
|
|
_In_opt_ PKPH_PARAMETERS Parameters
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
SC_HANDLE scmHandle;
|
|
SC_HANDLE serviceHandle;
|
|
|
|
if (!DeviceName)
|
|
DeviceName = KPH_DEVICE_SHORT_NAME;
|
|
|
|
scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
|
|
|
|
if (!scmHandle)
|
|
return PhGetLastWin32ErrorAsNtStatus();
|
|
|
|
serviceHandle = CreateService(
|
|
scmHandle,
|
|
DeviceName,
|
|
DeviceName,
|
|
SERVICE_ALL_ACCESS,
|
|
SERVICE_KERNEL_DRIVER,
|
|
SERVICE_SYSTEM_START,
|
|
SERVICE_ERROR_IGNORE,
|
|
FileName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
L""
|
|
);
|
|
|
|
if (serviceHandle)
|
|
{
|
|
// See KphConnect2Ex for more details.
|
|
if (Parameters)
|
|
{
|
|
status = KphSetParameters(DeviceName, Parameters);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DeleteService(serviceHandle);
|
|
goto CreateEnd;
|
|
}
|
|
}
|
|
|
|
if (!StartService(serviceHandle, 0, NULL))
|
|
status = PhGetLastWin32ErrorAsNtStatus();
|
|
|
|
CreateEnd:
|
|
CloseServiceHandle(serviceHandle);
|
|
}
|
|
else
|
|
{
|
|
status = PhGetLastWin32ErrorAsNtStatus();
|
|
}
|
|
|
|
CloseServiceHandle(scmHandle);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphUninstall(
|
|
_In_opt_ PWSTR DeviceName
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
SC_HANDLE scmHandle;
|
|
SC_HANDLE serviceHandle;
|
|
|
|
if (!DeviceName)
|
|
DeviceName = KPH_DEVICE_SHORT_NAME;
|
|
|
|
scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
|
|
|
if (!scmHandle)
|
|
return PhGetLastWin32ErrorAsNtStatus();
|
|
|
|
serviceHandle = OpenService(scmHandle, DeviceName, SERVICE_STOP | DELETE);
|
|
|
|
if (serviceHandle)
|
|
{
|
|
SERVICE_STATUS serviceStatus;
|
|
|
|
ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus);
|
|
|
|
if (!DeleteService(serviceHandle))
|
|
status = PhGetLastWin32ErrorAsNtStatus();
|
|
|
|
CloseServiceHandle(serviceHandle);
|
|
}
|
|
else
|
|
{
|
|
status = PhGetLastWin32ErrorAsNtStatus();
|
|
}
|
|
|
|
CloseServiceHandle(scmHandle);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphGetFeatures(
|
|
_Out_ PULONG Features
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
PULONG Features;
|
|
} input = { Features };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_GETFEATURES,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphVerifyClient(
|
|
_In_reads_bytes_(SignatureSize) PUCHAR Signature,
|
|
_In_ ULONG SignatureSize
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
struct
|
|
{
|
|
PVOID CodeAddress;
|
|
PUCHAR Signature;
|
|
ULONG SignatureSize;
|
|
} input = { KphpWithKeyApcRoutine, Signature, SignatureSize };
|
|
|
|
status = KphpDeviceIoControl(
|
|
KPH_VERIFYCLIENT,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
PhKphVerified = TRUE;
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphOpenProcess(
|
|
_Out_ PHANDLE ProcessHandle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_ PCLIENT_ID ClientId
|
|
)
|
|
{
|
|
KPH_OPEN_PROCESS_INPUT input = { ProcessHandle, DesiredAccess, ClientId, 0 };
|
|
|
|
if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) == DesiredAccess)
|
|
{
|
|
KphpGetL1Key(&input.Key);
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENPROCESS,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
return KphpWithKey(KphKeyLevel2, KphpOpenProcessContinuation, &input);
|
|
}
|
|
}
|
|
|
|
NTSTATUS KphOpenProcessToken(
|
|
_In_ HANDLE ProcessHandle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_Out_ PHANDLE TokenHandle
|
|
)
|
|
{
|
|
KPH_OPEN_PROCESS_TOKEN_INPUT input = { ProcessHandle, DesiredAccess, TokenHandle, 0 };
|
|
|
|
if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) == DesiredAccess)
|
|
{
|
|
KphpGetL1Key(&input.Key);
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENPROCESSTOKEN,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
return KphpWithKey(KphKeyLevel2, KphpOpenProcessTokenContinuation, &input);
|
|
}
|
|
}
|
|
|
|
NTSTATUS KphOpenProcessJob(
|
|
_In_ HANDLE ProcessHandle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_Out_ PHANDLE JobHandle
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
ACCESS_MASK DesiredAccess;
|
|
PHANDLE JobHandle;
|
|
} input = { ProcessHandle, DesiredAccess, JobHandle };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENPROCESSJOB,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphTerminateProcess(
|
|
_In_ HANDLE ProcessHandle,
|
|
_In_ NTSTATUS ExitStatus
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
KPH_TERMINATE_PROCESS_INPUT input = { ProcessHandle, ExitStatus, 0 };
|
|
|
|
status = KphpWithKey(KphKeyLevel2, KphpTerminateProcessContinuation, &input);
|
|
|
|
// Check if we're trying to terminate the current process, because kernel-mode can't do it.
|
|
if (status == STATUS_CANT_TERMINATE_SELF)
|
|
{
|
|
RtlExitUserProcess(ExitStatus);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphReadVirtualMemoryUnsafe(
|
|
_In_opt_ HANDLE ProcessHandle,
|
|
_In_ PVOID BaseAddress,
|
|
_Out_writes_bytes_(BufferSize) PVOID Buffer,
|
|
_In_ SIZE_T BufferSize,
|
|
_Out_opt_ PSIZE_T NumberOfBytesRead
|
|
)
|
|
{
|
|
KPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = { ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead, 0 };
|
|
|
|
return KphpWithKey(KphKeyLevel2, KphpReadVirtualMemoryUnsafeContinuation, &input);
|
|
}
|
|
|
|
NTSTATUS KphQueryInformationProcess(
|
|
_In_ HANDLE ProcessHandle,
|
|
_In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
|
|
_Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
|
|
_In_ ULONG ProcessInformationLength,
|
|
_Out_opt_ PULONG ReturnLength
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;
|
|
PVOID ProcessInformation;
|
|
ULONG ProcessInformationLength;
|
|
PULONG ReturnLength;
|
|
} input = { ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_QUERYINFORMATIONPROCESS,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphSetInformationProcess(
|
|
_In_ HANDLE ProcessHandle,
|
|
_In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
|
|
_In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,
|
|
_In_ ULONG ProcessInformationLength
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;
|
|
PVOID ProcessInformation;
|
|
ULONG ProcessInformationLength;
|
|
} input = { ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_SETINFORMATIONPROCESS,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphOpenThread(
|
|
_Out_ PHANDLE ThreadHandle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_ PCLIENT_ID ClientId
|
|
)
|
|
{
|
|
KPH_OPEN_THREAD_INPUT input = { ThreadHandle, DesiredAccess, ClientId, 0 };
|
|
|
|
if ((DesiredAccess & KPH_THREAD_READ_ACCESS) == DesiredAccess)
|
|
{
|
|
KphpGetL1Key(&input.Key);
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENTHREAD,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
return KphpWithKey(KphKeyLevel2, KphpOpenThreadContinuation, &input);
|
|
}
|
|
}
|
|
|
|
NTSTATUS KphOpenThreadProcess(
|
|
_In_ HANDLE ThreadHandle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_Out_ PHANDLE ProcessHandle
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
ACCESS_MASK DesiredAccess;
|
|
PHANDLE ProcessHandle;
|
|
} input = { ThreadHandle, DesiredAccess, ProcessHandle };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENTHREADPROCESS,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphCaptureStackBackTraceThread(
|
|
_In_ HANDLE ThreadHandle,
|
|
_In_ ULONG FramesToSkip,
|
|
_In_ ULONG FramesToCapture,
|
|
_Out_writes_(FramesToCapture) PVOID *BackTrace,
|
|
_Out_opt_ PULONG CapturedFrames,
|
|
_Out_opt_ PULONG BackTraceHash
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
ULONG FramesToSkip;
|
|
ULONG FramesToCapture;
|
|
PVOID *BackTrace;
|
|
PULONG CapturedFrames;
|
|
PULONG BackTraceHash;
|
|
} input = { ThreadHandle, FramesToSkip, FramesToCapture, BackTrace, CapturedFrames, BackTraceHash };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_CAPTURESTACKBACKTRACETHREAD,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphQueryInformationThread(
|
|
_In_ HANDLE ThreadHandle,
|
|
_In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
|
|
_Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,
|
|
_In_ ULONG ThreadInformationLength,
|
|
_Out_opt_ PULONG ReturnLength
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;
|
|
PVOID ThreadInformation;
|
|
ULONG ThreadInformationLength;
|
|
PULONG ReturnLength;
|
|
} input = { ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength, ReturnLength };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_QUERYINFORMATIONTHREAD,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphSetInformationThread(
|
|
_In_ HANDLE ThreadHandle,
|
|
_In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
|
|
_In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,
|
|
_In_ ULONG ThreadInformationLength
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;
|
|
PVOID ThreadInformation;
|
|
ULONG ThreadInformationLength;
|
|
} input = { ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_SETINFORMATIONTHREAD,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphEnumerateProcessHandles(
|
|
_In_ HANDLE ProcessHandle,
|
|
_Out_writes_bytes_(BufferLength) PVOID Buffer,
|
|
_In_opt_ ULONG BufferLength,
|
|
_Out_opt_ PULONG ReturnLength
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
PVOID Buffer;
|
|
ULONG BufferLength;
|
|
PULONG ReturnLength;
|
|
} input = { ProcessHandle, Buffer, BufferLength, ReturnLength };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_ENUMERATEPROCESSHANDLES,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphEnumerateProcessHandles2(
|
|
_In_ HANDLE ProcessHandle,
|
|
_Out_ PKPH_PROCESS_HANDLE_INFORMATION *Handles
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PVOID buffer;
|
|
ULONG bufferSize = 2048;
|
|
|
|
buffer = PhAllocate(bufferSize);
|
|
|
|
while (TRUE)
|
|
{
|
|
status = KphEnumerateProcessHandles(
|
|
ProcessHandle,
|
|
buffer,
|
|
bufferSize,
|
|
&bufferSize
|
|
);
|
|
|
|
if (status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
PhFree(buffer);
|
|
buffer = PhAllocate(bufferSize);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
PhFree(buffer);
|
|
return status;
|
|
}
|
|
|
|
*Handles = buffer;
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphQueryInformationObject(
|
|
_In_ HANDLE ProcessHandle,
|
|
_In_ HANDLE Handle,
|
|
_In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
|
_Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation,
|
|
_In_ ULONG ObjectInformationLength,
|
|
_Out_opt_ PULONG ReturnLength
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE Handle;
|
|
KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;
|
|
PVOID ObjectInformation;
|
|
ULONG ObjectInformationLength;
|
|
PULONG ReturnLength;
|
|
} input = { ProcessHandle, Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_QUERYINFORMATIONOBJECT,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphSetInformationObject(
|
|
_In_ HANDLE ProcessHandle,
|
|
_In_ HANDLE Handle,
|
|
_In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
|
_In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,
|
|
_In_ ULONG ObjectInformationLength
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE Handle;
|
|
KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;
|
|
PVOID ObjectInformation;
|
|
ULONG ObjectInformationLength;
|
|
} input = { ProcessHandle, Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_SETINFORMATIONOBJECT,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphOpenDriver(
|
|
_Out_ PHANDLE DriverHandle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_ POBJECT_ATTRIBUTES ObjectAttributes
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
PHANDLE DriverHandle;
|
|
ACCESS_MASK DesiredAccess;
|
|
POBJECT_ATTRIBUTES ObjectAttributes;
|
|
} input = { DriverHandle, DesiredAccess, ObjectAttributes };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENDRIVER,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphQueryInformationDriver(
|
|
_In_ HANDLE DriverHandle,
|
|
_In_ DRIVER_INFORMATION_CLASS DriverInformationClass,
|
|
_Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation,
|
|
_In_ ULONG DriverInformationLength,
|
|
_Out_opt_ PULONG ReturnLength
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
HANDLE DriverHandle;
|
|
DRIVER_INFORMATION_CLASS DriverInformationClass;
|
|
PVOID DriverInformation;
|
|
ULONG DriverInformationLength;
|
|
PULONG ReturnLength;
|
|
} input = { DriverHandle, DriverInformationClass, DriverInformation, DriverInformationLength, ReturnLength };
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_QUERYINFORMATIONDRIVER,
|
|
&input,
|
|
sizeof(input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphpDeviceIoControl(
|
|
_In_ ULONG KphControlCode,
|
|
_In_ PVOID InBuffer,
|
|
_In_ ULONG InBufferLength
|
|
)
|
|
{
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
return NtDeviceIoControlFile(
|
|
PhKphHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
KphControlCode,
|
|
InBuffer,
|
|
InBufferLength,
|
|
NULL,
|
|
0
|
|
);
|
|
}
|
|
|
|
VOID KphpWithKeyApcRoutine(
|
|
_In_ PVOID ApcContext,
|
|
_In_ PIO_STATUS_BLOCK IoStatusBlock,
|
|
_In_ ULONG Reserved
|
|
)
|
|
{
|
|
PKPHP_RETRIEVE_KEY_CONTEXT context = CONTAINING_RECORD(IoStatusBlock, KPHP_RETRIEVE_KEY_CONTEXT, Iosb);
|
|
KPH_KEY key = PtrToUlong(ApcContext);
|
|
|
|
if (context->Continuation != KphpGetL1KeyContinuation &&
|
|
context->Continuation != KphpOpenProcessContinuation &&
|
|
context->Continuation != KphpOpenProcessTokenContinuation &&
|
|
context->Continuation != KphpTerminateProcessContinuation &&
|
|
context->Continuation != KphpReadVirtualMemoryUnsafeContinuation &&
|
|
context->Continuation != KphpOpenThreadContinuation)
|
|
{
|
|
PhRaiseStatus(STATUS_ACCESS_DENIED);
|
|
context->Status = STATUS_ACCESS_DENIED;
|
|
return;
|
|
}
|
|
|
|
context->Status = context->Continuation(key, context->Context);
|
|
}
|
|
|
|
NTSTATUS KphpWithKey(
|
|
_In_ KPH_KEY_LEVEL KeyLevel,
|
|
_In_ PKPHP_WITH_KEY_CONTINUATION Continuation,
|
|
_In_ PVOID Context
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
struct
|
|
{
|
|
KPH_KEY_LEVEL KeyLevel;
|
|
} input = { KeyLevel };
|
|
KPHP_RETRIEVE_KEY_CONTEXT context;
|
|
|
|
context.Continuation = Continuation;
|
|
context.Context = Context;
|
|
context.Status = STATUS_UNSUCCESSFUL;
|
|
|
|
status = NtDeviceIoControlFile(
|
|
PhKphHandle,
|
|
NULL,
|
|
KphpWithKeyApcRoutine,
|
|
NULL,
|
|
&context.Iosb,
|
|
KPH_RETRIEVEKEY,
|
|
&input,
|
|
sizeof(input),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
NtTestAlert();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
return status;
|
|
|
|
return context.Status;
|
|
}
|
|
|
|
NTSTATUS KphpGetL1KeyContinuation(
|
|
_In_ KPH_KEY Key,
|
|
_In_ PVOID Context
|
|
)
|
|
{
|
|
PKPHP_GET_L1_KEY_CONTEXT context = Context;
|
|
|
|
*context->Key = Key;
|
|
PhKphL1Key = Key;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS KphpGetL1Key(
|
|
_Out_ PKPH_KEY Key
|
|
)
|
|
{
|
|
KPHP_GET_L1_KEY_CONTEXT context;
|
|
|
|
if (PhKphL1Key)
|
|
{
|
|
*Key = PhKphL1Key;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
context.Key = Key;
|
|
|
|
return KphpWithKey(KphKeyLevel1, KphpGetL1KeyContinuation, &context);
|
|
}
|
|
|
|
NTSTATUS KphpOpenProcessContinuation(
|
|
_In_ KPH_KEY Key,
|
|
_In_ PVOID Context
|
|
)
|
|
{
|
|
PKPH_OPEN_PROCESS_INPUT input = Context;
|
|
|
|
input->Key = Key;
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENPROCESS,
|
|
input,
|
|
sizeof(*input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphpOpenProcessTokenContinuation(
|
|
_In_ KPH_KEY Key,
|
|
_In_ PVOID Context
|
|
)
|
|
{
|
|
PKPH_OPEN_PROCESS_TOKEN_INPUT input = Context;
|
|
|
|
input->Key = Key;
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENPROCESSTOKEN,
|
|
input,
|
|
sizeof(*input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphpTerminateProcessContinuation(
|
|
_In_ KPH_KEY Key,
|
|
_In_ PVOID Context
|
|
)
|
|
{
|
|
PKPH_TERMINATE_PROCESS_INPUT input = Context;
|
|
|
|
input->Key = Key;
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_TERMINATEPROCESS,
|
|
input,
|
|
sizeof(*input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphpReadVirtualMemoryUnsafeContinuation(
|
|
_In_ KPH_KEY Key,
|
|
_In_ PVOID Context
|
|
)
|
|
{
|
|
PKPH_READ_VIRTUAL_MEMORY_UNSAFE_INPUT input = Context;
|
|
|
|
input->Key = Key;
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_READVIRTUALMEMORYUNSAFE,
|
|
input,
|
|
sizeof(*input)
|
|
);
|
|
}
|
|
|
|
NTSTATUS KphpOpenThreadContinuation(
|
|
_In_ KPH_KEY Key,
|
|
_In_ PVOID Context
|
|
)
|
|
{
|
|
PKPH_OPEN_PROCESS_INPUT input = Context;
|
|
|
|
input->Key = Key;
|
|
|
|
return KphpDeviceIoControl(
|
|
KPH_OPENTHREAD,
|
|
input,
|
|
sizeof(*input)
|
|
);
|
|
}
|