mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
ed81c34b2c
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@4534 21ef857c-d57f-4fe0-8362-d861dc6d29cd
1286 lines
51 KiB
HTML
1286 lines
51 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
|
<html>
|
|
<head>
|
|
<title>The Definitive Native API Guide</title>
|
|
<style type="text/css">
|
|
#footer {
|
|
font-size: 8pt;
|
|
}
|
|
|
|
pre {
|
|
background-color: #ccc;
|
|
border: dotted 1px #666;
|
|
}
|
|
|
|
p {
|
|
margin-top: 0.5em;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
.unsure {
|
|
color: #aa0000;
|
|
}
|
|
|
|
.warning {
|
|
color: #770000;
|
|
font-style: italic;
|
|
}
|
|
|
|
h1 {
|
|
border-top: solid 3px #000;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 20pt;
|
|
margin-top: 1.3em;
|
|
margin-bottom: 0.3em;
|
|
border-top: dashed 1px #333;
|
|
}
|
|
|
|
h3 {
|
|
font-size: 14pt;
|
|
margin-bottom: 0.3em;
|
|
}
|
|
|
|
h4 {
|
|
font-size: 12pt;
|
|
margin: 0 0 0 2em;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1 style="font-size: 30pt; border: none;">The Definitive Native API Guide</h1>
|
|
<p>Written by wj32.</p>
|
|
|
|
<h1>NT Concepts</h1>
|
|
|
|
<h3>Alertable</h3>
|
|
<p>A thread contains fields for two alertable states, one for kernel-mode and one for user-mode.
|
|
When a caller from one of these modes alerts a thread (e.g. using <code>NtAlertThread</code>),
|
|
the thread is put into an alerted state for the mode, and one of several things happen:</p>
|
|
<ul>
|
|
<li>If the thread is performing a kernel-mode alertable wait and it has just been alerted from
|
|
user-mode, nothing will happen.</li>
|
|
<li>If the thread is performing a kernel-mode alertable wait and it has just been alerted from
|
|
kernel-mode, the wait will be interrupted and the wait function will return
|
|
<code>STATUS_ALERTED</code>.</li>
|
|
<li>If the thread is performing a user-mode alertable wait and it has just been alerted from
|
|
user-mode, the wait will be interrupted as above.</li>
|
|
<li>If the thread is performing a user-mode alertable wait and it has just been alerted from
|
|
kernel-mode, the wait will be interrupted as above.</li>
|
|
</ul>
|
|
<p>Note that if the thread is alerted and then performs an alertable wait, it will be interrupted
|
|
immediately without performing the wait.</p>
|
|
<p>The thread can also call <code>NtTestAlert</code> to check if it is alerted. In all of these
|
|
cases, the thread will be reset to a non-alerted state if it is alerted.</p>
|
|
|
|
<h3>ALPC Port</h3>
|
|
<p>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 (<code>NtAlpc*</code>
|
|
system calls). Existing port-related system calls now redirect to the new ALPC port functions.</p>
|
|
<p>Related functions:
|
|
<code>NtCreatePort</code> (server),
|
|
<code>NtCreateWaitablePort</code> (server),
|
|
<code>NtConnectPort</code> (client),
|
|
<code>NtListenPort</code> (server),
|
|
<code>NtAcceptConnectPort</code> (server),
|
|
<code>NtRequestWaitReplyPort</code> (client),
|
|
<code>NtReplyWaitReceivePort</code> (server),
|
|
<code>NtReplyWaitReplyPort</code>,
|
|
<code>NtReplyPort</code>.
|
|
</p>
|
|
<p>Related types:
|
|
<code>PORT_MESSAGE</code>,
|
|
<code>PORT_VIEW</code>,
|
|
<code>REMOTE_PORT_VIEW</code>,
|
|
<code>LPCP_PORT_OBJECT</code>.
|
|
</p>
|
|
|
|
<h3>Asynchronous Procedure Calls (APCs)</h3>
|
|
<p>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.</p>
|
|
<p>User-mode APCs are queued using <code>NtQueueApcThread</code>. They will not be called
|
|
unless an <em>alertable</em> wait is being performed or <code>NtTestAlert</code> 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, if any, will be interrupted. When the
|
|
system call returns to user-mode, any pending user-mode APCs will be called.</p>
|
|
<p>A special use of user-mode APCs is thread termination, where a thread termination APC
|
|
(<code>PspExitNormalApc</code>) is inserted into the target thread. <code>KiInsertQueueApc</code>
|
|
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.</p>
|
|
<p>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
|
|
<code>KeEnterCriticalRegion</code> and both types of APCs can be temporarily disabled by using
|
|
<code>KeEnterGuardedRegion</code> or raising the IRQL to <code>APC_LEVEL</code> or higher.</p>
|
|
<ul>
|
|
<li>Normal kernel-mode APCs run at IRQL = <code>PASSIVE_LEVEL</code> and are inserted at the end
|
|
of the kernel-mode APC queue.</li>
|
|
<li>Special kernel-mode APCs run at IRQL = <code>APC_LEVEL</code> and are inserted after all existing
|
|
special APCs in the kernel-mode APC queue.</li>
|
|
</ul>
|
|
<p>When a kernel-mode APC is inserted:</p>
|
|
<ul>
|
|
<li>If the target thread is running, a software interrupt is issued to call any queued kernel-mode
|
|
APCs in the thread.</li>
|
|
<li>If the target thread is waiting at IRQL = <code>PASSIVE_LEVEL</code> and special kernel-mode APCs
|
|
are not disabled, the wait will be interrupted with <code>STATUS_KERNEL_APC</code>. 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.</li>
|
|
</ul>
|
|
<p>Normal kernel-mode APCs are used to implement thread suspension.</p>
|
|
|
|
<h3>Dispatcher Object</h3>
|
|
<p>A dispatcher object is one which has two states: <em>signaled</em> and <em>non-signaled</em>.
|
|
These objects can be used with standard wait functions such as <code>NtWaitForSingleObject</code> or
|
|
<code>NtWaitForMultipleObjects</code>. These functions wait until one or more objects are set to
|
|
a signaled state. The dispatcher objects are:</p>
|
|
<ul>
|
|
<li>Events</li>
|
|
<li>Gates (kernel-mode only)</li>
|
|
<li>Mutants</li>
|
|
<li>Processes</li>
|
|
<li>Queues (kernel-mode only)</li>
|
|
<li>Semaphores</li>
|
|
<li>Threads</li>
|
|
<li>Timers</li>
|
|
</ul>
|
|
<p>Events and gates are the most basic dispatcher objects, consisting of only a dispatcher header.</p>
|
|
<p>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.</p>
|
|
<p>Related types:
|
|
<code>DISPATCHER_HEADER</code>.
|
|
</p>
|
|
|
|
<h3>Event</h3>
|
|
<p>An event is a synchronization object that can be explicitly set to the signaled state. There are two
|
|
types of events:</p>
|
|
<ul>
|
|
<li><strong>Notification event.</strong> When a notification event is set, all waiting threads are
|
|
released. The event remains signaled until it is explicitly reset.</li>
|
|
<li><strong>Synchronization event.</strong> 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.</li>
|
|
</ul>
|
|
<p>Related functions:
|
|
<code>NtCreateEvent</code>,
|
|
<code>NtOpenEvent</code>,
|
|
<code>NtClearEvent</code>,
|
|
<code>NtPulseEvent</code>,
|
|
<code>NtQueryEvent</code>,
|
|
<code>NtResetEvent</code>,
|
|
<code>NtSetEvent</code>,
|
|
<code>NtSetEventBoostPriority</code>.
|
|
</p>
|
|
<p>Related types:
|
|
<code>EVENT_INFORMATION_CLASS</code>,
|
|
<code>EVENT_BASIC_INFORMATION</code>,
|
|
<code>KEVENT</code>.
|
|
</p>
|
|
|
|
<h3>Event Pair</h3>
|
|
<p>An event pair is a synchronization object containing two events, <em>high</em> and <em>low</em>. 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.</p>
|
|
<p>Related functions:
|
|
<code>NtCreateEventPair</code>,
|
|
<code>NtOpenEventPair</code>,
|
|
<code>NtSetHighEventPair</code>,
|
|
<code>NtSetHighWaitLowEventPair</code>,
|
|
<code>NtSetLowEventPair</code>,
|
|
<code>NtSetLowWaitHighEventPair</code>,
|
|
<code>NtWaitHighEvenPair</code>,
|
|
<code>NtWaitLowEventPair</code>.
|
|
</p>
|
|
<p>Related types:
|
|
<code>EEVENT_PAIR</code>.
|
|
</p>
|
|
|
|
<h3>Keyed Event</h3>
|
|
<p>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, <code>KeyedWaitValue</code> and <code>KeyedWaitSemaphore</code>. The <code>KeyedWaitValue</code>
|
|
contains the key being waited for by the thread. When a thread attempts to release a key which is not being
|
|
waited for, its <code>KeyedWaitValue</code> 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.</p>
|
|
<p>Related functions:
|
|
<code>NtCreateKeyedEvent</code>,
|
|
<code>NtOpenKeyedEvent</code>,
|
|
<code>NtReleaseKeyedEvent</code>,
|
|
<code>NtWaitForKeyedEvent</code>.
|
|
</p>
|
|
<p>Related types:
|
|
<code>KEYED_EVENT_OBJECT</code>.
|
|
</p>
|
|
|
|
<h3>Mutant</h3>
|
|
<p>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.</p>
|
|
<p>Related functions:
|
|
<code>NtCreateMutant</code>,
|
|
<code>NtOpenMutant</code>,
|
|
<code>NtQueryMutant</code>,
|
|
<code>NtReleaseMutant</code>
|
|
</p>
|
|
<p>Related types:
|
|
<code>MUTANT_INFORMATION_CLASS</code>,
|
|
<code>MUTANT_BASIC_INFORMATION</code>,
|
|
<code>KMUTANT</code>.
|
|
</p>
|
|
|
|
<h3>Port</h3>
|
|
<p>See <strong>ALPC Port</strong>.</p>
|
|
|
|
<h3>Profile</h3>
|
|
<p>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.</p>
|
|
<p>Related functions:
|
|
<code>NtCreateProfile</code>,
|
|
<code>NtQueryIntervalProfile</code>,
|
|
<code>NtSetIntervalProfile</code>,
|
|
<code>NtStartProfile</code>,
|
|
<code>NtStopProfile</code>.
|
|
</p>
|
|
|
|
<h3>Section</h3>
|
|
<p>Sections are objects describing a region of memory "backed" by a file. There are two types of section
|
|
objects:</p>
|
|
<ul>
|
|
<li><strong>File-backed section.</strong> 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.</li>
|
|
<li><strong>Pagefile-backed section.</strong> 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.</li>
|
|
</ul>
|
|
<p>Multiple views of the section can be mapped, and changes will be reflected across processes.</p>
|
|
<p>Related functions:
|
|
<code>NtCreateSection</code>,
|
|
<code>NtOpenSection</code>,
|
|
<code>NtAreMappedFilesTheSame</code>,
|
|
<code>NtExtendSection</code>,
|
|
<code>NtMapViewOfSection</code>,
|
|
<code>NtQuerySection</code>,
|
|
<code>NtUnmapViewOfSection</code>.
|
|
</p>
|
|
|
|
<h3>Semaphore</h3>
|
|
<p>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.</p>
|
|
<p>Related functions:
|
|
<code>NtCreateSemaphore</code>,
|
|
<code>NtOpenSemaphore</code>,
|
|
<code>NtQuerySemaphore</code>,
|
|
<code>NtReleaseSemaphore</code>.
|
|
</p>
|
|
<p>Related types:
|
|
<code>SEMAPHORE_INFORMATION_CLASS</code>,
|
|
<code>SEMAPHORE_BASIC_INFORMATION</code>,
|
|
<code>KSEMAPHORE</code>.
|
|
</p>
|
|
|
|
<h3>Timer</h3>
|
|
<p>A timer is executive object and a wrapper around the kernel timer object. There are two types of timers:</p>
|
|
<ul>
|
|
<li><strong>Notification timer.</strong> When a notification timer is signaled, all waiting threads are
|
|
released. The timer remains signaled until explicitly reset.</li>
|
|
<li><strong>Synchronization timer.</strong> When a synchronization timer is signaled, one waiting thread is
|
|
released and the timer is set to a non-signaled state.</li>
|
|
</ul>
|
|
<p>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.</p>
|
|
<p>Related functions:
|
|
<code>NtCreateTimer</code>,
|
|
<code>NtOpenTimer</code>,
|
|
<code>NtCancelTimer</code>,
|
|
<code>NtQueryTimer</code>,
|
|
<code>NtSetTimer</code>.
|
|
</p>
|
|
<p>Related types:
|
|
<code>TIMER_INFORMATION_CLASS</code>,
|
|
<code>TIMER_BASIC_INFORMATION</code>,
|
|
<code>ETIMER</code>,
|
|
<code>KTIMER</code>,
|
|
<code>PTIMER_APC_ROUTINE</code>.
|
|
</p>
|
|
|
|
<h3>Wait</h3>
|
|
<p>A thread can wait for one or more objects; the standard system calls are <code>NtWaitForSingleObject</code>,
|
|
<code>NtWaitForMultipleObjects</code>, <code>NtSignalAndWaitForSingleObject</code>, and a few type-specific
|
|
wait functions. The pointer-based kernel-mode functions are <code>KeWaitForSingleObject</code> and
|
|
<code>KeWaitForMultipleObjects</code>. These functions will block until a certain condition is met. For
|
|
example, <code>*WaitForSingleObject</code> will return when the specified object is signaled.
|
|
<code>*WaitForMultipleObjects</code> will return when all/any specified objects are signaled.</p>
|
|
<p>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.</p>
|
|
<p>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 <em>wait test</em> (<code>KiWaitTest</code>) 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.</p>
|
|
<p>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.</p>
|
|
<p>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 <em>side-effects</em>,
|
|
and are performed when a wait is satisfied.</p>
|
|
|
|
<h1>NT Enumerations</h1>
|
|
|
|
<h2>Debug Object Access</h2>
|
|
<pre>
|
|
#define DEBUG_READ_EVENT 0x0001
|
|
#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)</pre>
|
|
|
|
<h2>Directory Object Access</h2>
|
|
<pre>
|
|
#define DIRECTORY_QUERY 0x0001
|
|
#define DIRECTORY_TRAVERSE 0x0002
|
|
#define DIRECTORY_CREATE_OBJECT 0x0004
|
|
#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
|
|
|
|
#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xf)</pre>
|
|
|
|
<h2>Event Access</h2>
|
|
<pre>
|
|
#define EVENT_QUERY_STATE 0x0001
|
|
#define EVENT_MODIFY_STATE 0x0002
|
|
#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3)</pre>
|
|
|
|
<h2>Event Pair Access</h2>
|
|
<pre>
|
|
#define EVENT_PAIR_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE)</pre>
|
|
|
|
<h2>Keyed Event Access</h2>
|
|
<pre>
|
|
#define KEYEDEVENT_WAIT 0x0001
|
|
#define KEYEDEVENT_WAKE 0x0002
|
|
#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)</pre>
|
|
|
|
<h2>Mutant Access</h2>
|
|
<pre>
|
|
#define MUTANT_QUERY_STATE 0x0001
|
|
|
|
#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE| MUTANT_QUERY_STATE)</pre>
|
|
|
|
<h2>Object Flags</h2>
|
|
<pre>
|
|
#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</pre>
|
|
<h3>Members</h3>
|
|
<h4>OBJ_INHERIT</h4>
|
|
<p>Specifies that the handle (in the appropriate context) should be inherited by child processes.</p>
|
|
<h4>OBJ_PERMANENT</h4>
|
|
<p>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 <code>SeCreatePermanentPrivilege</code> in order to
|
|
create permanent objects.</p>
|
|
<h4>OBJ_EXCLUSIVE</h4>
|
|
<p>Specifies that the object should be opened for exclusive access; the object cannot be opened
|
|
again until the handle is closed.</p>
|
|
<h4>OBJ_CASE_INSENSITIVE</h4>
|
|
<p>Specifies that name comparisons should be made case insensitively.</p>
|
|
<h4>OBJ_OPENIF</h4>
|
|
<p>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 <code>STATUS_OBJECT_NAME_COLLISION</code>.</p>
|
|
<h4>OBJ_OPENLINK</h4>
|
|
<p>Not used.</p>
|
|
<h4>OBJ_KERNEL_HANDLE</h4>
|
|
<p>Specifies that the handle should be opened in the context of the System process, i.e. a kernel
|
|
handle.</p>
|
|
<h4>OBJ_FORCE_ACCESS_CHECK</h4>
|
|
<p>Specifies that an access check should be performed, even if the caller is from kernel-mode.</p>
|
|
|
|
<h2>Profile Access</h2>
|
|
<pre>
|
|
#define PROFILE_CONTROL 0x0001
|
|
#define PROFILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | PROFILE_CONTROL)</pre>
|
|
|
|
<h2>Section Access</h2>
|
|
<pre>
|
|
#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)</pre>
|
|
|
|
<h2>Semaphore Access</h2>
|
|
<pre>
|
|
#define SEMAPHORE_QUERY_STATE 0x0001
|
|
#define SEMAPHORE_MODIFY_STATE 0x0002
|
|
|
|
#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3)</pre>
|
|
|
|
<h2>Timer Access</h2>
|
|
<pre>
|
|
#define TIMER_QUERY_STATE 0x0001
|
|
#define TIMER_MODIFY_STATE 0x0002
|
|
|
|
#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
|
|
TIMER_QUERY_STATE | TIMER_MODIFY_STATE)</pre>
|
|
|
|
<h1>NT Structures</h1>
|
|
|
|
<h2>CLIENT_ID</h2>
|
|
<p>A structure identifying a process or thread.</p>
|
|
<pre>
|
|
typedef struct _CLIENT_ID
|
|
{
|
|
HANDLE UniqueProcess;
|
|
HANDLE UniqueThread;
|
|
} CLIENT_ID, *PCLIENT_ID;</pre>
|
|
<h3>Fields</h3>
|
|
<h4>UniqueProcess</h4>
|
|
<p>A handle to the process, usually a process ID (PID).</p>
|
|
<h4>UniqueThread</h4>
|
|
<p>A handle to the thread, usually a thread ID (TID).</p>
|
|
|
|
<h2>CURDIR</h2>
|
|
<p>A structure describing the current directory of a process.</p>
|
|
<pre>
|
|
typedef struct _CURDIR
|
|
{
|
|
UNICODE_STRING DosPath;
|
|
HANDLE Handle;
|
|
} CURDIR, *PCURDIR;</pre>
|
|
<h3>Fields</h3>
|
|
<h4>DosPath</h4>
|
|
<p>A string containing the current directory name. This path is usually in DOS path format
|
|
(e.g. <code>C:\Path\...</code>).</p>
|
|
<h4>Handle</h4>
|
|
<p>A handle to the current directory of the process.</p>
|
|
|
|
<h2>INITIAL_TEB</h2>
|
|
<p>A structure describing the initial contents of a TIB.</p>
|
|
<pre>
|
|
typedef struct _INITIAL_TEB
|
|
{
|
|
struct
|
|
{
|
|
PVOID OldStackBase;
|
|
PVOID OldStackLimit;
|
|
} OldInitialTeb;
|
|
PVOID StackBase;
|
|
PVOID StackLimit;
|
|
PVOID StackAllocationBase;
|
|
} INITIAL_TEB, *PINITIAL_TEB;</pre>
|
|
<h3>Fields</h3>
|
|
<h4>OldStackBase</h4>
|
|
<p>Reserved for internal use by the operating system, possibly during stack expansion. Initialize this to zero.</p>
|
|
<h4>OldStackLimit</h4>
|
|
<p>Reserved for internal use by the operating system, possibly during stack expansion. Initialize this to zero.</p>
|
|
<h4>StackBase</h4>
|
|
<p>The top of the stack, considering that the stack grows downward.</p>
|
|
<h4>StackLimit</h4>
|
|
<p>The bottom limit of the committed stack. This value is always greater than or equal to
|
|
<code>StackAllocationBase</code>.</p>
|
|
<h4>StackAllocationBase</h4>
|
|
<p>The bottom of the stack, including the reserved/free space below <code>StackLimit</code>.</p>
|
|
<h3>Notes</h3>
|
|
<p>The definition of INITIAL_TEB at NTinternals is incorrect. See
|
|
<a href="http://www.reactos.org/serendipity/index.php?/archives/15-They-lied-to-you-about-INITIAL_TEB!.html">this blog post</a>
|
|
for more details.</p>
|
|
|
|
<h2>OBJECT_ATTRIBUTES</h2>
|
|
<p>A structure describing object properties such as its name, location and security attributes.</p>
|
|
<pre>
|
|
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;</pre>
|
|
<h3>Fields</h3>
|
|
<h4>Length</h4>
|
|
<p>The length of the <code>OBJECT_ATTRIBUTES</code> structure; 24 on 32-bit systems and 40 on 64-bit systems.</p>
|
|
<h4>RootDirectory</h4>
|
|
<p>A handle to a directory object from which to begin searching for the object. If this value is <code>NULL</code>,
|
|
the object manager will use the default root directory.</p>
|
|
<h4>ObjectName</h4>
|
|
<p>The name of the object, optional when creating most types of objects.</p>
|
|
<h4>Attributes</h4>
|
|
<p>See <strong>Object Flags</strong>.</p>
|
|
<h4>SecurityDescriptor</h4>
|
|
<p>A pointer to a <code>SECURITY_DESCRIPTOR</code> structure for the object.</p>
|
|
<h4>SecurityQualityOfService</h4>
|
|
<p>A pointer to a <code>SECURITY_QUALITY_OF_SERVICE</code> structure for the object.</p>
|
|
|
|
<h2>RTL_DRIVE_LETTER_CURDIR</h2>
|
|
<p>Unknown.</p>
|
|
<pre>
|
|
typedef struct _RTL_DRIVE_LETTER_CURDIR
|
|
{
|
|
USHORT Flags;
|
|
USHORT Length;
|
|
ULONG TimeStamp;
|
|
STRING DosPath;
|
|
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;</pre>
|
|
<h3>Fields</h3>
|
|
<h4>Flags</h4>
|
|
<p>Possible values are:</p>
|
|
<pre>
|
|
#define RTL_USER_PROC_CURDIR_CLOSE 0x00000002
|
|
#define RTL_USER_PROC_CURDIR_INHERIT 0x00000003</pre>
|
|
<h4>Length</h4>
|
|
<p>Unknown.</p>
|
|
<h4>TimeStamp</h4>
|
|
<p>Unknown.</p>
|
|
<h4>DosPath</h4>
|
|
<p>Unknown.</p>
|
|
|
|
<h2>RTL_USER_PROCESS_PARAMETERS</h2>
|
|
<p>A structure describing startup parameters for a process.</p>
|
|
<pre>
|
|
#define RTL_MAX_DRIVE_LETTERS 32
|
|
#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001
|
|
|
|
typedef struct _RTL_USER_PROCESS_PARAMETERS
|
|
{
|
|
ULONG MaximumLength;
|
|
ULONG Length;
|
|
|
|
ULONG Flags;
|
|
ULONG DebugFlags;
|
|
|
|
HANDLE ConsoleHandle;
|
|
ULONG ConsoleFlags;
|
|
HANDLE StandardInput;
|
|
HANDLE StandardOutput;
|
|
HANDLE StandardError;
|
|
|
|
CURDIR CurrentDirectory;
|
|
UNICODE_STRING DllPath;
|
|
UNICODE_STRING ImagePathName;
|
|
UNICODE_STRING CommandLine;
|
|
PVOID Environment;
|
|
|
|
ULONG StartingX;
|
|
ULONG StartingY;
|
|
ULONG CountX;
|
|
ULONG CountY;
|
|
ULONG CountCharsX;
|
|
ULONG CountCharsY;
|
|
ULONG FillAttribute;
|
|
|
|
ULONG WindowFlags;
|
|
ULONG ShowWindowFlags;
|
|
UNICODE_STRING WindowTitle;
|
|
UNICODE_STRING DesktopInfo;
|
|
UNICODE_STRING ShellInfo;
|
|
UNICODE_STRING RuntimeData;
|
|
RTL_DRIVE_LETTER_CURDIR CurrentDirectores[RTL_MAX_DRIVE_LETTERS];
|
|
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;</pre>
|
|
|
|
<h2>STRING, ANSI_STRING</h2>
|
|
<p>A structure describing a counted ANSI string.</p>
|
|
<pre>
|
|
typedef struct _STRING
|
|
{
|
|
USHORT Length;
|
|
USHORT MaximumLength;
|
|
PCHAR Buffer;
|
|
} STRING, *PSTRING, ANSI_STRING, *PANSI_STRING;</pre>
|
|
<h3>Fields</h3>
|
|
<h4>Length</h4>
|
|
<p>The length, in bytes, of the string (excluding the null terminator, if present).</p>
|
|
<h4>MaximumLength</h4>
|
|
<p>The number of bytes allocated for the string in <code>Buffer</code>.</p>
|
|
<h4>Buffer</h4>
|
|
<p>A buffer containing the string.</p>
|
|
|
|
<h2>UNICODE_STRING</h2>
|
|
<p>A structure describing a counted Unicode string.</p>
|
|
<pre>
|
|
typedef struct _UNICODE_STRING
|
|
{
|
|
USHORT Length;
|
|
USHORT MaximumLength;
|
|
PWSTR Buffer;
|
|
} UNICODE_STRING, *PUNICODE_STRING;</pre>
|
|
<h3>Fields</h3>
|
|
<h4>Length</h4>
|
|
<p>The length, in bytes, of the string (excluding the null terminator, if present).</p>
|
|
<h4>MaximumLength</h4>
|
|
<p>The number of bytes allocated for the string in <code>Buffer</code>.</p>
|
|
<h4>Buffer</h4>
|
|
<p>A buffer containing the string.</p>
|
|
|
|
<h1>NT Functions</h1>
|
|
|
|
<h2>NtAlertThread</h2>
|
|
<p>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.</p>
|
|
<p>If the specified thread is in a Wait state, it will be unwaited with a status of <code>STATUS_ALERTED</code>.
|
|
If the function is being called from user-mode, it cannot unwait a kernel-mode wait operation.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtAlertThread(
|
|
__in HANDLE ThreadHandle
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A handle to the thread to alert. The handle must have <code>THREAD_ALERT</code> access.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll; <code>KeAlertThread</code> and <code>ZwAlertThread</code> are exported by ntoskrnl</p>
|
|
<h3>Notes</h3>
|
|
<p>If this function is called from user-mode, it will set the specified thread's <em>user-mode alert state</em> to
|
|
alerted. This will not affect kernel-mode code. The same is true when the function is called from kernel-mode.</p>
|
|
|
|
<h2>NtAlertResumeThread</h2>
|
|
<p>Alerts the specified thread (see <code>NtAlertThread</code>) and resumes it.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtAlertResumeThread(
|
|
__in HANDLE ThreadHandle,
|
|
__out_opt PULONG PreviousSuspendCount
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A handle to the thread to alert and resume. The handle must have <code>THREAD_SUSPEND_RESUME</code> access.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
<h3>Notes</h3>
|
|
<p>See notes in <code>NtAlertThread</code>.</p>
|
|
|
|
<h2>NtClose</h2>
|
|
<p>Closes a handle.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtClose(
|
|
__in HANDLE Handle
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>Handle</h4>
|
|
<p>The handle to close. If the object referenced by the handle is temporary and has no references, it will be freed.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll, ntoskrnl</p>
|
|
|
|
<h2>NtCreateDebugObject</h2>
|
|
<p>Creates a debug object.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateDebugObject(
|
|
__out PHANDLE DebugObjectHandle,
|
|
__in ACCESS_MASK DesiredAccess,
|
|
__in POBJECT_ATTRIBUTES ObjectAttributes,
|
|
__in ULONG Flags
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>DebugObjectHandle</h4>
|
|
<p>A variable that receives a handle to the new debug object.</p>
|
|
<h4>DesiredAccess</h4>
|
|
<p>The desired access to the new debug object. See <strong>Debug Object Access</strong>.</p>
|
|
<h4>ObjectAttributes</h4>
|
|
<p>See <code>OBJECT_ATTRIBUTES</code>.</p>
|
|
<h4>Flags</h4>
|
|
<p>The only flag currently defined is:</p>
|
|
<pre>
|
|
#define DEBUG_KILL_ON_CLOSE 0x1</pre>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
|
|
<h2>NtCreateDirectoryObject</h2>
|
|
<p>Creates a directory object.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateDirectoryObject(
|
|
__out PHANDLE DirectoryHandle,
|
|
__in ACCESS_MASK DesiredAccess,
|
|
__in POBJECT_ATTRIBUTES ObjectAttributes
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>DirectoryHandle</h4>
|
|
<p>A variable that receives a handle to the new directory object.</p>
|
|
<h4>DesiredAccess</h4>
|
|
<p>The desired access to the new directory object. See <strong>Directory Object Access</strong>.</p>
|
|
<h4>ObjectAttributes</h4>
|
|
<p>See <code>OBJECT_ATTRIBUTES</code>.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll; <code>ZwCreateDirectoryObject</code> is exported by ntoskrnl</p>
|
|
|
|
<h2>NtCreateProcess</h2>
|
|
<p>Creates a process (with no threads).</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateProcess(
|
|
__out PHANDLE ProcessHandle,
|
|
__in ACCESS_MASK DesiredAccess,
|
|
__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
|
|
__in HANDLE ParentProcess,
|
|
__in BOOLEAN InheritObjectTable,
|
|
__in_opt HANDLE SectionHandle,
|
|
__in_opt HANDLE DebugPort,
|
|
__in_opt HANDLE ExceptionPort
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ProcessHandle</h4>
|
|
<p>A variable that receives a handle to the new process.</p>
|
|
<h4>DesiredAccess</h4>
|
|
<p>The desired access to the new process.</p>
|
|
<h4>ObjectAttributes</h4>
|
|
<p>See <code>OBJECT_ATTRIBUTES</code>.</p>
|
|
<h4>ParentProcess</h4>
|
|
<p>A handle to a parent process. If no section (in <code>SectionHandle</code>) was specified, the new process
|
|
will inherit the address space, handles and other characteristics of the parent process. If a section was
|
|
specified, the new process will receive a new address space created from the section but will still inherit
|
|
handles (if specified in <code>InheritObjectTable</code>) and other characteristics. The parent process
|
|
must be specified unless the new process is the first process to be created on the system (the System process).</p>
|
|
<h4>InheritObjectTable</h4>
|
|
<p>Whether <code>ObInitProcess</code> will duplicate handles with the <code>OBJ_INHERIT</code> attribute from
|
|
the parent process into the new process.</p>
|
|
<h4>SectionHandle</h4>
|
|
<p>A handle to a section which will be used to create the new process' address space. The handle must have
|
|
<code>SECTION_MAP_EXECUTE</code> access.</p>
|
|
<h4>DebugPort</h4>
|
|
<p>A handle to a debug object which the process will be assigned to. The handle must have <code>DEBUG_PROCESS_ASSIGN</code>
|
|
access.</p>
|
|
<h4>ExceptionPort</h4>
|
|
<p>A handle to a LPC port which will be notified when an exception occurs in the process.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
<h3>Notes</h3>
|
|
<p>The new process does not have any threads. You can create one using <code>NtCreateThread</code> or
|
|
<code>RtlCreateUserThread</code>.</p>
|
|
|
|
<h2>NtCreateProcessEx</h2>
|
|
<p>Creates a process (with no threads).</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateProcessEx(
|
|
__out PHANDLE ProcessHandle,
|
|
__in ACCESS_MASK DesiredAccess,
|
|
__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
|
|
__in HANDLE ParentProcess,
|
|
__in ULONG Flags,
|
|
__in_opt HANDLE SectionHandle,
|
|
__in_opt HANDLE DebugPort,
|
|
__in_opt HANDLE ExceptionPort,
|
|
__in ULONG JobMemberLevel
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<p>See <code>NtCreateProcess</code>.</p>
|
|
<h4>Flags</h4>
|
|
<p>A combination of flags which control the creation of the new process:</p>
|
|
<pre>
|
|
#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001
|
|
#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002
|
|
#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004
|
|
#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008
|
|
#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010</pre>
|
|
<h4>JobMemberLevel</h4>
|
|
<p>The member level within a job set.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
|
|
<h2>NtCreateThread</h2>
|
|
<p>Creates a thread.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateThread(
|
|
__out PHANDLE ThreadHandle,
|
|
__in ACCESS_MASK DesiredAccess,
|
|
__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
|
|
__in HANDLE ProcessHandle,
|
|
__out PCLIENT_ID ClientId,
|
|
__in PCONTEXT ThreadContext,
|
|
__in PINITIAL_TEB InitialTeb,
|
|
__in BOOLEAN CreateSuspended
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A variable which receives a handle to the new thread.</p>
|
|
<h4>DesiredAccess</h4>
|
|
<p>The desired access to the new thread.</p>
|
|
<h4>ObjectAttributes</h4>
|
|
<p>See <code>OBJECT_ATTRIBUTES</code>.</p>
|
|
<h4>ProcessHandle</h4>
|
|
<p>A handle to the process in which the thread is to be created. The handle must have
|
|
<code>PROCESS_CREATE_THREAD</code> access.</p>
|
|
<h4>ClientId</h4>
|
|
<p>A variable which receives the client ID of the new thread.</p>
|
|
<h4>ThreadContext</h4>
|
|
<p>The initial context for the thread.</p>
|
|
<h4>InitialTeb</h4>
|
|
<p>A structure which describes the initial state of the thread's TIB. See <code>INITIAL_TEB</code>.</p>
|
|
<h4>CreateSuspended</h4>
|
|
<p>Whether the thread should be suspended when it is created. You can resume the thread using <code>NtResumeThread</code>.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
<h3>Notes</h3>
|
|
<p>In the arguments, <code>InitialTeb</code> actually specifies the initial Thread Information Block (TIB) for the thread.
|
|
The TIB is stored in the Thread Environment Block (TEB) of the thread, and can be referenced by the <code>fs</code>
|
|
segment register. The name TIB is pre-NT; see
|
|
<a href="http://www.microsoft.com/msj/archive/s2ce.aspx">Under The Hood -- MSJ, May 1996</a>. See <code>NT_TIB</code> for
|
|
more information on the TIB.</p>
|
|
|
|
<h2 class="unsure">NtCreateThreadEx</h2>
|
|
<p>Creates a thread.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateThreadEx(
|
|
__out PHANDLE ThreadHandle,
|
|
__in ACCESS_MASK DesiredAccess,
|
|
__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
|
|
__in HANDLE ProcessHandle,
|
|
__in PVOID StartRoutine,
|
|
__in_opt PVOID StartContext,
|
|
__in ULONG Flags,
|
|
__in_opt ULONG_PTR StackZeroBits,
|
|
__in_opt SIZE_T StackCommit,
|
|
__in_opt SIZE_T StackReserve,
|
|
__in_opt PPROCESS_ATTRIBUTE_LIST AttributeList
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A variable which receives a handle to the new thread.</p>
|
|
<h4>DesiredAccess</h4>
|
|
<p>The desired access to the new thread.</p>
|
|
<h4>ObjectAttributes</h4>
|
|
<p>See <code>OBJECT_ATTRIBUTES</code>.</p>
|
|
<h4>ProcessHandle</h4>
|
|
<p>A handle to the process in which the thread is to be created. The handle must have
|
|
<code>PROCESS_CREATE_THREAD</code> access.</p>
|
|
<h4>StartRoutine</h4>
|
|
<p>The function to call in the new thread.</p>
|
|
<h4>StartContext</h4>
|
|
<p>The parameter to pass to the start function.</p>
|
|
<h4>Flags</h4>
|
|
<p>Flags which control the creation of the thread:</p>
|
|
<pre>
|
|
#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001
|
|
<span class="unsure">#define THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH 0x00000002</span>
|
|
#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004
|
|
<span class="unsure">#define THREAD_CREATE_FLAGS_HAS_SECURITY_DESCRIPTOR 0x00000010</span>
|
|
<span class="unsure">#define THREAD_CREATE_FLAGS_ACCESS_CHECK_IN_TARGET 0x00000020</span>
|
|
#define THREAD_CREATE_FLAGS_INITIAL_THREAD 0x00000080</pre>
|
|
<h4>StackZeroBits</h4>
|
|
<p>The number of bits that must be clear when the thread stack is allocated.</p>
|
|
<h4>StackCommit</h4>
|
|
<p>The number of bytes to commit in the thread stack.</p>
|
|
<h4>StackReserve</h4>
|
|
<p>The number of bytes to reserve for the thread stack.</p>
|
|
<h4>AttributeList</h4>
|
|
<p>See <code>PROCESS_ATTRIBUTE_LIST</code>.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
|
|
<h2 class="unsure">NtCreateUserProcess</h2>
|
|
<p>Creates a process and an initial thread.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtCreateUserProcess(
|
|
__out PHANDLE ProcessHandle,
|
|
__out PHANDLE ThreadHandle,
|
|
__in ACCESS_MASK ProcessDesiredAccess,
|
|
__in ACCESS_MASK ThreadDesiredAccess,
|
|
__in_opt POBJECT_ATTRIBUTES ProcessObjectAttributes,
|
|
__in_opt POBJECT_ATTRIBUTES ThreadObjectAttributes,
|
|
__in ULONG ProcessFlags,
|
|
__in ULONG ThreadFlags,
|
|
__in_opt PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
|
|
__inout PPROCESS_CREATE_INFO CreateInfo,
|
|
__in_opt PPROCESS_ATTRIBUTE_LIST AttributeList
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ProcessHandle</h4>
|
|
<p>A variable which receives a handle to the new process.</p>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A variable which receives a handle to the new thread.</p>
|
|
<h4>ProcessDesiredAccess</h4>
|
|
<p>The desired access to the new process.</p>
|
|
<h4>ThreadDesiredAccess</h4>
|
|
<p>The desired access to the new thread.</p>
|
|
<h4>ProcessObjectAttributes</h4>
|
|
<p>See <code>OBJECT_ATTRIBUTES</code>.</p>
|
|
<h4>ThreadObjectAttributes</h4>
|
|
<p>See <code>OBJECT_ATTRIBUTES</code>.</p>
|
|
<h4>ProcessFlags</h4>
|
|
<p>Flags used in <code>NtCreateProcessEx</code>, plus the following:</p>
|
|
<pre>
|
|
#define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL 0x00000020
|
|
#define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS 0x00000040
|
|
<span class="unsure">#define PROCESS_CREATE_FLAGS_CREATE_SESSION 0x00000080</span>
|
|
#define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT 0x00000100</pre>
|
|
<h4>ThreadFlags</h4>
|
|
<p>See <code>NtCreateThreadEx</code>.</p>
|
|
<h4>ProcessParameters</h4>
|
|
<p>See <code>RTL_USER_PROCESS_PARAMETERS</code>.</p>
|
|
<h4>CreateInfo</h4>
|
|
<p>See <code>PROCESS_CREATE_INFO</code>.</p>
|
|
<h4>AttributeList</h4>
|
|
<p>See <code>PROCESS_ATTRIBUTE_LIST</code>.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
|
|
<h2>NtOpenProcess</h2>
|
|
<p>Opens a process.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtOpenProcess(
|
|
__out PHANDLE ProcessHandle,
|
|
__in ACCESS_MASK DesiredAccess,
|
|
__in POBJECT_ATTRIBUTES ObjectAttributes,
|
|
__in_opt PCLIENT_ID ClientId
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ProcessHandle</h4>
|
|
<p>A variable which receives a handle to a process.</p>
|
|
<h4>DesiredAccess</h4>
|
|
<p>The desired access to the process.</p>
|
|
<h4>ObjectAttributes</h4>
|
|
<p>See <code>OBJECT_ATTRIBUTES</code>. The <code>ObjectName</code> field must be NULL.</p>
|
|
<h4>ClientId</h4>
|
|
<p>A <code>CLIENT_ID</code> specifying the process to open. If the <code>UniqueThread</code> field
|
|
is not 0, the function will open the process belonging to the thread specified by the thread ID in
|
|
<code>UniqueThread</code>. Otherwise, the function will open the process specified by the process ID
|
|
in the <code>UniqueProcess</code> field.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll, ntoskrnl</p>
|
|
|
|
<h2>NtQueueApcThread</h2>
|
|
<p>Queues a user-mode APC to the specified thread. The APC will execute when the thread performs an alertable wait or
|
|
calls <code>NtTestAlert</code>. Any wait operations will return with <code>STATUS_USER_APC</code>.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtQueueApcThread(
|
|
__in HANDLE ThreadHandle,
|
|
__in PPS_APC_ROUTINE ApcRoutine,
|
|
__in_opt PVOID ApcArgument1,
|
|
__in_opt PVOID ApcArgument2,
|
|
__in_opt PVOID ApcArgument3
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A handle to a thread. The handle must have <code>THREAD_SET_CONTEXT</code> access.</p>
|
|
<h4>ApcRoutine.</h4>
|
|
<p>An APC routine to execute:</p>
|
|
<pre>
|
|
typedef
|
|
VOID
|
|
(*PPS_APC_ROUTINE)(
|
|
__in_opt PVOID ApcArgument1,
|
|
__in_opt PVOID ApcArgument2,
|
|
__in_opt PVOID ApcArgument3
|
|
);</pre>
|
|
<h4>ApcArgument1..3</h4>
|
|
<p>The arguments to pass to the APC routine.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll; <code>KeInsertQueueApc</code> is exported by ntoskrnl</p>
|
|
|
|
<h2>NtRegisterThreadTerminatePort</h2>
|
|
<p>Registers a port which will be notified when the current thread terminates.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtRegisterThreadTerminatePort(
|
|
__in HANDLE PortHandle
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>PortHandle</h4>
|
|
<p>A handle to the LPC port to be notified when the current thread terminates. The port will be added to a singly linked list
|
|
of ports which will all be notified when the thread terminates.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
|
|
<h2>NtResumeProcess</h2>
|
|
<p>Resumes each thread in a process.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtResumeProcess(
|
|
__in HANDLE ProcessHandle
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ProcessHandle</h4>
|
|
<p>A handle to the process to resume. The handle must have <code>PROCESS_SUSPEND_RESUME</code> access.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll; <code>PsResumeProcess</code> is exported by ntoskrnl</p>
|
|
|
|
<h2>NtResumeThread</h2>
|
|
<p>Resumes the specified thread. The thread is not actually resumed until the suspend count reaches 0
|
|
(i.e. the thread has been resumed the same number of times it has been suspended).</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtResumeThread(
|
|
__in HANDLE ThreadHandle,
|
|
__out_opt PULONG PreviousSuspendCount
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A handle to the thread to resume. The handle must have <code>THREAD_SUSPEND_RESUME</code> access.</p>
|
|
<h4>PreviousSuspendCount</h4>
|
|
<p>A variable that receives the previous suspend count (the number of times the thread has been suspended
|
|
minus the number of times the thread has been resumed).</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
|
|
<h2>NtSuspendProcess</h2>
|
|
<p>Suspends each thread in a process.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtSuspendProcess(
|
|
__in HANDLE ProcessHandle
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ProcessHandle</h4>
|
|
<p>A handle to the process to suspend. The handle must have <code>PROCESS_SUSPEND_RESUME</code> access.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll; <code>PsSuspendProcess</code> is exported by ntoskrnl</p>
|
|
|
|
<h2>NtSuspendThread</h2>
|
|
<p>Suspends the specified thread.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtSuspendThread(
|
|
__in HANDLE ThreadHandle,
|
|
__out_opt PULONG PreviousSuspendCount
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A handle to the thread to suspend. The handle must have <code>THREAD_SUSPEND_RESUME</code> access.</p>
|
|
<h4>PreviousSuspendCount</h4>
|
|
<p>A variable that receives the previous suspend count (the number of times the thread has been suspended
|
|
minus the number of times the thread has been resumed).</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
|
|
<h2>NtTerminateProcess</h2>
|
|
<p>Terminates the specified process.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtTerminateProcess(
|
|
__in_opt HANDLE ProcessHandle,
|
|
__in NTSTATUS ExitStatus
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ProcessHandle</h4>
|
|
<p>A handle to the process to terminate. The handle must have <code>PROCESS_TERMINATE</code> access. If this argument
|
|
is NULL, the current process will be terminated.</p>
|
|
<h4>ExitStatus</h4>
|
|
<p>A NT status value that will be saved.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll; <code>ZwTerminateProcess</code> is exported by ntoskrnl</p>
|
|
|
|
<h2>NtTerminateThread</h2>
|
|
<p>Terminates the specified thread.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtTerminateThread(
|
|
__in_opt HANDLE ThreadHandle,
|
|
__in NTSTATUS ExitStatus
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>ThreadHandle</h4>
|
|
<p>A handle to the thread to terminate. The handle must have <code>THREAD_TERMINATE</code> access. If this argument
|
|
is NULL, the current thread will be terminated. If the thread is the last in the process, the function will return
|
|
<code>STATUS_CANT_TERMINATE_SELF</code>. The reason for this is that user-mode libraries (such as ntdll) are required to
|
|
call <code>NtTerminateProcess</code> if this function fails with <code>STATUS_CANT_TERMINATE_SELF</code>.</p>
|
|
<h4>ExitStatus</h4>
|
|
<p>A NT status value that will be saved.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
|
|
<h2>NtTestAlert</h2>
|
|
<p>Checks whether the current thread is alerted. If it is, the thread's alerted state will be cleared and
|
|
<code>STATUS_ALERTED</code> will be returned. Otherwise, <code>STATUS_SUCCESS</code> will be returned.</p>
|
|
<p>If the function is being called from user-mode, any user-mode APCs will be called when the system service exits.</p>
|
|
<pre>
|
|
NTSYSCALLAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
NtTestAlert(
|
|
VOID
|
|
);</pre>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll; <code>KeTestAlertThread</code> is exported by ntoskrnl</p>
|
|
<h3>Notes</h3>
|
|
<p>See notes in <code>NtAlertThread</code>.</p>
|
|
|
|
<h2>RtlCreateUserProcess</h2>
|
|
<p>Creates a process and an initial thread.</p>
|
|
<pre>
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlCreateUserProcess(
|
|
__in PUNICODE_STRING NtImagePathName,
|
|
__in ULONG Attributes,
|
|
__in PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
|
|
__in_opt PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,
|
|
__in_opt PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
|
|
__in_opt HANDLE ParentProcess,
|
|
__in BOOLEAN InheritHandles,
|
|
__in_opt HANDLE DebugPort,
|
|
__in_opt HANDLE ExceptionPort,
|
|
__out PRTL_USER_PROCESS_INFORMATION ProcessInformation
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>NtImagePathName</h4>
|
|
<p>A <code>UNICODE_STRING</code> which specifies the image file (EXE) from which to create the process. The file name
|
|
must be in native format, e.g. <code>\SystemRoot\notepad.exe</code>.</p>
|
|
<h4>Attributes</h4>
|
|
<p>The object attributes to use when opening the image file, e.g. <code>OBJ_INHERIT</code>.</p>
|
|
<h4>ProcessParameters</h4>
|
|
<p>See <code>RTL_USER_PROCESS_PARAMETERS</code>.</p>
|
|
<h4>ProcessSecurityDescriptor</h4>
|
|
<p>A security descriptor for the new process.</p>
|
|
<h4>ThreadSecurityDescriptor</h4>
|
|
<p>A security descriptor for the initial thread in the new process.</p>
|
|
<h4>ParentProcess</h4>
|
|
<p>A process from which to inherit handles and other characteristics. <code>RtlCreateUserProcess</code> will also
|
|
duplicate standard handles (input, output and error) from the parent process to the new process.</p>
|
|
<h4>InheritHandles</h4>
|
|
<p>Whether <code>NtCreateProcess</code> should duplicate handles with the <code>OBJ_INHERIT</code> attribute.</p>
|
|
<h4>DebugPort</h4>
|
|
<p>A handle to a debug object which the process will be assigned to. The handle must have <code>DEBUG_PROCESS_ASSIGN</code>
|
|
access.</p>
|
|
<h4>ExceptionPort</h4>
|
|
<p>A handle to a LPC port which will be notified when an exception occurs in the process.</p>
|
|
<h4>ProcessInformation</h4>
|
|
<p>A <code>RTL_USER_PROCESS_INFORMATION</code> structure which will receive information about the new process:</p>
|
|
<pre>
|
|
typedef struct _RTL_USER_PROCESS_INFORMATION
|
|
{
|
|
ULONG Length;
|
|
HANDLE Process;
|
|
HANDLE Thread;
|
|
CLIENT_ID ClientId;
|
|
SECTION_IMAGE_INFORMATION ImageInformation;
|
|
} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION;</pre>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
<h3>Notes</h3>
|
|
<p>This <code>RtlCreateUserProcess</code> does not notify CSR of the new process, so the process' use of the
|
|
Win32 API is limited.</p>
|
|
|
|
<h2>RtlCreateUserThread</h2>
|
|
<p>Creates a thread.</p>
|
|
<pre>
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlCreateUserThread(
|
|
__in HANDLE Process,
|
|
__in_opt PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
|
|
__in BOOLEAN CreateSuspended,
|
|
__in_opt ULONG ZeroBits,
|
|
__in_opt SIZE_T MaximumStackSize,
|
|
__in_opt SIZE_T CommittedStackSize,
|
|
__in PUSER_THREAD_START_ROUTINE StartAddress,
|
|
__in_opt PVOID Parameter,
|
|
__out_opt PHANDLE Thread,
|
|
__out_opt PCLIENT_ID ClientId
|
|
);</pre>
|
|
<h3>Arguments</h3>
|
|
<h4>Process</h4>
|
|
<p>A handle to the process in which the thread will be created. The handle must have <code>PROCESS_CREATE_THREAD</code> and
|
|
<code>PROCESS_VM_OPERATION</code> access.</p>
|
|
<h4>ThreadSecurityDescriptor</h4>
|
|
<p>A security descriptor for the new thread.</p>
|
|
<h4>CreateSuspended</h4>
|
|
<p>Whether the thread should be suspended when it is created. You can resume the thread using <code>NtResumeThread</code>.</p>
|
|
<h4>ZeroBits</h4>
|
|
<p>The number of bits that must be clear when the thread stack is allocated. This value cannot be greater than 21.</p>
|
|
<h4>MaximumStackSize</h4>
|
|
<p>The maximum size of the thread stack.</p>
|
|
<h4>CommittedStackSize</h4>
|
|
<p>The number of bytes of initially committed thread stack.</p>
|
|
<h4>StartAddress</h4>
|
|
<p>The function to call in the new thread:</p>
|
|
<pre>
|
|
typedef
|
|
NTSTATUS
|
|
(*PUSER_THREAD_START_ROUTINE)(
|
|
PVOID ThreadParameter
|
|
);</pre>
|
|
<h4>Parameter</h4>
|
|
<p>A value to pass to the function specified by <code>StartAddress</code>.</p>
|
|
<h4>Thread</h4>
|
|
<p>A variable which receives a handle to the new thread. The handle will have <code>THREAD_ALL_ACCESS</code> access.</p>
|
|
<h4>ClientId</h4>
|
|
<p>A variable which receives the client ID of the new thread.</p>
|
|
<h3>Exported by</h3>
|
|
<p>ntdll</p>
|
|
<h3>Notes</h3>
|
|
<p>This function is not limited to creating threads in processes within the current session, a limitation present in
|
|
the <code>CreateRemoteThread</code> Windows API function. This is due to the fact that <code>RtlCreateUserThread</code>
|
|
does not attempt to notify CSR of the new thread, removing the session limitation but also limiting your use of the
|
|
Win32 API.</p>
|
|
|
|
<p id="footer">Copyright (c) 2009 wj32. Licensed under the GFDL 1.3.</p>
|
|
</body>
|
|
</html>
|