From 4e4036570b66ff05474aa97fc5abbe79f0e4ca83 Mon Sep 17 00:00:00 2001 From: wj32 Date: Thu, 30 Jul 2009 11:25:07 +0000 Subject: [PATCH] * added Ss logger code * refactored memory classes * added Kernel Transaction Manager (KTM) types git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1643 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- trunk/KProcessHacker/sysservice.c | 2 +- .../Api/NativeDefinitions.cs | 6 + trunk/ProcessHacker.Native/Api/NativeEnums.cs | 86 ++++++ .../Api/NativeFunctions.cs | 205 ++++++++++++ .../ProcessHacker.Native/Api/NativeStructs.cs | 18 ++ .../Debugging/DebugBuffer.cs | 8 +- trunk/ProcessHacker.Native/KProcessHacker.cs | 8 +- .../Memory/MemoryAlloc.cs | 267 +--------------- .../Memory/MemoryRegion.cs | 292 ++++++++++++++++++ ...ryAllocStream.cs => MemoryRegionStream.cs} | 6 +- .../Memory/VirtualMemoryAlloc.cs | 27 ++ .../ProcessHacker.Native.csproj | 15 +- .../Security/AccessControl/Ace.cs | 8 +- .../Security/AccessControl/Acl.cs | 4 +- .../Security/AccessControl/KnownAce.cs | 11 +- .../AccessControl/SecurityDescriptor.cs | 6 +- .../Security/EnlistmentAccess.cs | 22 ++ .../Security/PrivilegeSet.cs | 8 +- .../Security/ResourceManagerAccess.cs | 24 ++ .../ProcessHacker.Native/Security/TmAccess.cs | 21 ++ .../Security/TransactionAccess.cs | 26 ++ .../ProcessHacker.Native/SsLogging/SsData.cs | 10 + .../ProcessHacker.Native/SsLogging/SsEvent.cs | 62 ++++ .../SsLogging/SsHandle.cs | 51 +++ .../SsLogging/SsLogger.cs | 275 +++++++++++++++++ .../SsLogging/SsObjectAttributes.cs | 37 +++ .../SsLogging/SsSimple.cs | 21 ++ .../SsLogging/SsUnicodeString.cs | 38 +++ 28 files changed, 1278 insertions(+), 286 deletions(-) create mode 100644 trunk/ProcessHacker.Native/Memory/MemoryRegion.cs rename trunk/ProcessHacker.Native/Memory/{MemoryAllocStream.cs => MemoryRegionStream.cs} (90%) create mode 100644 trunk/ProcessHacker.Native/Memory/VirtualMemoryAlloc.cs create mode 100644 trunk/ProcessHacker.Native/Security/EnlistmentAccess.cs create mode 100644 trunk/ProcessHacker.Native/Security/ResourceManagerAccess.cs create mode 100644 trunk/ProcessHacker.Native/Security/TmAccess.cs create mode 100644 trunk/ProcessHacker.Native/Security/TransactionAccess.cs create mode 100644 trunk/ProcessHacker.Native/SsLogging/SsData.cs create mode 100644 trunk/ProcessHacker.Native/SsLogging/SsEvent.cs create mode 100644 trunk/ProcessHacker.Native/SsLogging/SsHandle.cs create mode 100644 trunk/ProcessHacker.Native/SsLogging/SsLogger.cs create mode 100644 trunk/ProcessHacker.Native/SsLogging/SsObjectAttributes.cs create mode 100644 trunk/ProcessHacker.Native/SsLogging/SsSimple.cs create mode 100644 trunk/ProcessHacker.Native/SsLogging/SsUnicodeString.cs diff --git a/trunk/KProcessHacker/sysservice.c b/trunk/KProcessHacker/sysservice.c index 9b780d865..9ecbb2370 100644 --- a/trunk/KProcessHacker/sysservice.c +++ b/trunk/KProcessHacker/sysservice.c @@ -1548,7 +1548,7 @@ NTSTATUS KphpSsWriteBlock( /* Now that we have succesfully copied the block, we need to * release the read semaphore to notify to the client that they have - * a block to read and advance the cursor. + * a block to read. We also need to advance our cursor. */ /* May cause an exception (STATUS_SEMAPHORE_LIMIT_EXCEEDED). */ diff --git a/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs b/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs index 9a15d84fe..ac18b1d72 100644 --- a/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs +++ b/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs @@ -57,6 +57,12 @@ namespace ProcessHacker.Native.Api public const int SizeOf80387Registers = 80; public const int TimeMsTo100Ns = 10000; + // KTM object paths + public const string TransactionManagerObjectPath = "\\TransactionManager\\"; + public const string TransactionObjectPath = "\\Transaction\\"; + public const string EnlistmentObjectPath = "\\Enlistment\\"; + public const string ResourceManagerObjectPath = "\\ResourceManager\\"; + public static readonly IntPtr KnownAceSidStartOffset = Marshal.OffsetOf(typeof(KnownAceStruct), "SidStart"); public static readonly IntPtr PebLdrOffset = Marshal.OffsetOf(typeof(Peb), "Ldr"); public static readonly IntPtr PebProcessHeapOffset = Marshal.OffsetOf(typeof(Peb), "ProcessHeap"); diff --git a/trunk/ProcessHacker.Native/Api/NativeEnums.cs b/trunk/ProcessHacker.Native/Api/NativeEnums.cs index 47536c8f5..461453238 100644 --- a/trunk/ProcessHacker.Native/Api/NativeEnums.cs +++ b/trunk/ProcessHacker.Native/Api/NativeEnums.cs @@ -99,6 +99,14 @@ namespace ProcessHacker.Native.Api All = Control | Integer | Segments | FloatingPoint | DebugRegisters | ExtendedRegisters } + [Flags] + public enum CrmProtocolOptions : int + { + ExplicitMarshalOnly = 0x1, + DynamicMarshalInfo = 0x2, + MaximumOption = 0x3 + } + [Flags] public enum DebugObjectFlags : uint { @@ -136,6 +144,13 @@ namespace ProcessHacker.Native.Api SameAttributes = 0x4 } + [Flags] + public enum EnlistmentOptions : int + { + Superior = 0x1, + MaximumOption = 0x1 + } + public enum EventInformationClass : int { EventBasicInformation @@ -442,6 +457,15 @@ namespace ProcessHacker.Native.Api ProfileMaximum } + public enum KtmObjectType : int + { + Transaction, + TransactionManager, + ResourceManager, + Enlistment, + Invalid + } + public enum KWaitReason : int { Executive = 0, @@ -578,6 +602,40 @@ namespace ProcessHacker.Native.Api MutantBasicInformation } + [Flags] + public enum NotificationMask : uint + { + Mask = 0x3fffffff, + PrePrepare = 0x00000001, + Prepare = 0x00000002, + Commit = 0x00000004, + Rollback = 0x00000008, + PrePrepareComplete = 0x00000010, + PrepareComplete = 0x00000020, + CommitComplete = 0x00000040, + RollbackComplete = 0x00000080, + Recover = 0x00000100, + SinglePhaseComplete = 0x00000200, + DelegateCommit = 0x00000400, + RecoverQuery = 0x00000800, + EnlistPrePrepare = 0x00001000, + LastRecover = 0x00002000, + InDoubt = 0x00004000, + PropagatePull = 0x00008000, + PropagatePush = 0x00010000, + Marshal = 0x00020000, + EnlistMask = 0x00040000, + RmDisconnected = 0x01000000, + TmOnline = 0x02000000, + CommitRequest = 0x04000000, + Promote = 0x08000000, + PromoteNew = 0x10000000, + RequestOutcome = 0x20000000, + + // For filter manager use only. DO NOT SPECIFY. + CommitFinalize = 0x40000000 + } + [Flags] public enum ObjectAceFlags : uint { @@ -766,6 +824,14 @@ namespace ProcessHacker.Native.Api ForceUnload = 0x1 } + [Flags] + public enum ResourceManagerOptions : int + { + Volatile = 0x1, + Communication = 0x2, + MaximumOption = 0x3 + } + [Flags] public enum RtlAcquirePrivilegeFlags : int { @@ -1084,6 +1150,19 @@ namespace ProcessHacker.Native.Api SynchronizationTimer } + [Flags] + public enum TmOptions : int + { + Volatile = 0x1, + CommitDefault = 0x0, + CommitSystemVolume = 0x2, + CommitSystemHives = 0x4, + CommitLowest = 0x8, + CorruptForRecovery = 0x10, + CorruptForProgress = 0x20, + MaximumOption = 0x3f + } + public enum TokenElevationType : int { Default = 1, @@ -1130,6 +1209,13 @@ namespace ProcessHacker.Native.Api Impersonation } + [Flags] + public enum TransactionOptions : int + { + DoNotPromote = 0x1, + MaximumOption = 0x1 + } + public enum WaitType : int { WaitAll, diff --git a/trunk/ProcessHacker.Native/Api/NativeFunctions.cs b/trunk/ProcessHacker.Native/Api/NativeFunctions.cs index 094371064..26c1934d9 100644 --- a/trunk/ProcessHacker.Native/Api/NativeFunctions.cs +++ b/trunk/ProcessHacker.Native/Api/NativeFunctions.cs @@ -33,6 +33,13 @@ namespace ProcessHacker.Native.Api { // IMPORTANT: All timeouts, etc. are in 100ns units except when stated otherwise. + // These definitions were gathered from these sources: + // + // * The NDK. + // * The NT API headers. + // * ReactOS source code. + // * The Windows DDK. + #region System Calls [DllImport("ntdll.dll")] @@ -131,6 +138,24 @@ namespace ProcessHacker.Native.Api [In] IntPtr Handle ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtCommitComplete( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCommitEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCommitTransaction( + [In] ref IntPtr TransactionHandle, + [In] bool Wait + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtCompareTokens( [In] IntPtr FirstTokenHandle, @@ -215,6 +240,18 @@ namespace ProcessHacker.Native.Api [In] ref ObjectAttributes ObjectAttributes ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateEnlistment( + [Out] out IntPtr EnlistmentHandle, + [In] EnlistmentAccess DesiredAccess, + [In] IntPtr ResourceManagerHandle, + [In] IntPtr TransactionHandle, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] EnlistmentOptions CreateOptions, + [In] NotificationMask NotificationMask, + [In] [Optional] IntPtr EnlistmentKey + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtCreateEvent( [Out] out IntPtr EventHandle, @@ -384,6 +421,17 @@ namespace ProcessHacker.Native.Api [In] IntPtr Affinity ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateResourceManager( + [Out] out IntPtr ResourceManagerHandle, + [In] ResourceManagerAccess DesiredAccess, + [In] IntPtr TmHandle, + [In] [Optional] ref Guid ResourceManagerGuid, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ResourceManagerOptions CreateOptions, + [In] [Optional] ref UnicodeString Description // should be null-terminated + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtCreateSection( [Out] out IntPtr SectionHandle, @@ -503,6 +551,30 @@ namespace ProcessHacker.Native.Api [In] ref TokenSource TokenSource ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateTransaction( + [Out] out IntPtr TransactionHandle, + [In] TransactionAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref Guid Uow, // Unit of work identifier + [In] [Optional] IntPtr TmHandle, + [In] [Optional] TransactionOptions CreateOptions, + [In] [Optional] int IsolationLevel, // Reserved + [In] [Optional] int IsolationFlags, // Reserved + [In] [Optional] ref long Timeout, + [In] [Optional] ref UnicodeString Description + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateTransactionManager( + [Out] out IntPtr TmHandle, + [In] TmAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref UnicodeString LogFileName, + [In] [Optional] TmOptions CreateOptions, + [In] [Optional] int CreateStrength // Reserved + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtCreateWaitablePort( [Out] out IntPtr PortHandle, @@ -580,6 +652,15 @@ namespace ProcessHacker.Native.Api [Out] out IntPtr NewTokenHandle ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtEnumerateTransactionObject( + [In] [Optional] IntPtr RootObjectHandle, + [In] KtmObjectType QueryType, + ref KtmObjectCursor ObjectCursor, + [In] int ObjectCursorLength, + [Out] out int ReturnLength + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtExtendSection( [In] IntPtr SectionHandle, @@ -640,6 +721,17 @@ namespace ProcessHacker.Native.Api [Out] out IntPtr NewThreadHandle ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtGetNotificationResourceManager( + [In] IntPtr ResourceManagerHandle, + [In] IntPtr TransactionNotification, // TransactionNotification* + [In] int NotificationLength, + [In] ref long Timeout, + [Out] [Optional] out int ReturnLength, + [In] int Asynchronous, // Must be zero. + [In] [Optional] IntPtr AsynchronousContext + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtImpersonateAnonymousToken( [In] IntPtr ThreadHandle @@ -714,6 +806,15 @@ namespace ProcessHacker.Native.Api [In] ref ObjectAttributes ObjectAttributes ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenEnlistment( + [Out] out IntPtr EnlistmentHandle, + [In] EnlistmentAccess DesiredAccess, + [In] IntPtr RmHandle, + [In] ref Guid EnlistmentGuid, + [In] [Optional] ref ObjectAttributes ObjectAttributes + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtOpenEvent( [Out] out IntPtr EventHandle, @@ -797,6 +898,15 @@ namespace ProcessHacker.Native.Api [Out] out IntPtr TokenHandle ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenResourceManager( + [Out] out IntPtr ResourceManagerHandle, + [In] ResourceManagerAccess DesiredAccess, + [In] IntPtr TmHandle, + [In] ref Guid ResourceManagerGuid, + [In] [Optional] ref ObjectAttributes ObjectAttributes + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtOpenSection( [Out] out IntPtr SectionHandle, @@ -858,6 +968,49 @@ namespace ProcessHacker.Native.Api [In] ref ObjectAttributes ObjectAttributes ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenTransaction( + [Out] out IntPtr TransactionHandle, + [In] TransactionAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] ref Guid Uow, + [In] [Optional] IntPtr TmHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenTransactionManager( + [Out] out IntPtr TmHandle, + [In] TmAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref UnicodeString LogFileName, + [In] [Optional] ref Guid TmIdentity, + [In] [Optional] int OpenOptions // Must be zero. + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrepareComplete( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrepareEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrePrepareComplete( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrePrepareEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtPrivilegeCheck( [In] IntPtr ClientToken, @@ -1229,6 +1382,12 @@ namespace ProcessHacker.Native.Api [In] [Optional] IntPtr ApcArgument3 ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtReadOnlyEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtReadRequestData( [In] IntPtr PortHandle, @@ -1248,6 +1407,22 @@ namespace ProcessHacker.Native.Api [Out] [Optional] out IntPtr ReturnLength ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtRecoverEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] IntPtr EnlistmentKey + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRecoverResourceManager( + [In] IntPtr ResourceManagerHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRecoverTransactionManager( + [In] IntPtr TransactionManagerHandle + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtRegisterThreadTerminatePort( [In] IntPtr PortHandle @@ -1348,6 +1523,30 @@ namespace ProcessHacker.Native.Api [Out] [Optional] out int PreviousSuspendCount ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtRollbackComplete( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRollbackEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRollbackTransaction( + [In] ref IntPtr TransactionHandle, + [In] bool Wait + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRollforwardTransactionManager( + [In] ref IntPtr TransactionManagerHandle, + [In] [Optional] ref long TmVirtualClock + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtSetContextThread( [In] IntPtr ThreadHandle, @@ -1507,6 +1706,12 @@ namespace ProcessHacker.Native.Api [In] [Optional] ref long Timeout ); + [DllImport("ntdll.dll")] + public static extern NtStatus NtSinglePhaseReject( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + [DllImport("ntdll.dll")] public static extern NtStatus NtStartProfile( [In] IntPtr ProfileHandle diff --git a/trunk/ProcessHacker.Native/Api/NativeStructs.cs b/trunk/ProcessHacker.Native/Api/NativeStructs.cs index 51e944f4d..59262c590 100644 --- a/trunk/ProcessHacker.Native/Api/NativeStructs.cs +++ b/trunk/ProcessHacker.Native/Api/NativeStructs.cs @@ -780,6 +780,15 @@ namespace ProcessHacker.Native.Api public int SidStart; } + [StructLayout(LayoutKind.Sequential)] + public struct KtmObjectCursor + { + public Guid LastQuery; + public int ObjectIdCount; + public byte ObjectIds; + // Array of Guids follows. + } + [StructLayout(LayoutKind.Explicit, Size = 8)] public struct LargeInteger { @@ -2326,6 +2335,15 @@ namespace ProcessHacker.Native.Api public SidAndAttributes User; } + [StructLayout(LayoutKind.Sequential)] + public struct TransactionNotification + { + public IntPtr TransactionKey; + public NotificationMask Notification; // Original name: TransactionNotification + public long TmVirtualClock; + public int ArgumentLength; + } + [StructLayout(LayoutKind.Sequential)] public struct UnicodeString : IComparable, IEquatable, IDisposable { diff --git a/trunk/ProcessHacker.Native/Debugging/DebugBuffer.cs b/trunk/ProcessHacker.Native/Debugging/DebugBuffer.cs index 66e58b8cc..561aadf8c 100644 --- a/trunk/ProcessHacker.Native/Debugging/DebugBuffer.cs +++ b/trunk/ProcessHacker.Native/Debugging/DebugBuffer.cs @@ -69,7 +69,7 @@ namespace ProcessHacker.Native.Debugging if (debugInfo.Heaps == IntPtr.Zero) throw new InvalidOperationException("Heap information does not exist."); - MemoryAlloc heapInfo = new MemoryAlloc(debugInfo.Heaps, false); + MemoryRegion heapInfo = new MemoryRegion(debugInfo.Heaps); var heaps = heapInfo.ReadStruct(); for (int i = 0; i < heaps.NumberOfHeaps; i++) @@ -92,7 +92,7 @@ namespace ProcessHacker.Native.Debugging if (debugInfo.Locks == IntPtr.Zero) throw new InvalidOperationException("Lock information does not exist."); - MemoryAlloc locksInfo = new MemoryAlloc(debugInfo.Locks, false); + MemoryRegion locksInfo = new MemoryRegion(debugInfo.Locks); var locks = locksInfo.ReadStruct(); for (int i = 0; i < locks.NumberOfLocks; i++) @@ -115,7 +115,7 @@ namespace ProcessHacker.Native.Debugging if (debugInfo.Modules == IntPtr.Zero) throw new InvalidOperationException("Module information does not exist."); - MemoryAlloc modulesInfo = new MemoryAlloc(debugInfo.Modules, false); + MemoryRegion modulesInfo = new MemoryRegion(debugInfo.Modules); var modules = modulesInfo.ReadStruct(); for (int i = 0; i < modules.NumberOfModules; i++) @@ -133,7 +133,7 @@ namespace ProcessHacker.Native.Debugging /// A RtlDebugInformation structure. private RtlDebugInformation GetDebugInformation() { - MemoryAlloc data = new MemoryAlloc(_buffer, false); + MemoryRegion data = new MemoryRegion(_buffer); return data.ReadStruct(); } diff --git a/trunk/ProcessHacker.Native/KProcessHacker.cs b/trunk/ProcessHacker.Native/KProcessHacker.cs index edfa132e9..1d2570039 100644 --- a/trunk/ProcessHacker.Native/KProcessHacker.cs +++ b/trunk/ProcessHacker.Native/KProcessHacker.cs @@ -1148,6 +1148,8 @@ namespace ProcessHacker.Native [StructLayout(LayoutKind.Sequential)] public struct KphSsArgumentBlock { + public static readonly int DataOffset = Marshal.OffsetOf(typeof(KphSsArgumentBlock), "Data").ToInt32(); + [StructLayout(LayoutKind.Explicit)] public struct KphSsArgumentUnion { @@ -1190,7 +1192,7 @@ namespace ProcessHacker.Native public struct KphSsEventBlock { public KphSsBlockHeader Header; - public int Flags; + public KphSsEventFlags Flags; public long Time; public ClientId ClientId; @@ -1221,6 +1223,8 @@ namespace ProcessHacker.Native [StructLayout(LayoutKind.Sequential)] public struct KphSsUnicodeString { + public static readonly int BufferOffset = Marshal.OffsetOf(typeof(KphSsUnicodeString), "Buffer").ToInt32(); + public ushort Length; public ushort MaximumLength; public IntPtr Pointer; @@ -1230,6 +1234,8 @@ namespace ProcessHacker.Native [StructLayout(LayoutKind.Sequential)] public struct KphSsWString { + public static readonly int BufferOffset = Marshal.OffsetOf(typeof(KphSsWString), "Buffer").ToInt32(); + public ushort Length; public byte Buffer; } diff --git a/trunk/ProcessHacker.Native/Memory/MemoryAlloc.cs b/trunk/ProcessHacker.Native/Memory/MemoryAlloc.cs index 228d696d1..9193c5cb2 100644 --- a/trunk/ProcessHacker.Native/Memory/MemoryAlloc.cs +++ b/trunk/ProcessHacker.Native/Memory/MemoryAlloc.cs @@ -30,53 +30,25 @@ using ProcessHacker.Native.Api; namespace ProcessHacker.Native { /// - /// Represents an unmanaged memory allocation. + /// Represents an unmanaged memory allocation from the heap. /// - public class MemoryAlloc : BaseObject + public class MemoryAlloc : MemoryRegion { // A private heap just for the client. private static Heap _privateHeap = new Heap(HeapFlags.Class1 | HeapFlags.Growable); private static Heap _processHeap = Heap.GetDefault(); - private static Dictionary _sizeCache = new Dictionary(); public static IntPtr PrivateHeap { get { return _privateHeap.Address; } } - public static implicit operator int(MemoryAlloc memory) - { - return memory.Memory.ToInt32(); - } - - public static implicit operator IntPtr(MemoryAlloc memory) - { - return memory.Memory; - } - - public unsafe static implicit operator byte*(MemoryAlloc memory) - { - return (byte*)memory.Memory; - } - - public unsafe static explicit operator void*(MemoryAlloc memory) - { - return (void*)memory.Memory; - } - - public unsafe static explicit operator int*(MemoryAlloc memory) - { - return (int*)memory.Memory; - } - - private IntPtr _memory; - private int _size; - /// /// Creates a new, invalid memory allocation. /// You must set the pointer using the Memory property. /// protected MemoryAlloc() + : base() { } public MemoryAlloc(IntPtr memory) @@ -88,11 +60,8 @@ namespace ProcessHacker.Native { } public MemoryAlloc(IntPtr memory, int size, bool owned) - : base(owned) - { - _memory = memory; - _size = size; - } + : base(memory, size, owned) + { } /// /// Creates a new memory allocation with the specified size. @@ -100,239 +69,23 @@ namespace ProcessHacker.Native /// The amount of memory, in bytes, to allocate. public MemoryAlloc(int size) { - _memory = _privateHeap.Allocate(0, size); - _size = size; + this.Memory = _privateHeap.Allocate(0, size); + this.Size = size; } - protected sealed override void DisposeObject(bool disposing) - { - this.Free(); - } - - protected virtual void Free() + protected override void Free() { _privateHeap.Free(0, this); } - /// - /// Gets a pointer to the allocated memory. - /// - public IntPtr Memory - { - get { return _memory; } - protected set { _memory = value; } - } - - /// - /// Gets the size of the allocated memory. - /// - public virtual int Size - { - get { return _size; } - protected set { _size = value; } - } - - public MemoryAllocStream GetStream() - { - return new MemoryAllocStream(this); - } - - private int GetStructSizeCached(Type structType) - { - if (!_sizeCache.ContainsKey(structType)) - _sizeCache.Add(structType, Marshal.SizeOf(structType)); - - return _sizeCache[structType]; - } - - public byte[] ReadBytes(int length) - { - return this.ReadBytes(0, length); - } - - public byte[] ReadBytes(int offset, int length) - { - byte[] buffer = new byte[length]; - - this.ReadBytes(offset, buffer, 0, length); - - return buffer; - } - - public void ReadBytes(byte[] buffer, int startIndex, int length) - { - this.ReadBytes(0, buffer, startIndex, length); - } - - public void ReadBytes(int offset, byte[] buffer, int startIndex, int length) - { - Marshal.Copy(_memory.Increment(offset), buffer, startIndex, length); - } - - /// - /// Reads a signed integer. - /// - /// The offset at which to begin reading. - /// The integer. - public int ReadInt32(int offset) - { - return this.ReadInt32(offset, 0); - } - - /// - /// Reads a signed integer. - /// - /// The offset at which to begin reading. - /// The index at which to begin reading, after the offset is added. - /// The integer. - public int ReadInt32(int offset, int index) - { - return Marshal.ReadInt32(_memory, offset + index * sizeof(int)); - } - - public IntPtr ReadIntPtr(int offset) - { - return this.ReadIntPtr(offset, 0); - } - - public IntPtr ReadIntPtr(int offset, int index) - { - return Marshal.ReadIntPtr(_memory, offset + index * IntPtr.Size); - } - - /// - /// Reads an unsigned integer. - /// - /// The offset at which to begin reading. - /// The integer. - public uint ReadUInt32(int offset) - { - return this.ReadUInt32(offset, 0); - } - - /// - /// Reads an unsigned integer. - /// - /// The offset at which to begin reading. - /// The index at which to begin reading, after the offset is added. - /// The integer. - public uint ReadUInt32(int offset, int index) - { - return (uint)this.ReadInt32(offset, index); - } - - /// - /// Creates a struct from the memory allocation. - /// - /// The type of the struct. - /// The new struct. - public T ReadStruct() - { - return this.ReadStruct(0); - } - - /// - /// Creates a struct from the memory allocation. - /// - /// The type of the struct. - /// The index at which to begin reading to the struct. This is multiplied by - /// the size of the struct. - /// The new struct. - public T ReadStruct(int index) - { - return this.ReadStruct(0, index); - } - - /// - /// Creates a struct from the memory allocation. - /// - /// The type of the struct. - /// The offset to add before reading. - /// The index at which to begin reading to the struct. This is multiplied by - /// the size of the struct. - /// The new struct. - public T ReadStruct(int offset, int index) - { - return (T)Marshal.PtrToStructure( - _memory.Increment(offset + this.GetStructSizeCached(typeof(T)) * index), typeof(T)); - } - /// /// Resizes the memory allocation. /// /// The new size of the allocation. public virtual void Resize(int newSize) { - _memory = _privateHeap.Reallocate(0, _memory, newSize); - _size = newSize; - } - - /// - /// Writes a single byte to the memory allocation. - /// - /// The offset at which to write. - /// The value of the byte. - public void WriteByte(int offset, byte b) - { - Marshal.WriteByte(this, offset, b); - } - - public void WriteBytes(int offset, byte[] b) - { - Marshal.Copy(b, 0, _memory.Increment(offset), b.Length); - } - - public void WriteInt16(int offset, short i) - { - Marshal.WriteInt16(this, offset, i); - } - - public void WriteInt32(int offset, int i) - { - Marshal.WriteInt32(this, offset, i); - } - - public void WriteIntPtr(int offset, IntPtr i) - { - Marshal.WriteIntPtr(this, offset, i); - } - - public void WriteMemory(int destOffset, IntPtr data, int srcOffset, int length) - { - ProcessHacker.Native.Api.Win32.RtlMoveMemory( - _memory.Increment(destOffset), - data.Increment(srcOffset), - length.ToIntPtr() - ); - } - - public void WriteStruct(T s) - { - this.WriteStruct(0, s); - } - - public void WriteStruct(int index, T s) - { - this.WriteStruct(0, index, s); - } - - public void WriteStruct(int offset, int index, T s) - { - Marshal.StructureToPtr(s, - _memory.Increment(offset + this.GetStructSizeCached(typeof(T)) * index), false); - } - - /// - /// Writes a Unicode string to the allocated memory. - /// - /// The offset to add. - /// The string to write. - public void WriteUnicodeString(int offset, string s) - { - byte[] b = UnicodeEncoding.Unicode.GetBytes(s); - - for (int i = 0; i < b.Length; i++) - Marshal.WriteByte(this.Memory, offset + i, b[i]); + this.Memory = _privateHeap.Reallocate(0, this.Memory, newSize); + this.Size = newSize; } } } diff --git a/trunk/ProcessHacker.Native/Memory/MemoryRegion.cs b/trunk/ProcessHacker.Native/Memory/MemoryRegion.cs new file mode 100644 index 000000000..2e841caa8 --- /dev/null +++ b/trunk/ProcessHacker.Native/Memory/MemoryRegion.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Common.Objects; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native +{ + public class MemoryRegion : BaseObject + { + private static Dictionary _sizeCache = new Dictionary(); + + public static implicit operator int(MemoryRegion memory) + { + return memory.Memory.ToInt32(); + } + + public static implicit operator IntPtr(MemoryRegion memory) + { + return memory.Memory; + } + + public unsafe static implicit operator byte*(MemoryRegion memory) + { + return (byte*)memory.Memory; + } + + public unsafe static explicit operator void*(MemoryRegion memory) + { + return (void*)memory.Memory; + } + + public unsafe static explicit operator int*(MemoryRegion memory) + { + return (int*)memory.Memory; + } + + private IntPtr _memory; + private int _size; + + /// + /// Creates a new, invalid memory allocation. + /// You must set the pointer using the Memory property. + /// + protected MemoryRegion() + { } + + public MemoryRegion(IntPtr memory) + : this(memory, 0) + { } + + public MemoryRegion(IntPtr memory, int offset) + : this(memory.Increment(offset), 0, false) + { } + + protected MemoryRegion(IntPtr memory, int size, bool owned) + : base(owned) + { + _memory = memory; + _size = size; + } + + protected sealed override void DisposeObject(bool disposing) + { + this.Free(); + } + + protected virtual void Free() + { } + + /// + /// Gets a pointer to the allocated memory. + /// + public IntPtr Memory + { + get { return _memory; } + protected set { _memory = value; } + } + + /// + /// Gets the size of the allocated memory. + /// + public virtual int Size + { + get { return _size; } + protected set { _size = value; } + } + + public MemoryRegionStream GetStream() + { + return new MemoryRegionStream(this); + } + + private int GetStructSizeCached(Type structType) + { + if (!_sizeCache.ContainsKey(structType)) + _sizeCache.Add(structType, Marshal.SizeOf(structType)); + + return _sizeCache[structType]; + } + + public byte[] ReadBytes(int length) + { + return this.ReadBytes(0, length); + } + + public byte[] ReadBytes(int offset, int length) + { + byte[] buffer = new byte[length]; + + this.ReadBytes(offset, buffer, 0, length); + + return buffer; + } + + public void ReadBytes(byte[] buffer, int startIndex, int length) + { + this.ReadBytes(0, buffer, startIndex, length); + } + + public void ReadBytes(int offset, byte[] buffer, int startIndex, int length) + { + Marshal.Copy(_memory.Increment(offset), buffer, startIndex, length); + } + + /// + /// Reads a signed integer. + /// + /// The offset at which to begin reading. + /// The integer. + public int ReadInt32(int offset) + { + return this.ReadInt32(offset, 0); + } + + /// + /// Reads a signed integer. + /// + /// The offset at which to begin reading. + /// The index at which to begin reading, after the offset is added. + /// The integer. + public int ReadInt32(int offset, int index) + { + return Marshal.ReadInt32(_memory, offset + index * sizeof(int)); + } + + public IntPtr ReadIntPtr(int offset) + { + return this.ReadIntPtr(offset, 0); + } + + public IntPtr ReadIntPtr(int offset, int index) + { + return Marshal.ReadIntPtr(_memory, offset + index * IntPtr.Size); + } + + /// + /// Reads an unsigned integer. + /// + /// The offset at which to begin reading. + /// The integer. + public uint ReadUInt32(int offset) + { + return this.ReadUInt32(offset, 0); + } + + /// + /// Reads an unsigned integer. + /// + /// The offset at which to begin reading. + /// The index at which to begin reading, after the offset is added. + /// The integer. + public uint ReadUInt32(int offset, int index) + { + return (uint)this.ReadInt32(offset, index); + } + + /// + /// Creates a struct from the memory allocation. + /// + /// The type of the struct. + /// The new struct. + public T ReadStruct() + { + return this.ReadStruct(0); + } + + /// + /// Creates a struct from the memory allocation. + /// + /// The type of the struct. + /// The index at which to begin reading to the struct. This is multiplied by + /// the size of the struct. + /// The new struct. + public T ReadStruct(int index) + { + return this.ReadStruct(0, index); + } + + /// + /// Creates a struct from the memory allocation. + /// + /// The type of the struct. + /// The offset to add before reading. + /// The index at which to begin reading to the struct. This is multiplied by + /// the size of the struct. + /// The new struct. + public T ReadStruct(int offset, int index) + { + return (T)Marshal.PtrToStructure( + _memory.Increment(offset + this.GetStructSizeCached(typeof(T)) * index), typeof(T)); + } + + public string ReadUnicodeString(int offset) + { + return Marshal.PtrToStringUni(_memory.Increment(offset)); + } + + public string ReadUnicodeString(int offset, int length) + { + return Marshal.PtrToStringUni(_memory.Increment(offset), length); + } + + /// + /// Writes a single byte to the memory allocation. + /// + /// The offset at which to write. + /// The value of the byte. + public void WriteByte(int offset, byte b) + { + Marshal.WriteByte(this, offset, b); + } + + public void WriteBytes(int offset, byte[] b) + { + Marshal.Copy(b, 0, _memory.Increment(offset), b.Length); + } + + public void WriteInt16(int offset, short i) + { + Marshal.WriteInt16(this, offset, i); + } + + public void WriteInt32(int offset, int i) + { + Marshal.WriteInt32(this, offset, i); + } + + public void WriteIntPtr(int offset, IntPtr i) + { + Marshal.WriteIntPtr(this, offset, i); + } + + public void WriteMemory(int destOffset, IntPtr data, int srcOffset, int length) + { + ProcessHacker.Native.Api.Win32.RtlMoveMemory( + _memory.Increment(destOffset), + data.Increment(srcOffset), + length.ToIntPtr() + ); + } + + public void WriteStruct(T s) + { + this.WriteStruct(0, s); + } + + public void WriteStruct(int index, T s) + { + this.WriteStruct(0, index, s); + } + + public void WriteStruct(int offset, int index, T s) + { + Marshal.StructureToPtr(s, + _memory.Increment(offset + this.GetStructSizeCached(typeof(T)) * index), false); + } + + /// + /// Writes a Unicode string to the allocated memory. + /// + /// The offset to add. + /// The string to write. + public void WriteUnicodeString(int offset, string s) + { + byte[] b = UnicodeEncoding.Unicode.GetBytes(s); + + for (int i = 0; i < b.Length; i++) + Marshal.WriteByte(this.Memory, offset + i, b[i]); + } + } +} diff --git a/trunk/ProcessHacker.Native/Memory/MemoryAllocStream.cs b/trunk/ProcessHacker.Native/Memory/MemoryRegionStream.cs similarity index 90% rename from trunk/ProcessHacker.Native/Memory/MemoryAllocStream.cs rename to trunk/ProcessHacker.Native/Memory/MemoryRegionStream.cs index 60e9b0105..c4a133b2a 100644 --- a/trunk/ProcessHacker.Native/Memory/MemoryAllocStream.cs +++ b/trunk/ProcessHacker.Native/Memory/MemoryRegionStream.cs @@ -6,12 +6,12 @@ using System.Runtime.InteropServices; namespace ProcessHacker.Native { - public class MemoryAllocStream : Stream + public class MemoryRegionStream : Stream { - private MemoryAlloc _memory; + private MemoryRegion _memory; private long _position = 0; - public MemoryAllocStream(MemoryAlloc memory) + public MemoryRegionStream(MemoryRegion memory) { _memory = memory; } diff --git a/trunk/ProcessHacker.Native/Memory/VirtualMemoryAlloc.cs b/trunk/ProcessHacker.Native/Memory/VirtualMemoryAlloc.cs new file mode 100644 index 000000000..bc9d8dbd7 --- /dev/null +++ b/trunk/ProcessHacker.Native/Memory/VirtualMemoryAlloc.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native +{ + public class VirtualMemoryAlloc : MemoryAlloc + { + public VirtualMemoryAlloc(int size) + { + this.Memory = ProcessHandle.Current.AllocateMemory(size, MemoryProtection.ReadWrite); + this.Size = size; + } + + protected override void Free() + { + base.Free(); + } + + public override void Resize(int newSize) + { + throw new NotImplementedException(); + } + } +} diff --git a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj index ce3ac9679..0fdd80d9e 100644 --- a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj +++ b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj @@ -62,10 +62,12 @@ - + + + @@ -78,11 +80,22 @@ + + + + + + + + + + + diff --git a/trunk/ProcessHacker.Native/Security/AccessControl/Ace.cs b/trunk/ProcessHacker.Native/Security/AccessControl/Ace.cs index bca80f73f..fc23705cb 100644 --- a/trunk/ProcessHacker.Native/Security/AccessControl/Ace.cs +++ b/trunk/ProcessHacker.Native/Security/AccessControl/Ace.cs @@ -46,7 +46,7 @@ namespace ProcessHacker.Native.Security.AccessControl public static AceType GetType(IntPtr ace) { - MemoryAlloc memory = new MemoryAlloc(ace, false); + MemoryRegion memory = new MemoryRegion(ace); return memory.ReadStruct().AceType; } @@ -56,7 +56,7 @@ namespace ProcessHacker.Native.Security.AccessControl return ace.Memory; } - private MemoryAlloc _memory; + private MemoryRegion _memory; private AceFlags _flags; private int _size; private AceType _type; @@ -80,7 +80,7 @@ namespace ProcessHacker.Native.Security.AccessControl } else { - _memory = new MemoryAlloc(memory, false); + _memory = new MemoryRegion(memory); } this.Read(); @@ -102,7 +102,7 @@ namespace ProcessHacker.Native.Security.AccessControl get { return _memory; } } - protected MemoryAlloc MemoryAlloc + protected MemoryRegion MemoryRegion { get { return _memory; } set { _memory = value; } diff --git a/trunk/ProcessHacker.Native/Security/AccessControl/Acl.cs b/trunk/ProcessHacker.Native/Security/AccessControl/Acl.cs index 879f7257e..c075d66a6 100644 --- a/trunk/ProcessHacker.Native/Security/AccessControl/Acl.cs +++ b/trunk/ProcessHacker.Native/Security/AccessControl/Acl.cs @@ -35,7 +35,7 @@ namespace ProcessHacker.Native.Security.AccessControl return acl.Memory; } - private MemoryAlloc _memory; + private MemoryRegion _memory; public Acl(int size) { @@ -79,7 +79,7 @@ namespace ProcessHacker.Native.Security.AccessControl } else { - _memory = new MemoryAlloc(memory, false); + _memory = new MemoryRegion(memory); } } diff --git a/trunk/ProcessHacker.Native/Security/AccessControl/KnownAce.cs b/trunk/ProcessHacker.Native/Security/AccessControl/KnownAce.cs index 9a306d08f..a6ee717a0 100644 --- a/trunk/ProcessHacker.Native/Security/AccessControl/KnownAce.cs +++ b/trunk/ProcessHacker.Native/Security/AccessControl/KnownAce.cs @@ -45,7 +45,7 @@ namespace ProcessHacker.Native.Security.AccessControl ) throw new ArgumentException("Invalid ACE type."); - this.MemoryAlloc = new MemoryAlloc( + this.MemoryRegion = new MemoryAlloc( Marshal.SizeOf(typeof(KnownAceStruct)) - // known ace struct size sizeof(int) + // minus SidStart field sid.Length // plus SID length @@ -56,12 +56,12 @@ namespace ProcessHacker.Native.Security.AccessControl // Initialize the ACE (minus the SID). knownAce.Header.AceType = type; knownAce.Header.AceFlags = flags; - knownAce.Header.AceSize = (ushort)this.MemoryAlloc.Size; + knownAce.Header.AceSize = (ushort)this.MemoryRegion.Size; knownAce.Mask = mask; // Write the ACE to memory. - this.MemoryAlloc.WriteStruct(knownAce); + this.MemoryRegion.WriteStruct(knownAce); // Write the SID. - this.MemoryAlloc.WriteMemory(Win32.KnownAceSidStartOffset.ToInt32(), sid, 0, sid.Length); + this.MemoryRegion.WriteMemory(Win32.KnownAceSidStartOffset.ToInt32(), sid, 0, sid.Length); // Update the cached info. this.Read(); } @@ -82,8 +82,7 @@ namespace ProcessHacker.Native.Security.AccessControl protected override void Read() { - var memory = new MemoryAlloc(this.Memory, false); - var knownAce = memory.ReadStruct(); + var knownAce = this.MemoryRegion.ReadStruct(); _mask = knownAce.Mask; _sid = Sid.FromPointer(this.Memory.Increment(Win32.KnownAceSidStartOffset)); diff --git a/trunk/ProcessHacker.Native/Security/AccessControl/SecurityDescriptor.cs b/trunk/ProcessHacker.Native/Security/AccessControl/SecurityDescriptor.cs index a56349ad9..883c1a77e 100644 --- a/trunk/ProcessHacker.Native/Security/AccessControl/SecurityDescriptor.cs +++ b/trunk/ProcessHacker.Native/Security/AccessControl/SecurityDescriptor.cs @@ -34,7 +34,7 @@ namespace ProcessHacker.Native.Security.AccessControl return securityDescriptor.Memory; } - private MemoryAlloc _memory; + private MemoryRegion _memory; private bool _memoryOwned = true; private Acl _dacl; private Acl _sacl; @@ -59,10 +59,10 @@ namespace ProcessHacker.Native.Security.AccessControl } public SecurityDescriptor(IntPtr memory) - : this(new MemoryAlloc(memory, false), false) + : this(new MemoryRegion(memory), false) { } - public SecurityDescriptor(MemoryAlloc memory, bool owned) + public SecurityDescriptor(MemoryRegion memory, bool owned) { _memory = memory; _memoryOwned = owned; diff --git a/trunk/ProcessHacker.Native/Security/EnlistmentAccess.cs b/trunk/ProcessHacker.Native/Security/EnlistmentAccess.cs new file mode 100644 index 000000000..061fd1f79 --- /dev/null +++ b/trunk/ProcessHacker.Native/Security/EnlistmentAccess.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum EnlistmentAccess : uint + { + QueryInformation = 0x0001, + SetInformation = 0x0002, + Recover = 0x0004, + SubordinateRights = 0x0008, + SuperiorRights = 0x0010, + GenericRead = StandardRights.Read | QueryInformation, + GenericWrite = StandardRights.Write | SetInformation | Recover | + SubordinateRights | SuperiorRights, + GenericExecute = StandardRights.Execute | Recover | SubordinateRights | + SuperiorRights, + All = StandardRights.Required | GenericRead | GenericWrite | GenericExecute + } +} diff --git a/trunk/ProcessHacker.Native/Security/PrivilegeSet.cs b/trunk/ProcessHacker.Native/Security/PrivilegeSet.cs index 6cff98d7f..4f07abc61 100644 --- a/trunk/ProcessHacker.Native/Security/PrivilegeSet.cs +++ b/trunk/ProcessHacker.Native/Security/PrivilegeSet.cs @@ -54,14 +54,14 @@ namespace ProcessHacker.Native.Security public PrivilegeSet(IntPtr memory) { - MemoryAlloc memoryAlloc = new MemoryAlloc(memory, false); - int count = memoryAlloc.ReadInt32(0); - PrivilegeSetFlags flags = (PrivilegeSetFlags)memoryAlloc.ReadInt32(4); + MemoryRegion memoryRegion = new MemoryRegion(memory); + int count = memoryRegion.ReadInt32(0); + PrivilegeSetFlags flags = (PrivilegeSetFlags)memoryRegion.ReadInt32(4); _privileges = new List(count); for (int i = 0; i < count; i++) - _privileges.Add(new Privilege(memoryAlloc.ReadStruct(8, i))); + _privileges.Add(new Privilege(memoryRegion.ReadStruct(8, i))); } public PrivilegeSetFlags Flags diff --git a/trunk/ProcessHacker.Native/Security/ResourceManagerAccess.cs b/trunk/ProcessHacker.Native/Security/ResourceManagerAccess.cs new file mode 100644 index 000000000..9f4408446 --- /dev/null +++ b/trunk/ProcessHacker.Native/Security/ResourceManagerAccess.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum ResourceManagerAccess : uint + { + QueryInformation = 0x0001, + SetInformation = 0x0002, + Recover = 0x0004, + Enlist = 0x0008, + GetNotification = 0x0010, + RegisterProtocol = 0x0020, + CompletePropagation = 0x0040, + GenericRead = StandardRights.Read | QueryInformation | StandardRights.Synchronize, + GenericWrite = StandardRights.Write | SetInformation | Recover | Enlist | + GetNotification | RegisterProtocol | CompletePropagation | StandardRights.Synchronize, + GenericExecute = StandardRights.Execute | Recover | Enlist | GetNotification | + CompletePropagation | StandardRights.Synchronize, + All = StandardRights.Required | GenericRead | GenericWrite | GenericExecute + } +} diff --git a/trunk/ProcessHacker.Native/Security/TmAccess.cs b/trunk/ProcessHacker.Native/Security/TmAccess.cs new file mode 100644 index 000000000..7794c5ecc --- /dev/null +++ b/trunk/ProcessHacker.Native/Security/TmAccess.cs @@ -0,0 +1,21 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum TmAccess : uint + { + QueryInformation = 0x0001, + SetInformation = 0x0002, + Recover = 0x0004, + Rename = 0x0008, + CreateRm = 0x0010, + // About to be deprecated - for DTC use only. + BindTransaction = 0x0020, + GenericRead = StandardRights.Read | QueryInformation, + GenericWrite = StandardRights.Write | SetInformation | Recover | Rename | CreateRm, + GenericExecute = StandardRights.Execute, + All = StandardRights.Required | GenericRead | GenericWrite | + GenericExecute | BindTransaction, + } +} diff --git a/trunk/ProcessHacker.Native/Security/TransactionAccess.cs b/trunk/ProcessHacker.Native/Security/TransactionAccess.cs new file mode 100644 index 000000000..870a38b8c --- /dev/null +++ b/trunk/ProcessHacker.Native/Security/TransactionAccess.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum TransactionAccess : uint + { + QueryInformation = 0x0001, + SetInformation = 0x0002, + Enlist = 0x0004, + Commit = 0x0008, + Rollback = 0x0010, + Propagate = 0x0020, + RightReserved1 = 0x0040, + GenericRead = StandardRights.Read | QueryInformation | StandardRights.Synchronize, + GenericWrite = StandardRights.Write | SetInformation | Commit | Enlist | Rollback | + Propagate | StandardRights.Synchronize, + GenericExecute = StandardRights.Execute | Commit | Rollback | StandardRights.Synchronize, + All = StandardRights.Required | GenericRead | GenericWrite | GenericExecute, + + ResourceManagerRights = GenericRead | StandardRights.Write | SetInformation | + Enlist | Rollback | Propagate | StandardRights.Synchronize + } +} diff --git a/trunk/ProcessHacker.Native/SsLogging/SsData.cs b/trunk/ProcessHacker.Native/SsLogging/SsData.cs new file mode 100644 index 000000000..73f30465f --- /dev/null +++ b/trunk/ProcessHacker.Native/SsLogging/SsData.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.SsLogging +{ + public class SsData + { + } +} diff --git a/trunk/ProcessHacker.Native/SsLogging/SsEvent.cs b/trunk/ProcessHacker.Native/SsLogging/SsEvent.cs new file mode 100644 index 000000000..ec697de49 --- /dev/null +++ b/trunk/ProcessHacker.Native/SsLogging/SsEvent.cs @@ -0,0 +1,62 @@ +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.SsLogging +{ + public sealed class SsEvent + { + public int[] Arguments + { + get; + internal set; + } + + public bool ArgumentsCopyFailed + { + get; + internal set; + } + + public bool ArgumentsProbeFailed + { + get; + internal set; + } + + public int CallNumber + { + get; + internal set; + } + + public KProcessorMode Mode + { + get; + internal set; + } + + public int ProcessId + { + get; + internal set; + } + + public IntPtr[] StackTrace + { + get; + internal set; + } + + public int ThreadId + { + get; + internal set; + } + + public DateTime Time + { + get; + internal set; + } + } +} diff --git a/trunk/ProcessHacker.Native/SsLogging/SsHandle.cs b/trunk/ProcessHacker.Native/SsLogging/SsHandle.cs new file mode 100644 index 000000000..d964e09e4 --- /dev/null +++ b/trunk/ProcessHacker.Native/SsLogging/SsHandle.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.SsLogging +{ + public sealed class SsHandle : SsData + { + internal SsHandle(MemoryRegion data) + { + KphSsHandle handleInfo = data.ReadStruct(); + + if (handleInfo.TypeNameOffset != 0) + { + this.TypeName = SsLogger.ReadWString(new MemoryRegion(data, handleInfo.TypeNameOffset)); + } + + if (handleInfo.NameOffset != 0) + { + this.Name = SsLogger.ReadWString(new MemoryRegion(data, handleInfo.NameOffset)); + } + + this.ProcessId = handleInfo.ClientId.ProcessId; + this.ThreadId = handleInfo.ClientId.ThreadId; + } + + public string Name + { + get; + private set; + } + + public int ProcessId + { + get; + private set; + } + + public int ThreadId + { + get; + private set; + } + + public string TypeName + { + get; + private set; + } + } +} diff --git a/trunk/ProcessHacker.Native/SsLogging/SsLogger.cs b/trunk/ProcessHacker.Native/SsLogging/SsLogger.cs new file mode 100644 index 000000000..91e78d5c2 --- /dev/null +++ b/trunk/ProcessHacker.Native/SsLogging/SsLogger.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using System.Threading; +using ProcessHacker.Native.Threading; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native.SsLogging +{ + public delegate void ArgumentBlockReceivedDelegate(SsData argBlock); + public delegate void EventBlockReceivedDelegate(SsEvent eventBlock); + + public sealed class SsLogger + { + private const int _highBlockSize = 0x200; + + internal static string ReadWString(MemoryRegion data) + { + KphSsWString wString = data.ReadStruct(); + + return data.ReadUnicodeString(KphSsWString.BufferOffset, wString.Length / 2); + } + + public event ArgumentBlockReceivedDelegate ArgumentBlockReceived; + public event EventBlockReceivedDelegate EventBlockReceived; + + private bool _started = false; + private object _startLock = new object(); + + private bool _terminating = false; + private Thread _bufferWorkerThread; + private ThreadHandle _bufferWorkerThreadHandle; + private Event _bufferWorkerThreadReadyEvent = new Event(true, false); + + private VirtualMemoryAlloc _buffer; + private SemaphoreHandle _readSemaphore; + private SemaphoreHandle _writeSemaphore; + private KphSsClientEntryHandle _clientEntryHandle; + private KphSsRuleSetEntryHandle _ruleSetEntryHandle; + + public SsLogger(int bufferedBlockCount, bool includeAll) + { + // Allocate a buffer. + _buffer = new VirtualMemoryAlloc(_highBlockSize * bufferedBlockCount); + + // Create the read and write semaphores. + + // Read semaphore: no blocks initially, so 0 initial count. + _readSemaphore = SemaphoreHandle.Create(SemaphoreAccess.All, 0, bufferedBlockCount); + // Write semaphore: all buffer blocks available so max. initial count. + _writeSemaphore = SemaphoreHandle.Create(SemaphoreAccess.All, bufferedBlockCount, bufferedBlockCount); + + // Create the client entry. + _clientEntryHandle = KProcessHacker.Instance.SsCreateClientEntry( + ProcessHandle.Current, + _readSemaphore, + _writeSemaphore, + _buffer, + _buffer.Size + ); + + // Create the ruleset entry. + _ruleSetEntryHandle = KProcessHacker.Instance.SsCreateRuleSetEntry( + _clientEntryHandle, + includeAll ? KphSsFilterType.Include : KphSsFilterType.Exclude, + KphSsRuleSetAction.Log + ); + } + + private void BufferWorkerThreadStart() + { + int cursor = 0; + + // Open a handle to the current thread so other functions + // can alert us. + _bufferWorkerThreadHandle = ThreadHandle.OpenCurrent(ThreadAccess.All); + + // We're ready. + _bufferWorkerThreadReadyEvent.Set(); + + while (!_terminating) + { + NtStatus status; + KphSsBlockHeader blockHeader; + + // Wait for a block to read (enable alerting so we can + // be interrupted if someone wants us to stop). + status = _readSemaphore.Wait(true); + + // Did we get alerted? + if (status == NtStatus.Alerted) + return; + + // Check if we have an implicit cursor reset. + if (_buffer.Size - cursor < Marshal.SizeOf(typeof(KphSsBlockHeader))) + cursor = 0; + + // Read the block header. + blockHeader = _buffer.ReadStruct(cursor, 0); + + // Check if we have an explicit cursor reset. + if (blockHeader.Type == KphSsBlockType.Reset) + { + cursor = 0; + blockHeader = _buffer.ReadStruct(cursor, 0); + } + + // Process the block. + if (blockHeader.Type == KphSsBlockType.Event) + { + var eventBlock = _buffer.ReadStruct(cursor, 0); + int[] arguments; + IntPtr[] stackTrace; + + // Reconstruct the argument and stack trace arrays. + + arguments = new int[eventBlock.NumberOfArguments]; + stackTrace = new IntPtr[eventBlock.TraceCount]; + + for (int i = 0; i < arguments.Length; i++) + arguments[i] = _buffer.ReadInt32(cursor + eventBlock.ArgumentsOffset, i); + for (int i = 0; i < stackTrace.Length; i++) + stackTrace[i] = _buffer.ReadIntPtr(cursor + eventBlock.TraceOffset, i); + + // Create an event object. + SsEvent ssEvent = new SsEvent(); + + // Basic information + ssEvent.Time = DateTime.FromFileTime(eventBlock.Time); + ssEvent.ThreadId = eventBlock.ClientId.ThreadId; + ssEvent.ProcessId = eventBlock.ClientId.ProcessId; + ssEvent.Arguments = arguments; + ssEvent.StackTrace = stackTrace; + + // Flags + ssEvent.ArgumentsCopyFailed = + (eventBlock.Flags & KphSsEventFlags.CopyArgumentsFailed) == KphSsEventFlags.CopyArgumentsFailed; + ssEvent.ArgumentsProbeFailed = + (eventBlock.Flags & KphSsEventFlags.ProbeArgumentsFailed) == KphSsEventFlags.ProbeArgumentsFailed; + ssEvent.CallNumber = eventBlock.Number; + + if ((eventBlock.Flags & KphSsEventFlags.UserMode) == KphSsEventFlags.UserMode) + ssEvent.Mode = KProcessorMode.UserMode; + else + ssEvent.Mode = KProcessorMode.KernelMode; + + // Raise the event. + if (this.EventBlockReceived != null) + this.EventBlockReceived(ssEvent); + } + else if (blockHeader.Type == KphSsBlockType.Argument) + { + var argBlock = _buffer.ReadStruct(cursor, 0); + SsData ssArg = null; + + // Process the argument block based on its type. + switch (argBlock.Type) + { + case KphSsArgumentType.Int8: + { + SsSimple simpleArg = new SsSimple(); + + simpleArg.Argument = argBlock.Data.Int8; + simpleArg.Type = typeof(Byte); + ssArg = simpleArg; + } + break; + case KphSsArgumentType.Int16: + { + SsSimple simpleArg = new SsSimple(); + + simpleArg.Argument = argBlock.Data.Int16; + simpleArg.Type = typeof(Int16); + ssArg = simpleArg; + } + break; + case KphSsArgumentType.Int32: + { + SsSimple simpleArg = new SsSimple(); + + simpleArg.Argument = argBlock.Data.Int32; + simpleArg.Type = typeof(Int32); + ssArg = simpleArg; + } + break; + case KphSsArgumentType.Int64: + { + SsSimple simpleArg = new SsSimple(); + + simpleArg.Argument = argBlock.Data.Int64; + simpleArg.Type = typeof(Int64); + ssArg = simpleArg; + } + break; + case KphSsArgumentType.Handle: + { + ssArg = new SsHandle( + new MemoryRegion(_buffer, cursor + KphSsArgumentBlock.DataOffset)); + } + break; + case KphSsArgumentType.UnicodeString: + { + ssArg = new SsUnicodeString( + new MemoryRegion(_buffer, cursor + KphSsArgumentBlock.DataOffset)); + } + break; + case KphSsArgumentType.ObjectAttributes: + { + ssArg = new SsObjectAttributes( + new MemoryRegion(_buffer, cursor + KphSsArgumentBlock.DataOffset)); + } + break; + } + + // Raise the event. + if (ssArg != null) + { + if (this.ArgumentBlockReceived != null) + this.ArgumentBlockReceived(ssArg); + } + } + + // Advance the cursor. + cursor += blockHeader.Size; + // Signal that a buffer block is available for writing. + _writeSemaphore.Release(); + } + } + + public void Start() + { + lock (_startLock) + { + if (!_started) + { + KProcessHacker.Instance.SsRef(); + _started = true; + + _terminating = false; + + // Create the buffer worker thread. + _bufferWorkerThread = new Thread(this.BufferWorkerThreadStart); + _bufferWorkerThread.IsBackground = true; + _bufferWorkerThread.Start(); + // Wait for the thread to initialize. + _bufferWorkerThreadReadyEvent.Wait(); + } + } + } + + public void Stop() + { + lock (_startLock) + { + if (_started) + { + KProcessHacker.Instance.SsUnref(); + _started = false; + + // Tell the worker thread to stop. + _terminating = true; + // Alert it just in case it is waiting. + _bufferWorkerThreadHandle.Alert(); + // Wait for the worker thread to terminate. + _bufferWorkerThreadHandle.Wait(); + // Close the thread handle. + _bufferWorkerThreadHandle.Dispose(); + } + } + } + } +} diff --git a/trunk/ProcessHacker.Native/SsLogging/SsObjectAttributes.cs b/trunk/ProcessHacker.Native/SsLogging/SsObjectAttributes.cs new file mode 100644 index 000000000..406a2f390 --- /dev/null +++ b/trunk/ProcessHacker.Native/SsLogging/SsObjectAttributes.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.SsLogging +{ + public class SsObjectAttributes : SsData + { + internal SsObjectAttributes(MemoryRegion data) + { + KphSsObjectAttributes oaInfo = data.ReadStruct(); + + this.ObjectName = new SsUnicodeString(new MemoryRegion(data, oaInfo.ObjectNameOffset)); + this.Original = oaInfo.ObjectAttributes; + this.RootDirectory = new SsHandle(new MemoryRegion(data, oaInfo.RootDirectoryOffset)); + } + + public SsUnicodeString ObjectName + { + get; + private set; + } + + public ObjectAttributes Original + { + get; + private set; + } + + public SsHandle RootDirectory + { + get; + private set; + } + } +} diff --git a/trunk/ProcessHacker.Native/SsLogging/SsSimple.cs b/trunk/ProcessHacker.Native/SsLogging/SsSimple.cs new file mode 100644 index 000000000..6c8d4eaf2 --- /dev/null +++ b/trunk/ProcessHacker.Native/SsLogging/SsSimple.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.SsLogging +{ + public sealed class SsSimple : SsData + { + public object Argument + { + get; + internal set; + } + + public Type Type + { + get; + internal set; + } + } +} diff --git a/trunk/ProcessHacker.Native/SsLogging/SsUnicodeString.cs b/trunk/ProcessHacker.Native/SsLogging/SsUnicodeString.cs new file mode 100644 index 000000000..b9212903a --- /dev/null +++ b/trunk/ProcessHacker.Native/SsLogging/SsUnicodeString.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.SsLogging +{ + public sealed class SsUnicodeString : SsData + { + internal SsUnicodeString(MemoryRegion data) + { + KphSsUnicodeString unicodeStringInfo = data.ReadStruct(); + + this.Original = new UnicodeString() + { + Length = unicodeStringInfo.Length, + MaximumLength = unicodeStringInfo.MaximumLength, + Buffer = unicodeStringInfo.Pointer + }; + this.String = data.ReadUnicodeString( + KphSsWString.BufferOffset, + unicodeStringInfo.Length / 2 + ); + } + + public UnicodeString Original + { + get; + private set; + } + + public string String + { + get; + private set; + } + } +}