我试图编写一些程序,直接调用系统调用,而不通过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,所以你的代码需要在堆栈顶部有返回地址。