Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Link to ntdll.lib and call functions inside ntdll.dll

I'm recently doing some research on private APIs. I tried to call functions such as NtOpenFile in ntdll.dll with LoadLibrary and GetProcAddress at runtime. Luckly, it succeed. This morning I performed a file search on my computer and find ntdll.lib in my C drive. As far as I know of, such .lib file should contain stubs for dll exports available for linking. So, I tried to link my application to that lib but I'm constantly getting unresolved external symbol errors. However, a dumpbin /EXPORTS shows that ntdll.lib clearly has NtOpenFile exported. How could I resolve this error?

like image 489
Kelvin Zhang Avatar asked Mar 13 '23 05:03

Kelvin Zhang


2 Answers

The problem is the name of the function as recorded in the library and as it is generated from compiler.
dumpbin just shows you the base exported symbol NtOpenFile (the undecorated one), but there is also a import symbol __imp_NtOpenFile. Now if you try to link statically NtOpenFile declaring it as:

NTSTATUS NtOpenFile(
  _Out_ PHANDLE            FileHandle,
  _In_  ACCESS_MASK        DesiredAccess,
  _In_  POBJECT_ATTRIBUTES ObjectAttributes,
  _Out_ PIO_STATUS_BLOCK   IoStatusBlock,
  _In_  ULONG              ShareAccess,
  _In_  ULONG              OpenOptions
);

The compiler will generate, for a __stdcall function under 32bits, the symbol _NtOpenFile@24, if I'm not wrong counting the bytes size of call arguments, that obviously is not in the library. This is due to the fact that ntdll.lib is intended to be used under DDK for drivers development, where the compiler generates undecorated symbols.
To clarify the concept open the ntdll.lib file with a binary editor and look for NtOpenFile, you will see only it and the import version __imp_NtOpenFile. Now open a standar library as gdi32.lib, just to name one, and search for CreateDIBSection you'll find a _CreateDIBSection@24 and also __imp__CreateDIBSection@24.
So what's going on? Simple dumpbin shows always the undecorated names, but the compiler generates decorated ones, result: the linker fails. It is said that names use PASCAL convention, that is the same as __stdcall, but doesn't decorate symbols (i.e. read this https://msdn.microsoft.com/en-us/library/aa235591(v=vs.60).aspx).
There is a way to solve the problem? Yes you have to create your own import library assigning an alias to the wanted function having the correct decorations. Start reading this https://msdn.microsoft.com/en-us/library/0b9xe492.aspx.

like image 22
Frankie_C Avatar answered Mar 28 '23 14:03

Frankie_C


No longer the case, you can find ntdll.lib import library and NT headers as I write this in 2019.

It's a lot of extra code to do it the GetProcAddress() way. Certainly direct imports is cleaner and is the pattern we're used to for C/C++ desktop applications.

I used to make my own "ntdll.lib" import library by creating a simple Windows DLL project with a .def file, etc. Adding each ntdll API function one at the time as I needed them as a stub and for a header file. Throwing away the .dll, just using the .lib from it.

But at least since MSVC 2017 it includes user mode (for desktop applications) ntdll.lib libraries for x86 and ARM in both 32bit and 64bit varieties. This might require the Windows 10 WDK to be installed. Just search your "C:\Program Files (x86)" for "ntdll.lib" and you should find them.

Then on the header front, a lot of the ntdll prototypes and definitions are in "winternl.h" but unfortunately many parts are missing and/or there are only simplified versions of structures, etc. To solve this you can use the fantastic NT header set from the "Process Hacker" project: https://github.com/processhacker/processhacker The headers are in "phnt".

Instead of the typical "windows.h" and "winternl.h" combo, you will use:

#include <phnt_windows.h>
#include <phnt.h>

And then to specificity Windows 10 as a target for example (default is Windows 7) you would follow that with:

#undef PHNT_VERSION
#define PHNT_VERSION PHNT_THRESHOLD 

Note "phnt_windows.h" already includes "windows.h" for you. So you should be able to follow it with any other Windows, stdlib, stl, etc., headers after; not much different then the typical desktop build environment.

Or some others to use:
https://github.com/Fyyre/ntdll
Also includes libs:
https://github.com/x64dbg/ScyllaHide/tree/master/3rdparty/ntdll
Yet another with ntdll libraries too:
https://github.com/odzhan/injection/tree/master/ntlib

like image 142
Sirmabus Avatar answered Mar 28 '23 14:03

Sirmabus