top | item 20854857

Windows X86-64 System Call Table

179 points| badrabbit | 6 years ago |j00ru.vexillium.org | reply

137 comments

order
[+] quotemstr|6 years ago|reply
It's important to note that unlike Linux, NT system call numbers are not stable. That's a very good thing --- it effectively forces all system calls to go through ntdll, which can coordinate closely with userspace in interesting ways. It's as if NT's "vdso" covered all interaction with the kernel.

For example, NT has no native 32-bit ABI like Linux does. Instead, userspace translates 32-bit to 64-bit system calls, handling the switch from long and back to long mode transparently. This elegant approach is possible because applications never make system calls directly.

[+] pkaye|6 years ago|reply
Then why is there a "Program Files" and "Program Files (x86) folder. I believe the second one is for 32-bit ABI apps for some special reasons?
[+] rocqua|6 years ago|reply
How does that work with regards to privilege separation. It sounds like bypassing nt.dll might be an exploit vector that is easily forgotten.
[+] mehrdadn|6 years ago|reply
Note that 64-bit kernel-mode stuff does still have to implement a fair number of 32-bit stuff, e.g. for DeviceIoControl (see e.g. IoIs32bitProcess()).
[+] mehrdadn|6 years ago|reply
Note that this page doesn't show the full set of syscalls, just a subset of them (seems to be the ones ntdll calls). The Win32k stuff, for one, don't seem to be there (edit: they're on this page instead: https://j00ru.vexillium.org/syscalls/win32k/64/), let alone more obscure ones that I expect exist but that I don't know about (like WSL stuff).
[+] monocasa|6 years ago|reply
The WSL stuff doesn't have system calls AFAIK. All the work is either kernel mode indirection to the kernel driver, and IPC (ALPC I think on WSL1?).
[+] ninkendo|6 years ago|reply
How do they deal with the syscall numbers being different from release to release, while still maintaining binary compatibility? From what I can tell, (in Linux at least) the syscall numbers are the thing that needs to stay constant for the kernel to not break user space.
[+] dataflow|6 years ago|reply
> How do they deal with the syscall numbers being different from release to release, while still maintaining binary compatibility

By not calling syscalls based on their numbers on Windows. That might sound crazy, but actually to me coming from Windows, calling them by ordinals is what sounds crazy. :-) You're supposed to call exported functions in shared libraries (ntdll.dll etc.) that call the syscalls for you.

[+] kccqzy|6 years ago|reply
Windows, like most other operating systems, doesn't have a stable user-kernel boundary. Instead the stable interface exists at the C level in libraries used by every process. This is no different from the situation in macOS (libSystem.dylib) or the various BSDs. Linux is the outlier because Linux is just a kernel; without an integrated C library, it by necessity has to keep the syscall numbers constant. Most other operating systems are free to change syscall numbers from release to release.
[+] detaro|6 years ago|reply
Application code does not use those syscalls directly, but functions from system libraries wrapping them, which have a stable interface.
[+] dblohm7|6 years ago|reply
The C stubs for NT system calls are not included as part of libc. They are implemented in ntdll.dll, which is implicitly mapped into every process (except for the new picoprocesses as used by WSL).
[+] moyix|6 years ago|reply
One odd bit of trivia: the Windows system call mechanism supports up to four different tables. The first two are what you'll usually see - the first is the basic kernel services, and the second is for Win32k, the graphical subsystem. The final two slots are up for grabs and historically could be used by drivers to implement custom system calls.

The system call number determines what table is used. Calls in the 0x0-0xFFF range are handled by the first table, 0x1000-0x1FFF by the second, and so on.

As far as I know, the ability to add another system call table was only ever used by the IIS web server kernel-mode component (spud.sys).

[+] crusader1099|6 years ago|reply
I don't doubt your interesting bit of trivia, but I couldn't find anything online about. Do you have a source for this? I would certainly love to read more about it.
[+] pedrocx486|6 years ago|reply
Sorry if this is an dumb question I could easily find on Google (been a webdev for most of my career), buy I'm curious why some syscalls exist on Vista SP1 for example, but don't exist on the versions before and after it.

Edit: I meant SP0, not SP1, sorry. It was this SysCall: NtListTransactions

[+] skissane|6 years ago|reply
It isn't a dumb question. I believe the reason is the following:

