链接到ntdll.lib并调用ntdll.dll内部的函数

Kel*_*ang 9 c dll window visual-studio

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

Sir*_*bus 10

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

使用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”中,但不幸的是许多部分丢失和/或只有结构的简化版本等。要解决这个问题,您可以使用神奇的 NT 标头从“Process Hacker”项目设置: https: //github.com/processhacker/processhacker 标头位于“phnt”中。

您将使用以下命令,而不是典型的“windows.h”和“winternl.h”组合:

#include <phnt_windows.h>
#include <phnt.h>
Run Code Online (Sandbox Code Playgroud)

然后,以 Windows 10 作为目标(默认为 Windows 7),您可以使用以下命令:

#undef PHNT_VERSION
#define PHNT_VERSION PHNT_THRESHOLD 
Run Code Online (Sandbox Code Playgroud)

请注意“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


Fra*_*e_C 3

问题在于库中记录的函数名称以及从编译器生成的函数名称。
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
);
Run Code Online (Sandbox Code Playgroud)

对于 32 位以下的函数,编译器将为__stdcall32 位以下的函数生成符号_NtOpenFile@24,如果我没有错误地计算调用参数的字节大小,那么该符号显然不在库中。这是因为 ntdll.lib 旨在在 DDK 下用于驱动程序开发,其中编译器会生成未修饰的符号。
为了阐明这个概念,请使用二进制编辑器打开 ntdll.lib 文件并查找NtOpenFile,您将只看到它和导入版本__imp_NtOpenFile。现在打开一个标准库,例如 gdi32.lib,仅举一个例子,然后搜索CreateDIBSection您会发现 a_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