Inspired by this answer about RE-ing IOCTLs, I tried to get the IOCTLs from NtDeviceIoControlFile() syscall. Here is an example of that syscall in Beep() function in KernelBase.dll file:

  • In x86_64 (__fastcall) Assembly language:
and     [rsp+72], ebx                   ; OutputBufferLength
and     [rsp+64], rbx                   ; OutputBuffer
mov     dword ptr [rsp+56], 8           ; InputBufferLength
lea     rax, [rsp+152]
mov     [rsp+48], rax                   ; InputBuffer
mov     dword ptr [rsp+40], 10000h      ; IoControlCode
lea     rax, [rsp+78h+var_18]
mov     [rsp+32], rax                   ; IoStatusBlock
xor     r9d, r9d                        ; ApcContext
xor     r8d, r8d                        ; ApcRoutine
xor     edx, edx                        ; Event
mov     rcx, [rsp+144]                  ; FileHandle
call    cs:__imp_NtDeviceIoControlFile
test    eax, eax
  • In C language:
Status = NtDeviceIoControlFile(FileHandle,

I tried this code in IDA Python to list all the cross references of that syscall:

# Global arrays
XrefList = []

# Get imported function address
FuncAddr = LocByName("__imp_NtDeviceIoControlFile")
print "NtDeviceIoControlFile found at 0x%08x" % FuncAddr

# Iterate over all call references
for xref in XrefsTo(FuncAddr, True):
    if xref.frm not in XrefList:
        print "xref @ 0x%08x (%s)" % (xref.frm, GetFunctionName(xref.frm))

This code can successfully list all the syscall in a list. But I want to list all the IOCTLs values at RSP+40 offset i.e. 6th parameter. What code should I add? If you have any suggestion with IDC code I shall appreciate it as well.


1 Answer 1


After iterating some arbitrary functions in IDA Python docs, I found a function get_arg_addrs() which shows the argument I need. Here is the Python code that I have appended with my question's code.

# Get IOCTLs
for i in XrefList:
    fifth_arg = idaapi.get_arg_addrs(i)[5]
    ioctl = GetOpnd(fifth_arg, 1)
    print "IOCTL: %s" % ioctl

This a for loop iterates over the XrefList array that had been created from previous operations. Then find the 5th argument and the 1st operand which is the IOCTL value. This method also works with DeviceIoControl(). But The code has one caveat. If NtDeviceIoControlFile() is used in some wrapper subroutine then the output of above code will be the CPU register name.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.