我正在尝试让程序使用系统调用而不是 dll(kernel32.dll
、ntdll.dll
)。
例如,我知道 Windows 10 64 位中的 0x2C (44) 系统调用是 NtTerminateProcess
buy that网页。此外,当我反汇编 ntdll.dll
时,我发现该代码:
NtTerminateProcess:
mov r10, rcx
mov eax, 44
test byte [abs 7FFE0308h], 01h ;also what is in that memory address?
jnz label
syscall
ret
label:
int 46 ;and why the 46 (the 2Eh windows NT interrupt) is here
ret
我的问题是如何以这种方式终止程序?
直接执行系统调用不是一个好主意,因为这不是一个稳定的 ABI。理论上,服务包之间的数字可能会发生变化,甚至是普通更新。
在 32 位 Windows 上使用的指令在所有系统上也不相同!
Windows NT 和 2000 总是使用 int 2e
。 Windows XP 开始使用 SysEnter
/SysCall
在“较新”的 Intel/AMD CPU(Pentium II、AMD K7 和更高版本)上运行时。由于 Windows XP 还支持较旧的 CPU,因此它使用了一些辅助函数 (SystemCallStub
) 来进入内核模式。此函数 (and later, the address of this function) 存储在位于 0x7ffe0000 的名为 _KUSER_SHARED_DATA
的所有进程均可访问的内存页中。
仍然支持原始的 int 2e
方法,但我不确定为什么 64 位 Windows 会费心检查使用哪种方法,因为它运行的每个 CPU 都支持 SysCall
。我的 Windows 8 机器不检查:
0:000> uf ntdll!NtTerminateProcess
ntdll!ZwTerminateProcess:
000007ff`1ad52ea0 4c8bd1 mov r10,rcx
000007ff`1ad52ea3 b82a000000 mov eax,2Ah
000007ff`1ad52ea8 0f05 syscall
000007ff`1ad52eaa c3 ret
无论如何,这些只是实现细节,它们可以随时更改。参见 https://j00ru.vexillium.org/syscalls/nt/64/用于按 Windows 内核版本分割的 x64 NT 系统调用编号的逆向工程表。 (请勿在可移植代码中使用,仅用于满足您对 Windows 和/或 asm 工作原理的好奇心的实验。)
int 2e
可能有点慢,所以只需在 64 位代码中使用 SysCall
并在 32 位代码中使用 int 2e
如果你想保持“便携”。