diff --git a/trunk/ProcessHacker.Native/Api/Functions.cs b/trunk/ProcessHacker.Native/Api/Functions.cs index 0cc955ccf..526d682ee 100644 --- a/trunk/ProcessHacker.Native/Api/Functions.cs +++ b/trunk/ProcessHacker.Native/Api/Functions.cs @@ -1885,7 +1885,7 @@ namespace ProcessHacker.Native.Api [return: MarshalAs(UnmanagedType.Bool)] public static extern bool QueueUserAPC( [MarshalAs(UnmanagedType.FunctionPtr)] - [In] Action APC, + [In] ApcRoutine APC, [In] IntPtr ThreadHandle, [In] IntPtr Data ); diff --git a/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs b/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs index facc4c182..9a15d84fe 100644 --- a/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs +++ b/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs @@ -26,6 +26,7 @@ using System.Runtime.InteropServices; namespace ProcessHacker.Native.Api { public delegate void ApcCallbackDelegate(NtStatus ioStatus, IntPtr apcContext, IntPtr context); + public delegate void ApcRoutine(IntPtr parameter); public delegate void TimerApcRoutine(IntPtr context, int lowValue, int highValue); public delegate void WaitOrTimerCallbackDelegate(IntPtr context, bool timeout); public delegate void WorkerCallbackDelegate(IntPtr context); diff --git a/trunk/ProcessHacker.Native/Memory/HeapMemoryAlloc.cs b/trunk/ProcessHacker.Native/Memory/HeapMemoryAlloc.cs deleted file mode 100644 index d3fcd7a71..000000000 --- a/trunk/ProcessHacker.Native/Memory/HeapMemoryAlloc.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Process Hacker - - * heap memory allocation wrapper - * - * Copyright (C) 2008 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -using System; -using ProcessHacker.Native.Api; - -namespace ProcessHacker.Native -{ - /// - /// Represents a heap memory allocation. - /// - public sealed class HeapMemoryAlloc : MemoryAlloc - { - public HeapMemoryAlloc(int size) - { - this.Memory = Win32.HeapAlloc(Win32.GetProcessHeap(), 0, size); - - if (this.Memory == IntPtr.Zero) - throw new OutOfMemoryException(); - - base.Size = size; - } - - protected override void Free() - { - Win32.HeapFree(Win32.GetProcessHeap(), 0, this); - } - - public override void Resize(int newSize) - { - IntPtr newMemory; - - newMemory = Win32.HeapReAlloc(Win32.GetProcessHeap(), 0, this, newSize); - - if (newMemory == IntPtr.Zero) - throw new OutOfMemoryException(); - - this.Memory = newMemory; - base.Size = newSize; - } - } -} diff --git a/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs b/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs index 71ee98734..6983a40ac 100644 --- a/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs @@ -713,7 +713,7 @@ namespace ProcessHacker.Native.Objects Win32.ThrowLastError(); } - public void QueueApc(Action action, IntPtr parameter) + public void QueueApc(ApcRoutine action, IntPtr parameter) { if (!Win32.QueueUserAPC(action, this, parameter)) Win32.ThrowLastError(); diff --git a/trunk/native.html b/trunk/native.html index 51a300189..ac9236a90 100644 --- a/trunk/native.html +++ b/trunk/native.html @@ -26,11 +26,15 @@ p { font-style: italic; } +h1 { + border-top: solid 3px #000; +} + h2 { font-size: 20pt; margin-top: 1.3em; margin-bottom: 0.3em; - border-top: dotted 3px #333; + border-top: dashed 1px #333; } h3 { @@ -45,10 +49,280 @@ h4 { -

The Definitive Native API Guide

+

The Definitive Native API Guide

Written by wj32.

-

Native API

+

NT Concepts

+ +

ALPC Port

+

Local Inter-process Communication (LPC) ports are an interprocess communication (IPC) method. + A server process creates a port object and waits for a client to connect to the port. Once + the connection is established, both the client and server receive a handle to a communication + port, a special instance of a port object which can be used to send and receive messages. From + Windows Vista onward, LPC ports have been replaced with ALPC ports (NtAlpc* + system calls). Existing port-related system calls now redirect to the new ALPC port functions.

+

Related functions: + NtCreatePort (server), + NtCreateWaitablePort (server), + NtConnectPort (client), + NtListenPort (server), + NtAcceptConnectPort (server), + NtRequestWaitReplyPort (client), + NtReplyWaitReceivePort (server), + NtReplyWaitReplyPort, + NtReplyPort. +

+

Related types: + PORT_MESSAGE, + PORT_VIEW, + REMOTE_PORT_VIEW, + LPCP_PORT_OBJECT. +

+ +

Asynchronous Procedure Calls (APCs)

+

Asynchronous procedure calls are functions which execute in the context of a specific thread. + There are two types of APCs, user-mode and kernel-mode. Each thread has two APC queues, one for + each type.

+

User-mode APCs are queued using NtQueueApcThread. They will not be called + unless an alertable wait is being performed or NtTestAlert is called in the + target thread. In those cases, a flag will be set in the target thread's APC state indicating that + one or more user-mode APCs are pending and the wait operation will be interrupted. When the system + call returns to user-mode, any pending user-mode APCs will be called.

+

A special use of user-mode APCs is thread termination, where a thread termination APC + (PspExitNormalApc) is inserted into the target thread. KiInsertQueueApc + contains a special case for thread termination and inserts the APC at the beginning of the + user-mode APC queue so that any wait operations in the target thread are interrupted and + the thread is terminated upon exiting the currently executing system service.

+

Kernel-mode APCs always preempt user-mode code, including user-mode APCs. There are two types of + kernel-mode APCs, normal and special. Normal APCs can be temporarily disabled by using + KeEnterCriticalRegion and both types of APCs can be temporarily disabled by using + KeEnterGuardedRegion or raising the IRQL to APC_LEVEL or higher.

+
    +
  • Normal kernel-mode APCs run at IRQL = PASSIVE_LEVEL and are inserted at the end + of the kernel-mode APC queue.
  • +
  • Special kernel-mode APCs run at IRQL = APC_LEVEL and are inserted after all existing + special APCs in the kernel-mode APC queue.
  • +
+

When a kernel-mode APC is inserted:

+
    +
  • If the target thread is running, a software interrupt is issued to call any queued kernel-mode + APCs in the thread.
  • +
  • If the target thread is waiting at IRQL = PASSIVE_LEVEL and special kernel-mode APCs + are not disabled, the wait will be interrupted with STATUS_KERNEL_APC. Note that normal + kernel-mode APCs cannot interrupt currently executing kernel-mode APCs which are waiting. Kernel-mode + APCs do not cause wait operations to return; rather, the wait function will be interrupted, + execute any queued kernel-mode APCs, and continue waiting.
  • +
+

Normal kernel-mode APCs are used to implement thread suspension.

+ +

Dispatcher Object

+

A dispatcher object is one which has two states: signaled and non-signaled. + These objects can be used with standard wait functions such as NtWaitForSingleObject or + NtWaitForMultipleObjects. These functions wait until one or more objects are set to + a signaled state. The dispatcher objects are:

+
    +
  • Events
  • +
  • Gates (kernel-mode only)
  • +
  • Mutants
  • +
  • Processes
  • +
  • Queues (kernel-mode only)
  • +
  • Semaphores
  • +
  • Threads
  • +
  • Timers
  • +
+

Events and gates are the most basic dispatcher objects, consisting of only a dispatcher header.

+

Note that the dispatcher header of a dispatcher object uses a signed integer field to represent + its signal state. Signal state values greater than 0 are considered to be signaled, while 0 is + considered to be non-signaled. This is useful for objects such as mutants and semaphores which can be + acquired and released multiple times.

+

Related types: + DISPATCHER_HEADER. +

+ +

Event

+

An event is a synchronization object that can be explicitly set to the signaled state. There are two + types of events:

+
    +
  • Notification event. When a notification event is set, all waiting threads are + released. The event remains signaled until it is explicitly reset.
  • +
  • Synchronization event. When a synchronization event is set, a single waiting + thread is released and the event is reset to a non-signaled state. When multiple threads wait + on a synchronization event, there is no guarantee of first-in first-out (FIFO) ordering.
  • +
+

Related functions: + NtCreateEvent, + NtOpenEvent, + NtClearEvent, + NtPulseEvent, + NtQueryEvent, + NtResetEvent, + NtSetEvent, + NtSetEventBoostPriority. +

+

Related types: + EVENT_INFORMATION_CLASS, + EVENT_BASIC_INFORMATION, + KEVENT. +

+ +

Event Pair

+

An event pair is a synchronization object containing two events, high and low. The + system provides set, wait, and atomic signal-and-wait functions for event pairs. Note that an event pair + object is not a dispatcher object and cannot be used with the standard wait functions.

+

Related functions: + NtCreateEventPair, + NtOpenEventPair, + NtSetHighEventPair, + NtSetHighWaitLowEventPair, + NtSetLowEventPair, + NtSetLowWaitHighEventPair, + NtWaitHighEvenPair, + NtWaitLowEventPair. +

+

Related types: + EEVENT_PAIR. +

+ +

Keyed Event

+

A keyed event is a dictionary of events. Each key must be even (the lowest bit must be clear). Internally, + the keyed event object is implemented using a linked list of pointers to threads. Every thread object has + two fields, KeyedWaitValue and KeyedWaitSemaphore. The KeyedWaitValue + contains the key being waited for by the thread. When a thread attempts to release a key which is not being + waited for, its KeyedWaitValue will be set to the key OR'ed with 1, to indicate that the thread + is attempting to release the key, and the thread will wait until another thread waits for the key.

+

Related functions: + NtCreateKeyedEvent, + NtOpenKeyedEvent, + NtReleaseKeyedEvent, + NtWaitForKeyedEvent. +

+

Related types: + KEYED_EVENT_OBJECT. +

+ +

Mutant

+

A "mutant" is a standard mutex. When a thread successfully waits for a mutant, it will acquire the mutant + and become the owner of the mutant; the mutant will be set to a non-signaled state. When the owning thread + releases the mutant the same number of times it has acquired it, the mutant will be set to a signaled state + and the mutant will no longer be owned, allowing other threads to acquire the mutant. Note that the mutant + can be acquired recursively, i.e. the owning thread can acquire the mutant more than once without causing a + deadlock.

+

Related functions: + NtCreateMutant, + NtOpenMutant, + NtQueryMutant, + NtReleaseMutant +

+

Related types: + MUTANT_INFORMATION_CLASS, + MUTANT_BASIC_INFORMATION, + KMUTANT. +

+ +

Port

+

See ALPC Port.

+ +

Profile

+

A profile object can be used for performance monitoring. When certain profiling events are triggered, + a corresponding counter in a user-allocated buffer is incremented.

+

Related functions: + NtCreateProfile, + NtQueryIntervalProfile, + NtSetIntervalProfile, + NtStartProfile, + NtStopProfile. +

+ +

Section

+

Sections are objects describing a region of memory "backed" by a file. There are two types of section + objects:

+
    +
  • File-backed section. File-backed sections are memory-mapped files, where mapped + view contents are the same as in the file. Writing to mapped views will also change the contents of the + the file, unless the section is mapped copy-on-write, where any changes are discarded after the last + view is unmapped and the last reference to the section is closed.
  • +
  • Pagefile-backed section. Page-file-backed sections are a form of shared memory; + any changes will be discarded after the section is freed. The section is not backed by any + user-specified file.
  • +
+

Multiple views of the section can be mapped, and changes will be reflected across processes.

+

Related functions: + NtCreateSection, + NtOpenSection, + NtAreMappedFilesTheSame, + NtExtendSection, + NtMapViewOfSection, + NtQuerySection, + NtUnmapViewOfSection. +

+ +

Semaphore

+

A semaphore is a synchronization object with a signal state that represents how many times it has been + acquired. Each time a semaphore is acquired, its signal state is decremented. Each time a semaphore is + released, its signal state is incremented (but cannot be greater than the limit). If a semaphore's + signal state is 0 (non-signaled), threads must wait until another thread releases the semaphore before they + can acquire the semaphore.

+

Related functions: + NtCreateSemaphore, + NtOpenSemaphore, + NtQuerySemaphore, + NtReleaseSemaphore. +

+

Related types: + SEMAPHORE_INFORMATION_CLASS, + SEMAPHORE_BASIC_INFORMATION, + KSEMAPHORE. +

+ +

Timer

+

A timer is executive object and a wrapper around the kernel timer object. There are two types of timers:

+
    +
  • Notification timer. When a notification timer is signaled, all waiting threads are + released. The timer remains signaled until explicitly reset.
  • +
  • Synchronization timer. When a synchronization timer is signaled, one waiting thread is + released and the timer is set to a non-signaled state.
  • +
+

A timer can be configured to be signaled periodically or to insert an APC into the thread that set the + timer when the timer is signaled.

+

Related functions: + NtCreateTimer, + NtOpenTimer, + NtCancelTimer, + NtQueryTimer, + NtSetTimer. +

+

Related types: + TIMER_INFORMATION_CLASS, + TIMER_BASIC_INFORMATION, + ETIMER, + KTIMER, + PTIMER_APC_ROUTINE. +

+ +

Wait

+

A thread can wait for one or more objects; the standard system calls are NtWaitForSingleObject, + NtWaitForMultipleObjects, NtSignalAndWaitForSingleObject, and a few type-specific + wait functions. The pointer-based kernel-mode functions are KeWaitForSingleObject and + KeWaitForMultipleObjects. These functions will block until a certain condition is met. For + example, *WaitForSingleObject will return when the specified object is signaled. + *WaitForMultipleObjects will return when all/any specified objects are signaled.

+

When a wait function is called, it initializes a wait block for each object to be waited for. The storage + for the wait blocks is supplied in the thread object by default, but the caller can allocate storage if + they wish. The wait function then checks if the wait can be satisfied immediately. If it could not, the + wait function inserts the wait block(s) into the dispatch header(s) of the object(s), sets the thread's state + to Waiting and will no longer be considered for execution. It then switches to another ready thread.

+

When an object is set to a signaled state (such as when an event is set or a mutant is released), + the function performs a wait test (KiWaitTest) which enumerates the wait blocks in the + object's dispatcher header and unwaits each waiting thread. Each waiting thread will now be ready to run.

+

A waiting thread regains control due to either a wait test or a kernel-mode APC. It proceeds to + call any queued kernel-mode APCs and check if the wait operation has been satisfied (for multiple-object + waits, this is when any/all objects have been signaled). If it has not, the wait function continues to repeat + the wait process until the wait operation has been satisfied.

+

For some object types, object state must be modified when a thread is finished waiting for the object. + For example, a semaphore's signal state must be decremented. These operations are called side-effects, + and are performed when a wait is satisfied.

+ +

NT Enumerations

Debug Object Access

@@ -56,8 +330,8 @@ h4 {
 #define DEBUG_PROCESS_ASSIGN 0x0002
 #define DEBUG_SET_INFORMATION 0x0004
 #define DEBUG_QUERY_INFORMATION 0x0008
-#define DEBUG_ALL_ACCESS STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | DEBUG_READ_EVENT | 
-    DEBUG_PROCESS_ASSIGN | DEBUG_SET_INFORMATION | DEBUG_QUERY_INFORMATION
+#define DEBUG_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | DEBUG_READ_EVENT | \ + DEBUG_PROCESS_ASSIGN | DEBUG_SET_INFORMATION | DEBUG_QUERY_INFORMATION)

Directory Object Access

@@ -68,6 +342,99 @@ h4 {
 
 #define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xf)
+

Event Access

+
+#define EVENT_QUERY_STATE 0x0001
+#define EVENT_MODIFY_STATE 0x0002
+#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3)
+ +

Event Pair Access

+
+#define EVENT_PAIR_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE)
+ +

Keyed Event Access

+
+#define KEYEDEVENT_WAIT 0x0001
+#define KEYEDEVENT_WAKE 0x0002
+#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)
+ +

Mutant Access

+
+#define MUTANT_QUERY_STATE 0x0001
+
+#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE| MUTANT_QUERY_STATE)
+ +

Object Flags

+
+#define OBJ_INHERIT 0x00000002L
+#define OBJ_PERMANENT 0x00000010L
+#define OBJ_EXCLUSIVE 0x00000020L
+#define OBJ_CASE_INSENSITIVE 0x00000040L
+#define OBJ_OPENIF 0x00000080L
+#define OBJ_OPENLINK 0x00000100L
+#define OBJ_KERNEL_HANDLE 0x00000200L
+#define OBJ_FORCE_ACCESS_CHECK 0x00000400L
+#define OBJ_VALID_ATTRIBUTES 0x000007f2L
+

Members

+

OBJ_INHERIT

+

Specifies that the handle (in the appropriate context) should be inherited by child processes.

+

OBJ_PERMANENT

+

Specifies that the object is permanent and should not be freed when all references to it have been + closed. If this flag is not specified, the object is temporary and will be freed when all references + have been closed. User-mode callers must have SeCreatePermanentPrivilege in order to + create permanent objects.

+

OBJ_EXCLUSIVE

+

Specifies that the object should be opened for exclusive access; the object cannot be opened + again until the handle is closed.

+

OBJ_CASE_INSENSITIVE

+

Specifies that name comparisons should be made case insensitively.

+

OBJ_OPENIF

+

Specifies that if an object with the specified name already exists, the creation routine should + open the existing object. If this flag is not specified and the name already exists, the creation + routine will return STATUS_OBJECT_NAME_COLLISION.

+

OBJ_OPENLINK

+

Not used.

+

OBJ_KERNEL_HANDLE

+

Specifies that the handle should be opened in the context of the System process, i.e. a kernel + handle.

+

OBJ_FORCE_ACCESS_CHECK

+

Specifies that an access check should be performed, even if the caller is from kernel-mode.

+ +

Profile Access

+
+#define PROFILE_CONTROL 0x0001
+#define PROFILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | PROFILE_CONTROL)
+ +

Section Access

+
+#define SECTION_QUERY 0x0001
+#define SECTION_MAP_WRITE 0x0002
+#define SECTION_MAP_READ 0x0004
+#define SECTION_MAP_EXECUTE 0x0008
+#define SECTION_EXTEND_SIZE 0x0010
+#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020
+
+#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | \
+    SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | \
+    SECTION_EXTEND_SIZE)
+ +

Semaphore Access

+
+#define SEMAPHORE_QUERY_STATE 0x0001
+#define SEMAPHORE_MODIFY_STATE 0x0002
+
+#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3)
+ +

Timer Access

+
+#define TIMER_QUERY_STATE 0x0001
+#define TIMER_MODIFY_STATE 0x0002
+
+#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
+    TIMER_QUERY_STATE | TIMER_MODIFY_STATE)
+ +

NT Structures

+

CLIENT_ID

A structure identifying a process or thread.

@@ -128,6 +495,33 @@ typedef struct _INITIAL_TEB
     this blog post 
     for more details.

+

OBJECT_ATTRIBUTES

+

A structure describing object properties such as its name, location and security attributes.

+
+typedef struct _OBJECT_ATTRIBUTES
+{
+    ULONG Length;
+    HANDLE RootDirectory;
+    PUNICODE_STRING ObjectName;
+    ULONG Attributes;
+    PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR
+    PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE
+} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
+

Fields

+

Length

+

The length of the OBJECT_ATTRIBUTES structure; 24 on 32-bit systems and 40 on 64-bit systems.

+

RootDirectory

+

A handle to a directory object from which to begin searching for the object. If this value is NULL, + the object manager will use the default root directory.

+

ObjectName

+

The name of the object, optional when creating most types of objects.

+

Attributes

+

See Object Flags.

+

SecurityDescriptor

+

A pointer to a SECURITY_DESCRIPTOR structure for the object.

+

SecurityQualityOfService

+

A pointer to a SECURITY_QUALITY_OF_SERVICE structure for the object.

+

RTL_DRIVE_LETTER_CURDIR

Unknown.

@@ -228,6 +622,8 @@ typedef struct _UNICODE_STRING
     

Buffer

A buffer containing the string.

+

NT System Calls

+

NtAlertThread

Alerts the specified thread, causing it to resume execution if it is in an alertable Wait state. Otherwise, the thread is set to an alerted state.

@@ -503,7 +899,7 @@ NtCreateThreadEx( __in_opt ULONG Reserved, __in_opt ULONG StackCommit, __in_opt ULONG StackReserve, - __in_opt PVOID Unknown + __in_opt PVOID ProcessContext );

Arguments

ThreadHandle

@@ -529,7 +925,7 @@ NtCreateThreadEx(

The number of bytes to commit in the thread stack.

StackReserve

The number of bytes to reserve for the thread stack.

-

Unknown

+

ProcessContext

An optional structure which is passed to PspBuildCreateProcessContext.

Code paths

NtCreateThreadEx ... PspCreateThread ... PspAllocateThread ... @@ -572,7 +968,7 @@ NtOpenProcess(

NtQueueApcThread

Queues a user-mode APC to the specified thread. The APC will execute when the thread performs an alertable wait or - calls NtTestAlert.

+ calls NtTestAlert. Any wait operations will return with STATUS_USER_APC.

 NTSYSCALLAPI
 NTSTATUS