Hok*_*ama 6 c++ winapi linker-errors visual-c++
我的代码面临链接器错误.我试图用Win-7 X64位m/c中的Visual Studio命令Prompt(2010)进行编译.我看到的错误如下.
dust2.obj
dust2.obj:错误LNK2019:函数_main中引用的未解析的外部符号_NtOpenFile @ 24
dust2.obj:错误LNK2019: 函数_main中引用的未解析的外部符号_RtlAnsiStringToUnicodeStr ing @ 12
dust2.obj:错误LNK2019:未解析的外部符号_RtlInitAnsiString @ 8在函数_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;
}
Run Code Online (Sandbox Code Playgroud)
在本论坛的另一篇文章中,提到这类问题的解决方案包括#pragma.
我通过像这样添加#pragma来尝试这个解决方案
#pragma comment(lib, "ntdll")
Run Code Online (Sandbox Code Playgroud)
但在编译时我看到另一个错误,上面写着"LINK:致命错误LNK1104:无法打开文件'ntdll.lib'".
我将非常感谢您帮助解决此问题.谢谢..
0xC*_*22L 25
不能让这个问题像这样没有答案.因为虽然Mladen的评论在很大程度上适用于这个特定的原生API,但整个主题值得深入讨论.
在前面我应该注意到,在很多情况下,在Windows上使用本机API函数既不可取也不必要.但是,在某些情况下,Win32 API不提供查询信息甚至操作数据等的方法.其中一个案例是几个可用于NtQueryInformationFile/ZwQueryInformationFile的信息类.
一个很好的例子是文件和目录上的备用数据流的枚举,可以使用Win32 API完成,特别是使用备份API,但在这种情况下需要特殊权限.如果您使用本机API则不是这样.在引入CreateHardLinkWin32 API的Windows 2000之前,硬链接也是如此.虽然在这种特殊情况下,如果你知道你的方式在你身边也可以使用MoveFileEx带有MOVEFILE_CREATE_HARDLINK自从它得到介绍(尽管微软仍然在编写这本书将其标记为保留供未来使用 ... MEH).
关于本机API的规范书籍是这两个:
...还有更多,包括讨论NT 4并且在Nebbett的书之前.但Nebbett的书曾经开始围绕原生API开始大肆宣传,就像Hoglund的书开始围绕Windows rootkit的炒作一样.不是关于Native API主题的参考,但仍然很好:
查看此网站,了解大量原生API函数"已记录":
所以请记住:使用这些功能时的固有风险是它们在未来的Windows版本或其语义更改中消失,恕不另行通知.所以,要小心,当你使用它们,如果你使用它们.
荣耀......
实际上有两种方法可以调用这些函数.几年前,微软被迫在一项反托拉斯法诉讼中披露了一些原生API函数.这些都被推到winternl.h了SDK中.微软表达了这样的意见:
该
NtOpenFile文档提供了完整的API覆盖的缘故.NtOpenFile等同ZwOpenFile于DDK中记录的功能.有关ZwOpenFile相关功能的更多信息,请访问http://msdn.microsoft.com/library.在左侧窗格中,单击"Windows开发",然后单击"驱动程序开发工具包".
但是,ntdll.libSDK中没有附带的文件.Microsoft建议您动态链接这些功能(下面的第二个选项).
你有几个选择:
ntdll.lib导入库只是WDK的一部分,而不是DDK.GetProcAddress查找函数指针,并调用它.GetModuleHandle对于Win32子系统来说已足够,因为每个Win32程序都保证已加载ntdll.dll.ntdll.lib如果你有DDK/WDK - 分别用于驱动程序开发工具包和Windows驱动程序工具包 - 你ntdll.lib已经获得了一整套文件.在我的系统上(Windows 7 WDK 7600.16385.1):
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
Run Code Online (Sandbox Code Playgroud)
ntdll.lib否则,您必须ntdll.lib从输出dumpbin(或通过其他允许解析DLL导出的方法)生成自己,然后您可以将其输出到模块定义文件中,您可以从中创建导出.lib.听起来很复杂?不是那么多,让我们看看;)
使用Ero Carrera的pefilePython模块,我们可以这样做:
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]))
Run Code Online (Sandbox Code Playgroud)
运行此脚本(命名时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
Run Code Online (Sandbox Code Playgroud)
然后我们运行最后一行给出的命令./machine:当然,给出参数更好.这留给读者作为"运动"(*咳嗽**咳嗽*).VS 2012的输出将是:
> 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
Run Code Online (Sandbox Code Playgroud)
恭喜.您现在可以使用ntdll.libMicrosoft自己创建的lib.exe静态导入ntdll.dll,即使.lib您的系统上没有"真实"(原始).
根据您的需要和品味调整路径和文件名.
Damon在评论中指出,MinGW附带的工具链包含一个工具gendef,可以完成上述Python脚本的工作,输出可以输入dlltool.
当针对x64(64位)时,上述方法可以正常工作,但对于x86(32位),我有时会遇到链接器错误.
问题是名称修饰__stdcall在x64和x86之间有所不同.前者并没有真正使用与__stdcallx86 相同的功能,因此只需要一个下划线.然而,后者还附加了多个参数次数sizeof(void*)(即4).因此,对于一个参数,函数的修饰函数名称int __stdcall foo(int);变为_foo@4.
微软的这篇知识库文章概述了一种解决问题的方法.
GetProcAddressMSDN状态(for NtOpenFile)中的文档:
请注意,DDK头文件
Ntdef.h对于许多常量定义以及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
);
Run Code Online (Sandbox Code Playgroud)
...然后检索函数指针并调用它:
TFNNtOpenFile pfnNtOpenFile = (TFNNtOpenFile)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenFile");
status = pfnNtOpenFile(...); // can't be bothered to type out all parameters ;)
Run Code Online (Sandbox Code Playgroud)
检索函数指针的另一种方法可能就是这样:
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");
Run Code Online (Sandbox Code Playgroud)
这可以通过使用预处理器字符串化运算符(#)进一步压缩.这是你的选择.
| 归档时间: |
|
| 查看次数: |
7656 次 |
| 最近记录: |