/*
* Process Hacker -
* process handle
*
* Copyright (C) 2008-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 .
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using ProcessHacker.Native.Api;
using ProcessHacker.Native.Security;
namespace ProcessHacker.Native.Objects
{
///
/// Represents a handle to a Windows process.
///
/// The idea of a ProcessHandle class is
/// different to the class;
/// instead of opening the process with the right permissions every
/// time a query or set function is called, this lets the users control
/// when they want to open handles with certain permissions. This
/// means that handles can be cached (by the users).
public class ProcessHandle : Win32Handle, IWithToken
{
///
/// The callback for enumerating process memory regions.
///
/// The basic information for the memory region.
/// Return true to continue enumerating; return false to stop.
public delegate bool EnumMemoryDelegate(MemoryBasicInformation info);
///
/// The callback for enumerating process modules.
///
/// The module information.
/// Return true to continue enumerating; return false to stop.
public delegate bool EnumModulesDelegate(ProcessModule module);
public static ProcessHandle Create(SectionHandle sectionHandle, ProcessAccess access, ProcessHandle parent, bool inheritHandles)
{
int status;
IntPtr process;
if ((status = Win32.NtCreateProcess(
out process,
access,
IntPtr.Zero,
parent,
inheritHandles,
sectionHandle,
IntPtr.Zero,
IntPtr.Zero)) < 0)
Win32.ThrowLastError(status);
return new ProcessHandle(process, true);
}
public static ProcessHandle Create(string fileName, ProcessAccess access, bool inheritHandles)
{
using (var fhandle = new FileHandle(
fileName,
(FileAccess)StandardRights.Synchronize | FileAccess.Execute | FileAccess.ReadData,
FileShareMode.Delete | FileShareMode.Read, FileCreationDisposition.OpenAlways))
{
using (var shandle = new SectionHandle(
SectionAccess.All, fhandle,
SectionAttributes.Image, MemoryProtection.Execute))
{
return Create(shandle, access, ProcessHandle.GetCurrent(), inheritHandles);
}
}
}
///
/// Creates a process handle using an existing handle.
/// The handle will not be closed automatically.
///
/// The handle value.
/// The process handle.
public static ProcessHandle FromHandle(IntPtr handle)
{
return new ProcessHandle(handle, false);
}
///
/// Gets a handle to the current process.
///
/// A process handle.
public static ProcessHandle GetCurrent()
{
return new ProcessHandle(new IntPtr(-1), false);
}
internal ProcessHandle(IntPtr handle, bool owned)
: base(handle, owned)
{ }
///
/// Creates a new process handle.
///
/// The ID of the process to open.
public ProcessHandle(int pid)
: this(pid, ProcessAccess.All)
{ }
///
/// Creates a new process handle.
///
/// The ID of the process to open.
/// The desired access to the process.
public ProcessHandle(int pid, ProcessAccess access)
{
// If we have KPH, use it.
if (KProcessHacker.Instance != null)
{
try
{
this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcess(pid, access));
}
catch (WindowsException)
{
// This would only happen if the process is DRM-protected or if
// some part of ObReferenceObjectByHandle is hooked. We can
// open the process with SYNCHRONIZE access and set the granted access
// using KPH.
this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcess(pid,
(ProcessAccess)StandardRights.Synchronize));
KProcessHacker.Instance.KphSetHandleGrantedAccess(this.Handle, (int)access);
}
}
else
{
this.Handle = Win32.OpenProcess(access, false, pid);
}
if (this.Handle == IntPtr.Zero)
Win32.ThrowLastError();
}
///
/// Allocates a memory region in the process' virtual memory.
///
/// The base address of the region.
/// The size of the region.
/// The protection of the region.
/// The base address of the allocated pages.
public IntPtr AllocMemory(IntPtr address, int size, MemoryProtection protection)
{
IntPtr newAddress;
if ((newAddress = Win32.VirtualAllocEx(this, address, size, MemoryState.Commit, protection))
== IntPtr.Zero)
Win32.ThrowLastError();
return newAddress;
}
///
/// Allocates a memory region in the process' virtual memory. The function decides where
/// to allocate the memory.
///
/// The size of the region.
/// The protection of the region.
/// The base address of the allocated pages.
public IntPtr AllocMemory(int size, MemoryProtection protection)
{
return this.AllocMemory(IntPtr.Zero, size, protection);
}
///
/// Assigns the process to a job object. The job handle must have the
/// JOB_OBJECT_ASSIGN_PROCESS permission and the process handle must have
/// the PROCESS_SET_QUOTA and PROCESS_TERMINATE permissions.
///
/// The job object to assign the process to.
public void AssignToJobObject(JobObjectHandle job)
{
if (!Win32.AssignProcessToJobObject(job, this))
Win32.ThrowLastError();
}
///
/// Creates a remote thread in the process.
///
/// The address at which to begin execution (e.g. a function). The
/// function must be accessible from the remote process; that is, it must be in its
/// virtual address space, either copied using AllocMemory or loaded as module using
/// LoadLibrary.
///
/// The parameter to pass to the function.
/// The ID of the new thread.
public int CreateThread(IntPtr startAddress, IntPtr parameter)
{
int threadId;
if (!Win32.CreateRemoteThread(this, IntPtr.Zero, 0, startAddress, parameter, 0, out threadId))
Win32.ThrowLastError();
return threadId;
}
///
/// Creates a remote thread in the process, returning a handle to the new thread.
///
/// The address at which to begin execution (e.g. a function). The
/// function must be accessible from the remote process; that is, it must be in its
/// virtual address space, either copied using AllocMemory or loaded as module using
/// LoadLibrary.
///
/// The parameter to pass to the function.
/// The desired access to the new thread.
/// A handle to the new thread.
public ThreadHandle CreateThread(IntPtr startAddress, IntPtr parameter, ThreadAccess access)
{
return new ThreadHandle(this.CreateThread(startAddress, parameter), access);
}
///
/// Debugs the process with the specified debug object. This requires the
/// PROCESS_SUSPEND_RESUME permission.
///
/// A handle to a debug object.
public void Debug(DebugObjectHandle debugObjectHandle)
{
int status;
if ((status = Win32.NtDebugActiveProcess(this, debugObjectHandle)) < 0)
Win32.ThrowLastError(status);
}
///
/// Removes as many pages as possible from the process' working set. This requires the
/// PROCESS_QUERY_INFORMATION and PROCESS_SET_INFORMATION permissions.
///
public void EmptyWorkingSet()
{
if (!Win32.EmptyWorkingSet(this))
Win32.ThrowLastError();
}
///
/// Enumerates the memory regions of the process.
///
/// The callback for the enumeration.
public void EnumMemory(EnumMemoryDelegate enumMemoryCallback)
{
IntPtr address = IntPtr.Zero;
MemoryBasicInformation mbi = new MemoryBasicInformation();
int mbiSize = Marshal.SizeOf(mbi);
while (Win32.VirtualQueryEx(this, address, out mbi, mbiSize) != 0)
{
if (!enumMemoryCallback(mbi))
break;
address = address.Increment(mbi.RegionSize);
//address += mbi.RegionSize;
}
}
///
/// Enumerates the modules loaded by the process.
///
/// The callback for the enumeration.
public void EnumModules(EnumModulesDelegate enumModulesCallback)
{
this.EnumModulesNative(enumModulesCallback);
}
private void EnumModulesApi(EnumModulesDelegate enumModulesCallback)
{
IntPtr[] moduleHandles;
int requiredSize;
Win32.EnumProcessModules(this, null, 0, out requiredSize);
moduleHandles = new IntPtr[requiredSize / 4];
if (!Win32.EnumProcessModules(this, moduleHandles, requiredSize, out requiredSize))
Win32.ThrowLastError();
for (int i = 0; i < moduleHandles.Length; i++)
{
ModuleInfo moduleInfo = new ModuleInfo();
StringBuilder baseName = new StringBuilder(0x400);
StringBuilder fileName = new StringBuilder(0x400);
if (!Win32.GetModuleInformation(this, moduleHandles[i], moduleInfo, Marshal.SizeOf(moduleInfo)))
Win32.ThrowLastError();
if (Win32.GetModuleBaseName(this, moduleHandles[i], baseName, baseName.Capacity * 2) == 0)
Win32.ThrowLastError();
if (Win32.GetModuleFileNameEx(this, moduleHandles[i], fileName, fileName.Capacity * 2) == 0)
Win32.ThrowLastError();
if (!enumModulesCallback(new ProcessModule(
moduleInfo.BaseOfDll, moduleInfo.SizeOfImage, moduleInfo.EntryPoint,
baseName.ToString(), FileUtils.FixPath(fileName.ToString())
)))
break;
}
}
private unsafe void EnumModulesNative(EnumModulesDelegate enumModulesCallback)
{
byte* buffer = stackalloc byte[4];
this.ReadMemory(this.GetBasicInformation().PebBaseAddress.Increment(0xc), buffer, 4);
IntPtr loaderData = new IntPtr(*(int*)buffer);
PebLdrData* data = stackalloc PebLdrData[1];
this.ReadMemory(loaderData, data, Marshal.SizeOf(typeof(PebLdrData)));
if (data->Initialized == 0)
throw new Exception("Loader data is not initialized.");
IntPtr currentLink = data->InLoadOrderModuleList.Flink;
IntPtr startLink = currentLink;
LdrModule* currentModule = stackalloc LdrModule[1];
int i = 0;
while (currentLink != IntPtr.Zero)
{
// Stop when we have reached the beginning of the linked list
if (i > 0 && currentLink == startLink)
break;
// Safety guard
if (i > 0x800)
break;
this.ReadMemory(currentLink, currentModule, Marshal.SizeOf(typeof(LdrModule)));
if (currentModule->BaseAddress != IntPtr.Zero)
{
string baseDllName = null;
string fullDllName = null;
try
{
baseDllName = Utils.ReadUnicodeString(this, currentModule->BaseDllName).TrimEnd('\0');
}
catch
{ }
try
{
fullDllName =
FileUtils.FixPath(Utils.ReadUnicodeString(this, currentModule->FullDllName).TrimEnd('\0'));
}
catch
{ }
if (!enumModulesCallback(new ProcessModule(
currentModule->BaseAddress,
currentModule->SizeOfImage,
currentModule->EntryPoint,
baseDllName,
fullDllName
)))
break;
}
currentLink = currentModule->InLoadOrderModuleList.Flink;
i++;
}
}
///
/// Frees a memory region in the process' virtual memory.
///
/// The address of the region to free.
/// The size to free.
/// Specifies whether or not to only
/// reserve the memory instead of freeing it.
public void FreeMemory(IntPtr address, int size, bool reserveOnly)
{
// size needs to be 0 if we're freeing
if (!reserveOnly)
size = 0;
if (!Win32.VirtualFreeEx(this, address, size,
reserveOnly ? MemoryState.Decommit : MemoryState.Release))
Win32.ThrowLastError();
}
///
/// Gets the base priority of the process.
///
public int GetBasePriority()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessBasePriority);
}
///
/// Gets the process' basic information through the undocumented Native API function
/// NtQueryInformationProcess. This function requires the PROCESS_QUERY_LIMITED_INFORMATION
/// permission.
///
/// A PROCESS_BASIC_INFORMATION structure.
public ProcessBasicInformation GetBasicInformation()
{
int status;
ProcessBasicInformation pbi;
int retLen;
if ((status = Win32.NtQueryInformationProcess(this, ProcessInformationClass.ProcessBasicInformation,
out pbi, Marshal.SizeOf(typeof(ProcessBasicInformation)), out retLen)) < 0)
Win32.ThrowLastError(status);
return pbi;
}
///
/// Gets the command line used to start the process. This requires
/// the PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ permissions.
///
/// A string.
public string GetCommandLine()
{
return this.GetPebString(PebOffset.CommandLine);
}
///
/// Gets the process' cookie (a random value).
///
public int GetCookie()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessCookie);
}
///
/// Gets the creation time of the process.
///
public FileTime GetCreateTime()
{
return this.GetTimes()[0];
}
///
/// Gets the number of processor cycles consumed by the process' threads.
///
public ulong GetCycleTime()
{
ulong cycles;
if (!Win32.QueryProcessCycleTime(this, out cycles))
Win32.ThrowLastError();
return cycles;
}
///
/// Gets the process' DEP policy.
///
/// A DEPStatus enum.
public DepStatus GetDepStatus()
{
int status;
MemExecuteOptions options;
int retLength;
if ((status = Win32.NtQueryInformationProcess(this, ProcessInformationClass.ProcessExecuteFlags,
out options, 4, out retLength)) < 0)
Win32.ThrowLastError(status);
DepStatus depStatus = 0;
// Check if execution of data pages is enabled.
if ((options & MemExecuteOptions.ExecuteEnable) != 0)
return 0;
// Check if execution of data pages is disabled.
if ((options & MemExecuteOptions.ExecuteDisable) != 0)
depStatus = DepStatus.Enabled;
// ExecuteDisable and ExecuteEnable are both disabled in OptOut mode.
else if ((options & MemExecuteOptions.ExecuteDisable) == 0 &&
(options & MemExecuteOptions.ExecuteEnable) == 0)
depStatus = DepStatus.Enabled;
if ((options & MemExecuteOptions.DisableThunkEmulation) != 0)
depStatus |= DepStatus.AtlThunkEmulationDisabled;
if ((options & MemExecuteOptions.Permanent) != 0)
depStatus |= DepStatus.Permanent;
return depStatus;
}
///
/// Gets the process' environment variables. This requires the
/// PROCESS_QUERY_INFORMATION and PROCESS_VM_READ permissions.
///
/// A dictionary of variables.
public unsafe IDictionary GetEnvironmentVariables()
{
IntPtr pebBaseAddress = this.GetBasicInformation().PebBaseAddress;
byte* buffer = stackalloc byte[IntPtr.Size];
this.ReadMemory(pebBaseAddress.Increment(0x10), buffer, IntPtr.Size);
IntPtr processParameters = *(IntPtr*)buffer;
/*
* RTL_USER_PROCESS_PARAMETERS
* off field
* +00 ULONG MaximumLength
* +04 ULONG Length
* +08 ULONG Flags
* +0c ULONG DebugFlags
* +10 PVOID ConsoleHandle
* +14 ULONG ConsoleFlags
* +18 HANDLE StdInputHandle
* +1c HANDLE StdOutputHandle
* +20 HANDLE StdErrorHandle
* +24 UNICODE_STRING CurrentDirectoryPath
* +2c HANDLE CurrentDirectoryHandle
* +30 UNICODE_STRING DllPath
* +38 UNICODE_STRING ImagePathName
* +40 UNICODE_STRING CommandLine
* +48 PVOID Environment
*/
this.ReadMemory(processParameters.Increment(0x48), buffer, IntPtr.Size);
IntPtr envBase = *(IntPtr*)buffer;
int length = 0;
{
MemoryBasicInformation mbi = this.QueryMemory(envBase);
if (mbi.Protect == MemoryProtection.NoAccess)
throw new WindowsException();
length = mbi.RegionSize - envBase.Decrement(mbi.BaseAddress).ToInt32();
}
// Now we read in the entire region of memory
// And yes, some memory is wasted.
byte[] memory = this.ReadMemory(envBase, length);
/* The environment variables block is a series of Unicode strings separated by
* two null bytes. The entire block is terminated by four null bytes.
*/
Dictionary vars = new Dictionary();
StringBuilder currentVariable = new StringBuilder();
int i = 0;
while (true)
{
char currentChar =
UnicodeEncoding.Unicode.GetChars(memory, i, 2)[0];
i += 2;
if (currentChar == '\0')
{
// Two nulls in a row, the env. block is finished.
if (currentVariable.Length == 0)
break;
string[] s = currentVariable.ToString().Split(new char[] { '=' }, 2);
if (!vars.ContainsKey(s[0]) && s.Length > 1)
vars.Add(s[0], s[1]);
currentVariable = new StringBuilder();
}
else
{
currentVariable.Append(currentChar);
}
}
return vars;
}
///
/// Gets the process' exit code.
///
/// A number.
public int GetExitCode()
{
int exitCode;
if (!Win32.GetExitCodeProcess(this, out exitCode))
Win32.ThrowLastError();
return exitCode;
}
///
/// Gets the exit time of the process.
///
///
public FileTime GetExitTime()
{
return this.GetTimes()[1];
}
///
/// Gets a GUI handle count.
///
/// If true, returns the number of USER handles. Otherwise, returns
/// the number of GDI handles.
/// A handle count.
public int GetGuiResources(bool userObjects)
{
return Win32.GetGuiResources(this, userObjects ? 1 : 0);
}
///
/// Gets the number of handles opened by the process.
///
public int GetHandleCount()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessHandleCount);
}
///
/// Gets the file name of the process' image. This requires the
/// PROCESS_QUERY_LIMITED_INFORMATION permission.
///
/// A file name, in DOS (normal) format.
public string GetImageFileName()
{
var sb = new StringBuilder(1024);
int len = 1024;
if (!Win32.QueryFullProcessImageName(this, false, sb, ref len))
Win32.ThrowLastError();
return FileUtils.FixPath(sb.ToString(0, len));
}
private int GetInformationInt32(ProcessInformationClass infoClass)
{
int status;
int value;
int retLength;
if ((status = Win32.NtQueryInformationProcess(
this, infoClass, out value, sizeof(int), out retLength)) < 0)
Win32.ThrowLastError(status);
return value;
}
///
/// Gets the process' I/O priority, ranging from 0-7.
///
///
public int GetIoPriority()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessIoPriority);
}
///
/// Opens the job associated with the process.
///
/// A job handle.
public JobObjectHandle GetJob(JobObjectAccess access)
{
return new JobObjectHandle(this, access);
}
///
/// Gets the main module of the process. This requires the
/// PROCESS_QUERY_INFORMATION and PROCESS_VM_READ permissions.
///
/// A ProcessModule.
public ProcessModule GetMainModule()
{
ProcessModule mainModule = null;
this.EnumModules((module) =>
{
mainModule = module;
return false;
});
return mainModule;
}
public string GetMappedFileName(IntPtr address)
{
StringBuilder sb = new StringBuilder(0x400);
int length = Win32.GetMappedFileName(this, address, sb, sb.Capacity);
if (length > 0)
{
string fileName = sb.ToString(0, length);
if (fileName.StartsWith("\\"))
fileName = FileUtils.DeviceFileNameToDos(fileName);
System.IO.FileInfo fi = new System.IO.FileInfo(fileName);
return fi.ToString();
}
return null;
}
///
/// Gets the modules loaded by the process. This requires the
/// PROCESS_QUERY_INFORMATION and PROCESS_VM_READ permissions.
///
/// An array of ProcessModule objects.
public ProcessModule[] GetModules()
{
List modules = new List();
this.EnumModules((module) =>
{
modules.Add(module);
return true;
});
return modules.ToArray();
}
///
/// Gets the file name of the process' image, in device name format. This
/// requires the PROCESS_QUERY_LIMITED_INFORMATION permission.
///
/// A file name, in device/native format.
public string GetNativeImageFileName()
{
int status;
int retLen;
Win32.NtQueryInformationProcess(this, ProcessInformationClass.ProcessImageFileName,
IntPtr.Zero, 0, out retLen);
using (MemoryAlloc data = new MemoryAlloc(retLen))
{
if ((status = Win32.NtQueryInformationProcess(this, ProcessInformationClass.ProcessImageFileName,
data, retLen, out retLen)) < 0)
Win32.ThrowLastError(status);
UnicodeString str = data.ReadStruct();
return Utils.ReadUnicodeString(str);
}
}
///
/// Opens the next linked process.
///
/// The desired access to the next process.
/// A process handle.
public ProcessHandle GetNextProcess(ProcessAccess access)
{
int status;
IntPtr handle;
if ((status = Win32.NtGetNextProcess(
this,
access,
0,
0,
out handle
)) < 0)
Win32.ThrowLastError(status);
return new ProcessHandle(handle, true);
}
///
/// Opens the next linked thread belonging to the process.
///
/// A thread handle. You may specify null.
/// The desired access to the next thread.
/// A thread handle.
public ThreadHandle GetNextThread(ThreadHandle threadHandle, ThreadAccess access)
{
int status;
IntPtr handle;
if ((status = Win32.NtGetNextThread(
this,
threadHandle != null ? threadHandle : IntPtr.Zero,
access,
0,
0,
out handle
)) < 0)
Win32.ThrowLastError(status);
return new ThreadHandle(handle, true);
}
///
/// Gets the process' page priority, ranging from 0-7.
///
public int GetPagePriority()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessPagePriority);
}
///
/// Gets the process' parent's process ID. This requires
/// the PROCESS_QUERY_LIMITED_INFORMATION permission.
///
/// The process ID.
public int GetParentPid()
{
return this.GetBasicInformation().InheritedFromUniqueProcessId;
}
///
/// Reads a UNICODE_STRING from the process' process environment block.
///
/// The offset to the UNICODE_STRING structure.
/// A string.
public unsafe string GetPebString(PebOffset offset)
{
byte* buffer = stackalloc byte[IntPtr.Size];
IntPtr pebBaseAddress = this.GetBasicInformation().PebBaseAddress;
/* read address of parameter information block
*
* PEB
* off field
* +00 BOOLEAN InheritedAddressSpace;
* +01 BOOLEAN ReadImageFileExecOptions;
* +02 BOOLEAN BeingDebugged;
* +03 BOOLEAN Spare;
* +04 HANDLE Mutant;
* +08 PVOID ImageBaseAddress;
* +0c PVOID LoaderData;
* +10 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
*/
this.ReadMemory(pebBaseAddress.Increment(0x10), buffer, IntPtr.Size);
IntPtr processParameters = *(IntPtr*)buffer;
// Read length (in bytes) of string. The offset of the UNICODE_STRING structure is
// specified in the enum.
//
// UNICODE_STRING
// off field
// +00 USHORT Length;
// +02 USHORT MaximumLength;
// +04 PWSTR Buffer;
this.ReadMemory(processParameters.Increment((int)offset), buffer, 2);
ushort stringLength = *(ushort*)buffer;
byte[] stringData = new byte[stringLength];
// read address of string
this.ReadMemory(processParameters.Increment((int)offset + 0x4), buffer, 4);
IntPtr stringAddr = *(IntPtr*)buffer;
// read string and decode it
return UnicodeEncoding.Unicode.GetString(
this.ReadMemory(stringAddr, stringLength)).TrimEnd('\0');
}
///
/// Gets the process' priority class.
///
/// A ProcessPriorityClass enum.
public ProcessPriorityClass GetPriorityClass()
{
int priority = Win32.GetPriorityClass(this);
if (priority == 0)
Win32.ThrowLastError();
return (ProcessPriorityClass)priority;
}
///
/// Gets the process' unique identifier.
///
public int GetProcessId()
{
return this.GetBasicInformation().UniqueProcessId;
}
///
/// Gets the process' session ID.
///
public int GetSessionId()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessSessionInformation);
}
public FileTime[] GetTimes()
{
FileTime[] times = new FileTime[4];
if (!Win32.GetProcessTimes(this, out times[0], out times[1], out times[2], out times[3]))
Win32.ThrowLastError();
return times;
}
///
/// Forces the process to load the specified library.
///
/// The path to the library.
public void InjectDll(string path)
{
this.InjectDll(path, 0xffffffff);
}
///
/// Forces the process to load the specified library.
///
/// The path to the library.
/// The timeout, in seconds, for the process to load the library.
public void InjectDll(string path, uint timeout)
{
IntPtr stringPage = this.AllocMemory(path.Length * 2 + 2, MemoryProtection.ExecuteReadWrite);
this.WriteMemory(stringPage, UnicodeEncoding.Unicode.GetBytes(path));
this.CreateThread(Win32.GetProcAddress(Win32.GetModuleHandle("kernel32.dll"), "LoadLibraryW"),
stringPage, ThreadAccess.All).Wait(timeout);
this.FreeMemory(stringPage, path.Length * 2 + 2, false);
}
///
/// Gets whether the process is currently being debugged. This requires
/// the PROCESS_QUERY_INFORMATION permission.
///
public bool IsBeingDebugged()
{
bool debugged = false;
if (!Win32.CheckRemoteDebuggerPresent(this, ref debugged))
Win32.ThrowLastError();
return debugged;
}
///
/// Gets whether the process is being debugged.
///
public bool IsBeingDebuggedNative()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessDebugFlags) != 0;
}
///
/// Gets whether the system will crash upon the process being terminated.
///
public bool IsCritical()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessBreakOnTermination) != 0;
}
///
/// Determines whether the process is running in a job.
///
/// A boolean.
public bool IsInJob()
{
bool result;
if (!Win32.IsProcessInJob(this, IntPtr.Zero, out result))
Win32.ThrowLastError();
return result;
}
///
/// Determines whether the process is running in the specified job.
///
/// The job object to check.
/// A boolean.
public bool IsInJob(JobObjectHandle jobObjectHandle)
{
bool result;
if (!Win32.IsProcessInJob(this, jobObjectHandle, out result))
Win32.ThrowLastError();
return result;
}
///
/// Gets whether the process is a NTVDM process.
///
public bool IsNtVdmProcess()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessWx86Information) != 0;
}
///
/// Gets whether the process has priority boost enabled.
///
public bool IsPriorityBoostEnabled()
{
return this.GetInformationInt32(ProcessInformationClass.ProcessPriorityBoost) == 0;
}
///
/// Sets the protection for a page in the process.
///
/// The address to modify.
/// The number of bytes to modify.
/// The new memory protection.
/// The old memory protection.
public MemoryProtection ProtectMemory(IntPtr address, int size, MemoryProtection protection)
{
MemoryProtection oldProtection;
if (!Win32.VirtualProtectEx(this,address, size, protection, out oldProtection))
Win32.ThrowLastError();
return oldProtection;
}
///
/// Gets information about the memory region starting at the specified address.
///
/// The address to query.
/// A MEMORY_BASIC_INFORMATION structure.
public MemoryBasicInformation QueryMemory(IntPtr address)
{
MemoryBasicInformation mbi = new MemoryBasicInformation();
if (Win32.VirtualQueryEx(this, address, out mbi, Marshal.SizeOf(mbi)) == 0)
Win32.ThrowLastError();
return mbi;
}
///
/// Reads data from the process' virtual memory.
///
/// The offset at which to begin reading.
/// The length, in bytes, to read.
/// An array of bytes
public byte[] ReadMemory(IntPtr offset, int length)
{
byte[] buffer = new byte[length];
this.ReadMemory(offset, buffer, length);
return buffer;
}
public unsafe int ReadMemory(IntPtr offset, byte[] buffer, int length)
{
fixed (byte* bufferPtr = buffer)
return this.ReadMemory(offset, bufferPtr, length);
}
public unsafe int ReadMemory(IntPtr offset, void* buffer, int length)
{
int readLen;
if (KProcessHacker.Instance != null)
{
KProcessHacker.Instance.KphReadVirtualMemory(this, offset.ToInt32(), buffer, length, out readLen);
}
else
{
if (!Win32.ReadProcessMemory(this, offset, buffer, length, out readLen))
Win32.ThrowLastError();
}
return readLen;
}
///
/// Stops debugging the process attached to the specified debug object.
///
/// The debug object which was used to debug the process.
public void RemoveDebug(DebugObjectHandle debugObjectHandle)
{
int status;
if ((status = Win32.NtRemoveProcessDebug(this, debugObjectHandle)) < 0)
Win32.ThrowLastError(status);
}
///
/// Resumes the process. This requires the PROCESS_SUSPEND_RESUME permission.
///
public void Resume()
{
if (KProcessHacker.Instance != null && OSVersion.HasPsSuspendResumeProcess)
{
KProcessHacker.Instance.KphResumeProcess(this);
}
else
{
int status;
if ((status = Win32.NtResumeProcess(this)) < 0)
Win32.ThrowLastError(status);
}
}
public unsafe void SetModuleReferenceCount(IntPtr baseAddress, ushort count)
{
byte* buffer = stackalloc byte[IntPtr.Size];
this.ReadMemory(this.GetBasicInformation().PebBaseAddress.Increment(0xc), buffer, IntPtr.Size);
IntPtr loaderData = *(IntPtr*)buffer;
PebLdrData* data = stackalloc PebLdrData[1];
this.ReadMemory(loaderData, data, Marshal.SizeOf(typeof(PebLdrData)));
if (data->Initialized == 0)
throw new Exception("Loader data is not initialized.");
List modules = new List();
IntPtr currentLink = data->InLoadOrderModuleList.Flink;
IntPtr startLink = currentLink;
LdrModule* currentModule = stackalloc LdrModule[1];
int i = 0;
while (currentLink != IntPtr.Zero)
{
if (modules.Count > 0 && currentLink == startLink)
break;
if (i > 0x800)
break;
this.ReadMemory(currentLink, currentModule, Marshal.SizeOf(typeof(LdrModule)));
if (currentModule->BaseAddress == baseAddress)
{
this.WriteMemory(currentLink.Increment(0x38), &count, 2);
break;
}
currentLink = currentModule->InLoadOrderModuleList.Flink;
i++;
}
}
///
/// Sets the process' priority class.
///
/// The process' priority.
public void SetPriorityClass(ProcessPriorityClass priority)
{
if (!Win32.SetPriorityClass(this, (int)priority))
Win32.ThrowLastError();
}
///
/// Suspends the process. This requires the PROCESS_SUSPEND_RESUME permission.
///
public void Suspend()
{
if (KProcessHacker.Instance != null && OSVersion.HasPsSuspendResumeProcess)
{
KProcessHacker.Instance.KphSuspendProcess(this);
}
else
{
int status;
if ((status = Win32.NtSuspendProcess(this)) < 0)
Win32.ThrowLastError(status);
}
}
///
/// Terminates the process. This requires the PROCESS_TERMINATE permission.
///
public void Terminate()
{
this.Terminate(0);
}
///
/// Terminates the process, specifying the exit code. This requires the
/// PROCESS_TERMINATE permission.
///
/// The exit code.
public void Terminate(int ExitCode)
{
if (KProcessHacker.Instance != null)
{
KProcessHacker.Instance.KphTerminateProcess(this, ExitCode);
}
else
{
if (!Win32.TerminateProcess(this, ExitCode))
Win32.ThrowLastError();
}
}
///
/// Writes data to the process' virtual memory.
///
/// The offset at which to begin writing.
/// The data to write.
/// The length, in bytes, that was written.
public unsafe int WriteMemory(IntPtr offset, byte[] data)
{
fixed (byte* dataPtr = data)
{
return WriteMemory(offset, dataPtr, data.Length);
}
}
///
/// Writes data to the process' virtual memory.
///
/// The offset at which to begin writing.
/// The data to write.
/// The length to be written.
/// The length, in bytes, that was written.
public unsafe int WriteMemory(IntPtr offset, void* data, int length)
{
int writtenLen;
if (KProcessHacker.Instance != null)
{
KProcessHacker.Instance.KphWriteVirtualMemory(this, offset.ToInt32(), data, length, out writtenLen);
}
else
{
if (!Win32.WriteProcessMemory(this, offset, data, length, out writtenLen))
Win32.ThrowLastError();
}
return writtenLen;
}
///
/// Opens and returns a handle to the process' token. This requires the
/// PROCESS_QUERY_LIMITED_INFORMATION permission.
///
/// A handle to the process' token.
public TokenHandle GetToken()
{
return GetToken(TokenAccess.All);
}
///
/// Opens and returns a handle to the process' token. This requires the
/// PROCESS_QUERY_LIMITED_INFORMATION permission.
///
/// The desired access to the token.
/// A handle to the process' token.
public TokenHandle GetToken(TokenAccess access)
{
return new TokenHandle(this, access);
}
}
public class ProcessModule
{
public ProcessModule(IntPtr baseAddress, int size, IntPtr entryPoint, string baseName, string fileName)
{
this.BaseAddress = baseAddress;
this.Size = size;
this.EntryPoint = entryPoint;
this.BaseName = baseName;
this.FileName = fileName;
}
public IntPtr BaseAddress { get; private set; }
public int Size { get; private set; }
public IntPtr EntryPoint { get; private set; }
public string BaseName { get; private set; }
public string FileName { get; private set; }
}
///
/// Specifies the DEP status of a process.
///
[Flags]
public enum DepStatus
{
///
/// DEP is enabled.
///
Enabled = 0x1,
///
/// DEP is permanently enabled or disabled and cannot
/// be enabled or disabled.
///
Permanent = 0x2,
///
/// DEP is enabled with DEP-ATL thunk emulation disabled.
///
AtlThunkEmulationDisabled = 0x4
}
///
/// Specifies an offset in a process' process environment block (PEB).
///
public enum PebOffset
{
///
/// The current directory of the process. This may, as the name
/// implies, change very often.
///
CurrentDirectoryPath = 0x24,
///
/// A copy of the PATH environment variable for the process.
///
DllPath = 0x30,
///
/// The image file name, in kernel format (e.g. \\?\C:\...,
/// \SystemRoot\..., \Device\Harddisk1\...).
///
ImagePathName = 0x38,
///
/// The command used to start the program, including arguments.
///
CommandLine = 0x40,
///
/// Usually blank.
///
WindowTitle = 0x70,
///
/// For interactive programs, contains the window station and
/// desktop name of the first thread that was started, e.g.
/// WinSta0\Default.
///
DesktopName = 0x78,
///
/// Usually blank.
///
ShellInfo = 0x80,
///
/// Usually blank.
///
RuntimeData = 0x88
}
}