#可读写syscall参数的API
1. 读取syscall参数
我们需要在根据nitro事件构建的sycall对象之上设计一个API,提供透明的方式来获取跨不同操作系统的syscall参数。
以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 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 |
关键点
- Linux系统调用最多具有6个参数
- Linux始终将寄存器用于syscall参数传递
- Windows使用寄存器和内存。
修改系统调用参数
由上述描述可知,为了即时修改系统调用参数以改变虚拟机的行为,必须应对两种情况:
- 参数存储在寄存器中,可以通过nitro_set_regs ioctl替换寄存器值;
- 参数存储在内存中,利用libvmi的vmi_write_va API写入内存。
以NtOpenFile MSDN定义为例:
def enter_NtCreateFile(syscall):
KeyHandle, DesiredAccess, object_attributes = syscall.collect_args(3)
obj = ObjectAttributes(object_attributes, syscall.process)
buffer = obj.ObjectName.Buffer
access = FileAccessMask(DesiredAccess)
syscall.hook = {
'object_name': buffer,
'access': access.rights
}
注意
collect_args
仅限于Windows/syscall