简单的活着

修改系统调用参数

Posted on By Mista Cai

修改系统调用参数

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允许的最大参数数量。