/* * Process Hacker - * job handle * * 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 . */ using System; using System.Collections.Generic; using ProcessHacker.Native.Api; using ProcessHacker.Native.Security; namespace ProcessHacker.Native.Objects { /// /// Represents a handle to a Windows job object. /// public sealed class JobObjectHandle : NativeHandle { public static JobObjectHandle Create(JobObjectAccess access) { return Create(access, null); } public static JobObjectHandle Create(JobObjectAccess access, string name) { return Create(access, name, 0, null); } public static JobObjectHandle Create(JobObjectAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory) { ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); IntPtr handle; try { Win32.NtCreateJobObject( out handle, access, ref oa ).ThrowIf(); } finally { oa.Dispose(); } return new JobObjectHandle(handle, true); } internal static IntPtr Open(ProcessHandle processHandle, JobObjectAccess access) { try { return KProcessHacker2.Instance.KphOpenProcessJob(processHandle, (TokenAccess)access); } catch (WindowsException) { // Use KPH to set the handle's granted access. IntPtr handle = KProcessHacker2.Instance.KphOpenProcessJob(processHandle, (TokenAccess)StandardRights.Synchronize); //if (handle != IntPtr.Zero) //KProcessHacker2.Instance.KphSetHandleGrantedAccess(handle, (int)access); return handle; } } /// /// Creates a service handle using an existing handle. /// The handle will not be closed automatically. /// /// The handle value. /// The job handle. public static JobObjectHandle FromHandle(IntPtr handle) { return new JobObjectHandle(handle, false); } internal JobObjectHandle(IntPtr handle, bool owned) : base(handle, owned) { } public JobObjectHandle(string name, JobObjectAccess access) : this(name, 0, null, access) { } public JobObjectHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, JobObjectAccess access) { ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); IntPtr handle; try { Win32.NtOpenJobObject( out handle, access, ref oa ).ThrowIf(); } finally { oa.Dispose(); } this.Handle = handle; } /// /// Opens the job object associated with the specified process. /// /// The process. /// The desired access to the job object. public JobObjectHandle(ProcessHandle processHandle, JobObjectAccess access) { this.Handle = Open(processHandle, access); // If we don't have a handle assume the process isn't in a job. if (this.Handle == IntPtr.Zero) { this.MarkAsInvalid(); Win32.Throw(NtStatus.ProcessNotInJob); } } public JobObjectBasicAccountingInformation GetBasicAccountingInformation() { return this.QueryStruct( JobObjectInformationClass.JobObjectBasicAccountingInformation, JobObjectBasicAccountingInformation.SizeOf ); } public JobObjectBasicAndIoAccountingInformation GetBasicAndIoAccountingInformation() { return this.QueryStruct( JobObjectInformationClass.JobObjectBasicAndIoAccountingInformation, JobObjectBasicAndIoAccountingInformation.SizeOf ); } public JobObjectBasicLimitInformation BasicLimitInformation { get { return this.QueryStruct( JobObjectInformationClass.JobObjectBasicLimitInformation, JobObjectBasicLimitInformation.SizeOf ); } } public JobObjectBasicUiRestrictions BasicUiRestrictions { get { JobObjectBasicUiRestrictions uiRestrictions; int retLength; if (!Win32.QueryInformationJobObject(this, JobObjectInformationClass.JobObjectBasicUIRestrictions, out uiRestrictions, 4, out retLength)) Win32.Throw(); return uiRestrictions; } } public JobObjectExtendedLimitInformation ExtendedLimitInformation { get { return this.QueryStruct( JobObjectInformationClass.JobObjectExtendedLimitInformation, JobObjectExtendedLimitInformation.SizeOf ); } } public int[] ProcessIdList { get { List processIds = new List(); int retLength; // FIXME: Fixed buffer using (MemoryAlloc data = new MemoryAlloc(0x1000)) { if (!Win32.QueryInformationJobObject(this, JobObjectInformationClass.JobObjectBasicProcessIdList, data, data.Size, out retLength)) Win32.Throw(); JobObjectBasicProcessIdList listInfo = data.ReadStruct(); for (int i = 0; i < listInfo.NumberOfProcessIdsInList; i++) { processIds.Add(data.ReadInt32(8, i)); } } return processIds.ToArray(); } } public void Terminate() { this.Terminate(0); } public void Terminate(int exitCode) { if (!Win32.TerminateJobObject(this, exitCode)) Win32.Throw(); } private T QueryStruct(JobObjectInformationClass informationClass, int size) where T : struct { int retLength; using (MemoryAlloc data = new MemoryAlloc(size)) { bool ret = Win32.QueryInformationJobObject(this, informationClass, data, data.Size, out retLength); int res = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); if (!Win32.QueryInformationJobObject(this, informationClass, data, data.Size, out retLength)) { data.ResizeNew(retLength); if (!Win32.QueryInformationJobObject(this, informationClass, data, data.Size, out retLength)) Win32.Throw(); } return data.ReadStruct(); } } } }