记一次符号类型不一致导致的链接错误
两个头文件
在WDK中,有两个头文件:
- ntddk.h:包含 wdm.h,传统的 NT 架构驱动(非即插即用)
- ntifs.h:包含 ntddk.h 和 wdm.h,文件系统驱动、文件系统过滤驱动
由于 ntifs.h 已经包含了 ntddk.h,只需包含 ntifs.h 即可。同时包含两者可能导致类型重定义等编译错误。
报错信息
IoCtlHandler.obj : error LNK2019: 无法解析的外部符号 "public: static long __cdecl HelpTool::GetEprocess(void *,struct _EPROCESS * *)" (?GetEprocess@HelpTool@@SAJPEAXPEAPEAU_EPROCESS@@@Z),函数 "long __cdecl ProtectProcess(void *)" (?ProtectProcess@@YAJPEAX@Z) 中引用了该符号
符号类型不一致
我的源代码中,分别引用了上面的两个头文件。Windows WDK 头文件(如 wdm.h / ntifs.h)中的 PEPROCESS 定义,会根据预处理器宏(尤其是 NT_KERNEL 或 _KERNEL_MODE)来决定到底是引用 _EPROCESS 还是 _KPROCESS。
检查HelpTool.obj中导出的符号,发现:
txt
dumpbin /SYMBOLS ".\HelpTool.obj"
Microsoft (R) COFF/PE Dumper Version 14.51.36252.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file .\HelpTool.obj
File Type: COFF OBJECT
COFF SYMBOL TABLE
000 01058D9C ABS notype Static | @comp.id
001 C0010990 ABS notype Static | @feat.00
002 00000000 SECT1 notype Static | .drectve
Section length 2F, #relocs 0, #linenums 0, checksum 0
004 00000000 SECT2 notype Static | .debug$S
Section length 2028, #relocs 0, #linenums 0, checksum 0
006 00000000 SECT3 notype Static | .bss
Section length 1, #relocs 0, #linenums 0, checksum 0, selection 2 (pick any)
008 00000000 SECT3 notype External | ExPoolZeroingNativelySupported
009 00000000 SECT4 notype Static | .text$mn
Section length 62, #relocs 3, #linenums 0, checksum 4519E64B, selection 1 (pick no duplicates)
00B 00000000 SECT5 notype Static | .debug$S
Section length 144, #relocs 8, #linenums 0, checksum 0, selection 5 (pick associative Section 0x4)
00D 00000000 UNDEF notype External | __imp_DbgPrintEx
00E 00000000 UNDEF notype External | __imp_PsLookupProcessByProcessId
00F 00000000 SECT4 notype () External | ?GetEprocess@HelpTool@@SAJPEAXPEAPEAU_KPROCESS@@@Z (public: static long __cdecl HelpTool::GetEprocess(void *,struct _KPROCESS * *))
010 00000000 SECT4 notype Label | $LN6
011 00000000 SECT6 notype Static | .xdata
Section length C, #relocs 0, #linenums 0, checksum B9123A2D, selection 5 (pick associative Section 0x4)
013 00000000 SECT6 notype Static | $unwind$?GetEprocess@HelpTool@@SAJPEAXPEAPEAU_KPROCESS@@@Z
014 00000000 SECT7 notype Static | .pdata
Section length C, #relocs 3, #linenums 0, checksum 92CEA7C6, selection 5 (pick associative Section 0x4)
016 00000000 SECT7 notype Static | $pdata$?GetEprocess@HelpTool@@SAJPEAXPEAPEAU_KPROCESS@@@Z
017 00000000 SECT8 notype Static | .text$s
Section length 39, #relocs 0, #linenums 0, checksum 81C4C899, selection 2 (pick any)
019 00000000 SECT8 notype External | ??_C@_0DJ@KDOKOJHK@?$FLProtectMyProcess?3?3HelpTool?$FN?3?5Ge@FNODOBFM@ ( ?? ?? ::FNODOBFM::`string')
01A 00000000 SECT9 notype Static | .debug$S
Section length 3C, #relocs 2, #linenums 0, checksum 0, selection 5 (pick associative Section 0x3)
01C 00000000 SECTA notype Static | .debug$T
Section length 7C, #relocs 0, #linenums 0, checksum 0
01E 00000000 SECTB notype Static | .chks64
Section length 58, #relocs 0, #linenums 0, checksum 0
String Table Size = 0x145 bytes
Summary
1 .bss
58 .chks64
21A8 .debug$S
7C .debug$T
2F .drectve
C .pdata
62 .text$mn
39 .text$s
C .xdata
对比两个编译单元看到的函数签名:
-
IoCtlHandler.cpp(报错方) 期望的符号是:?GetEprocess@HelpTool@@SAJPEAXPEAPEAU**_EPROCESS**@@@Z
(参数为 struct _EPROCESS **)
-
HelpTool.obj导出的符号是:?GetEprocess@HelpTool@@SAJPEAXPEAPEAU**_KPROCESS**@@@Z
(参数为 struct _KPROCESS **)
在编译 HelpTool.cpp 时,编译器认为 PEPROCESS 是 struct _KPROCESS *;而在编译 IoCtlHandler.cpp 时,PEPROCESS 被解析为 struct _EPROCESS *。
解决方案
我把参数中的peprocess改为了pvoid类型,反正eprocess在内核驱动开发中就是一个不透明的数据结构,最终都是要使用基址+偏移的方式访问其中的字段,索性让它直接为pvoid类型。