/* * Process Hacker * * Copyright (C) 2008 wj32 * * This program 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. * * This program 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 this program. If not, see . */ using System; using System.Runtime.InteropServices; namespace ProcessHacker { public partial class Win32 { /// /// Represents a handle to a Windows process. /// public class ProcessHandle : Win32Handle, IWithToken { /// /// Specifies an offset in a process' process environment block (PEB). /// public enum PEBOffset { CurrentDirectoryPath = 0x24, DllPath = 0x30, ImagePathName = 0x38, CommandLine = 0x40, WindowTitle = 0x70, DesktopName = 0x78, ShellInfo = 0x80, RuntimeData = 0x88 } [Flags] public enum DEPStatus { Enabled = 0x1, Permanent, ATLThunkEmulationDisabled } /// /// 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(int Handle) { return new ProcessHandle(Handle, false); } internal ProcessHandle(int Handle, bool Owned) : base(Handle, Owned) { } /// /// Creates a new process handle. /// /// The ID of the process to open. public ProcessHandle(int PID) : this(PID, PROCESS_RIGHTS.PROCESS_ALL_ACCESS) { } /// /// Creates a new process handle. /// /// The ID of the process to open. /// The desired access to the process. public ProcessHandle(int PID, PROCESS_RIGHTS access) { this.Handle = OpenProcess(access, 0, PID); if (this.Handle == 0) throw new Exception(GetLastErrorMessage()); } /// /// Creates a remote thread in the process. /// /// The address at which to begin execution (e.g. a function). /// The parameter to pass to the function. /// The ID of the new thread. public int CreateThread(int startAddress, int parameter) { int threadId; if (!CreateRemoteThread(this, 0, 0, startAddress, parameter, 0, out threadId)) throw new Exception(GetLastErrorMessage()); return threadId; } /// /// Gets the process' basic information through the undocumented Native API function /// ZwQueryInformationProcess. This function requires the PROCESS_QUERY_LIMITED_INFORMATION /// permission. /// /// A PROCESS_BASIC_INFORMATION structure. public PROCESS_BASIC_INFORMATION GetBasicInformation() { PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION(); int retLen; if (ZwQueryInformationProcess(this, PROCESS_INFORMATION_CLASS.ProcessBasicInformation, ref pbi, Marshal.SizeOf(pbi), out retLen) != 0) throw new Exception(GetLastErrorMessage()); 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' DEP policy. /// /// A DEPStatus enum. public DEPStatus GetDEPStatus() { DEPFLAGS flags; int perm; if (!GetProcessDEPPolicy(this, out flags, out perm)) throw new Exception(GetLastErrorMessage()); return ((flags & DEPFLAGS.PROCESS_DEP_ENABLE) != 0 ? DEPStatus.Enabled : 0) | ((flags & DEPFLAGS.PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION) != 0 ? (DEPStatus.Enabled | DEPStatus.ATLThunkEmulationDisabled) : 0) | ((perm != 0) ? DEPStatus.Permanent : 0); } /// /// Gets the file name of the process' image. This requires /// the PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ permissions. /// /// A file name, in kernel file name format. public string GetImageFileName() { return this.GetPEBString(PEBOffset.ImagePathName); } /// /// 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 string GetPEBString(PEBOffset offset) { int readLen; int pebBaseAddress = 0x7ffd7000; try { pebBaseAddress = this.GetBasicInformation().PebBaseAddress; } catch { } byte[] data2 = new byte[4]; // read address of parameter information block if (!ReadProcessMemory(this, pebBaseAddress + 16, data2, 4, out readLen)) throw new Exception(GetLastErrorMessage()); int paramInfoAddrI = Misc.BytesToInt(data2, Misc.Endianness.Little); // read length of string if (!ReadProcessMemory(this, paramInfoAddrI + (int)offset, data2, 2, out readLen)) throw new Exception(GetLastErrorMessage()); ushort strLength = Misc.BytesToUShort(data2, Misc.Endianness.Little); byte[] stringData = new byte[strLength]; // read address of string if (!ReadProcessMemory(this, paramInfoAddrI + (int)offset + 4, data2, 4, out readLen)) throw new Exception(GetLastErrorMessage()); int strAddr = Misc.BytesToInt(data2, Misc.Endianness.Little); // read string if (!ReadProcessMemory(this, strAddr, stringData, strLength, out readLen)) throw new Exception(GetLastErrorMessage()); // return decoded unicode string return System.Text.UnicodeEncoding.Unicode.GetString(stringData).TrimEnd('\0'); } /// /// Gets whether the process is currently being debugged. This requires /// the PROCESS_QUERY_INFORMATION permission. /// /// A boolean value. public bool IsBeingDebugged() { bool debugged; if (!Win32.CheckRemoteDebuggerPresent(this, out debugged)) throw new Exception(GetLastErrorMessage()); return debugged; } /// /// Waits for the process. /// /// The timeout of the wait. /// Either WAIT_OBJECT_0, WAIT_TIMEOUT or WAIT_FAILED. public int Wait(int Timeout) { return WaitForSingleObject(this.Handle, Timeout); } /// /// 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 (!TerminateProcess(this, ExitCode)) throw new Exception(GetLastErrorMessage()); } /// /// 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(TOKEN_RIGHTS.TOKEN_ALL_ACCESS); } /// /// 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(TOKEN_RIGHTS access) { return new TokenHandle(this, access); } } } }