我的代码遇到链接器错误。我试图用Win-7 X64位m / c中的Visual Studio命令Prompt(2010)进行编译。 我看到的错误如下。
dust2.obj
dust2.obj:错误LNK2019:未解析的外部符号_NtOpenFile @ 24引用 在函数_main
中dust2.obj:错误LNK2019:未解析的外部符号_RtlAnsiStringToUnicodeStr 在函数_main
中引用了@ 12dust2.obj:错误LNK2019:未解析的外部符号_RtlInitAnsiString @ 8参考 enced in function _main
dust2.exe:致命错误LNK1120:3个未解析的外部
我的代码的简化版本是这样的:
#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;
}
在本论坛的另一篇文章中,提到这类问题的解决方案包括#pragma。
我通过像这样添加#pragma来尝试这个解决方案
#pragma comment(lib, "ntdll")
但是在编译时我看到另一个错误,上面写着“LINK:致命错误LNK1104:无法打开文件'ntdll.lib'”。
我将非常感谢您帮助解决此问题。感谢..
答案 0 :(得分:23)
不能让这个问题像这样未答复。因为尽管Mladen的评论在很大程度上适用于这个特定的原生API,但整个主题值得进行深入讨论。
在前面我应该注意到在很多情况下它是neither desirable nor necessary to use one of the native API functions on Windows。但是,在某些情况下,Win32 API无法提供查询信息甚至操作数据等的方法。其中一个案例是NtQueryInformationFile
/ZwQueryInformationFile
可用的几个信息类。
一个很好的例子是文件和目录上的备用数据流的枚举,可以使用Win32 API完成,特别是使用备份API,但在这种情况下需要特殊权限。如果您使用本机API则不是这样。在Windows 2000引入CreateHardLink
到Win32 API之前,硬链接也是如此。虽然在这种特殊情况下,如果您知道自己的方式,自从它被引入以来就可以使用MoveFileEx
和MOVEFILE_CREATE_HARDLINK
(尽管Microsoft 仍然在撰写本文时将其标记为< em>保留供将来使用 ... meh)。
关于本机API的规范书是这两个:
......还有更多,包括讨论NT 4并且在Nebbett的书之前。但Nebbett的书过去常常围绕原生API开始大肆宣传,就像Hoglund的书开始围绕Windows rootkit的炒作一样。不是关于Native API主题的参考,但仍然很好:
查看此网站,了解大量原生API函数&#34;记录&#34;:
请记住:使用这些功能时的固有风险是,它们会在未来的Windows版本中消失,或者在不事先通知的情况下更改其语义。所以当你使用它们时要小心,如果你使用它们。
荣耀......
实际上有两种方法可以调用这些函数。几年前,微软被迫在一项反托拉斯法诉讼中披露了一些原生API函数。这些被推入SDK的winternl.h
。微软表达了这一点:
提供
NtOpenFile
文档是为了完整的API 覆盖。NtOpenFile
等同于ZwOpenFile
函数 记录在DDK中。有关ZwOpenFile
和ntdll.lib
的更多信息 相关功能,请转到http://msdn.microsoft.com/library。在里面 单击左侧窗格,单击Windows开发,然后单击驱动程序 开发套件。
但是,SDK中没有附带的ntdll.lib
文件。 Microsoft建议您动态链接这些功能(下面的第二个选项)。
您有几种选择:
GetProcAddress
导入库只是WDK的一部分,而不是DDK。GetModuleHandle
查找函数指针并调用它。 ntdll.dll
足以满足Win32子系统,因为每个Win32程序都保证加载ntdll.lib
。ntdll.lib
如果你有DDK / WDK - 分别用于驱动程序开发工具包和Windows Driver Kit - 你已经获得了一整套C:\WINDDK\7600.16385.1\lib\win7\amd64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\win7\i386\ntdll.lib
C:\WINDDK\7600.16385.1\lib\win7\ia64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wlh\amd64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wlh\i386\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wlh\ia64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wnet\amd64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wnet\i386\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wnet\ia64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wxp\i386\ntdll.lib
文件。在我的系统上(Windows 7 WDK 7600.16385.1):
ntdll.lib
ntdll.lib
否则,您必须自己从dumpbin
的输出(或通过其他允许解析DLL导出的方法)生成.lib
,然后您可以将其输出到模块定义文件中。您可以构建导出import os, re, sys
from os.path import basename, dirname, join, realpath
try:
import pefile
except ImportError:
try:
sys.path.append(join(realpath(dirname(__file__)), "pefile"))
import pefile
except:
raise
def main(pename):
from pefile import PE
print "Parsing %s" % pename
pe = PE(pename)
if not getattr(pe, "DIRECTORY_ENTRY_EXPORT", None):
return "ERROR: given file has no exports."
modname = basename(pename)
libname = re.sub(r"(?i)^.*?([^\\/]+)\.(?:dll|exe|sys|ocx)$", r"\1.lib", modname)
defname = libname.replace(".lib", ".def")
print "Writing module definition file %s for %s" % (defname, modname)
with open(defname, "w") as f: # want it to throw, no sophisticated error handling here
print >>f, "LIBRARY %s\n" % (modname)
print >>f, "EXPORTS"
numexp = 0
for exp in [x for x in pe.DIRECTORY_ENTRY_EXPORT.symbols if x.name]:
numexp += 1
print >>f, "\t%s" % (exp.name)
print "Wrote %s with %d exports" % (defname, numexp)
print "\n\nUse this to create the export lib:\n\tlib /def:%s /out:%s" % (defname, libname)
if __name__ == '__main__':
if len(sys.argv) != 2:
sys.exit("ERROR:\n\tSyntax: fakelib <dllfile>\n")
sys.exit(main(sys.argv[1]))
。听起来很复杂?不是那么多,让我们看看;)
使用Ero Carrera的pefile
Python module,我们可以这样做:
fakelib.py
运行此脚本的示例输出(名称为> fakelib.py ntdll.dll
Parsing ntdll.dll
Writing module definition file ntdll.def for ntdll.dll
Wrote ntdll.def with 1984 exports
Use this to create the export lib:
lib /def:ntdll.def /out:ntdll.lib
时)为:
/machine:
然后我们运行最后一行给出的命令。当然,提供> lib /def:ntdll.def /out:ntdll.lib
Microsoft (R) Library Manager Version 11.00.51106.1
Copyright (C) Microsoft Corporation. All rights reserved.
LINK : warning LNK4068: /MACHINE not specified; defaulting to X86
Creating library ntdll.lib and object ntdll.exp
参数会更好。这是一个&#34;练习&#34; (*咳嗽* *咳嗽*)给读者。 VS 2012的输出将是:
ntdll.lib
祝贺。您现在可以使用Microsoft自己lib.exe
创建的ntdll.dll
从.lib
静态导入,即使没有&#34;真实&#34; (原始)gendef
在您的系统上。
根据您的需要和品味调整路径和文件名。
Damon在评论中指出MinGW附带的工具链包含一个工具dlltool
,它可以完成上述Python脚本的工作,输出可以输入__stdcall
。
上述方法在定位x64(64位)时效果很好,但对于x86(32位),我偶尔会遇到链接器错误。
问题是__stdcall
的名称修饰在x64和x86之间有所不同。前者并没有真正使用与x86相同的sizeof(void*)
,因此只是假装下划线。但是,后者还附加了多个参数int __stdcall foo(int);
(即4)。因此,对于一个参数,函数_foo@4
的修饰函数名称变为GetProcAddress
。
This KB article from Microsoft概述了解决问题的方法。
NtOpenFile
MSDN状态(Ntdef.h
)的文档:
请注意,许多常量都需要DDK头文件
InitializeObjectAttributes
定义以及Ntdll.lib
宏。该 DDK中也提供了相关的导入库LoadLibrary
。您 也可以使用GetProcAddress
和Ntdll.dll
函数 动态链接到TFNNtOpenFile
。
声明一个函数类型,例如这里我们声明适合您的类型typedef NTSTATUS (NTAPI *TFNNtOpenFile)(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
:
TFNNtOpenFile pfnNtOpenFile = (TFNNtOpenFile)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenFile");
status = pfnNtOpenFile(...); // can't be bothered to type out all parameters ;)
...然后检索函数指针并调用它:
static NTSTATUS (NTAPI *NtOpenFile)(
OUT PHANDLE,
IN ACCESS_MASK,
IN POBJECT_ATTRIBUTES,
OUT PIO_STATUS_BLOCK,
IN ULONG,
IN ULONG
);
(FARPROC)&NtOpenFile = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenFile");
检索函数指针的另一种方法可能是:
#
可以通过使用预处理程序字符串化运算符({{1}})进一步压缩。选择是你的。
答案 1 :(得分:3)
这些函数无法直接调用,因为它们属于内部API,不会通过任何库公开。您需要使用GetProcAddress获取这些函数的地址。
有关详细信息,请查看此处:http://msdn.microsoft.com/en-us/library/bb432200.aspx