无法在Win32项目中包含ntifs.h

7
我尝试使用名为NTCreateFile的函数。当我编译时,它给了我一个错误,显示“_NTCreateFile标识符未找到”。我包含了头文件winternl.h。所以下一步我尝试使用ZwCreatFile,根据MSDN的建议,我包含了ntifs.h,但我无法包含该头文件。它说“无法打开/找到目录”。我正在使用V@2008。问题出在哪里?我错过了什么吗?
typedef NTSTATUS (*fp_CreatFile)(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN PLARGE_INTEGER AllocationSize OPTIONAL,
    IN ULONG FileAttributes,
    IN ULONG ShareAccess,
    IN ULONG CreateDisposition,
    IN ULONG CreateOptions,
    IN PVOID EaBuffer OPTIONAL,
    IN ULONG EaLength
    );
OBJECT_ATTRIBUTES myAttributes;

int _tmain(int argc, _TCHAR* argv[])
{
    fp_CreatFile myFunction;
    HMODULE module = LoadLibrary(L"ntdll.dll");
    if(NULL != module)
    {
        myFunction = (fp_CreatFile)GetProcAddress(module,"NtCreateFile");
    }

    UNICODE_STRING string;
    IO_STATUS_BLOCK fileStatus;
    string.Length = 56;
    string.Buffer = L"C:\\user\\kiddo\\Desktop\\7zFM.exe";
    string.MaximumLength = 56;

    HANDLE fileHandle;
    myAttributes.ObjectName = &string;
    myAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
    long mystatus = myFunction(&fileHandle,FILE_GENERIC_READ,&myAttributes ,&fileStatus,NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ,
        NULL,NULL,NULL,NULL);
    return 0;
}

当它试图调用时,会在消息框中给出以下错误信息。 错误: 运行时检查失败#0-跨函数调用未正确保存ESP的值。这通常是由于使用不同调用约定声明的函数指针调用声明为一种调用约定的函数而导致的。


你应该逐字发布编译器输出消息(复制和粘贴比描述更简单、更准确);重要的是要知道这是链接器还是编译器错误(消息会告诉我们)。显然,文件未找到是一个预处理器错误,但在你尝试修复原始问题之前呢? - Clifford
4个回答

9

如果您阅读MSDN文档,第一段内容如下:

注意:在使用此函数之前,请阅读调用内部APIs

这意味着:(我突出了重要部分)

"Winternl.h" 头文件公开了内部的 Windows API 原型。没有关联的导入库,因此开发人员必须使用运行时动态链接来调用该头文件中描述的函数。"Winternl.h" 中的函数和结构是操作系统的内部内容,在每个 Windows 版本的发布之间以及可能在每个版本的服务包之间都会发生变化。为了保持应用程序的兼容性,您应该使用等效的公共函数。有关更多信息,请参阅头文件 "Winternl.h" 和每个函数的文档。如果确实要使用这些函数,则可以通过运行时动态链接使用 LoadLibraryGetProcAddress 来访问它们。这将给您的代码一个机会,以便在函数已被更改或从操作系统中删除时优雅地响应。但是,签名的更改可能无法检测到。"

因此,您必须从NtDll.dll中加载要使用的函数,然后才能使用它们。

这是一个未经测试的示例代码:

typedef NTSTATUS (__stdcall *NtCreateFile)(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN PLARGE_INTEGER AllocationSize OPTIONAL,
    IN ULONG FileAttributes,
    IN ULONG ShareAccess,
    IN ULONG CreateDisposition,
    IN ULONG CreateOptions,
    IN PVOID EaBuffer OPTIONAL,
    IN ULONG EaLength
    );

NtCreateFile _NtCreateFile = (NtCreateFile)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtCreateFile");

// You can now use the function
_NtCreateFile(/* params */);

// Don't forget the release the resources

谢谢您的回复,ereOn。我按照您的建议进行了操作,但仍然出现了运行时错误。请进一步检查我的编辑。 - kiddo
@kiddo:你最后的错误相当明显:你试图使用与编译方法不同的“调用约定”来调用方法。如果你在函数声明前面尝试其中一种:__cdecl__stdcall可能是这个)或__fastcall,会怎样呢?我编辑了我的回答以添加有趣的部分。 - ereOn
它运行了,但是没有接收到任何文件句柄...如果您对函数NtCreateFile有了解,请帮助我。 - kiddo
@kiddo 我从未使用过这个函数。我能做的就是“破译”文档并给你一些通用建议。如果你真的卡住了,我建议你开始一个新的基础示例项目来测试它。一旦你让它工作起来,你就可以将其与你实际的代码进行比较,找出问题所在。 - ereOn
嘿,ereOn..为什么不给我你的电子邮件地址..我们可以保持联系... 如果你有兴趣的话 - kiddo

2

有几种可能:

  • 您说错误消息是“_NTCreateFile标识符未找到”。API的名称是NtCreateFile()(注意小写的“t”)。您可能只是使用了错误的名称。

  • ntifs.h和相关的链接库包含在Windows驱动程序工具包(WDK)中,可以从这里下载:http://www.microsoft.com/whdc/devtools/wdk/wdkpkg.mspx。您应该能够使用WDK比使用动态链接更直接地完成您想要的操作,但是您通常需要购买一个全新的构建系统或者想出如何将头文件和库集成到您当前的构建中。

  • 您可以使用ereOn概述的动态链接技术


1

ZwCreateFile是Windows Driver Kit的一部分,而不是Windows SDK。您需要安装驱动程序套件。NTCreateFile使用的一些宏和类型也需要WDK头文件。这在MSDN文档中明确说明。


1

正如错误信息所清楚指出的那样,您调用约定错误,您省略了NTAPI。应该是:

typedef NTSTATUS (__stdcall * fp_CreatFile)(
  // etc..
);

正确初始化myAttributes通常很重要。我没有看到你做任何需要调用未记录的本机API函数的事情。只要可以,请使用CreateFile()。


是的,它运行了...但它什么也没做...你对这个函数有什么想法吗?NtcreatFile - kiddo
本地的Windows API是未记录的,我不应该知道任何关于它的东西。但肯定有一些功能,那么函数返回值是什么? - Hans Passant
这是一个垃圾值...一些很大的负数值。 - kiddo
NTSTATUS代码是一个很大的值,而不是垃圾数据。它们在ntstatus.h SDK头文件中列出。 - Hans Passant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接