Leading up to any Windows release, Microsoft has a whole bunch of teams working on different features. Some of those features make it into the release, other features don't make it and get cut. What sometimes happens, is that a feature makes it in, but then problems are discovered in testing, and it gets pulled out again at the last minute. When a feature is removed late in the game like that, it is desired to take the lowest risk removal mechanism as possible–one way of doing that is to actually leave the feature in the code, but leave it undocumented, and hope nobody discovers it and uses it (an approach avoided nowadays due to the risk of exploitable security bugs in the buggy API, but in the past it was more common). Another way is to leave its APIs in-place, and either stub out their implementations (to always return an error), or even hide the actual implementation behind a #define that is turned off in the shipping copy. That way, you avoid making any changes to DLL export tables, the system call table, etc., which you worry (even just out of an abundance of caution) might have some downstream negative effect, but also don't have to worry about anyone discovering the broken feature and trying to use it. Then, in the next release, you have a choice – sometimes they will fix the issues with the feature and put it back in, other times priorities have changed and the remnants of the feature (such as API stubs) get removed altogether. That is why sometimes Windows DLLs export undocumented APIs that don't do anything.

(I've never worked for Microsoft, so this is not based on any internal info, just an inference from observing how Microsoft and other vendors do things.)

[+] mehrdadn|6 years ago|reply
Could you give an example? I don't see anything that's on Vista SP1 but not on SP2.
[+] rolph|6 years ago|reply
i would suspect a brand new idea [thus not appearing earlier] lost traction or relevence and didnt make the cut to migrate into the next revision
[+] jolmg|6 years ago|reply
Interesting that on a linux machine

  man syscalls \
  | grep -Po '\w+(?=\(2\))' \
  | sort \
  | uniq \
  | wc -l
gives the same number of 481 as the number of rows in that table. Though, the grep includes man-pages that don't correspond with a syscall, like intro(2). It's just a curious coincidence.
[+] october_sky|6 years ago|reply
Could someone provide examples of what to type in the field, with perhaps the relevance? (I'm not a Windows user, but this looks cool enough to test)
[+] kuroguro|6 years ago|reply
Has anyone ever done a mapping of which regular API functions map to which syscalls?
[+] sbierwagen|6 years ago|reply
Huh. Why is this so slow? According to Chrome, it took 704 milliseconds from clicking the "show" button on "Windows XP" to displaying the results. No network calls at all. A whole 525ms of script evaluation. Modern computer, thousand row table, wouldn't expect it to take that long.
[+] mehrdadn|6 years ago|reply
Not sure, but innerHTML seems to be taking a long time, in a call that loops over the results of getElementsByName. Given that getElementsByName doesn't return a real array, is it possible internally it's doing bookkeeping to make sure the iteration is still over the same set of nodes? Or alternatively maybe modifying innerHTML is just slow.
[+] nitwit005|6 years ago|reply
Not an answer exactly, but I did some work with large HTML tables for an analytics project, and I did learn browsers struggle with larger tables.

After doing a number of optimizations, our 2000 row table took 1.2 seconds for chrome to insert the elements (purely the appendChild call). That was down from around 2.6 before trimming down the HTML.

[+] lucb1e|6 years ago|reply
Works fine for me on an average laptop with latest stable Firefox.
[+] prolurker|6 years ago|reply
Tables layout is generally complex and slow, only hiding the text with CSS feels very fast.

Once layout is involved even without looping to set innerHTML it becomes a lot slower.

[+] bediger4000|6 years ago|reply
Windows NT has been around since what, 1993 or 94?

Why is this even news? Doesn't Microsoft document this stuff? How does anybody use a system that doesn't have this documented?

PS http://stratigery.com/nt.sekrits.html

[+] shanemhansen|6 years ago|reply
Because developers aren't supposed to to use them. The documented interface is ntdll or whatever.
[+] derpherpsson|6 years ago|reply
I also ask myself this question. How can anyone use an OS where the creators deliberately hide some of the documentation?

I would love to read up on windows internals, but there are no real resources out there. A few books that at first glance appears to cover it, but then just deals with the application layer and up to point-and-click.

This is why I don't use windows anymore. I don't ever again want a job where I have to debug why old program P stopped working after an update. I prefer to be able to learn stuff.