-
Notifications
You must be signed in to change notification settings - Fork 139
Finding Unexported ZwXx Functions Reliably
One of the issues I faced during development was that certain functions such as ZwCreateUserProcess
are not reliably exported by the Windows kernel. At the end of the day, this was still a ZwXx
function and I thought there had to be a way to find it without running into stability issues. 0xNemi pointed out that the ZwCreateUserProcess
function sets the same system call number seen in NtCreateUserProcess
, the user-mode equivalent of the function, and that we can use the number inside of NtCreateUserProcess
to find ZwCreateUserProcess
. How do we go about doing this?
Well it's actually pretty simple. First of all, the system call number is going to change across different Windows versions; hard-coding the system call is not an option. Instead I opted to extract the system call number by parsing ntdll.dll
myself.
- The rootkit loads
ntdll.dll
into member. - We find the
NtCreateUserProcess
function by enumerating the export address table (EAT) of thentdll.dll
module. - We can extract the system call number easily since
NtXx
functions follow the same assembly format starting with amov r10, rcx
and then amov eax, [system call number]
.
With the system call number in hand, finding the ZwXx
equivalent is simple as well. ZwXx
functions use the following format:
push rax
mov eax, [system call number]
jmp KiServiceInternal
To find the ZwXx
function, all we need to do is search the executable sections of ntoskrnl.exe
for the above format except replacing the [system call number]
with the number we found previously. That's it! Here is the NtFunctionResolver.cpp source in case you'd like to see the code.