Windows 7 x86使用sysenter执行直接系统调用

我试图编写一些程序,直接调用系统调用,而不通过ntdll.dll

我的代码(Visual Studio的语法…):

#include <windows.h> int main() { _asm{ push arg1 push arg2 push arg3 mov eax,syscall_id mov edx,esp _emit 0xf _emit 0x34 //sysenter opcodes... } 

当程序尝试执行sysenter指令时,程序崩溃时会出现以下访问冲突:

 CALL DWORD PTR DS:[EAX+EDX*4] // Access Violation when reading [00000128] EAX == 0x00000000 EDX == 0x0000004D 

我试图在所需的系统调用中使用内核debugging器来放置一个hw断点,并且执行stream程没有到达那里…

我想这个问题与堆栈顺序/深度有关。

非常感谢!

解决了:

我想问题是我试图执行win32k系统调用,而不加载user32和gdi32 dll。

刚刚添加:

 LoadLibraryW(L"user32.dll"); LoadLibraryW(L"gdi32.dll"); 

和问题解决..

如果有人有一个更好的主意,为什么发生这种情况下没有加载这些DLL,我会很高兴知道:)

SYSENTER和SYSEXIT操作码不像普通的call / ret操作码。

SYSENTER和SYSEXIT都会跳转到预定义的地址(一个在内核空间,另一个在用户空间)。

具体来说,SYSEXIT被设置为在ntdll中跳转到KiFastSystemCallRet。 通常在ntdll中导出的系统程序调用KiFastSystemCall,而不是直接使用SYSENTER。 让我们来看看ntdll中的KiFastSystemCall和KiFastSystemCallRet:

 KiFastSystemCall: mov edx, esp sysenter KiFastSystemCallRet: retn 

你的代码将导致从内核返回到一个RETN指令的系统过程,这意味着返回你在arg3中的任何地址。 我不知道为什么加载user32和gdi32改变任何东西,也许它与arg3的价值。

无论如何,自己调用内核系统过程最安全的方法是使用KiFastSystemCall。 你也可以编写自己的代码,记住当从内核模式返回时的第一个操作码是RETN,所以你的代码需要在堆栈顶部有返回地址。