如何从所有 NtDeviceIoControlFile 函数调用中获取 IOCTL?

逆向工程 艾达 视窗 蟒蛇
2021-06-29 21:32:14

受到这个关于 RE-ing IOCTL 的回答的启发,我试图从NtDeviceIoControlFile()系统调用中获取 IOCTL 这是文件Beep()函数中该系统调用的示例KernelBase.dll

  • 在 x86_64 (__fastcall) 汇编语言中:
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
  • 在 C 语言中:
NTSTATUS Status;
Status = NtDeviceIoControlFile(FileHandle,
                               NULL,
                               NULL,
                               NULL,
                               &IoStatusBlock,
                               0x10000u,
                               &InputBuffer,
                               InputBufferLength,
                               OutputBuffer,
                               OutputBufferLength);

我在 IDA Python 中尝试了这段代码来列出该系统调用的所有交叉引用:

# 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:
        XrefList.append(xref.frm)
        print "xref @ 0x%08x (%s)" % (xref.frm, GetFunctionName(xref.frm))
    else:
        continue

此代码可以成功列出列表中的所有系统调用。但我想列出RSP+40偏移量处的所有 IOCTL 值,即第 6 个参数。我应该添加什么代码?如果您对 IDC 代码有任何建议,我也将不胜感激。

1个回答

IDA Python docs 中迭代一些任意函数后,我找到了一个函数 get_arg_addrs(),它显示了我需要的参数。这是我附加在我的问题代码中的 Python 代码。

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

这个 for 循环遍历XrefList从先前操作创建数组。然后找到第 5 个参数和第一个操作数,即 IOCTL 值。此方法也适用于DeviceIoControl(). 但是代码有一个警告。如果NtDeviceIoControlFile()在某些包装子程序中使用,则上述代码的输出将是 CPU 寄存器名称。