【问题标题】:Link to ntdll.lib and call functions inside ntdll.dll链接到 ntdll.lib 并调用 ntdll.dll 中的函数
【发布时间】:2016-06-01 06:24:47
【问题描述】:

我最近正在对私有 API 进行一些研究。我尝试在运行时使用LoadLibraryGetProcAddress 在ntdll.dll 中调用诸如NtOpenFile 之类的函数。幸运的是,它成功了。今天早上我在我的电脑上进行了文件搜索,在我的 C 盘中找到了ntdll.lib。据我所知,这样的 .lib 文件应该包含可用于链接的 dll 导出的存根。因此,我尝试将我的应用程序链接到该库,但我不断收到unresolved external symbol 错误。但是,dumpbin /EXPORTS 表明 ntdll.lib 清楚地导出了 NtOpenFile。我该如何解决这个错误?

【问题讨论】:

  • 你不能静态链接到 NtDll。您已经以正确的方式进行操作,调用 LoadLibraryGetProcAddress
  • 但是ntdll.ib 的意义何在?如果我们不能静态链接到它,它为什么会存在?
  • lib 可以被链接,但是你必须有一个头文件来给你所有的函数定义。
  • 问题是,VS 和 CodeBlock 对我大喊大叫说找不到 NtOpenFile 符号。 @LPs
  • 错了,现在有 ntdll 导入库(带有完整的头文件)可用。默认设置 Windows SDK 是的。

标签: c visual-studio dll window


【解决方案1】:

不再是这样了,你可以在我 2019 年写这篇文章时找到 ntdll.lib 导入库和 NT 头文件。

GetProcAddress() 的方式执行此操作需要大量额外的代码。当然,直接导入更简洁,是我们习惯用于 C/C++ 桌面应用程序的模式。

我曾经通过使用 .def 文件等创建一个简单的 Windows DLL 项目来制作我自己的“ntdll.lib”导入库。我需要将每个 ntdll API 函数添加为一个存根和一个头文件。 丢弃 .dll,只使用其中的 .lib。

但至少从 MSVC 2017 开始,它包括用于 32 位和 64 位版本的 x86 和 ARM 的用户模式(用于桌面应用程序)ntdll.lib 库。这可能需要安装 Windows 10 WDK。 只需在“C:\Program Files (x86)”中搜索“ntdll.lib”即可找到它们。

然后在标题前面,很多 ntdll 原型和定义都在“winternl.h”中,但不幸的是许多部分丢失了和/或只有结构的简化版本等。 要解决这个问题,您可以使用“Process Hacker”项目中出色的 NT 标头集: https://github.com/processhacker/processhacker 标题在“phnt”中。

代替典型的“windows.h”和“winternl.h”组合,您将使用:

#include <phnt_windows.h>
#include <phnt.h>

然后以特定的 Windows 10 为目标(例如,默认为 Windows 7),您将遵循:

#undef PHNT_VERSION
#define PHNT_VERSION PHNT_THRESHOLD 

注意“phnt_windows.h”已经为您包含了“windows.h”。 所以你应该能够在它之后使用任何其他 Windows、stdlib、stl 等头文件;与典型的桌面构建环境没有太大区别。

或其他一些使用:
https://github.com/Fyyre/ntdll
还包括库:
https://github.com/x64dbg/ScyllaHide/tree/master/3rdparty/ntdll
另一个也有 ntdll 库:
https://github.com/odzhan/injection/tree/master/ntlib

【讨论】:

    【解决方案2】:

    问题是函数的名称记录在库中,因为它是从编译器生成的。
    dumpbin 只显示基本导出符号NtOpenFile(未修饰的符号),但也有导入符号__imp_NtOpenFile。 现在,如果您尝试静态链接 NtOpenFile 将其声明为:

    NTSTATUS NtOpenFile(
      _Out_ PHANDLE            FileHandle,
      _In_  ACCESS_MASK        DesiredAccess,
      _In_  POBJECT_ATTRIBUTES ObjectAttributes,
      _Out_ PIO_STATUS_BLOCK   IoStatusBlock,
      _In_  ULONG              ShareAccess,
      _In_  ULONG              OpenOptions
    );
    

    对于 32 位下的 __stdcall 函数,编译器将生成符号 _NtOpenFile@24,如果我计算调用参数的字节大小没有错,那显然不在库中。 这是因为 ntdll.lib 旨在在 DDK 下用于驱动程序开发,其中编译器会生成未修饰的符号。
    为了澄清这个概念,使用二进制编辑器打开 ntdll.lib 文件并查找NtOpenFile,您将只看到它和导入版本__imp_NtOpenFile。现在打开一个标准库作为 gdi32.lib,仅举个例子,搜索 CreateDIBSection 你会找到一个 _CreateDIBSection@24__imp__CreateDIBSection@24
    发生什么了?简单的 dumpbin 总是显示未修饰的名称,但编译器会生成修饰的名称,结果:链接器失败。据说名称使用PASCAL约定,与__stdcall相同,但不装饰符号(即阅读此https://msdn.microsoft.com/en-us/library/aa235591(v=vs.60).aspx)。
    有没有办法解决问题?是的,您必须创建自己的导入库,为具有正确装饰的所需函数分配别名。开始阅读这个https://msdn.microsoft.com/en-us/library/0b9xe492.aspx

    【讨论】:

    • 这描述了直接调用 NTdll 所需的过程。正如他所说,您可以为函数调用创建一个 typedef 别名,该函数调用由指向您使用在 LoadLibrary 函数上调用的 GetProcAddress 获得的地址的指针表示。 resources.infosecinstitute.com/calling-ntdll-functions-directly/…
    • VS2017 不再是这种情况。它可能需要 WDK,但它有一个“ntdll.lib”,您可以从用户模式桌面程序中使用它。
    猜你喜欢
    • 2021-12-01
    • 2017-09-22
    • 2020-10-20
    • 2012-04-21
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多