Files
mirror-processhacker/1.x/branches/ph-plugins/KProcessHacker/kph.c
T
wj32 7bd28e4357 moved branches, tags, trunk to 1.x branch
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@2304 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2009-10-25 02:22:46 +00:00

374 lines
10 KiB
C

/*
* Process Hacker Driver -
* custom APIs
*
* Copyright (C) 2009 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/>.
*/
#define _KPH_PRIVATE
#include "include/kph.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, GetSystemRoutineAddress)
#pragma alloc_text(PAGE, KphNtInit)
#pragma alloc_text(PAGE, OpenProcess)
#pragma alloc_text(PAGE, SetProcessToken)
#endif
/* GetSystemRoutineAddress
*
* Gets the address of a function exported by ntoskrnl or hal.
*/
PVOID GetSystemRoutineAddress(WCHAR *Name)
{
UNICODE_STRING routineName;
PVOID routineAddress = NULL;
RtlInitUnicodeString(&routineName, Name);
/* Wrap in SEH because MmGetSystemRoutineAddress is known to cause
some BSODs. */
try
{
routineAddress = MmGetSystemRoutineAddress(&routineName);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
routineAddress = NULL;
}
return routineAddress;
}
/* KphNtInit
*
* Initializes the KProcessHacker NT component.
*/
NTSTATUS KphNtInit()
{
NTSTATUS status = STATUS_SUCCESS;
/* Confuse those damn AVs... */
PWCHAR keService = L"KeService"; // length 9, 18 bytes
PWCHAR descriptorTable = L"DescriptorTable"; // 15, 30 bytes
WCHAR keServiceDescriptorTable[9 + 15 + 1];
/* Reconstruct the string. */
memcpy(keServiceDescriptorTable, keService, 18);
memcpy(keServiceDescriptorTable + 9, descriptorTable, 30);
keServiceDescriptorTable[9 + 15] = L'\0';
/* Dynamically get function pointers. */
__KeServiceDescriptorTable = GetSystemRoutineAddress(keServiceDescriptorTable);
dfprintf("KeServiceDescriptorTable: %#x\n", __KeServiceDescriptorTable);
PsGetProcessJob = GetSystemRoutineAddress(L"PsGetProcessJob");
dfprintf("PsGetProcessJob: %#x\n", PsGetProcessJob);
PsResumeProcess = GetSystemRoutineAddress(L"PsResumeProcess");
dfprintf("PsResumeProcess: %#x\n", PsResumeProcess);
PsSuspendProcess = GetSystemRoutineAddress(L"PsSuspendProcess");
dfprintf("PsSuspendProcess: %#x\n", PsSuspendProcess);
if (WindowsVersion >= WINDOWS_7)
{
ObGetObjectType = GetSystemRoutineAddress(L"ObGetObjectType");
dfprintf("ObGetObjectType: %#x\n", ObGetObjectType);
}
/* Scan for functions. */
if (KiFastCallEntryScan.Initialized)
{
__KiFastCallEntry = KvScanProc(&KiFastCallEntryScan);
dfprintf("KiFastCallEntry+x: %#x\n", __KiFastCallEntry);
}
if (PsTerminateProcessScan.Initialized)
{
__PsTerminateProcess = KvScanProc(&PsTerminateProcessScan);
dfprintf("PsTerminateProcess: %#x\n", __PsTerminateProcess);
}
if (PspTerminateThreadByPointerScan.Initialized)
{
__PspTerminateThreadByPointer = KvScanProc(&PspTerminateThreadByPointerScan);
dfprintf("PspTerminateThreadByPointer: %#x\n", __PspTerminateThreadByPointer);
}
return status;
}
/* KphAttachProcess
*
* Attaches to a process represented by the specified EPROCESS.
*/
VOID KphAttachProcess(
__in PEPROCESS Process,
__out PKPH_ATTACH_STATE AttachState
)
{
AttachState->Attached = FALSE;
/* Don't attach if we are already attached to the target. */
if (Process != PsGetCurrentProcess())
{
KeStackAttachProcess(Process, &AttachState->ApcState);
AttachState->Attached = TRUE;
AttachState->Process = Process;
}
}
/* KphAttachProcessHandle
*
* Attaches to a process represented by the specified handle.
*/
NTSTATUS KphAttachProcessHandle(
__in HANDLE ProcessHandle,
__out PKPH_ATTACH_STATE AttachState
)
{
NTSTATUS status = STATUS_SUCCESS;
PEPROCESS processObject;
AttachState->Attached = FALSE;
status = ObReferenceObjectByHandle(
ProcessHandle,
0,
*PsProcessType,
KernelMode,
&processObject,
NULL
);
if (!NT_SUCCESS(status))
return status;
KphAttachProcess(processObject, AttachState);
ObDereferenceObject(processObject);
return status;
}
/* KphAttachProcessId
*
* Attaches to a process represented by the specified process ID.
*/
NTSTATUS KphAttachProcessId(
__in HANDLE ProcessId,
__out PKPH_ATTACH_STATE AttachState
)
{
NTSTATUS status = STATUS_SUCCESS;
PEPROCESS processObject;
AttachState->Attached = FALSE;
status = PsLookupProcessByProcessId(ProcessId, &processObject);
if (!NT_SUCCESS(status))
return status;
KphAttachProcess(processObject, AttachState);
ObDereferenceObject(processObject);
return status;
}
/* KphCaptureUnicodeString
*
* Captures a UNICODE_STRING. This function will not throw exceptions.
*/
NTSTATUS KphCaptureUnicodeString(
__in PUNICODE_STRING UnicodeString,
__out PUNICODE_STRING CapturedUnicodeString
)
{
__try
{
CapturedUnicodeString->Length = UnicodeString->Length;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
CapturedUnicodeString->MaximumLength = CapturedUnicodeString->Length;
CapturedUnicodeString->Buffer = ExAllocatePoolWithTag(
PagedPool,
CapturedUnicodeString->Length,
TAG_CAPTURED_UNICODE_STRING
);
if (!CapturedUnicodeString->Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
__try
{
memcpy(
CapturedUnicodeString->Buffer,
UnicodeString->Buffer,
CapturedUnicodeString->Length
);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
KphFreeCapturedUnicodeString(CapturedUnicodeString);
return GetExceptionCode();
}
return STATUS_SUCCESS;
}
/* KphDetachProcess
*
* Detaches from the currently attached process.
*/
VOID KphDetachProcess(
__in PKPH_ATTACH_STATE AttachState
)
{
if (AttachState->Attached)
KeUnstackDetachProcess(&AttachState->ApcState);
}
/* KphFreeCapturedUnicodeString
*
* Frees a UNICODE_STRING captured by KphCaptureUnicodeString.
*/
VOID KphFreeCapturedUnicodeString(
__in PUNICODE_STRING CapturedUnicodeString
)
{
ExFreePoolWithTag(
CapturedUnicodeString->Buffer,
TAG_CAPTURED_UNICODE_STRING
);
}
/* KphProbeForReadUnicodeString
*
* Probes a UNICODE_STRING structure for reading.
*/
VOID KphProbeForReadUnicodeString(
__in PUNICODE_STRING UnicodeString
)
{
ProbeForRead(UnicodeString, sizeof(UNICODE_STRING), 1);
ProbeForRead(UnicodeString->Buffer, UnicodeString->Length, 1);
}
/* KphProbeSystemAddressRange
*
* Probes an address range in kernel-mode memory for reading.
*/
VOID KphProbeSystemAddressRange(
__in PVOID BaseAddress,
__in ULONG Length
)
{
ULONG_PTR page, pageEnd;
/* HACK HACK HACK HACK HACK HACK */
/* Check the address range by checking each page. */
/* Round down the base address to the page size. Note: please make sure you are
* not using a dumbass compiler which optimizes the following line by removing
* the divide and multiply.
*/
page = (ULONG_PTR)BaseAddress / PAGE_SIZE * PAGE_SIZE;
/* BaseAddress + Length - 1 is the last address we will be reading. */
pageEnd = ((ULONG_PTR)BaseAddress + Length - 1) / PAGE_SIZE * PAGE_SIZE;
for (; page <= pageEnd; page += PAGE_SIZE)
{
/* Check the page. */
if (!MmIsAddressValid((PVOID)page))
ExRaiseStatus(STATUS_ACCESS_VIOLATION);
}
}
/* OpenProcess
*
* Opens the process with the specified PID.
*/
NTSTATUS OpenProcess(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in HANDLE ProcessId
)
{
OBJECT_ATTRIBUTES objAttr = { 0 };
CLIENT_ID clientId;
objAttr.Length = sizeof(objAttr);
clientId.UniqueThread = 0;
clientId.UniqueProcess = ProcessId;
return KphOpenProcess(ProcessHandle, DesiredAccess, &objAttr, &clientId, KernelMode);
}
/* SetProcessToken
*
* Assigns the primary token of the target process from the
* primary token of source process.
*/
NTSTATUS SetProcessToken(
__in HANDLE sourcePid,
__in HANDLE targetPid
)
{
NTSTATUS status;
HANDLE source;
if (NT_SUCCESS(status = OpenProcess(&source, PROCESS_QUERY_INFORMATION, sourcePid)))
{
HANDLE target;
if (NT_SUCCESS(status = OpenProcess(&target, PROCESS_QUERY_INFORMATION |
PROCESS_SET_INFORMATION, targetPid)))
{
HANDLE sourceToken;
if (NT_SUCCESS(status = KphOpenProcessTokenEx(source, TOKEN_DUPLICATE, 0,
&sourceToken, UserMode)))
{
HANDLE dupSourceToken;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
objectAttributes.Length = sizeof(objectAttributes);
if (NT_SUCCESS(status = ZwDuplicateToken(sourceToken, TOKEN_ASSIGN_PRIMARY, &objectAttributes,
FALSE, TokenPrimary, &dupSourceToken)))
{
PROCESS_ACCESS_TOKEN token;
token.Token = dupSourceToken;
token.Thread = 0;
status = ZwSetInformationProcess(target, ProcessAccessToken, &token, sizeof(token));
}
ZwClose(dupSourceToken);
}
ZwClose(sourceToken);
}
ZwClose(target);
}
ZwClose(source);
return status;
}