NTDLL 函数前向声明
ntdll function forward declaration
在尝试实现我发现的一些示例代码时,我遇到了一个错误,我无法完全理解其原因。所以它来了。
在标题中,我看到它声明了类似的东西。但是,当我尝试编译它时,VS 给了我一个错误,其中包含此"未解析的外部符号..."。
NTSYSAPI
NTSTATUS
NTAPI
NtOpenSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
但是,当我将其更改为类似的东西时,我不再看到错误。
NTSTATUS(NTAPI *NtOpenSection)(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
我不完全确定是什么原因造成的。如果有人也发布一些在线参考资料,让我了解更多,那就太好了。
您需要了解编译器和链接器的工作原理。 编译器创建通用对象文件格式 (COFF(文件。 这里存在源文件中声明的每个符号的COFF 符号表。 以二进制形式,它实现为IMAGE_SYMBOL
(查找winnt.h
或ntimage.h
(。 这里对我们来说最有趣的是节号值(SHORT SectionNumber;
(。 一般而言 - 符号可以定义– 已创建并在文件中分配存储地址和空间的符号。(从 1 开始索引到节表中(或未定义– 已在文件中引用但尚未分配存储地址的符号。
IMAGE_SYM_UNDEFINED
-尚未为符号记录分配 部分。值为零表示对外部的引用 符号在别处定义。非零值是常用符号 具有由值指定的大小。
当您使用
NTSYSAPI
NTSTATUS
NTAPI
NtOpenSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
编译器使用IMAGE_SYM_UNDEFINED
节值创建__imp_NtOpenSection
(x64,arm,arm64(或__imp__NtOpenSection@12
(x86(符号 - 实际上你在这里声明函数,但你没有实现它。 这个函数(NtOpenSection
(必须在其他地方定义(实现(。 当链接器链接 - 它在所有 OBJ 和 lib 文件中搜索它的实现(__imp_NtOpenSection
符号(,并将其作为输入传递给他。 如果找不到它的实现- 将具有 1 的索引的记录IMAGE_SYMBOL
到节表 - 他说 - 未解析的外部符号。所以你必须自己实现函数(符号(,或者给链接器库或 obj 文件,其中实现了这个函数。在用户模式下,它以ntdll.lib
或ntdllp.lib
实现。所以你需要把这个库文件之一传递给链接器输入 - 这个解决错误。
在第二种情况下
NTSTATUS(NTAPI *NtOpenSection)(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
声明并实现变量。 它已被创建并在文件中分配了存储地址和空间。 因此,这里没有任何未解析的外部。
另请阅读符号处理以更好地了解此过程。
我还建议 - 编译您的 C/C++ 文件而不/GL
选项(只有/HEADERS
DUMPBIN 选项可用于使用/GL
编译器选项生成的文件。
link.exe /dump /symbols your.obj > some.txt
并在此处查找NtOpenSection
:
00000000 UNDEF notype External | __imp_NtOpenSection
在第一种情况下和
00000000 SECT4 notype External | ?NtOpenSection@@3P6AJPEAPEAXKPEAUOBJECT_ATTRIBUTES@@@ZEA (long (__cdecl* NtOpenSection)(void * *,unsigned long,struct OBJECT_ATTRIBUTES *))
在第二种情况下。
UNDEF
与SECTx
从二进制视图 在这两种情况下,您都声明指针大小(4或8字节(变量(__imp_NtOpenSection
或?NtOpenSection@@...
(,该变量将保持地址以运行。 在这两种情况下,二进制级别的间接调用将是相同的:
call [__imp_NtOpenSection]
或call [?NtOpenSection@@...]
. 不同的 -__imp_
在这种情况下 - 这个变量的地址(__imp_NtOpenSection
(将被写入PE结构Import Lookup Table
,并被放置在Import Address Table
中。 结果 - 加载器(NTDLL中的代码(将自动解析地址或NtOpenSection
并将此地址存储在__imp_NtOpenSection
变量中。 或故障加载您的 PE, 如果地址将无法解析。因此,当您的代码开始执行时 - 内部已经__imp_NtOpenSection
NtOpenSection
函数的有效地址,您可以使用它 - 从C/C ++代码调用NtOpenSection
或从ASM调用call [__imp_NtOpenSection]
。
在第二种情况下(?NtOpenSection@@...
或[_]NtOpenSection
,如果您使用extern "C"
或 C 代码声明它,则仅适用于 x86,_
( - 这将只是可变的。 当你的代码开始执行时 - 这里将是0(如果你将其声明为全局/静态(或未定义的值(堆栈中的局部变量(。 在通过此类变量调用NtOpenSection
之前, 你需要首先初始化它 - 分配NtOpenSection
的真实地址。说*(void**)&NtOpenSection = GetProcAddress(GetModuleHandle(L"ntdll"), "NtOpenSection");
.在此之后,您可以使用它。我怎么说 - 通过 #1 或 #2 声明调用NtOpenSection
没有任何不同 - 代码将是绝对相同的
- C++:为什么允许在另一个函数中声明函数,而不允许在函数定义中声明?
- 在c++中在类外声明函数有什么好处
- 使用 #define 声明函数
- 在静态库中声明函数,在使用该相同库的应用程序中定义它
- 如何强制编译器在 C/C++ 本身中声明函数?
- 如果您只需要在 .h 文件中声明函数.cpp是否需要在 .h 文件中声明函数?
- C++:<sys/sysctl.h> 无法声明函数CTL_HW和HW_NCPU
- 尝试声明函数的局部变量,但得到范围错误
- 如何在C++模板中声明函数
- 如何在另一个文件的类中声明函数
- 使用非类型模板参数正向声明函数模板
- 在此范围错误中未声明函数错误
- 当我们不能声明函数内联(GCC 编译器)时?
- 未在此作用域中声明函数,即使存在头文件也是如此
- 无法声明函数中的模板类型别名
- 单个CPP文件中多次声明函数声明可以吗?
- 编译一个支持VBA中声明函数的dll
- 使用从外部参数包中获取的参数类型声明函数
- 使用类成员正确地声明函数
- 在函数内重新声明函数