Struct распаковать на win32file.DeviceIoControl - PullRequest
0 голосов
/ 15 ноября 2018

Я пытаюсь понять и работать с win32file. Мне нужно взять USN Journals и с трудом понять фрагменты кода, которые я нашел в Интернете. Это фрагмент кода, который я нашел -

format = 'qqqqqLLLLqqqqq'
length = struct.calcsize(format)
out_buffer = win32file.DeviceIoControl(volh, winioctlcon.FSCTL_GET_NTFS_VOLUME_DATA, None, length)
data = struct.unpack(format, out_buffer)

Теперь я действительно ржавый, когда дело доходит до C и его структур. На данный момент я понял, что format - это 96-байтовый буфер, и он получит вывод из DeviceIoControl

Поэтому я попытался изменить формат на 'QQQQQQQQQQQQQQQQQQQ', чтобы посмотреть, что произойдет (чтобы увидеть, потому что я отчасти не понимаю, что на самом деле может произойти), и оказалось, что на этот раз я получил больший out_buffer. Вот я и подумал распаковать его -

struct.unpack(format, out_buffer)

И для меня сюрприз, я получил -

struct.error: unpack requires a string argument of length 152

Поэтому я добавил еще один 'Q', чтобы увеличить размер, и получил тот же результат. Я не понимаю, почему «qqqqqLLLLqqqqq» работает, а «QQQQQQQQQQQQQQQQQQQ» - нет. Так что мои вопросы -

  • Насколько я понимаю, мы можем распаковать, если буфер был больше, чем вывод, так почему распаковка не работает?

  • Придется ли мне запоминать эти форматы каждый раз, когда я хочу получить что-то из DeviceIoControl?

Указание мне на ресурсы также было бы дополнительным бонусом, так как мне нужно основываться на коде для чтения USN Journal, и я не думаю, что хит-парад приведет меня куда-либо

1 Ответ

0 голосов
/ 17 ноября 2018

Давайте разделим задачу на более мелкие части и рассмотрим каждую из них.

После ознакомления с вышеупомянутыми материаламидолжно стать понятнее.

Пара замечаний:

  • Если кто-то не знает, что функция делает (возвращает), они, вероятно, не должны ее использовать (не читаямануал, конечно).Хотя в наши дни Win (который всегда имел множество ограничений для обычного пользователя) и Ux"защищают пользователей от себя" (например: root login noдольше разрешено, защита от записи % SystemDrive% )
  • Попытки (методом проб и ошибок) показывают некоторый недостаток опыта (вероятно, каждый делает это в какой-то момент, ключ не в том, чтобы полагаться исключительно наэто)
  • " Должен ли я вспоминать эти форматы каждый раз, когда я хочу получить что-то от DeviceIoControl "?
    • Опять же, если вы не знаете, что делает функция, в чем причина ее вызова?Если вы имели в виду изучение NTFS_VOLUME_DATA_BUFFER наизусть, это определенно не тот случай.Вы должны знать его структуру только при использовании (и, как вы заметили, есть некоторые места, из которых вы можете получить его, включая этот пост :))
  • "Насколько я понимаю, мы можем распаковать, если буфер был больше, чем вывод, так почему распаковка не работает?"
    • Ваше понимание верно.Но win32file.DeviceIoControl кажется иногда (вероятно, при достижении 1 st NULL после 96 байт) усекает выходной буфер при передаче значения больше ожидаемого (через аргумент length ).При прохождении меньшего, он потерпит неудачу (как и ожидалось)

Я также подготовил фиктивный пример Python .

code.py

#!/usr/bin/env python3

import sys
import struct
import win32file
import win32api
import win32con
import winioctlcon


VOLUME_LETTER = "E"

FILE_READ_ATTRIBUTES = 0x0080
FILE_EXECUTE = 0x0020

vol_data_buf_fmt = "qqqqqLLLLqqqqq"  # This is the format that matches NTFS_VOLUME_DATA_BUFFER definition (96 bytes). Note: Instead of each 'q' you could also use 'Ll' as 'LARGE_INTEGER' is an union

BINARY_FORMAT_LIST = [
    vol_data_buf_fmt,
    "QQQQQQQQQQQQQQQQQQQ",
]


def print_formats():  # Dummy func
    print("Formats and lengths:")
    for format in BINARY_FORMAT_LIST:
        print("    {:s}: {:d}".format(format, struct.calcsize(format)))


def main():
    #print_formats()
    vol_unc_name = "\\\\.\\{:s}:".format(VOLUME_LETTER)
    print("volume: ", vol_unc_name)
    access_flags = FILE_READ_ATTRIBUTES | FILE_EXECUTE  # Apparently, doesn't work without FILE_EXECUTE
    share_flags = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE  # Doesn't work withou FILE_SHARE_WRITE
    creation_flags = win32con.OPEN_EXISTING
    attributes_flags = win32con.FILE_ATTRIBUTE_NORMAL
    vol_handle = win32file.CreateFile(vol_unc_name, access_flags, share_flags, None, creation_flags, attributes_flags, None)

    buf_len = struct.calcsize(vol_data_buf_fmt)
    for i in [buf_len]:
        print("    Passing a buffer size of: {:d}".format(i))
        buf = win32file.DeviceIoControl(vol_handle, winioctlcon.FSCTL_GET_NTFS_VOLUME_DATA, None, i)
        print("    DeviceIocontrol returned a {:d} bytes long {:}".format(len(buf), type(buf)))
        out = struct.unpack_from(vol_data_buf_fmt, buf)
        print("\n    NumberSectors: {:}\n    TotalClusters: {:}\n    BytesPerCluster: {:}".format(out[1], out[2], out[6]))
    win32api.CloseHandle(vol_handle)


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Вывод :

(py35x64_test) e:\Work\Dev\StackOverflow\q053318932>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" ./code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32

volume:  \\.\E:
    Passing a buffer size of: 96
    DeviceIocontrol returned a 96 bytes long <class 'bytes'>

    NumberSectors: 494374911
    TotalClusters: 61796863
    BytesPerCluster: 4096

Нет необходимости говорить, что умножение TotalClusters на BytesPerCluster ,Я получаю правильный номер байта (как сообщает Win ) для моего E: диска.

...