从Ntdll.dll
调用导出的方法时遇到一些麻烦在使用VS2012的调试模式下,我得到:
运行时检查失败#0 - 未正确保存ESP的值 跨函数调用。这通常是调用a的结果 用一个带有函数指针的调用约定声明的函数 用不同的调用约定声明
这是我使用过的代码(x86平台,Windows 7)。
#include "stdafx.h"
#include <Windows.h>
typedef NTSTATUS (* NTAPI ZwClose)(HANDLE handle);
int _tmain(int argc, _TCHAR* argv[])
{
ZwClose close = (ZwClose) ::GetProcAddress(GetModuleHandle(L"ntdll.dll"), "ZwClose");
close(INVALID_HANDLE_VALUE); // Error happens here
return -1;
}
从我所看到的它应该起作用。我也尝试过__cdecl和__fastcall作为备用调用约定,但没有任何工作。
答案 0 :(得分:4)
你做错了,应该是:
typedef NTSTATUS (NTAPI* ZwClose)(HANDLE handle);
你的声明指出函数是在C约定中。 C调用约定与STDCALL相同,除了调用者更正了堆栈。
;C
push arg1
call fun
add esp, 4
...
; STDCALL
push arg1
call func
在反汇编中你可以看到在调用ZwClose之后,正在检查Esp的值。 由于您对ZwClose的调用是在C约定中,因此esp值由调用者和 通过函数本身导致错误。
000F14C4 mov esi,esp
000F14C6 push 0FFFFFFFFh
000F14C8 call dword ptr [close]
000F14CB add esp,4
000F14CE cmp esi,esp
000F14D0 call @ILT+380(__RTC_CheckEsp) (0F1181h) ; Run-Time Check Failure #0