/* * 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 } }