mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
83ff30039b
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1080 21ef857c-d57f-4fe0-8362-d861dc6d29cd
526 lines
19 KiB
C#
526 lines
19 KiB
C#
/*
|
|
* Process Hacker -
|
|
* interfacing code to kernel-mode driver
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.ComponentModel;
|
|
using ProcessHacker.PE;
|
|
using System.Runtime.InteropServices;
|
|
using System.Diagnostics;
|
|
using System.Windows.Forms;
|
|
|
|
namespace ProcessHacker
|
|
{
|
|
/// <summary>
|
|
/// Provides an interface to KProcessHacker.
|
|
/// </summary>
|
|
public class KProcessHacker
|
|
{
|
|
/// <summary>
|
|
/// A control code used by KProcessHacker to represent a specific function.
|
|
/// </summary>
|
|
private enum Control : uint
|
|
{
|
|
Read = 0,
|
|
Write,
|
|
GetFileObjectName,
|
|
KphOpenProcess,
|
|
KphOpenThread,
|
|
KphOpenProcessToken,
|
|
GetProcessProtected,
|
|
SetProcessProtected,
|
|
KphTerminateProcess,
|
|
KphSuspendProcess,
|
|
KphResumeProcess,
|
|
KphReadVirtualMemory,
|
|
KphWriteVirtualMemory,
|
|
SetProcessToken,
|
|
GetThreadWin32StartAddress,
|
|
GetObjectName,
|
|
GetHandleObjectName,
|
|
KphOpenProcessJob,
|
|
KphGetContextThread,
|
|
KphSetContextThread,
|
|
KphGetThreadWin32Thread,
|
|
KphDuplicateObject,
|
|
ZwQueryObject
|
|
}
|
|
|
|
private string _deviceName;
|
|
private Win32.FileHandle _fileHandle;
|
|
private uint _baseControlNumber;
|
|
private Win32.ServiceHandle _service;
|
|
|
|
/// <summary>
|
|
/// Creates a connection to KProcessHacker.
|
|
/// </summary>
|
|
/// <param name="deviceName">The device to connect to.</param>
|
|
public KProcessHacker(string deviceName)
|
|
{
|
|
_deviceName = deviceName;
|
|
|
|
bool started = false;
|
|
|
|
if (!Properties.Settings.Default.EnableKPH)
|
|
throw new Exception("KProcessHacker is not enabled.");
|
|
|
|
// delete the service if it exists
|
|
try
|
|
{
|
|
using (var shandle = new Win32.ServiceHandle(deviceName))
|
|
{
|
|
started = shandle.GetStatus().CurrentState == Win32.SERVICE_STATE.Running;
|
|
|
|
if (!started)
|
|
shandle.Delete();
|
|
}
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
try
|
|
{
|
|
Win32.ServiceManagerHandle scm =
|
|
new Win32.ServiceManagerHandle(Win32.SC_MANAGER_RIGHTS.SC_MANAGER_CREATE_SERVICE);
|
|
|
|
_service = scm.CreateService(deviceName, deviceName, Win32.SERVICE_TYPE.KernelDriver,
|
|
Application.StartupPath + "\\kprocesshacker.sys");
|
|
_service.Start();
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
_fileHandle = new Win32.FileHandle("\\\\.\\" + deviceName,
|
|
Win32.FILE_RIGHTS.FILE_GENERIC_READ | Win32.FILE_RIGHTS.FILE_GENERIC_WRITE);
|
|
|
|
try
|
|
{
|
|
if (!started)
|
|
_service.Delete(); // the service will automatically get deleted once it stops
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
_baseControlNumber = Misc.BytesToUInt(_fileHandle.Read(4), Misc.Endianness.Little);
|
|
}
|
|
|
|
public string DeviceName
|
|
{
|
|
get { return _deviceName; }
|
|
}
|
|
|
|
private uint CtlCode(Control ctl)
|
|
{
|
|
return _baseControlNumber + ((uint)ctl * 4);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Closes the connection to KProcessHacker.
|
|
/// </summary>
|
|
public void Close()
|
|
{
|
|
_fileHandle.Dispose();
|
|
}
|
|
|
|
public string GetFileObjectName(Win32.SYSTEM_HANDLE_INFORMATION handle)
|
|
{
|
|
byte[] buffer = new byte[12];
|
|
byte[] outBuffer = new byte[2048];
|
|
|
|
Array.Copy(Misc.IntToBytes(handle.Handle, Misc.Endianness.Little), buffer, 4);
|
|
Array.Copy(Misc.IntToBytes(handle.Object, Misc.Endianness.Little), 0, buffer, 4, 4);
|
|
Array.Copy(Misc.IntToBytes(handle.ProcessId, Misc.Endianness.Little), 0, buffer, 8, 4);
|
|
|
|
try
|
|
{
|
|
int len = _fileHandle.IoControl(CtlCode(Control.GetFileObjectName), buffer, outBuffer);
|
|
|
|
return UnicodeEncoding.Unicode.GetString(outBuffer, 8, len - 8).TrimEnd('\0');
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
return null;
|
|
}
|
|
|
|
public string GetHandleObjectName(Win32.ProcessHandle processHandle, int handle)
|
|
{
|
|
byte[] inBuffer = new byte[8];
|
|
byte[] outBuffer = new byte[2048];
|
|
|
|
Array.Copy(Misc.IntToBytes(processHandle, Misc.Endianness.Little), 0, inBuffer, 0, 4);
|
|
Array.Copy(Misc.IntToBytes(handle, Misc.Endianness.Little), 0, inBuffer, 4, 4);
|
|
|
|
try
|
|
{
|
|
int len = _fileHandle.IoControl(CtlCode(Control.GetHandleObjectName),
|
|
inBuffer, outBuffer);
|
|
|
|
return UnicodeEncoding.Unicode.GetString(outBuffer, 8, len - 8).TrimEnd('\0');
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
return null;
|
|
}
|
|
|
|
public string GetObjectName(int obj)
|
|
{
|
|
byte[] outBuffer = new byte[2048];
|
|
|
|
try
|
|
{
|
|
int len = _fileHandle.IoControl(CtlCode(Control.GetObjectName),
|
|
Misc.IntToBytes(obj, Misc.Endianness.Little), outBuffer);
|
|
|
|
return UnicodeEncoding.Unicode.GetString(outBuffer, 8, len - 8).TrimEnd('\0');
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
return null;
|
|
}
|
|
|
|
public bool GetProcessProtected(int pid)
|
|
{
|
|
byte[] result = new byte[1];
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.GetProcessProtected),
|
|
Misc.IntToBytes(pid, Misc.Endianness.Little), result);
|
|
|
|
return result[0] != 0;
|
|
}
|
|
|
|
public uint GetThreadWin32StartAddress(Win32.ThreadHandle threadHandle)
|
|
{
|
|
byte[] buffer = new byte[4];
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.GetThreadWin32StartAddress),
|
|
Misc.IntToBytes(threadHandle, Misc.Endianness.Little), buffer);
|
|
|
|
return Misc.BytesToUInt(buffer, Misc.Endianness.Little);
|
|
}
|
|
|
|
public unsafe void KphDuplicateObject(
|
|
int sourceProcessHandle,
|
|
int sourceHandle,
|
|
int targetProcessHandle,
|
|
out int targetHandle,
|
|
int desiredAccess,
|
|
int handleAttributes,
|
|
int options
|
|
)
|
|
{
|
|
int handle;
|
|
|
|
KphDuplicateObject(
|
|
sourceProcessHandle,
|
|
sourceHandle,
|
|
targetProcessHandle,
|
|
(int)&handle,
|
|
desiredAccess,
|
|
handleAttributes,
|
|
options
|
|
);
|
|
|
|
targetHandle = handle;
|
|
}
|
|
|
|
public unsafe void KphDuplicateObject(
|
|
int sourceProcessHandle,
|
|
int sourceHandle,
|
|
int targetProcessHandle,
|
|
int targetHandle,
|
|
int desiredAccess,
|
|
int handleAttributes,
|
|
int options
|
|
)
|
|
{
|
|
byte[] data = new byte[7 * sizeof(int)];
|
|
|
|
fixed (byte* dataPtr = data)
|
|
{
|
|
*(int*)(dataPtr + 0x0) = sourceProcessHandle;
|
|
*(int*)(dataPtr + 0x4) = sourceHandle;
|
|
*(int*)(dataPtr + 0x8) = targetProcessHandle;
|
|
*(int*)(dataPtr + 0xc) = targetHandle;
|
|
*(int*)(dataPtr + 0x10) = desiredAccess;
|
|
*(int*)(dataPtr + 0x14) = handleAttributes;
|
|
*(int*)(dataPtr + 0x18) = options;
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphDuplicateObject), data, null);
|
|
}
|
|
}
|
|
|
|
public unsafe void KphGetContextThread(Win32.ThreadHandle threadHandle, Win32.CONTEXT* context)
|
|
{
|
|
byte[] data = new byte[8];
|
|
|
|
Array.Copy(Misc.IntToBytes(threadHandle, Misc.Endianness.Little), 0, data, 0, 4);
|
|
Array.Copy(Misc.IntToBytes((int)context, Misc.Endianness.Little), 0, data, 4, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphGetContextThread), data, null);
|
|
}
|
|
|
|
public int KphGetThreadWin32Thread(Win32.ThreadHandle threadHandle)
|
|
{
|
|
byte[] inData = Misc.IntToBytes(threadHandle, Misc.Endianness.Little);
|
|
byte[] outData = new byte[4];
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphGetThreadWin32Thread), inData, outData);
|
|
|
|
return Misc.BytesToInt(outData, Misc.Endianness.Little);
|
|
}
|
|
|
|
public int KphOpenProcess(int pid, Win32.PROCESS_RIGHTS desiredAccess)
|
|
{
|
|
byte[] inData = new byte[8];
|
|
byte[] outData = new byte[4];
|
|
|
|
Array.Copy(Misc.IntToBytes(pid, Misc.Endianness.Little), 0, inData, 0, 4);
|
|
Array.Copy(Misc.UIntToBytes((uint)desiredAccess, Misc.Endianness.Little), 0, inData, 4, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphOpenProcess), inData, outData);
|
|
|
|
return Misc.BytesToInt(outData, Misc.Endianness.Little);
|
|
}
|
|
|
|
public int KphOpenProcessJob(Win32.ProcessHandle processHandle, Win32.JOB_OBJECT_RIGHTS desiredAccess)
|
|
{
|
|
byte[] inData = new byte[8];
|
|
byte[] outData = new byte[4];
|
|
|
|
Array.Copy(Misc.IntToBytes(processHandle, Misc.Endianness.Little), 0, inData, 0, 4);
|
|
Array.Copy(Misc.UIntToBytes((uint)desiredAccess, Misc.Endianness.Little), 0, inData, 4, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphOpenProcessJob), inData, outData);
|
|
|
|
return Misc.BytesToInt(outData, Misc.Endianness.Little);
|
|
}
|
|
|
|
public int KphOpenProcessToken(Win32.ProcessHandle processHandle, Win32.TOKEN_RIGHTS desiredAccess)
|
|
{
|
|
byte[] inData = new byte[8];
|
|
byte[] outData = new byte[4];
|
|
|
|
Array.Copy(Misc.IntToBytes(processHandle, Misc.Endianness.Little), 0, inData, 0, 4);
|
|
Array.Copy(Misc.UIntToBytes((uint)desiredAccess, Misc.Endianness.Little), 0, inData, 4, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphOpenProcessToken), inData, outData);
|
|
|
|
return Misc.BytesToInt(outData, Misc.Endianness.Little);
|
|
}
|
|
|
|
public int KphOpenThread(int tid, Win32.THREAD_RIGHTS desiredAccess)
|
|
{
|
|
byte[] inData = new byte[8];
|
|
byte[] outData = new byte[4];
|
|
|
|
Array.Copy(Misc.IntToBytes(tid, Misc.Endianness.Little), 0, inData, 0, 4);
|
|
Array.Copy(Misc.UIntToBytes((uint)desiredAccess, Misc.Endianness.Little), 0, inData, 4, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphOpenThread), inData, outData);
|
|
|
|
return Misc.BytesToInt(outData, Misc.Endianness.Little);
|
|
}
|
|
|
|
public unsafe void KphReadVirtualMemory(Win32.ProcessHandle processHandle, int baseAddress, byte[] buffer, int length, out int bytesRead)
|
|
{
|
|
fixed (byte* bufferPointer = buffer)
|
|
{
|
|
this.KphReadVirtualMemory(processHandle, baseAddress, bufferPointer, length, out bytesRead);
|
|
}
|
|
}
|
|
|
|
public unsafe void KphReadVirtualMemory(Win32.ProcessHandle processHandle, int baseAddress, void* buffer, int length, out int bytesRead)
|
|
{
|
|
byte[] data = new byte[0x15];
|
|
int returnLength;
|
|
|
|
Array.Copy(Misc.IntToBytes(processHandle, Misc.Endianness.Little), 0, data, 0x0, 4);
|
|
Array.Copy(Misc.IntToBytes(baseAddress, Misc.Endianness.Little), 0, data, 0x4, 4);
|
|
Array.Copy(Misc.IntToBytes((int)buffer, Misc.Endianness.Little), 0, data, 0x8, 4);
|
|
Array.Copy(Misc.IntToBytes(length, Misc.Endianness.Little), 0, data, 0xc, 4);
|
|
Array.Copy(Misc.IntToBytes((int)&returnLength, Misc.Endianness.Little), 0, data, 0x10, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphReadVirtualMemory), data, null);
|
|
bytesRead = returnLength;
|
|
}
|
|
|
|
public unsafe bool KphReadVirtualMemorySafe(Win32.ProcessHandle processHandle, int baseAddress, byte[] buffer, int length, out int bytesRead)
|
|
{
|
|
byte[] data = new byte[0x15];
|
|
int returnLength;
|
|
int br;
|
|
|
|
fixed (byte* bufferPointer = buffer)
|
|
{
|
|
Array.Copy(Misc.IntToBytes(processHandle, Misc.Endianness.Little), 0, data, 0x0, 4);
|
|
Array.Copy(Misc.IntToBytes(baseAddress, Misc.Endianness.Little), 0, data, 0x4, 4);
|
|
Array.Copy(Misc.IntToBytes((int)bufferPointer, Misc.Endianness.Little), 0, data, 0x8, 4);
|
|
Array.Copy(Misc.IntToBytes(length, Misc.Endianness.Little), 0, data, 0xc, 4);
|
|
Array.Copy(Misc.IntToBytes((int)&br, Misc.Endianness.Little), 0, data, 0x10, 4);
|
|
|
|
bool r = Win32.DeviceIoControl(_fileHandle, (int)CtlCode(Control.KphReadVirtualMemory), data, data.Length, null, 0, out returnLength, 0);
|
|
|
|
bytesRead = br;
|
|
|
|
return r;
|
|
}
|
|
}
|
|
|
|
public void KphResumeProcess(Win32.ProcessHandle processHandle)
|
|
{
|
|
_fileHandle.IoControl(CtlCode(Control.KphResumeProcess),
|
|
Misc.IntToBytes(processHandle, Misc.Endianness.Little), null);
|
|
}
|
|
|
|
public unsafe void KphSetContextThread(Win32.ThreadHandle threadHandle, Win32.CONTEXT* context)
|
|
{
|
|
byte[] data = new byte[8];
|
|
|
|
Array.Copy(Misc.IntToBytes(threadHandle, Misc.Endianness.Little), 0, data, 0, 4);
|
|
Array.Copy(Misc.IntToBytes((int)context, Misc.Endianness.Little), 0, data, 4, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphSetContextThread), data, null);
|
|
}
|
|
|
|
public void KphSuspendProcess(Win32.ProcessHandle processHandle)
|
|
{
|
|
_fileHandle.IoControl(CtlCode(Control.KphSuspendProcess),
|
|
Misc.IntToBytes(processHandle, Misc.Endianness.Little), null);
|
|
}
|
|
|
|
public void KphTerminateProcess(Win32.ProcessHandle processHandle, int exitStatus)
|
|
{
|
|
byte[] data = new byte[8];
|
|
|
|
Array.Copy(Misc.IntToBytes(processHandle, Misc.Endianness.Little), 0, data, 0, 4);
|
|
Array.Copy(Misc.IntToBytes(exitStatus, Misc.Endianness.Little), 0, data, 4, 4);
|
|
|
|
try
|
|
{
|
|
_fileHandle.IoControl(CtlCode(Control.KphTerminateProcess), data, null);
|
|
}
|
|
catch (WindowsException ex)
|
|
{
|
|
// STATUS_DISK_FULL means we tried to terminate ourself. Kernel-mode can't do it,
|
|
// so we do it now.
|
|
if (ex.ErrorCode == 112)
|
|
Win32.ExitProcess(exitStatus);
|
|
}
|
|
}
|
|
|
|
public unsafe void KphWriteVirtualMemory(Win32.ProcessHandle processHandle, int baseAddress, byte[] buffer, int length, out int bytesWritten)
|
|
{
|
|
byte[] data = new byte[0x14];
|
|
int returnLength;
|
|
|
|
fixed (byte* bufferPointer = buffer)
|
|
{
|
|
Array.Copy(Misc.IntToBytes(processHandle, Misc.Endianness.Little), 0, data, 0x0, 4);
|
|
Array.Copy(Misc.IntToBytes(baseAddress, Misc.Endianness.Little), 0, data, 0x4, 4);
|
|
Array.Copy(Misc.IntToBytes((int)bufferPointer, Misc.Endianness.Little), 0, data, 0x8, 4);
|
|
Array.Copy(Misc.IntToBytes(length, Misc.Endianness.Little), 0, data, 0xc, 4);
|
|
Array.Copy(Misc.IntToBytes((int)&returnLength, Misc.Endianness.Little), 0, data, 0x10, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.KphWriteVirtualMemory), data, null);
|
|
bytesWritten = returnLength;
|
|
}
|
|
}
|
|
|
|
public byte[] Read(int address, int length)
|
|
{
|
|
byte[] buffer = new byte[length];
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.Read), Misc.IntToBytes(address, Misc.Endianness.Little), buffer);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
public void SetProcessProtected(int pid, bool protecte)
|
|
{
|
|
byte[] data = new byte[5];
|
|
|
|
Array.Copy(Misc.IntToBytes(pid, Misc.Endianness.Little), 0, data, 0, 4);
|
|
data[4] = (byte)(protecte ? 1 : 0);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.SetProcessProtected), data, null);
|
|
}
|
|
|
|
public void SetProcessToken(int sourcePid, int targetPid)
|
|
{
|
|
byte[] data = new byte[8];
|
|
|
|
Array.Copy(Misc.IntToBytes(sourcePid, Misc.Endianness.Little), 0, data, 0, 4);
|
|
Array.Copy(Misc.IntToBytes(targetPid, Misc.Endianness.Little), 0, data, 4, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.SetProcessToken), data, null);
|
|
}
|
|
|
|
public int Write(int address, byte[] data)
|
|
{
|
|
byte[] newData = new byte[data.Length + 4];
|
|
|
|
Array.Copy(Misc.IntToBytes(address, Misc.Endianness.Little), newData, 4);
|
|
Array.Copy(data, 0, newData, 4, data.Length);
|
|
|
|
return _fileHandle.IoControl(CtlCode(Control.Write), newData, null);
|
|
}
|
|
|
|
public unsafe int ZwQueryObject(
|
|
Win32.ProcessHandle processHandle,
|
|
int handle,
|
|
Win32.OBJECT_INFORMATION_CLASS objectInformationClass,
|
|
IntPtr buffer,
|
|
int bufferLength,
|
|
out int returnLength,
|
|
out int baseAddress
|
|
)
|
|
{
|
|
byte[] inBuffer = new byte[12];
|
|
byte[] outBuffer = new byte[bufferLength + 12];
|
|
|
|
Array.Copy(Misc.IntToBytes(processHandle, Misc.Endianness.Little), 0, inBuffer, 0, 4);
|
|
Array.Copy(Misc.IntToBytes(handle, Misc.Endianness.Little), 0, inBuffer, 4, 4);
|
|
Array.Copy(Misc.IntToBytes((int)objectInformationClass, Misc.Endianness.Little), 0, inBuffer, 8, 4);
|
|
|
|
_fileHandle.IoControl(CtlCode(Control.ZwQueryObject), inBuffer, outBuffer);
|
|
|
|
fixed (byte* outBufferPtr = outBuffer)
|
|
{
|
|
int status;
|
|
|
|
status = *(int*)outBufferPtr;
|
|
returnLength = *(int*)(outBufferPtr + 4);
|
|
baseAddress = *(int*)(outBufferPtr + 8);
|
|
|
|
if (buffer != IntPtr.Zero)
|
|
Marshal.Copy(outBuffer, 12, buffer, bufferLength);
|
|
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
}
|