* dynamic PEB offsets

* hooking/unhooking is now completely safe on multi-processor systems

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1303 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
wj32
2009-05-21 06:13:09 +00:00
parent 2f9425d2e4
commit 860d7b751d
13 changed files with 555 additions and 59 deletions
+61 -17
View File
@@ -21,6 +21,7 @@
*/
#include "include/hook.h"
#include "include/sync.h"
typedef struct _MAPPED_MDL
{
@@ -38,10 +39,15 @@ VOID KphpFreeMappedMdl(
PMAPPED_MDL MappedMdl
);
static KPH_PROCESSOR_LOCK HookProcessorLock;
/* KphHook
*
* Hooks a kernel-mode function.
* WARNING: DO NOT HOOK A FUNCTION THAT IS CALLABLE ABOVE PASSIVE_LEVEL.
* WARNING: DO NOT HOOK A FUNCTION THAT IS CALLABLE ABOVE APC_LEVEL.
*
* Thread safety: Full
* IRQL: <= APC_LEVEL
*/
NTSTATUS KphHook(
PKPH_HOOK Hook
@@ -62,27 +68,49 @@ NTSTATUS KphHook(
return status;
function = (PCHAR)mappedMdl.Address;
/* Raise to APC_LEVEL to prevent drivers calling the function while we're patching it. */
/* If they do, it's their problem because the function we're patching should only be
called at PASSIVE_LEVEL anyway (see hook.h for definition of KPH_HOOK). */
KeRaiseIrql(APC_LEVEL, &oldIrql);
memcpy(Hook->Bytes, function, 5);
Hook->Hooked = TRUE;
/* jmp Target */
*function = 0xe9;
*(PULONG_PTR)(function + 1) = (ULONG_PTR)Hook->Target - (ULONG_PTR)Hook->Function - 5;
/* Lower the IRQL back. */
KeLowerIrql(oldIrql);
/* Acquire a lock on all other processors. */
if (KphAcquireProcessorLock(&HookProcessorLock))
{
/* Patch the function. */
memcpy(Hook->Bytes, function, 5);
Hook->Hooked = TRUE;
/* jmp Target */
*function = 0xe9;
*(PULONG_PTR)(function + 1) = (ULONG_PTR)Hook->Target - (ULONG_PTR)Hook->Function - 5;
/* Release the processor lock. */
KphReleaseProcessorLock(&HookProcessorLock);
}
else
{
dprintf("KphHook: Could not acquire processor lock!\n");
status = STATUS_INSUFFICIENT_RESOURCES;
}
KphpFreeMappedMdl(&mappedMdl);
return status;
}
/* KphHookInit
*
* Initializes the hooking module.
*/
NTSTATUS KphHookInit()
{
KphInitializeProcessorLock(&HookProcessorLock);
return STATUS_SUCCESS;
}
/* KphUnhook
*
* Unhooks a kernel-mode function.
* WARNING: DO NOT UNHOOK A FUNCTION THAT IS CALLABLE ABOVE PASSIVE_LEVEL.
* WARNING: DO NOT UNHOOK A FUNCTION THAT IS CALLABLE ABOVE APC_LEVEL.
*
* Thread safety: Full
* IRQL: <= APC_LEVEL
*/
NTSTATUS KphUnhook(
PKPH_HOOK Hook
@@ -104,10 +132,20 @@ NTSTATUS KphUnhook(
if (!NT_SUCCESS(status))
return status;
KeRaiseIrql(APC_LEVEL, &oldIrql);
memcpy(mappedMdl.Address, Hook->Bytes, 5);
Hook->Hooked = FALSE;
KeLowerIrql(oldIrql);
/* Acquire a lock on all other processors. */
if (KphAcquireProcessorLock(&HookProcessorLock))
{
/* Unpatch the function. */
memcpy(mappedMdl.Address, Hook->Bytes, 5);
Hook->Hooked = FALSE;
/* Release the processor lock. */
KphReleaseProcessorLock(&HookProcessorLock);
}
else
{
dprintf("KphUnhook: Could not acquire processor lock!\n");
status = STATUS_INSUFFICIENT_RESOURCES;
}
KphpFreeMappedMdl(&mappedMdl);
@@ -117,6 +155,9 @@ NTSTATUS KphUnhook(
/* KphpCreateMappedMdl
*
* Creates and maps a MDL.
*
* Thread safety: Full
* IRQL: Any
*/
NTSTATUS KphpCreateMappedMdl(
PVOID Address,
@@ -158,6 +199,9 @@ NTSTATUS KphpCreateMappedMdl(
/* KphpFreeMappedMdl
*
* Unmaps and frees a MDL.
*
* Thread safety: Full
* IRQL: Any
*/
VOID KphpFreeMappedMdl(
PMAPPED_MDL MappedMdl
Binary file not shown.
+6 -2
View File
@@ -20,12 +20,16 @@
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DEBUG_H
#define _DEBUG_H
#ifdef DBG
#define dprintf(fs, ...) DbgPrint("KProcessHacker: " fs, __VA_ARGS__)
#define dfprintf DbgPrint
#else
#define dprintf
#define dfprintf DbgPrint
#endif
#define dfprintf(fs, ...) DbgPrint("KProcessHacker: " fs, __VA_ARGS__)
#define dwprintf DbgPrint
#endif
+2
View File
@@ -53,6 +53,8 @@ NTSTATUS KphHook(
PKPH_HOOK Hook
);
NTSTATUS KphHookInit();
NTSTATUS KphUnhook(
PKPH_HOOK Hook
);
+56
View File
@@ -0,0 +1,56 @@
/*
* Process Hacker Driver -
* synchronization code
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _SYNC_H
#define _SYNC_H
#include "kprocesshacker.h"
typedef struct _KPH_PROCESSOR_LOCK
{
/* Synchronizes access to the processor lock. */
FAST_MUTEX Mutex;
/* Storage allocated for DPCs. */
PKDPC Dpcs;
/* The number of currently acquired processors. */
LONG AcquiredProcessors;
/* The signal for acquired processors to be released. */
LONG ReleaseSignal;
/* The old IRQL. */
KIRQL OldIrql;
/* Whether the processor lock has been acquired. */
BOOLEAN Acquired;
} KPH_PROCESSOR_LOCK, *PKPH_PROCESSOR_LOCK;
BOOLEAN KphAcquireProcessorLock(
PKPH_PROCESSOR_LOCK ProcessorLock
);
VOID KphInitializeProcessorLock(
PKPH_PROCESSOR_LOCK ProcessorLock
);
VOID KphReleaseProcessorLock(
PKPH_PROCESSOR_LOCK ProcessorLock
);
#endif
+21 -5
View File
@@ -34,10 +34,11 @@ typedef struct _KPH_CLIENT_ENTRY
HANDLE ProcessId;
} KPH_CLIENT_ENTRY, *PKPH_CLIENT_ENTRY;
LIST_ENTRY ClientListHead;
KSPIN_LOCK ClientListLock;
NPAGED_LOOKASIDE_LIST ClientLookasideList;
static LIST_ENTRY ClientListHead;
static KSPIN_LOCK ClientListLock;
static NPAGED_LOOKASIDE_LIST ClientLookasideList;
static BOOLEAN ProtectionInitialized = FALSE;
static FAST_MUTEX ProtectionMutex;
#pragma alloc_text(PAGE, KphDispatchCreate)
#pragma alloc_text(PAGE, KphDispatchClose)
@@ -83,6 +84,9 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
0
);
/* Initialize process protection. */
ExInitializeFastMutex(&ProtectionMutex);
RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME);
RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME);
@@ -121,12 +125,16 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject)
/* Destroy client list structures */
ExDeleteNPagedLookasideList(&ClientLookasideList);
ExAcquireFastMutex(&ProtectionMutex);
if (ProtectionInitialized)
{
KphProtectDeinit();
ProtectionInitialized = FALSE;
}
ExReleaseFastMutex(&ProtectionMutex);
dprintf("Driver unloaded\n");
}
@@ -161,12 +169,16 @@ NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS status = STATUS_SUCCESS;
ExAcquireFastMutex(&ProtectionMutex);
if (ProtectionInitialized)
{
ULONG count = KphProtectRemoveByTag(PsGetCurrentProcessId());
dprintf("Removed %d protection entries\n", count);
}
ExReleaseFastMutex(&ProtectionMutex);
/* Remove the client entry. */
RemoveClientEntry(PsGetCurrentProcessId());
@@ -177,11 +189,15 @@ NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
VOID InitProtection()
{
ExAcquireFastMutex(&ProtectionMutex);
if (!ProtectionInitialized)
{
KphProtectInit();
ProtectionInitialized = TRUE;
if (NT_SUCCESS(KphProtectInit()))
ProtectionInitialized = TRUE;
}
ExReleaseFastMutex(&ProtectionMutex);
}
BOOLEAN AddClientEntry(HANDLE ProcessId)
+66 -28
View File
@@ -22,38 +22,38 @@
#include "include/protect.h"
/* ProtectedProcessRundownProtect
*
* Rundown protection making sure this module doesn't deinitialize before all hook targets
* have finished executing and no one is accessing the lookaside list.
*/
EX_RUNDOWN_REF ProtectedProcessRundownProtect;
/* ProtectedProcessListHead
*
* The head of the process protection linked list. Each entry stores protection
* information for a process.
*/
LIST_ENTRY ProtectedProcessListHead;
/* ProtectedProcessListLock
*
* The spinlock which protects all accesses to the protected process list (even
* the individual entries)
*/
KSPIN_LOCK ProtectedProcessListLock;
/* ProtectedProcessLookasideList
*
* The lookaside list for protected process entries.
*/
NPAGED_LOOKASIDE_LIST ProtectedProcessLookasideList;
KPH_HOOK ObOpenObjectByPointerHook = { 0 };
BOOLEAN KphpIsCurrentProcessProtected();
VOID KphpProtectRemoveEntry(
PKPH_PROCESS_ENTRY Entry
);
/* ProtectedProcessRundownProtect
*
* Rundown protection making sure this module doesn't deinitialize before all hook targets
* have finished executing and no one is accessing the lookaside list.
*/
static EX_RUNDOWN_REF ProtectedProcessRundownProtect;
/* ProtectedProcessListHead
*
* The head of the process protection linked list. Each entry stores protection
* information for a process.
*/
static LIST_ENTRY ProtectedProcessListHead;
/* ProtectedProcessListLock
*
* The spinlock which protects all accesses to the protected process list (even
* the individual entries)
*/
static KSPIN_LOCK ProtectedProcessListLock;
/* ProtectedProcessLookasideList
*
* The lookaside list for protected process entries.
*/
static NPAGED_LOOKASIDE_LIST ProtectedProcessLookasideList;
static KPH_HOOK ObOpenObjectByPointerHook = { 0 };
KPH_DEFINE_HOOK_CALL(
NTSTATUS NTAPI KphOldObOpenObjectByPointer,
OBOPENOBJECTBYPOINTER_ARGS,
@@ -63,6 +63,8 @@ KPH_DEFINE_HOOK_CALL(
/* KphProtectInit
*
* Initializes process protection.
*
* IRQL: <= APC_LEVEL
*/
NTSTATUS KphProtectInit()
{
@@ -83,6 +85,9 @@ NTSTATUS KphProtectInit()
0
);
/* Initialize hooking. */
KphHookInit();
/* Hook various functions. */
ObOpenObjectByPointerHook.Function = ObOpenObjectByPointer;
ObOpenObjectByPointerHook.Target = KphNewObOpenObjectByPointer;
@@ -95,14 +100,20 @@ NTSTATUS KphProtectInit()
/* KphProtectDeinit
*
* Removes process protection and frees associated structures.
*
* IRQL: <= APC_LEVEL
*/
NTSTATUS KphProtectDeinit()
{
NTSTATUS status = STATUS_SUCCESS;
KIRQL oldIrql;
LARGE_INTEGER waitLi;
/* Unhook. */
KphUnhook(&ObOpenObjectByPointerHook);
status = KphUnhook(&ObOpenObjectByPointerHook);
if (!NT_SUCCESS(status))
return status;
/* Wait for all activity to finish. */
ExWaitForRundownProtectionRelease(&ProtectedProcessRundownProtect);
@@ -115,12 +126,15 @@ NTSTATUS KphProtectDeinit()
/* Free all process protection entries. */
ExDeleteNPagedLookasideList(&ProtectedProcessLookasideList);
return STATUS_SUCCESS;
return status;
}
/* KphNewObOpenObjectByPointer
*
* New ObOpenObjectByPointer function.
*
* Thread safety: Full
* IRQL: PASSIVE_LEVEL
*/
NTSTATUS NTAPI KphNewObOpenObjectByPointer(
OBOPENOBJECTBYPOINTER_ARGS
@@ -210,6 +224,9 @@ NTSTATUS NTAPI KphNewObOpenObjectByPointer(
/* KphProtectAddEntry
*
* Protects the specified process.
*
* Thread safety: Full
* IRQL: <= DISPATCH_LEVEL
*/
PKPH_PROCESS_ENTRY KphProtectAddEntry(
PEPROCESS Process,
@@ -250,6 +267,9 @@ PKPH_PROCESS_ENTRY KphProtectAddEntry(
/* KphProtectCopyEntry
*
* Copies process protection data for the specified process.
*
* Thread safety: Full
* IRQL: <= DISPATCH_LEVEL
*/
BOOLEAN KphProtectCopyEntry(
PEPROCESS Process,
@@ -285,6 +305,10 @@ BOOLEAN KphProtectCopyEntry(
/* KphProtectFindEntry
*
* Finds process protection data.
*
* Thread safety: Limited. The returned pointer is not guaranteed to
* point to a valid process entry.
* IRQL: <= DISPATCH_LEVEL
*/
PKPH_PROCESS_ENTRY KphProtectFindEntry(
PEPROCESS Process,
@@ -322,6 +346,10 @@ PKPH_PROCESS_ENTRY KphProtectFindEntry(
/* KphProtectRemoveByProcess
*
* Removes protection from the specified process.
*
* Thread safety: Limited. Callers must synchronize remove calls such
* as KphProtectRemoveByProcess and KphProtectRemoveByTag.
* IRQL: <= DISPATCH_LEVEL
*/
BOOLEAN KphProtectRemoveByProcess(
PEPROCESS Process
@@ -340,6 +368,10 @@ BOOLEAN KphProtectRemoveByProcess(
/* KphProtectRemoveByTag
*
* Removes protection from all processes with the specified tag.
*
* Thread safety: Limited. Callers must synchronize remove calls such
* as KphProtectRemoveByProcess and KphProtectRemoveByTag.
* IRQL: <= DISPATCH_LEVEL
*/
ULONG KphProtectRemoveByTag(
HANDLE Tag
@@ -362,6 +394,9 @@ ULONG KphProtectRemoveByTag(
/* KphpIsCurrentProcessProtected
*
* Determines whether the current process is protected.
*
* Thread safety: Full
* IRQL: <= DISPATCH_LEVEL
*/
BOOLEAN KphpIsCurrentProcessProtected()
{
@@ -371,6 +406,9 @@ BOOLEAN KphpIsCurrentProcessProtected()
/* KphpProtectRemoveEntry
*
* Removes and frees process protection data.
*
* Thread safety: Full
* IRQL: <= DISPATCH_LEVEL
*/
VOID KphpProtectRemoveEntry(
PKPH_PROCESS_ENTRY Entry
+1
View File
@@ -11,6 +11,7 @@ SOURCES= \
kph.c \
hook.c \
protect.c \
sync.c \
mm.c \
ob.c \
ps.c \
+234
View File
@@ -0,0 +1,234 @@
/*
* Process Hacker Driver -
* synchronization code
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "include/sync.h"
#include "include/debug.h"
ULONG KphpCountBits(
ULONG_PTR Number
);
VOID KphpProcessorLockDpc(
PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2
);
/* KphAcquireProcessorLock
*
* Raises the IRQL to DISPATCH_LEVEL and prevents threads from
* executing on other processors until the processor lock is released.
* Blocks if the supplied processor lock is already in use.
*
* ProcessorLock: A processor lock structure that is present in
* non-paged memory.
*
* Thread safety: Full
* IRQL: <= APC_LEVEL
*/
BOOLEAN KphAcquireProcessorLock(
PKPH_PROCESSOR_LOCK ProcessorLock
)
{
ULONG i;
ULONG numberProcessors;
ULONG currentProcessor;
/* Acquire the processor lock mutex. */
ExAcquireFastMutex(&ProcessorLock->Mutex);
/* Reset some state. */
ASSERT(ProcessorLock->AcquiredProcessors == 0);
ProcessorLock->AcquiredProcessors = 0;
ProcessorLock->ReleaseSignal = 0;
/* Get the number of processors. */
numberProcessors = KphpCountBits(KeQueryActiveProcessors());
/* If there's only one processor we can simply raise the IRQL and exit. */
if (numberProcessors == 1)
{
dprintf("KphAcquireProcessorLock: Only one processor, raising IRQL and exiting...\n");
KeRaiseIrql(DISPATCH_LEVEL, &ProcessorLock->OldIrql);
ProcessorLock->Acquired = TRUE;
return TRUE;
}
/* Allocate storage for the DPCs. */
ProcessorLock->Dpcs = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(KDPC) * numberProcessors,
KPH_TAG
);
if (!ProcessorLock->Dpcs)
{
dprintf("KphAcquireProcessorLock: Could not allocate storage for DPCs!\n");
return FALSE;
}
/* Initialize the DPCs. */
for (i = 0; i < numberProcessors; i++)
{
KeInitializeDpc(&ProcessorLock->Dpcs[i], KphpProcessorLockDpc, NULL);
KeSetTargetProcessorDpc(&ProcessorLock->Dpcs[i], (CCHAR)i);
KeSetImportanceDpc(&ProcessorLock->Dpcs[i], HighImportance);
}
/* Raise the IRQL to DISPATCH_LEVEL to prevent context switching. */
KeRaiseIrql(DISPATCH_LEVEL, &ProcessorLock->OldIrql);
/* Get the current processor number. */
currentProcessor = KeGetCurrentProcessorNumber();
/* Queue the DPCs (except on the current processor). */
for (i = 0; i < numberProcessors; i++)
if (i != currentProcessor)
KeInsertQueueDpc(&ProcessorLock->Dpcs[i], ProcessorLock, NULL);
/* Spinwait for all (other) processors to be acquired. */
while (InterlockedCompareExchange(
&ProcessorLock->AcquiredProcessors,
numberProcessors - 1,
numberProcessors - 1
) != numberProcessors - 1)
NOTHING;
dprintf("KphAcquireProcessorLock: All processors acquired.\n");
ProcessorLock->Acquired = TRUE;
return TRUE;
}
/* KphInitializeProcessorLock
*
* Initializes a processor lock.
*
* ProcessorLock: A processor lock structure that is present in
* non-paged memory.
*
* IRQL: Any
*/
VOID KphInitializeProcessorLock(
PKPH_PROCESSOR_LOCK ProcessorLock
)
{
ExInitializeFastMutex(&ProcessorLock->Mutex);
ProcessorLock->Dpcs = NULL;
ProcessorLock->AcquiredProcessors = 0;
ProcessorLock->ReleaseSignal = 0;
ProcessorLock->OldIrql = PASSIVE_LEVEL;
ProcessorLock->Acquired = FALSE;
}
/* KphReleaseProcessorLock
*
* Allows threads to execute on other processors and restores the IRQL.
*
* ProcessorLock: A processor lock structure that is present in
* non-paged memory.
*
* Thread safety: Full
* IRQL: <= APC_LEVEL
*/
VOID KphReleaseProcessorLock(
PKPH_PROCESSOR_LOCK ProcessorLock
)
{
if (!ProcessorLock->Acquired)
return;
/* Signal for the acquired processors to be released. */
InterlockedExchange(&ProcessorLock->ReleaseSignal, 1);
/* Spinwait for all acquired processors to be released. */
while (InterlockedCompareExchange(
&ProcessorLock->AcquiredProcessors,
0,
0
))
NOTHING;
dprintf("KphReleaseProcessorLock: All processors released.\n");
/* Restore the old IRQL (should always be APC_LEVEL due to the
* fast mutex). */
KeLowerIrql(ProcessorLock->OldIrql);
/* Free the DPCs if necessary. */
if (ProcessorLock->Dpcs != NULL)
{
ExFreePoolWithTag(ProcessorLock->Dpcs, KPH_TAG);
ProcessorLock->Dpcs = NULL;
}
ProcessorLock->Acquired = FALSE;
/* Release the processor lock mutex. */
ExReleaseFastMutex(&ProcessorLock->Mutex);
}
ULONG KphpCountBits(
ULONG_PTR Number
)
{
ULONG count = 0;
while (Number)
{
count++;
Number &= Number - 1;
}
return count;
}
VOID KphpProcessorLockDpc(
PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2
)
{
PKPH_PROCESSOR_LOCK processorLock = (PKPH_PROCESSOR_LOCK)SystemArgument1;
ASSERT(processorLock != NULL);
dprintf("KphpProcessorLockDpc: Acquiring processor %d.\n", KeGetCurrentProcessorNumber());
/* Increase the number of acquired processors. */
InterlockedIncrement(&processorLock->AcquiredProcessors);
/* Spin until we get the signal to release the processor. */
while (!InterlockedCompareExchange(
&processorLock->ReleaseSignal,
1,
1
))
NOTHING;
/* Decrease the number of acquired processors. */
InterlockedDecrement(&processorLock->AcquiredProcessors);
dprintf("KphpProcessorLockDpc: Releasing processor %d.\n", KeGetCurrentProcessorNumber());
}
+1 -1
View File
@@ -87,7 +87,7 @@ NTSTATUS KvInit()
minorVersion = RtlWindowsVersion.dwMinorVersion;
servicePack = RtlWindowsVersion.wServicePackMajor;
buildNumber = RtlWindowsVersion.dwBuildNumber;
dprintf("Windows %d.%d, SP%d.%d, build %d\n",
dfprintf("Windows %d.%d, SP%d.%d, build %d\n",
majorVersion, minorVersion, servicePack,
RtlWindowsVersion.wServicePackMinor, buildNumber
);
@@ -31,14 +31,23 @@ namespace ProcessHacker.Native.Api
public partial class Win32
{
public const int FlsMaximumAvailable = 128;
#if _X64
public const int GdiHandleBufferSize = 60;
#else
public const int GdiHandleBufferSize = 34;
#endif
public const int MaximumSupportedExtension = 512;
public const int SecurityDescriptorMinLength = 20;
public const int SecurityDescriptorRevision = 1;
public readonly int SecurityMaxSidSize =
public static readonly int SecurityMaxSidSize =
Marshal.SizeOf(typeof(Sid)) - sizeof(int) + (SidMaxSubAuthorities * sizeof(int));
public const int SidMaxSubAuthorities = 15;
public const int SidRecommendedSubAuthorities = 1;
public const int SidRevision = 1;
public const int SizeOf80387Registers = 80;
public static readonly IntPtr PebLdrOffset = Marshal.OffsetOf(typeof(Peb), "Ldr");
public static readonly IntPtr PebProcessParametersOffset = Marshal.OffsetOf(typeof(Peb), "ProcessParameters");
}
}
@@ -392,6 +392,98 @@ namespace ProcessHacker.Native.Api
public int NonPagedPoolUsage;
}
[StructLayout(LayoutKind.Sequential)]
public struct Peb
{
[MarshalAs(UnmanagedType.I1)]
public bool InheritedAddressSpace;
[MarshalAs(UnmanagedType.I1)]
public bool ReadImageFileExecOptions;
[MarshalAs(UnmanagedType.I1)]
public bool BeingDebugged;
[MarshalAs(UnmanagedType.I1)]
public bool BitField;
public IntPtr Mutant;
public IntPtr ImageBaseAddress;
public IntPtr Ldr; // ptr to PebLdrData
public IntPtr ProcessParameters; // ptr to RtlUserProcessParameters
public IntPtr SubSystemData;
public IntPtr ProcessHeap;
public IntPtr FastPebLock;
public IntPtr AtlThunkSListPtr;
public IntPtr SparePrt2;
public int EnvironmentUpdateCount;
public IntPtr KernelCallbackTable;
public int SystemReserved;
public int SpareUlong;
public IntPtr FreeList;
public int TlsExpansionCounter;
public IntPtr TlsBitmap;
public unsafe fixed int TlsBitmapBits[2];
public IntPtr ReadOnlySharedMemoryBase;
public IntPtr ReadOnlySharedMemoryHeap;
public IntPtr ReadOnlyStaticServerData;
public IntPtr AnsiCodePageData;
public IntPtr OemCodePageData;
public IntPtr UnicodeCaseTableData;
public int NumberOfProcessors;
public int NtGlobalFlag;
public long CriticalSectionTimeout;
public IntPtr HeapSegmentReserve;
public IntPtr HeapSegmentCommit;
public IntPtr HeapDeCommitTotalFreeThreshold;
public IntPtr HeapDeCommitFreeBlockThreshold;
public int NumberOfHeaps;
public int MaximumNumberOfHeaps;
public IntPtr ProcessHeaps;
public IntPtr GdiSharedHandleTable;
public IntPtr ProcessStarterHelper;
public int GdiDCAttributeList;
public IntPtr LoaderLock;
public int OSMajorVersion;
public int OSMinorVersion;
public short OSBuildNumber;
public short OSCSDVersion;
public int OSPlatformId;
public int ImageSubsystem;
public int ImageSubsystemMajorVersion;
public int ImageSubsystemMinorVersion;
public IntPtr ImageProcessAffinityMask;
public unsafe fixed byte GdiHandleBuffer[Win32.GdiHandleBufferSize];
public IntPtr PostProcessInitRoutine;
public IntPtr TlsExpansionBitmap;
public unsafe fixed int TlsExpansionBitmapBits[32];
public int SessionId;
public long AppCompatFlags;
public long AppCompatFlagsUser;
public IntPtr pShimData;
public IntPtr AppCompatInfo;
public UnicodeString CSDVersion;
public IntPtr ActivationContextData;
public IntPtr ProcessAssemblyStorageMap;
public IntPtr SystemDefaultActivationContextData;
public IntPtr SystemAssemblyStorageMap;
public IntPtr MinimumStackCommit;
public IntPtr FlsCallback;
public ListEntry FlsListHead;
public IntPtr FlsBitmap;
public unsafe fixed int FlsBitmapBits[Win32.FlsMaximumAvailable / (sizeof(int) * 8)];
public int FlsHighIndex;
}
[StructLayout(LayoutKind.Sequential)]
public struct PebLdrData
{
@@ -401,11 +401,11 @@ namespace ProcessHacker.Native.Objects
private unsafe void EnumModulesNative(EnumModulesDelegate enumModulesCallback)
{
byte* buffer = stackalloc byte[4];
byte* buffer = stackalloc byte[IntPtr.Size];
this.ReadMemory(this.GetBasicInformation().PebBaseAddress.Increment(0xc), buffer, 4);
this.ReadMemory(this.GetBasicInformation().PebBaseAddress.Increment(Win32.PebLdrOffset), buffer, IntPtr.Size);
IntPtr loaderData = new IntPtr(*(int*)buffer);
IntPtr loaderData = *(IntPtr*)buffer;
PebLdrData* data = stackalloc PebLdrData[1];
this.ReadMemory(loaderData, data, Marshal.SizeOf(typeof(PebLdrData)));
@@ -925,7 +925,7 @@ namespace ProcessHacker.Native.Objects
* +0c PVOID LoaderData;
* +10 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
*/
this.ReadMemory(pebBaseAddress.Increment(0x10), buffer, IntPtr.Size);
this.ReadMemory(pebBaseAddress.Increment(Win32.PebProcessParametersOffset), buffer, IntPtr.Size);
IntPtr processParameters = *(IntPtr*)buffer;
// Read length (in bytes) of string. The offset of the UNICODE_STRING structure is
@@ -941,7 +941,7 @@ namespace ProcessHacker.Native.Objects
byte[] stringData = new byte[stringLength];
// read address of string
this.ReadMemory(processParameters.Increment((int)offset + 0x4), buffer, 4);
this.ReadMemory(processParameters.Increment((int)offset + 0x4), buffer, IntPtr.Size);
IntPtr stringAddr = *(IntPtr*)buffer;
// read string and decode it