I am facing linker error with my code. I am trying to compile with Visual Studio command Prompt (2010) in Win-7 X64 bit m/c.
The error which i see are as below.
dust2.obj
dust2.obj : error LNK2019: unresolved external symbol _NtOpenFile@24 referenced
in function _maindust2.obj : error LNK2019: unresolved external symbol _RtlAnsiStringToUnicodeStr
ing@12 referenced in function _maindust2.obj : error LNK2019: unresolved external symbol _RtlInitAnsiString@8 refer
enced in function _maindust2.exe : fatal error LNK1120: 3 unresolved externals
The simplified version of my code is like this:
#include <windows.h>
#include <iostream>
#include <Winternl.h>
using namespace std;
int main()
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE SourceFile;
PUNICODE_STRING PathName=0;
PANSI_STRING p_path=0;
const char* ccp_path = "D:\\txt.txt";
RtlInitAnsiString( p_path,ccp_path );
RtlAnsiStringToUnicodeString( PathName, p_path, true );
IO_STATUS_BLOCK IoStatusBlock;
wprintf(L"%s", PathName->Buffer);
InitializeObjectAttributes(
&Obja,
PathName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile(
&SourceFile,
FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_READ_ATTRIBUTES,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
);
if(SourceFile == INVALID_HANDLE_VALUE){
printf("\nError: Could not open file\n");
return 0;
}
cout<<endl<<endl;
system("pause");
return 0;
}
In another post in this forum the solution of these kind of problem was mention to include a #pragma.
I tried this solution by adding #pragma like this
#pragma comment(lib, "ntdll")
but on compilation i see another error that says "LINK : fatal error LNK1104: cannot open file 'ntdll.lib'".
I will much appreciate your help to resolve this problem. Thanks..
Best Answer
Can't let this question go unanswered like this. Because although the remark by Mladen is largely right for this particular native API, the whole topic deserves an in-depth discussion.
Preliminary cautionary note
Up front I should note that in many many cases it is neither desirable nor necessary to use one of the native API functions on Windows. However, there are a few cases where the Win32 API doesn't provide the means to query information or even manipulate data and so on. One such case would be several of the information classes available for
NtQueryInformationFile
/ZwQueryInformationFile
.One good example is the enumeration of alternate data streams on files and directories, which can be done using the Win32 API, in particular by using the backup APIs, but will require special privileges in that case. Not so if you resort to the native API. The same used to be true for hard links until Windows 2000, which introduced
CreateHardLink
to the Win32 API. Although in this particular case if you knew your way around you could have usedMoveFileEx
withMOVEFILE_CREATE_HARDLINK
ever since it got introduced (although Microsoft still as of this writing marks it as Reserved for future use ... meh).The canonical books about the native API are these two:
... there are more, including one that discusses NT 4 and preceded Nebbett's book. But Nebbett's book used to start the hype around the native API, much like Hoglund's book started the hype around Windows rootkits. Not a reference regarding the Native API topic but still good:
Check out this website for a huge number of native API functions "documented":
So remember: the inherent risk when using these functions is that they go away in a future Windows version or their semantics change without prior notice. So be careful when you use them, if you use them.
On to glory ...
How to call native API functions
Actually there are two ways to call these functions. Microsoft was forced to disclose some of the native API functions in one of the antitrust law suits some years ago. These were shoved into
winternl.h
of the SDK. Microsoft expresses it thus:However, there is no accompanying
ntdll.lib
file in the SDK. Microsoft suggests you link those functions dynamically (second option below).You have several options:
ntdll.lib
import library is only part of the WDKs, not the DDKs.GetProcAddress
to find the function pointer and call it.GetModuleHandle
is sufficient for the Win32 subsystem since every Win32 program is guaranteed to have loadedntdll.dll
.Method 1:
ntdll.lib
If you have the DDK/WDK - for Driver Development Kit and Windows Driver Kit respectively - you get a full set of
ntdll.lib
files already. On my system (Windows 7 WDK 7600.16385.1):Create your own makeshift
ntdll.lib
Otherwise you have to generate
ntdll.lib
yourself from the output ofdumpbin
(or by other means that allow to parse the exports of the DLL) which you can then output into a module definition file from which you can build an export.lib
. Sounds convoluted? Not so much, let's see ;)Using Ero Carrera's
pefile
Python module, we can do this:A sample output of running this script (when named
fakelib.py
) would be:Then we run the command as given on the last line. It is even better to give the
/machine:
parameter, of course. This is left as an "exercise" (*cough* *cough*) to the reader. The output with VS 2012 will be:Congratulations. You can now use the
ntdll.lib
created by Microsoft's ownlib.exe
to statically import fromntdll.dll
, even without having the "real" (original).lib
on your system.Adjust the path and file names to your needs and tastes.
When using MinGW
Damon pointed out in a comment that the toolchain included with MinGW contains a tool
gendef
that can do the job of above Python script and that the output can be fed todlltool
.Issues
The above method works perfectly when targeting x64 (64-bit), but for x86 (32-bit) I have encountered linker errors at times.
The issue is that the name decoration for
__stdcall
differs between x64 and x86. The former doesn't really use the same__stdcall
as x86 and therefore just prepends an underscore. However, the latter also appends a the number of arguments timessizeof(void*)
(i.e. 4). So for one argument the decorated function name for a functionint __stdcall foo(int);
becomes_foo@4
.This KB article from Microsoft outlines a way to get around the issue.
Method 2: dynamically imported, using
GetProcAddress
Documentation in MSDN states (for
NtOpenFile
):Declare a function type, e.g. here we declare the type
TFNNtOpenFile
suitable in your case:... and then retrieve the function pointer and call it:
an alternative way of retrieving the function pointer could be this one:
which could be condensed even further by using the preprocessor stringification operator (
#
). The choice is yours.