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?
问题:
回答1:
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.
回答2:
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