0

我从 Ntdll.dll 调用导出的方法有些麻烦

在 VS2012 的调试模式下,我得到:

运行时检查失败 #0 - ESP 的值未在函数调用中正确保存。这通常是调用使用一种调用约定声明的函数和使用另一种调用约定声明的函数指针的结果

这是我使用的代码(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 作为备用调用约定,但没有任何效果。

4

1 回答 1

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 值,这会导致错误 ofc。

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
于 2013-03-02T15:07:42.187 回答