修改系统调用参数
以NtOpenFile
MSDN为例:
NTSTATUS NtOpenFile(
_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_ ULONG ShareAccess,
_In_ ULONG OpenOptions
);
参数将以特定的方式传递给内核,具体取决于
- 操作系统调用协议
- 系统调用类型(syscall或sysenter)
Windows/Linux syscall arguments passing
Windows sysenter | Windows syscall | Linux sysenter | Linux syscall | |
---|---|---|---|---|
arg 1 | edx | rcx | ebx | rdi |
arg 2 | edx + 4 | rdx | ecx | rsi |
arg 3 | edx + 8 | r8 | edx | rdx |
arg 4 | edx + 12 | r9 | esi | r10 |
arg 5 | edx + 16 | rsp + ? | edi | r8 |
arg 6 | edx + 20 | rsp + ? + 8 | ebp | r9 |
arg 7 | edx + 24 | rsp + ? + 16 | no | no |
References
主要发现
- Linux系统调用最多有6个参数。
- Linux始终将寄存器用于syscall参数传递。
- Windows使用寄存器和内存。
修改系统调用参数
Nitro可以即时修改syscall参数并更改Guset的行为。
按照我们先前发现的内容,如果要提供这样的API,则必须涵盖2种情况:
- 参数存储在寄存器中
- 参数存储在内存中(Windows)
我们分别有2个解决方案:
- 利用
nitro_set_regs ioctl
替换寄存器值 - 利用libvmi的
vmi_write_va
API写入内存
ArguementMap
class ArgumentMap:
CONVENTION = {
SyscallType.syscall: [
(SyscallArgumentType.register, 'rcx'),
(SyscallArgumentType.register, 'rdx'),
(SyscallArgumentType.register, 'r8'),
(SyscallArgumentType.register, 'r9'),
(SyscallArgumentType.memory, 5),
],
}
该参数可以映射到寄存器或内存中。
如果参数索引超出范围,则无论如何都会将其获取到内存中,因为我们无法确切知道Windows syscall允许的最大参数数量。