Chapter 4/ System Briefing
I truncated the output of this command for the sake of brevity. One thing
you'll notice is that all of the routine names begin with the prefix "Nt."
Hence, I will often refer to the Native API as Nt*(} calls, v�here I've used the
asterisk character as a wild-card symbol to represent the entire family of pos¬
sible calls.
Can user-mode code access all 401 of these Native API routines? To answer
this question, we can examine the functions exported by ntdl 1 .d11, the user-
mode front man for the operating system. Using the ever-handy dumpbin.
exe, wc find that ntdll .dll exports 1,981 routines. Of these, 407 roudnes
are of the form Nt*{), This is because there are extra Nt*{) routines exported
by ntdl 1 .dll that are implemented entirely in user space. One of these extra
routines, NtCurrentTeb(), is particularly noteworthy.
> uf ntdl1INtCurrentTeb
ntdl1INtCurrentTeb;
fnov eax,dword ptr fs; [OOOOOOlSh]
ret
The disassembly of NtCurrentTEBC) is interesting because it demonstrates that
we can access thread execution blocks in our applications with nothing more
than raw assembly code. We'll use this fact again later on in the book.
Nt*() Versus Z\n*{) System Calls
Looking at the dump of exported functions from ntdll .dll, you'll see what
might appear to be duplicate entries.
NtAcceptConnectPort ZwAcceptCoTinectPort
NtAccessCheck ZwAccessCheck
NtAccessCheckAndAuditAlarmZwAccessCheckAndAudItAlarm
NtAccessCheckByType ZwAccessCheckByType
With a few minor exceptions, each Nt*() function has a matching Zw*()
function. For example, NtCreateTokenO can be paired with ZwCreateToken{).
This might leave you scratching your head and wondering why there are two
versions of the same function.
As it turns out, from the standpoint of a user-mode program, there is no
difference. Both routines end up calling the same code. For example, take
NtCreateProcess0 and ZwCreateProcess(). Using CDB.exe, we can see that a
call to NtCreateProcess (} ends up calling the same code as a call to ZwCre¬
ateProcess {).