在ntdll.dll中调用导出方法的约定

时间:2013-03-02 13:36:39

标签: c windows

从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作为备用调用约定,但没有任何工作。

1 个答案:

答案 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