diff --git a/Seatbelt/Commands/Windows/ProcessesCommand.cs b/Seatbelt/Commands/Windows/ProcessesCommand.cs index 4a7f62f..6c7f6ef 100644 --- a/Seatbelt/Commands/Windows/ProcessesCommand.cs +++ b/Seatbelt/Commands/Windows/ProcessesCommand.cs @@ -7,7 +7,9 @@ using Seatbelt.Output.TextWriters; using Seatbelt.Output.Formatters; using Seatbelt.Util; - +using System.ComponentModel; +using System.Runtime.InteropServices; +using Seatbelt.Interop; namespace Seatbelt.Commands.Windows { @@ -38,7 +40,29 @@ internal class ProcessesCommand : CommandBase public ProcessesCommand(Runtime runtime) : base(runtime) { } - + private int? GetProcessProtectionInfo(int ProcessId) + { + int pplValueString; + IntPtr ProcessHandle = Kernel32.OpenProcess(Interop.Kernel32.ProcessAccess.QueryLimitedInformation, false, ProcessId); + if (ProcessHandle == null) + { + WriteError($" [!] Could not get a handle to ProcessId " + ProcessId); + } + PsProtection ppl = new PsProtection(); + int returnlength; + int status = Ntdll.NtQueryInformationProcess(ProcessHandle, PROCESSINFOCLASS.ProcessProtectionInformation, ref ppl, Marshal.SizeOf(ppl), out returnlength); + if (status != 0) + { + WriteError($" [!] Could not get Process Protection Info for ProcessId " + ProcessId); + var handleResult = Kernel32.CloseHandle(ProcessHandle); + return null; + } + else + { + pplValueString = ((byte)ppl.Type | (byte)ppl.Audit | ((int)ppl.Signer) << 4); + return pplValueString; + } + } public override IEnumerable Execute(string[] args) { // lists currently running processes that don't have "Microsoft Corporation" as the company name in their file info @@ -64,16 +88,27 @@ select new Path = (string)mo["ExecutablePath"], CommandLine = (string)mo["CommandLine"], }; - + foreach (var proc in query) { var isDotNet = false; string? companyName = null; string? description = null; - string? version = null; - + string? version = null; + int? ProtectionLevelinfo = null; + + if (!SecurityUtil.IsHighIntegrity() || proc.Process.Id == 0) + { + ProtectionLevelinfo = null; + } + else + { + ProtectionLevelinfo = GetProcessProtectionInfo(proc.Process.Id); + } + if (proc.Path != null) - { + { + isDotNet = FileUtil.IsDotNetAssembly(proc.Path); try @@ -132,7 +167,8 @@ select new proc.Path, proc.CommandLine, isDotNet, - processModules + processModules, + ProtectionLevelinfo ); } } @@ -140,7 +176,7 @@ select new internal class ProcessesDTO : CommandDTOBase { - public ProcessesDTO(string processName, int processId, int parentProcessId, string? companyName, string? description, string? version, string? path, string commandLine, bool? isDotNet, List modules) + public ProcessesDTO(string processName, int processId, int parentProcessId, string? companyName, string? description, string? version, string? path, string commandLine, bool? isDotNet, List modules, int? ProtectionLevelinfo) { ProcessName = processName; ProcessId = processId; @@ -152,6 +188,7 @@ public ProcessesDTO(string processName, int processId, int parentProcessId, stri CommandLine = commandLine; IsDotNet = isDotNet; Modules = modules; + ProcessProtectionLevelinfo = ProtectionLevelinfo; } public string ProcessName { get; set; } public string? CompanyName { get; set; } @@ -163,6 +200,7 @@ public ProcessesDTO(string processName, int processId, int parentProcessId, stri public string CommandLine { get; set; } public bool? IsDotNet { get; set; } public List Modules { get; set; } + public int? ProcessProtectionLevelinfo { get; set; } } [CommandOutputType(typeof(ProcessesDTO))] @@ -174,7 +212,21 @@ public ProcessFormatter(ITextWriter writer) : base(writer) public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults) { - var dto = (ProcessesDTO)result; + var dto = (ProcessesDTO)result; + + string? ProtectionLevelString; + if (dto.ProcessProtectionLevelinfo == null) + { + ProtectionLevelString = null; + } + else + { + string pplValue = ((int)dto.ProcessProtectionLevelinfo).ToString("X"); + ProtectionValueName protectionLevel = (ProtectionValueName)Enum.Parse(typeof(ProtectionValueName), pplValue, true); + string protectionValueName = protectionLevel.ToString(); + string pplValueHex = "(0x" + pplValue + ")"; + ProtectionLevelString = protectionValueName + pplValueHex; + } WriteLine(" {0,-40} : {1}", "ProcessName", dto.ProcessName); WriteLine(" {0,-40} : {1}", "ProcessId", dto.ProcessId); @@ -185,6 +237,7 @@ public override void FormatResult(CommandBase? command, CommandDTOBase result, b WriteLine(" {0,-40} : {1}", "Path", dto.Path); WriteLine(" {0,-40} : {1}", "CommandLine", dto.CommandLine); WriteLine(" {0,-40} : {1}", "IsDotNet", dto.IsDotNet); + WriteLine(" {0,-40} : {1}", "ProcessProtectionInformation", ProtectionLevelString); if (dto.Modules.Count != 0) { diff --git a/Seatbelt/Interop/Kernel32.cs b/Seatbelt/Interop/Kernel32.cs index e6d8210..d4004dc 100644 --- a/Seatbelt/Interop/Kernel32.cs +++ b/Seatbelt/Interop/Kernel32.cs @@ -29,6 +29,12 @@ internal class Kernel32 public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr OpenProcess( + ProcessAccess processAccess, + bool bInheritHandle, + int processId); + [DllImport("kernel32.dll", SetLastError = true)] public static extern bool FindClose(IntPtr hFindFile); @@ -67,5 +73,22 @@ public struct WIN32_FIND_DATA IntPtr hPipe, out int ClientProcessId); + [Flags] + public enum ProcessAccess + { + AllAccess = 0x001FFFFF, + Terminate = 0x00000001, + CreateThread = 0x00000002, + VirtualMemoryOperation = 0x00000008, + VirtualMemoryRead = 0x00000010, + VirtualMemoryWrite = 0x00000020, + DuplicateHandle = 0x00000040, + CreateProcess = 0x000000080, + SetQuota = 0x00000100, + SetInformation = 0x00000200, + QueryInformation = 0x00000400, + QueryLimitedInformation = 0x00001000, + Synchronize = 0x00100000 + } } } diff --git a/Seatbelt/Interop/Ntdll.cs b/Seatbelt/Interop/Ntdll.cs new file mode 100644 index 0000000..f9b4055 --- /dev/null +++ b/Seatbelt/Interop/Ntdll.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.InteropServices; + + +namespace Seatbelt.Interop +{ + internal class Ntdll + { + #region Function Definitions + [DllImport("ntdll.dll", SetLastError = true)] + public static extern int NtQueryInformationProcess( + IntPtr processHandle, + PROCESSINFOCLASS processInformationClass, + ref PsProtection processInformation, + int processInformationLength, + out int returnLength); + } + #endregion + + #region Enum Definitions + [Flags] + public enum PROCESSINFOCLASS + { + ProcessProtectionInformation = 0x3D, + } + [StructLayout(LayoutKind.Sequential)] + public struct PsProtection + { + public PsProtectedType Type; + public PsProtectedSigner Signer; + public PsProtectedAudit Audit; + } + [Flags] + public enum PsProtectedType + { + PsProtectedTypeNone = 0x0, + PsProtectedTypeProtectedLight = 0x1, + PsProtectedTypeProtected = 0x2, + PsProtectedTypeMax = 0x3, + } + [Flags] + public enum PsProtectedSigner + { + PsProtectedSignerNone = 0x0, + PsProtectedSignerAuthenticode = 0x1, + PsProtectedSignerCodeGen = 0x2, + PsProtectedSignerAntimalware = 0x3, + PsProtectedSignerLsa = 0x4, + PsProtectedSignerWindows = 0x5, + PsProtectedSignerWinTcb = 0x6, + PsProtectedSignerMax = 0x7, + } + + public enum PsProtectedAudit + { + None = 0x0 + } + + [Flags] + public enum ProtectionValueName + { + PsProtectedTypeNone = 0, + PsProtectedSignerAuthenticodeLight = 11, + PsProtectedSignerCodeGenLight = 21, + PsProtectedSignerAntimalwareLight = 31, + PsProtectedSignerLsaLight = 41, + PsProtectedSignerWindowsLight = 51, + PsProtectedSignerWinTcbLight = 61, + PsProtectedSignerMaxLight = 71, + PsProtectedSignerAuthenticode = 12, + PsProtectedSignerCodeGen = 22, + PsProtectedSignerAntimalware = 32, + PsProtectedSignerLsa = 42, + PsProtectedSignerWindows = 52, + PsProtectedSignerWinTcb = 62, + PsProtectedSignerMax = 72, + PsProtectedSignerAuthenticodeMax = 13, + PsProtectedSignerCodeGenMax = 23, + PsProtectedSignerAntimalwareMax = 33, + PsProtectedSignerLsaMax = 43, + PsProtectedSignerWindowsMax = 53, + PsProtectedSignerWinTcbMax = 63, + PsProtectedSignerMaxMax = 73 + } + #endregion +} + + diff --git a/Seatbelt/Seatbelt.csproj b/Seatbelt/Seatbelt.csproj index 0cf5cfb..275d288 100644 --- a/Seatbelt/Seatbelt.csproj +++ b/Seatbelt/Seatbelt.csproj @@ -98,6 +98,7 @@ +