Often times while writing a proof of concept for an exploit or doing vulnerability research its necessary to make a raw syscall on Windows. Usually syscalls are called by a thin wrapping function in userland, often provided as an exported function from within a DLL. Many of these userland functions modify and manipulate the arguments prior to passing them to the kernel, which can be very undesirable for an exploit that needs full control of them. In order to get around this it’s often necessary to make a raw syscall.
Raw syscalls are most frequently done in C by using inline assembly which places the arguments in the necessary registers and uses the platform specific calling convention. This can however be done using a more friendly language for exploit prototyping such as Python by leveraging it’s powerful ctypes library. The Python ctypes library facilitates calling native functions (implemented in C usually) directly from within Python, which handles the conversion of the arguments and return value. In order to do this however a native function would need to be implemented in order to be called. No such documented function exists, so to address this a small assembly stub can be placed into executable memory. This assembly stub needs to support a calling convention in which the caller (Python) is responsible for cleaning up the stack, thus supporting an arbitrary number of arguments. This function will then be called with the syscall number as it’s first argument and places it into the correct register before realigning the remaining arguments.
The functionality of calling system calls can be further expanding in a “pythonic” way by using a class which has dynamic attributes corresponding to the names of the different syscall functions. When the attribute is referenced, it returns a callable object which sets the syscall number to the value corresponding to the function’s name on the specified platform and architecture.
An implementation of this technique is provided in the mayhem.exploit.windows module.
# initialize the syscall object for Windows 7 SP1
syscall = WindowsX86Syscall('7 SP1')
# these two calls are equivalent
# the first specifies the syscall number
syscall(261, 5, 0x010000, 1024**2, None)
# while the second looks it up by it's name
syscall.NtQuerySystemInformation(5, 0x010000, 1024**2, None)
The assembly stub for x86-64 is larger due to the fact that the calling convention on this architecture relies more heavily on utilizing registers than it’s x86 counter part. Where the 32-bit version can adjust the stack pointer to remove the one argument of the syscall number, the 64-bit version must shift the various registers and adjust the stack.
References:
Windows syscall references: http://j00ru.vexillium.org/
Windows syscall conventions: http://visi.kenshoto.com/viki/WindowsSyscallConventions