A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #20551  by Tigzy
 Wed Aug 21, 2013 9:04 am
Hello

I know that's a newbie question, but I'm stuck on it :(
I was using notepad++ to code my driver, and recently migrated to VisualDDK to code inside Visual Studio.
That works fine, except when I want to use undocumented function/calls, I got linker error. It seems not linking with ntdll.lib as it does previously.

Here's the problem:
Before, I was declaring KeAddSystemServiceTablelike this, and it was working:
Code: Select all
__declspec(dllimport) _stdcall KeAddSystemServiceTable(PVOID, PVOID, PVOID, PVOID, PVOID);
Now it generates linker error:
1>c:\tools\functions.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) int __stdcall KeAddSystemServiceTable(void *,void *,void *,void *,void *)" (__imp_?KeAddSystemServiceTable@@YGHPAX0000@Z) referenced in function "void * __stdcall GetKeServiceDescriptorTableShadow(void)" (?GetKeServiceDescriptorTableShadow@@YGPAXXZ)
So I decided to look a bit on Google, and changed the declaration for that:
Code: Select all
extern "C" BOOLEAN __stdcall KeAddSystemServiceTable(PVOID, PVOID, PVOID, PVOID, PVOID);
And it compiles fine. But at runtime both pointers are NULL.
It does the same for undocumented functions (linker error and NULL pointer if declared as extern C):

ZwQuerySystemInformation / ZwOpenDirectoryObject

Any idea?


EDIT: It's actually not NULL, but points to not logical area.
I tested with my previous driver, and the new one:
00000024 252.87759399 KeAddSystemServiceTable : 0x80596784 <= Good (ntoskrnl)
00000009 0.00026400 KeAddSystemServiceTable : 0xf89e3e0c <= Bad (my driver)
 #20554  by SomeUnusedName
 Wed Aug 21, 2013 3:39 pm
__declspec(dllimport) says "import a publicly available symbol" only.

The key here is the extern "C" as it says how to look for that symbol. It only makes sense to use extern "C" if your compiler is a C++ compiler.

If you export/import a symbol without extern "C", the compiler will take your symbol (be it a function or not) and create a new name that won't clash for overloaded functions. Overloaded functions would have the same name but different arguments, so the compiler incorporates this info in the final unique name. If you use extern "C" you say "import the symbol as I said, don't derive a mangled name from it and look for that".

In your example, not having extern "C" made the compiler generate the following name: "__imp_?KeAddSystemServiceTable@@YGHPAX0000@Z" which wasn't found because the WinAPI calls are exported as extern "C".
 #20560  by SomeUnusedName
 Thu Aug 22, 2013 8:17 am
Tigzy wrote:Thanks for the explanation!
So why do I need to put this too? "__declspec(dllimport)"
Because your symbol (KeAddSystemServiceTable) is not to be found somewhere in your source. The __declspec(dllimport) tells the linker that it should search for that symbol in a linked lib, in your case I guess it's ntoskrnl exporting the symbol.