ctypes.windll.kernel32.DeviceIoControl returns error code 5 (access denied)

48 Views Asked by At

I'm trying to get a data structure that describes the allocation and location on disk of a specific file on python using ctypes.windll.kernel32.DeviceIoControl call.

import os
import json
import shutil
import ctypes
import ctypes.wintypes as wintypes
import struct
import winioctlcon

import json
import subprocess

FILE_ATTRIBUTE_NORMAL = 0x00000080
#FILE_READ_ATTRIBUTES = 0x80000000
FILE_READ_ATTRIBUTES = (0x0080)
#FILE_SHARE_READ = 1
#FILE_SHARE_WRITE = 2
#FILE_SHARE_DELETE = 4
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
FILE_SHARE_DELETE = 0x00000004
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
FILE_FLAG_NO_BUFFERING = 0x20000000
FILE_FLAG_RANDOM_ACCESS = 0x10000000
FILE_FLAG_WRITE_THROUGH = 0x80000000
SYNCHRONIZE = 0x00100000

OPEN_EXISTING = 3
OPEN_ALWAYS = 4

#FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
#FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
#FILE_FLAG_OPEN_NO_RECALL = 0x00100000
FILE_FLAG_OPEN_NO_RECALL = 0x00100000

class FileChunkInfo(ctypes.Structure):
    _fields_ = [
        ("fileOffset", ctypes.c_ulonglong),
        ("chunkSize", ctypes.c_ulonglong),
        ("volumeOffset", ctypes.c_ulonglong)
    ]

class LARGE_INTEGER(ctypes.Structure):
    _fields_ = [
        ('LowPart', ctypes.c_ulong),
        ('HighPart', ctypes.c_long),
        ('QuadPart', ctypes.c_longlong),
    ]

class STARTING_VCN_INPUT_BUFFER(ctypes.Structure):
    _fields_ = [("StartingVcn", LARGE_INTEGER)]

class RETRIEVAL_POINTERS_EXTENT(ctypes.Structure):
    _fields_ = [
        ('NextVcn', LARGE_INTEGER),
        ('Lcn', LARGE_INTEGER),
    ]

class RETRIEVAL_POINTERS_BUFFER(ctypes.Structure):
    _fields_ = [
        ('ExtentCount', wintypes.DWORD),
        ('StartingVcn', LARGE_INTEGER),
        ('Extents', RETRIEVAL_POINTERS_EXTENT * 1),  # Adjust the array size as needed
    ]

def get_file_info(full_path, bytes_per_cluster):
    file_size = 0
    file_parts = {}

    full_path_wchar = ctypes.c_wchar_p(full_path)

    # Retrieve handle to a file
    h_file = ctypes.windll.kernel32.CreateFileW(
        full_path_wchar,
        FILE_READ_ATTRIBUTES,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        None,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_OPEN_NO_RECALL,
        None,
    )

    if h_file == -1:
        print("Invalid handle. Error: {}", ctypes.windll.kernel32.GetLastError())
        return False

    if h_file != -1:
        file_size = LARGE_INTEGER(0)
        res = ctypes.windll.kernel32.GetFileSize(h_file, ctypes.byref(file_size ))
        print("fileSize{}".format(res))

        # Retrieve file extents using DeviceIoControl with FSCTL_GET_RETRIEVAL_POINTERS
        start_buffer = STARTING_VCN_INPUT_BUFFER()
        p_start_buffer = ctypes.pointer(start_buffer)

        extents = RETRIEVAL_POINTERS_BUFFER()
        p_extents = ctypes.pointer(extents)

        bytes_returned = wintypes.DWORD(0)

        try:
            res = ctypes.windll.kernel32.DeviceIoControl(
                h_file,
                winioctlcon.FSCTL_GET_RETRIEVAL_POINTERS, #0x90083C,  # FSCTL_GET_RETRIEVAL_POINTERS
                p_start_buffer,
                ctypes.sizeof(STARTING_VCN_INPUT_BUFFER),
                p_extents,
                ctypes.sizeof(RETRIEVAL_POINTERS_BUFFER),
                ctypes.byref(bytes_returned),
                None
            )
            print(ctypes.windll.kernel32.GetLastError())
            print("Res: {}".format(res))
            #print("Extents count: {}".format(extents.ExtentCount))

            return
        except Exception as err:
            print(err)
            return False

        ctypes.windll.kernel32.CloseHandle(h_file)

    return True

For some reasons DeviceIoControl returns 0 which means the call failed and GetLastError() returns error code 5 which is access denied. Cna you help me to understand what did I do wrong? Also, I tried this example: https://gist.github.com/santa4nt/11068180. It works fine for Geometry. But my specific case also fails with code 5 using an approach provided in this sources. Furthemore, code 5 returns even if file is not opened by anyone. My shell was opened as Administrator but I'm sure the reason something else.

I tried to rewrite the DeviceIoControl call using this approach: https://gist.github.com/santa4nt/11068180. Didn't help.

0

There are 0 best solutions below