From f028ca4ca658e4fbc2a337e247ecb8907bdcc154 Mon Sep 17 00:00:00 2001 From: wj32 Date: Sun, 10 May 2009 09:29:40 +0000 Subject: [PATCH] * Terminator test: TD1 (debugs a process and closes the debug object) * added DebugObjectHandle * added copyright headers git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1259 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- trunk/CHANGELOG.txt | 1 + trunk/ProcessHacker.Native/Api/Enums.cs | 6 + trunk/ProcessHacker.Native/Api/Functions.cs | 78 ++++++-- .../Objects/DebugObjectHandle.cs | 53 +++++ .../Objects/DesktopHandle.cs | 24 ++- .../Objects/JobObjectHandle.cs | 16 +- .../ProcessHacker.Native/Objects/LsaHandle.cs | 2 +- .../Objects/LsaPolicyHandle.cs | 2 +- .../Objects/ProcessHandle.cs | 90 ++++++++- .../Objects/WindowStationHandle.cs | 24 ++- .../ProcessHacker.Native.csproj | 2 + .../Security/DebugObjectAccess.cs | 15 ++ trunk/ProcessHacker/Forms/TerminatorWindow.cs | 182 ++++++++++-------- 13 files changed, 380 insertions(+), 115 deletions(-) create mode 100644 trunk/ProcessHacker.Native/Objects/DebugObjectHandle.cs create mode 100644 trunk/ProcessHacker.Native/Security/DebugObjectAccess.cs diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt index fd8dbff53..0188763bd 100644 --- a/trunk/CHANGELOG.txt +++ b/trunk/CHANGELOG.txt @@ -7,6 +7,7 @@ Process Hacker * KProcessHacker can now bypass all handle-opening protections * Ability to set handle flags such as protect-from-close and inherit * Better highlighting + * Terminator test: TD1 (debugs a process and closes the debug object) * Terminator test: TT3 (TT1 is now completely user-mode) * Shows function file and line numbers where available * FIXED: diff --git a/trunk/ProcessHacker.Native/Api/Enums.cs b/trunk/ProcessHacker.Native/Api/Enums.cs index 0d5279042..26485b397 100644 --- a/trunk/ProcessHacker.Native/Api/Enums.cs +++ b/trunk/ProcessHacker.Native/Api/Enums.cs @@ -102,6 +102,12 @@ namespace ProcessHacker.Native.Api CreateIgnoreSystemDefault = 0x80000000 } + [Flags] + public enum DebugObjectFlags : uint + { + KillOnClose = 0x1 + } + public enum DepFlags : uint { Disable = 0x00000000, diff --git a/trunk/ProcessHacker.Native/Api/Functions.cs b/trunk/ProcessHacker.Native/Api/Functions.cs index 401d14ff8..2d8e66595 100644 --- a/trunk/ProcessHacker.Native/Api/Functions.cs +++ b/trunk/ProcessHacker.Native/Api/Functions.cs @@ -93,6 +93,28 @@ namespace ProcessHacker.Native.Api #endregion + #region Debugging + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DebugActiveProcess( + [In] int Pid + ); + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DebugActiveProcessStop( + [In] int Pid + ); + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DebugSetProcessKillOnExit( + [In] bool KillOnExit + ); + + #endregion + #region Error Handling [DllImport("ntdll.dll")] @@ -493,6 +515,20 @@ namespace ProcessHacker.Native.Api [In] IntPtr ThreadHandle ); + [DllImport("ntdll.dll", SetLastError = true)] + public static extern int NtAlertResumeThread( + [In] IntPtr ThreadHandle, + [Out] [Optional] out int PreviousSuspendCount + ); + + [DllImport("ntdll.dll", SetLastError = true)] + public static extern int NtCreateDebugObject( + [Out] out IntPtr DebugObjectHandle, + [In] DebugObjectAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] DebugObjectFlags Flags + ); + [DllImport("ntdll.dll", SetLastError = true)] public static extern int NtCreateProcess( [Out] out IntPtr ProcessHandle, @@ -516,6 +552,12 @@ namespace ProcessHacker.Native.Api [In] [Optional] IntPtr FileHandle ); + [DllImport("ntdll.dll", SetLastError = true)] + public static extern int NtDebugActiveProcess( + [In] IntPtr ProcessHandle, + [In] IntPtr DebugObjectHandle + ); + [DllImport("ntdll.dll", SetLastError = true)] public static extern int NtDuplicateObject( [In] IntPtr SourceProcessHandle, @@ -529,7 +571,7 @@ namespace ProcessHacker.Native.Api [DllImport("ntdll.dll", SetLastError = true)] public static extern int NtGetNextProcess( - [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr ProcessHandle, [In] ProcessAccess DesiredAccess, [In] int HandleAttributes, [In] int Flags, @@ -538,11 +580,12 @@ namespace ProcessHacker.Native.Api [DllImport("ntdll.dll", SetLastError = true)] public static extern int NtGetNextThread( - [In] IntPtr ProcessHandle, - [In] ProcessAccess DesiredAccess, + [In] [Optional] IntPtr ProcessHandle, + [In] [Optional] IntPtr ThreadHandle, + [In] ThreadAccess DesiredAccess, [In] int HandleAttributes, [In] int Flags, - [Out] out int NewProcessHandle + [Out] out IntPtr NewThreadHandle ); [DllImport("ntdll.dll", SetLastError = true)] @@ -559,6 +602,12 @@ namespace ProcessHacker.Native.Api [Out] [Optional] out int DataWritten ); + [DllImport("ntdll.dll", SetLastError = true)] + public static extern int NtRemoveProcessDebug( + [In] IntPtr ProcessHandle, + [In] IntPtr DebugObjectHandle + ); + [DllImport("ntdll.dll", SetLastError = true)] public static extern int NtResumeProcess( [In] IntPtr ProcessHandle @@ -569,6 +618,15 @@ namespace ProcessHacker.Native.Api [In] IntPtr ProcessHandle ); + [DllImport("ntdll.dll", SetLastError = true)] + public static extern int NtQueueApcThread( + [In] IntPtr ThreadHandle, + [In] IntPtr ApcRoutine, + [In] [Optional] IntPtr ApcArgument1, + [In] [Optional] IntPtr ApcArgument2, + [In] [Optional] IntPtr ApcArgument3 + ); + [DllImport("ntdll.dll", SetLastError = true)] public static extern int NtQuerySection( [In] IntPtr SectionHandle, @@ -935,18 +993,6 @@ namespace ProcessHacker.Native.Api [In] int ProcessId ); - [DllImport("kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DebugActiveProcess( - [In] int Pid - ); - - [DllImport("kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DebugActiveProcessStop( - [In] int Pid - ); - [DllImport("psapi.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool EnumProcessModules( diff --git a/trunk/ProcessHacker.Native/Objects/DebugObjectHandle.cs b/trunk/ProcessHacker.Native/Objects/DebugObjectHandle.cs new file mode 100644 index 000000000..d6ba7a603 --- /dev/null +++ b/trunk/ProcessHacker.Native/Objects/DebugObjectHandle.cs @@ -0,0 +1,53 @@ +/* + * Process Hacker - + * debug object 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 System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public class DebugObjectHandle : Win32Handle + { + public static DebugObjectHandle Create(DebugObjectAccess access, DebugObjectFlags flags) + { + int status; + IntPtr handle; + + if ((status = Win32.NtCreateDebugObject( + out handle, + access, + IntPtr.Zero, + flags + )) < 0) + Win32.ThrowLastError(status); + + return new DebugObjectHandle(handle, true); + } + + private DebugObjectHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + } +} diff --git a/trunk/ProcessHacker.Native/Objects/DesktopHandle.cs b/trunk/ProcessHacker.Native/Objects/DesktopHandle.cs index 744057b9a..6cd5b9b5c 100644 --- a/trunk/ProcessHacker.Native/Objects/DesktopHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/DesktopHandle.cs @@ -1,4 +1,26 @@ -using System; +/* + * Process Hacker - + * desktop 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 System.Text; using ProcessHacker.Native.Api; diff --git a/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs b/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs index fc9fa9a6c..ea628d9f4 100644 --- a/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs @@ -185,13 +185,15 @@ namespace ProcessHacker.Native.Objects public enum JobObjectInformationClass : int { JobObjectBasicAccountingInformation = 1, - JobObjectBasicLimitInformation = 2, - JobObjectBasicProcessIdList = 3, - JobObjectBasicUIRestrictions = 4, - JobObjectSecurityLimitInformation = 5, - JobObjectBasicAndIoAccountingInformation = 8, - JobObjectExtendedLimitInformation = 9, - JobObjectGroupInformation = 11 + JobObjectBasicLimitInformation, + JobObjectBasicProcessIdList, + JobObjectBasicUIRestrictions, + JobObjectSecurityLimitInformation, + JobObjectEndOfJobTimeInformation, + JobObjectAssociateCompletionPortInformation, + JobObjectBasicAndIoAccountingInformation, + JobObjectExtendedLimitInformation, + JobObjectJobSetInformation } [Flags] diff --git a/trunk/ProcessHacker.Native/Objects/LsaHandle.cs b/trunk/ProcessHacker.Native/Objects/LsaHandle.cs index 67928e1ef..698662ffe 100644 --- a/trunk/ProcessHacker.Native/Objects/LsaHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/LsaHandle.cs @@ -2,7 +2,7 @@ * Process Hacker - * local security authority handle * - * Copyright (C) 2008 wj32 + * Copyright (C) 2008-2009 wj32 * * This file is part of Process Hacker. * diff --git a/trunk/ProcessHacker.Native/Objects/LsaPolicyHandle.cs b/trunk/ProcessHacker.Native/Objects/LsaPolicyHandle.cs index 24f874501..598ebef4d 100644 --- a/trunk/ProcessHacker.Native/Objects/LsaPolicyHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/LsaPolicyHandle.cs @@ -2,7 +2,7 @@ * Process Hacker - * local security policy handle * - * Copyright (C) 2008 wj32 + * Copyright (C) 2008-2009 wj32 * * This file is part of Process Hacker. * diff --git a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs index cbbbf8c9f..057d93279 100644 --- a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs @@ -234,6 +234,19 @@ namespace ProcessHacker.Native.Objects 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. @@ -744,6 +757,52 @@ namespace ProcessHacker.Native.Objects } } + /// + /// 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. /// @@ -909,9 +968,6 @@ namespace ProcessHacker.Native.Objects /// Determines whether the process is running in a job. /// /// A boolean. - /// According to this function, almost every single - /// process is in a job! This function does not tell us - /// the name of the job though. public bool IsInJob() { bool result; @@ -921,6 +977,22 @@ namespace ProcessHacker.Native.Objects 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. /// @@ -1007,6 +1079,18 @@ namespace ProcessHacker.Native.Objects 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. /// diff --git a/trunk/ProcessHacker.Native/Objects/WindowStationHandle.cs b/trunk/ProcessHacker.Native/Objects/WindowStationHandle.cs index e39bd43a1..ac962c544 100644 --- a/trunk/ProcessHacker.Native/Objects/WindowStationHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/WindowStationHandle.cs @@ -1,4 +1,26 @@ -using System; +/* + * Process Hacker - + * window station 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 System.Text; using ProcessHacker.Native.Api; diff --git a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj index 301e20ec5..dcf42d639 100644 --- a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj +++ b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj @@ -49,6 +49,7 @@ + @@ -77,6 +78,7 @@ + diff --git a/trunk/ProcessHacker.Native/Security/DebugObjectAccess.cs b/trunk/ProcessHacker.Native/Security/DebugObjectAccess.cs new file mode 100644 index 000000000..4cef678bc --- /dev/null +++ b/trunk/ProcessHacker.Native/Security/DebugObjectAccess.cs @@ -0,0 +1,15 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum DebugObjectAccess : uint + { + ReadEvent = 0x1, + ProcessAssign = 0x2, + SetInformation = 0x4, + QueryInformation = 0x8, + All = StandardRights.Required | StandardRights.Synchronize | + ReadEvent | ProcessAssign | SetInformation | QueryInformation + } +} diff --git a/trunk/ProcessHacker/Forms/TerminatorWindow.cs b/trunk/ProcessHacker/Forms/TerminatorWindow.cs index a7fb02d59..3f0aa7e88 100644 --- a/trunk/ProcessHacker/Forms/TerminatorWindow.cs +++ b/trunk/ProcessHacker/Forms/TerminatorWindow.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Threading; using System.Windows.Forms; using ProcessHacker.Native; using ProcessHacker.Native.Api; @@ -47,10 +48,11 @@ namespace ProcessHacker this.AddTest("TP1", "Terminates the process using TerminateProcess"); this.AddTest("TP2", "Creates a remote thread in the process which terminates the process"); - this.AddTest("TJ1", "Assigns the process to a job object and terminates the job"); this.AddTest("TT1", "Terminates the process' threads"); this.AddTest("TT2", "Modifies the process' threads with contexts which terminate the process"); this.AddTest("CH1", "Closes the process' handles"); + this.AddTest("TJ1", "Assigns the process to a job object and terminates the job"); + this.AddTest("TD1", "Debugs the process and closes the debug object"); this.AddTest("TP3", "Terminates the process in kernel-mode (if possible)"); this.AddTest("TT3", "Terminates the process' threads in kernel-mode (if possible)"); this.AddTest("M1", "Writes garbage to the process' memory regions"); @@ -122,6 +124,97 @@ namespace ProcessHacker return false; } + private void CH1() + { + using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.DupHandle)) + { + int i = 0; + + while (true) + { + if (i >= 0x1000) + break; + + try + { + Win32.DuplicateObject(phandle, new IntPtr(i), 0, 0, 0x1); + } + catch + { } + + i++; + } + } + } + + private void M1() + { + this.M1Internal(); + } + + private unsafe void M1Internal() + { + using (MemoryAlloc alloc = new MemoryAlloc(0x1000)) + { + using (ProcessHandle phandle = new ProcessHandle(_pid, + ProcessAccess.QueryInformation | + Program.MinProcessWriteMemoryRights)) + { + phandle.EnumMemory((info) => + { + for (int i = 0; i < info.RegionSize; i += 0x1000) + { + try + { + phandle.WriteMemory(info.BaseAddress.Increment(i), alloc, 0x1000); + } + catch + { } + } + + return true; + }); + } + } + } + + private void M2() + { + using (ProcessHandle phandle = new ProcessHandle(_pid, + ProcessAccess.QueryInformation | ProcessAccess.VmOperation)) + { + phandle.EnumMemory((info) => + { + phandle.ProtectMemory(info.BaseAddress, info.RegionSize, MemoryProtection.NoAccess); + return true; + }); + } + } + + private void TD1() + { + using (var dhandle = + DebugObjectHandle.Create(DebugObjectAccess.ProcessAssign, DebugObjectFlags.KillOnClose)) + { + using (var phandle = new ProcessHandle(_pid, ProcessAccess.SuspendResume)) + phandle.Debug(dhandle); + } + } + + private void TJ1() + { + using (var jhandle = JobObjectHandle.Create(null)) + { + using (ProcessHandle phandle = + new ProcessHandle(_pid, ProcessAccess.SetQuota | ProcessAccess.Terminate)) + { + phandle.AssignToJobObject(jhandle); + } + + jhandle.Terminate(); + } + } + private void TP1() { using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.Terminate)) @@ -143,17 +236,11 @@ namespace ProcessHacker Win32.ThrowLastError(); } - private void TJ1() + private void TP3() { - using (var jhandle = JobObjectHandle.Create(null)) + using (ProcessHandle phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) { - using (ProcessHandle phandle = - new ProcessHandle(_pid, ProcessAccess.SetQuota | ProcessAccess.Terminate)) - { - phandle.AssignToJobObject(jhandle); - } - - jhandle.Terminate(); + phandle.Terminate(); } } @@ -195,81 +282,6 @@ namespace ProcessHacker } } - private void M1() - { - this.M1Internal(); - } - - private unsafe void M1Internal() - { - using (MemoryAlloc alloc = new MemoryAlloc(0x1000)) - { - using (ProcessHandle phandle = new ProcessHandle(_pid, - ProcessAccess.QueryInformation | - Program.MinProcessWriteMemoryRights)) - { - phandle.EnumMemory((info) => - { - for (int i = 0; i < info.RegionSize; i += 0x1000) - { - try - { - phandle.WriteMemory(info.BaseAddress.Increment(i), alloc, 0x1000); - } - catch - { } - } - - return true; - }); - } - } - } - - private void M2() - { - using (ProcessHandle phandle = new ProcessHandle(_pid, - ProcessAccess.QueryInformation | ProcessAccess.VmOperation)) - { - phandle.EnumMemory((info) => - { - phandle.ProtectMemory(info.BaseAddress, info.RegionSize, MemoryProtection.NoAccess); - return true; - }); - } - } - - private void CH1() - { - using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.DupHandle)) - { - int i = 0; - - while (true) - { - if (i >= 0x1000) - break; - - try - { - Win32.DuplicateObject(phandle, new IntPtr(i), 0, 0, 0x1); - } - catch - { } - - i++; - } - } - } - - private void TP3() - { - using (ProcessHandle phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) - { - phandle.Terminate(); - } - } - private void TT3() { System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(_pid);