Skip to content

Commit

Permalink
SystemProcessAndThreadsInformation
Browse files Browse the repository at this point in the history
  • Loading branch information
FuzzySecurity committed Mar 10, 2019
1 parent 2c10546 commit faaab14
Show file tree
Hide file tree
Showing 7 changed files with 493 additions and 0 deletions.
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 47,50 @@ C:\>SwampThing.exe -l C:\Windows\System32\notepad.exe -f C:\aaa.txt -r C:\bbb.tx
[ ] Remote UNICODE_STRING.Buffer : 0x20DA9B10000
[ ] pRTL_USER_PROCESS_PARAMETERS : 0x20DA9870FE0
[?] Success rewrote Len, MaxLen, Buffer..
```

## Windows API

### SystemProcessAndThreadsInformation

While working on a side project I had to access out-of-process thread information, to do this I used NtQuerySystemInformation -> SystemProcessAndThreadInformation. As it may be helpful for reference I wrote a small wrapper round this function to list process and thread information for a specific PID. Note that I am not extracting all available information from SYSTEM_PROCESSES and SYSTEM_THREAD_INFORMATION, feel free to extend the output with a pull request.

```
C:\> SystemProcessAndThreadsInformation.exe -p 4508
[ ] Process Details
ImageName : powershell.exe
ProcessId : 4508
ParentPid : 8256
HandleCount : 701
ThreadCount : 25
SessionId : 1
Priority : 8
CreateTime : 0d:22h:0m:31s:876ms
UserTime : 0d:0h:0m:0s:328ms
KernelTime : 0d:0h:0m:0s:281ms
WorkingSetSize : 73.52734375 MB
PeakWorkingSetSize : 73.5859375 MB
PageFaultCount : 26896
[ ] Thread Details
[>] TID: 9832, Priority: 9
|-> StartAddress: 0x7FFB84833670
|-> Created: 0d:22h:0m:31s:876ms, uTime: 0d:0h:0m:0s:46ms, kTime: 0d:0h:0m:0s:93ms
|-> WaitTime: 5843708, WaitReason: UserRequest
|-> State: Wait, ContextSwitches: 232
[>] TID: 5552, Priority: 8
|-> StartAddress: 0x7FFB84833670
|-> Created: 0d:22h:0m:31s:970ms, uTime: 0d:0h:0m:0s:15ms, kTime: 0d:0h:0m:0s:15ms
|-> WaitTime: 5843460, WaitReason: WrQueue
|-> State: Wait, ContextSwitches: 38
[>] TID: 15716, Priority: 8
|-> StartAddress: 0x7FFB84833670
|-> Created: 0d:22h:0m:31s:970ms, uTime: 0d:0h:0m:0s:15ms, kTime: 0d:0h:0m:0s:0ms
|-> WaitTime: 5843460, WaitReason: WrQueue
|-> State: Wait, ContextSwitches: 30
[...Snipped...]
```
321 changes: 321 additions & 0 deletions SystemProcessAndThreadsInformation/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 1,321 @@
using System;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using Colorful;
using Console = Colorful.Console;
using System.Drawing;

namespace SystemProcessAndThreadsInformation
{
class SPTI
{
// Global vars
//===================
public static int LoopSize = 0;
public static int SystemInformationLength = 0;
public static IntPtr BuffPtr = IntPtr.Zero;
public static IntPtr SeekPtr = IntPtr.Zero;
public static Formatter[] pProperties =
{
new Formatter("[>]", Color.LightGreen),
new Formatter(":", Color.LightGreen),
new Formatter("ImageName ", Color.Orange),
new Formatter("ProcessId ", Color.Orange),
new Formatter("ParentPid ", Color.Orange),
new Formatter("HandleCount ", Color.Orange),
new Formatter("ThreadCount ", Color.Orange),
new Formatter("SessionId ", Color.Orange),
new Formatter("Priority ", Color.Orange),
new Formatter("CreateTime ", Color.Orange),
new Formatter("UserTime ", Color.Orange),
new Formatter("KernelTime ", Color.Orange),
new Formatter("WorkingSetSize ", Color.Orange),
new Formatter("PeakWorkingSetSize ", Color.Orange),
new Formatter("PageFaultCount ", Color.Orange),
};
public static Formatter[] tProperties =
{
new Formatter("[>]", Color.LightGreen),
new Formatter(":", Color.LightGreen),
new Formatter("|->", Color.LightGreen),
new Formatter("TID", Color.Orange),
new Formatter("Priority", Color.Orange),
new Formatter("StartAddress", Color.Orange),
new Formatter("Created", Color.Orange),
new Formatter("uTime", Color.Orange),
new Formatter("kTime", Color.Orange),
new Formatter("WaitTime", Color.Orange),
new Formatter("WaitReason", Color.Orange),
new Formatter("State", Color.Orange),
new Formatter("ContextSwitches", Color.Orange),
new Formatter(",", Color.LightGreen),
};

// Enums
//===================
public enum KWAIT_REASON
{
Executive,
FreePage,
PageIn,
PoolAllocation,
DelayExecution,
Suspended,
UserRequest,
WrExecutive,
WrFreePage,
WrPageIn,
WrPoolAllocation,
WrDelayExecution,
WrSuspended,
WrUserRequest,
WrEventPair,
WrQueue,
WrLpcReceive,
WrLpcReply,
WrVirtualMemory,
WrPageOut,
WrRendezvous,
Spare2,
Spare3,
Spare4,
Spare5,
WrCalloutStack,
WrKernel,
WrResource,
WrPushLock,
WrMutex,
WrQuantumEnd,
WrDispatchInt,
WrPreempted,
WrYieldExecution,
WrFastMutex,
WrGuardedMutex,
WrRundown,
MaximumWaitReason
}

public enum THREAD_STATE
{
Initialized,
Ready,
Running,
Standby,
Terminated,
Wait,
Transition,
Unknown
}

// Structs
//===================
[StructLayout(LayoutKind.Sequential)]
public struct LARGE_INTEGER
{
public UInt32 LowPart;
public UInt32 HighPart;
}

[StructLayout(LayoutKind.Sequential)]
public struct UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}

[StructLayout(LayoutKind.Sequential)]
public struct CLIENT_ID
{
public IntPtr UniqueProcess;
public IntPtr UniqueThread;
}

[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_THREAD_INFORMATION
{
public long KernelTime;
public long UserTime;
public long CreateTime;
public uint WaitTime;
public IntPtr StartAddress;
public CLIENT_ID ClientId;
public int Priority;
public int BasePriority;
public uint ContextSwitchCount;
public THREAD_STATE State;
public KWAIT_REASON WaitReason;
}

[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_PROCESSES
{
public int NextEntryOffset;
public int NumberOfThreads;
public LARGE_INTEGER WorkingSetPrivateSize;
public uint HardFaultCount;
public uint NumberOfThreadsHighWatermark;
public ulong CycleTime;
public long CreateTime;
public long UserTime;
public long KernelTime;
public UNICODE_STRING ImageName;
public int BasePriority;
public IntPtr UniqueProcessId;
public IntPtr InheritedFromUniqueProcessId;
public int HandleCount;
public int SessionId;
public IntPtr UniqueProcessKey;
public IntPtr PeakVirtualSize;
public IntPtr VirtualSize;
public uint PageFaultCount;
public IntPtr PeakWorkingSetSize;
public IntPtr WorkingSetSize;
public IntPtr QuotaPeakPagedPoolUsage;
public IntPtr QuotaPagedPoolUsage;
public IntPtr QuotaPeakNonPagedPoolUsage;
public IntPtr QuotaNonPagedPoolUsage;
public IntPtr PagefileUsage;
public IntPtr PeakPagefileUsage;
public IntPtr PrivatePageCount;
public LARGE_INTEGER ReadOperationCount;
public LARGE_INTEGER WriteOperationCount;
public LARGE_INTEGER OtherOperationCount;
public LARGE_INTEGER ReadTransferCount;
public LARGE_INTEGER WriteTransferCount;
public LARGE_INTEGER OtherTransferCount;
}

// API's
//===================
[DllImport("ntdll.dll")]
public static extern UInt32 NtQuerySystemInformation(
int SystemInformationClass,
IntPtr SystemInformation,
int SystemInformationLength,
ref int ReturnLength);

// Helpers
//===================
public static object GetThreadInformation(UInt32 ProcId)
{
// We loop till success or error out
while (true)
{
BuffPtr = Marshal.AllocHGlobal(LoopSize);
UInt32 CallResult = NtQuerySystemInformation(0x5, BuffPtr, LoopSize, ref SystemInformationLength); // 0x5 = SystemProcessAndThreadInformation

if (CallResult == 0xC0000004)
{
Marshal.FreeHGlobal(BuffPtr);
LoopSize = Math.Max(LoopSize, SystemInformationLength);
}
else if (CallResult == 0x00000000)
{
break;
}
else
{
Marshal.FreeHGlobal(BuffPtr);
return false;
}
}

// Duplicate BuffPtr so we can seek on the data
SeekPtr = BuffPtr;

// Seek result data
while (true)
{
var SysProcess = (SYSTEM_PROCESSES)Marshal.PtrToStructure(SeekPtr, typeof(SYSTEM_PROCESSES));
if (SysProcess.UniqueProcessId == (IntPtr)ProcId)
{
// Grab process details
Console.WriteLine("\n[ ] Process Details", Color.LightGreen);
Console.WriteLineFormatted(" {2} {1} " Marshal.PtrToStringUni(SysProcess.ImageName.Buffer), Color.White, pProperties);
Console.WriteLineFormatted(" {3} {1} " SysProcess.UniqueProcessId, Color.White, pProperties);
Console.WriteLineFormatted(" {4} {1} " SysProcess.InheritedFromUniqueProcessId, Color.White, pProperties);
Console.WriteLineFormatted(" {5} {1} " SysProcess.HandleCount, Color.White, pProperties);
Console.WriteLineFormatted(" {6} {1} " SysProcess.NumberOfThreads, Color.White, pProperties);
Console.WriteLineFormatted(" {7} {1} " SysProcess.SessionId, Color.White, pProperties);
Console.WriteLineFormatted(" {8} {1} " SysProcess.BasePriority, Color.White, pProperties);
Console.WriteLineFormatted(" {9} {1} " DateTime.FromBinary(SysProcess.CreateTime).TimeOfDay.Days "d:" DateTime.FromBinary(SysProcess.CreateTime).TimeOfDay.Hours "h:" DateTime.FromBinary(SysProcess.CreateTime).TimeOfDay.Minutes "m:" DateTime.FromBinary(SysProcess.CreateTime).TimeOfDay.Seconds "s:" DateTime.FromBinary(SysProcess.CreateTime).TimeOfDay.Milliseconds "ms", Color.White, pProperties);
Console.WriteLineFormatted(" {10} {1} " DateTime.FromBinary(SysProcess.UserTime).TimeOfDay.Days "d:" DateTime.FromBinary(SysProcess.UserTime).TimeOfDay.Hours "h:" DateTime.FromBinary(SysProcess.UserTime).TimeOfDay.Minutes "m:" DateTime.FromBinary(SysProcess.UserTime).TimeOfDay.Seconds "s:" DateTime.FromBinary(SysProcess.UserTime).TimeOfDay.Milliseconds "ms", Color.White, pProperties);
Console.WriteLineFormatted(" {11} {1} " DateTime.FromBinary(SysProcess.KernelTime).TimeOfDay.Days "d:" DateTime.FromBinary(SysProcess.KernelTime).TimeOfDay.Hours "h:" DateTime.FromBinary(SysProcess.KernelTime).TimeOfDay.Minutes "m:" DateTime.FromBinary(SysProcess.KernelTime).TimeOfDay.Seconds "s:" DateTime.FromBinary(SysProcess.KernelTime).TimeOfDay.Milliseconds "ms", Color.White, pProperties);
Console.WriteLineFormatted(" {12} {1} " (SysProcess.WorkingSetSize.ToInt64() / Math.Pow(1024,2)) " MB", Color.White, pProperties);
Console.WriteLineFormatted(" {13} {1} " (SysProcess.PeakWorkingSetSize.ToInt64() / Math.Pow(1024, 2)) " MB", Color.White, pProperties);
Console.WriteLineFormatted(" {14} {1} " SysProcess.PageFaultCount, Color.White, pProperties);

// Move Ptr to thread array & grab thread details
Console.WriteLine("\n[ ] Thread Details", Color.LightGreen);
SeekPtr = new IntPtr(Marshal.SizeOf(typeof(SYSTEM_PROCESSES)) SeekPtr.ToInt64());
for (int i = 0; i < SysProcess.NumberOfThreads; i )
{
var ThreadPtr = (SYSTEM_THREAD_INFORMATION)Marshal.PtrToStructure(SeekPtr, typeof(SYSTEM_THREAD_INFORMATION));
var TID = ThreadPtr.ClientId.UniqueThread;
var Priority = ThreadPtr.Priority;
var StartAddress = "0x" String.Format("{0:X}", (ThreadPtr.StartAddress).ToInt64());
var Created = DateTime.FromBinary(ThreadPtr.CreateTime).TimeOfDay.Days "d:" DateTime.FromBinary(ThreadPtr.CreateTime).TimeOfDay.Hours "h:" DateTime.FromBinary(ThreadPtr.CreateTime).TimeOfDay.Minutes "m:" DateTime.FromBinary(ThreadPtr.CreateTime).TimeOfDay.Seconds "s:" DateTime.FromBinary(ThreadPtr.CreateTime).TimeOfDay.Milliseconds "ms";
var uTime = DateTime.FromBinary(ThreadPtr.UserTime).TimeOfDay.Days "d:" DateTime.FromBinary(ThreadPtr.UserTime).TimeOfDay.Hours "h:" DateTime.FromBinary(ThreadPtr.UserTime).TimeOfDay.Minutes "m:" DateTime.FromBinary(ThreadPtr.UserTime).TimeOfDay.Seconds "s:" DateTime.FromBinary(ThreadPtr.UserTime).TimeOfDay.Milliseconds "ms";
var kTime = DateTime.FromBinary(ThreadPtr.KernelTime).TimeOfDay.Days "d:" DateTime.FromBinary(ThreadPtr.KernelTime).TimeOfDay.Hours "h:" DateTime.FromBinary(ThreadPtr.KernelTime).TimeOfDay.Minutes "m:" DateTime.FromBinary(ThreadPtr.KernelTime).TimeOfDay.Seconds "s:" DateTime.FromBinary(ThreadPtr.KernelTime).TimeOfDay.Milliseconds "ms";
var WaitTime = ThreadPtr.WaitTime;
var WaitReason = ThreadPtr.WaitReason;
var State = ThreadPtr.State;
var ContextSwitches = ThreadPtr.ContextSwitchCount;

Console.WriteLineFormatted("{0} {3}{1} " TID "{13} {4}{1} " Priority, Color.White, tProperties);
Console.WriteLineFormatted(" {2} {5}{1} " StartAddress, Color.White, tProperties);
Console.WriteLineFormatted(" {2} {6}{1} " Created "{13} {7}{1} " uTime "{13} {8}{1} " kTime, Color.White, tProperties);
Console.WriteLineFormatted(" {2} {9}{1} " WaitTime "{13} {10}{1} " WaitReason, Color.White, tProperties);
Console.WriteLineFormatted(" {2} {11}{1} " State "{13} {12}{1} " ContextSwitches "\n", Color.White, tProperties);

SeekPtr = new IntPtr(Marshal.SizeOf(typeof(SYSTEM_THREAD_INFORMATION)) SeekPtr.ToInt64());

}
break;
}
else if (Marshal.ReadInt32(SeekPtr) == 0)
{
Console.WriteLine("[!] Process ID not found..", Color.Red);
break;
}
else
{
SeekPtr = new IntPtr(Marshal.ReadInt32(SeekPtr) SeekPtr.ToInt64());
}
}
// Free BuffPtr
Marshal.FreeHGlobal(BuffPtr);
return true;
}

static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("[!] Please specify a process id (-p|--ProcId)", Color.Red);
}
else
{
int ProcId = Array.FindIndex(args, s => new Regex(@"(?i)(-|--|/)(p|ProcId)$").Match(s).Success);
if (ProcId != -1)
{
try
{
UInt32 Proc = uint.Parse(args[(ProcId 1)]);
GetThreadInformation(Proc);
} catch
{
Console.WriteLine("[!] Please specify a valid process id (-p|--ProcId)", Color.Red);
return;
}
}
else
{
Console.WriteLine("[!] Please specify a process id (-p|--ProcId)", Color.Red);
}
}
}

}
}
Loading

0 comments on commit faaab14

Please sign in to comment.