Opening a file by ID – FILE_OPEN_BY_FILE_ID

Sample code to open a file by its file-id. Had to use it for some tests and thought it might be useful for other people out there.

#include windows.h

typedef ULONG (__stdcall *pNtCreateFile)(
  PHANDLE FileHandle,
  ULONG DesiredAccess,
  PVOID ObjectAttributes,
  PVOID IoStatusBlock,
  PLARGE_INTEGER AllocationSize,
  ULONG FileAttributes,
  ULONG ShareAccess,
  ULONG CreateDisposition,
  ULONG CreateOptions,
  PVOID EaBuffer,
  ULONG EaLength
);

typedef ULONG (__stdcall *pNtReadFile)(
	IN HANDLE  FileHandle,
	IN HANDLE  Event  OPTIONAL,
	IN PVOID  ApcRoutine  OPTIONAL,
	IN PVOID  ApcContext  OPTIONAL,
	OUT PVOID  IoStatusBlock,
	OUT PVOID  Buffer,
	IN ULONG  Length,
	IN PLARGE_INTEGER  ByteOffset  OPTIONAL,
	IN PULONG  Key  OPTIONAL    );

typedef struct _UNICODE_STRING {
	USHORT Length, MaximumLength;
	PWCH Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
    PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;

#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );          \
    (p)->RootDirectory = r;                             \
    (p)->Attributes = a;                                \
    (p)->ObjectName = n;                                \
    (p)->SecurityDescriptor = s;                        \
    (p)->SecurityQualityOfService = NULL;               \
    }

#define OBJ_CASE_INSENSITIVE					0x00000040L
#define FILE_NON_DIRECTORY_FILE                 0x00000040
#define FILE_OPEN_BY_FILE_ID                    0x00002000
#define FILE_OPEN								0x00000001

int main(int argc, char* argv[])
{
	HANDLE d = CreateFile(L"\\\\.\\c:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0  );
	BY_HANDLE_FILE_INFORMATION i;
	HANDLE f = CreateFile(L"c:\\bla.bla", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	ULONG bla;
	WriteFile(f, "helloworld", 11, &bla, NULL);
	printf("%x, %d\n", f, GetLastError());
	GetFileInformationByHandle(f, &i);
	printf("id:%08x-%08x\n", i.nFileIndexHigh, i.nFileIndexLow);
	CloseHandle(f);

	pNtCreateFile NtCreatefile = (pNtCreateFile)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateFile");
	pNtReadFile NtReadFile = (pNtReadFile)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtReadFile");

	ULONG fid[2] = {i.nFileIndexLow, i.nFileIndexHigh};
	UNICODE_STRING fidstr = {8, 8, (PWSTR) fid};

	OBJECT_ATTRIBUTES oa = {0};
    InitializeObjectAttributes (&oa, &fidstr, OBJ_CASE_INSENSITIVE, d, NULL);

    ULONG iosb[2];
    ULONG status = NtCreatefile(&f, GENERIC_ALL, &oa, iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_BY_FILE_ID | FILE_NON_DIRECTORY_FILE, NULL, 0);
	printf("status: %X, handle: %x\n", status, f);
	UCHAR buf[11] = {0};
	LONG Off[2] = {0};
	status = NtReadFile(f, NULL, NULL, NULL, (PVOID)&iosb, (PVOID)buf, sizeof(buf), (PLARGE_INTEGER)&Off, NULL);
	printf("status: %X, bytes: %d\n", status, iosb[1]);
	printf("buf: %s\n", buf);
	CloseHandle(f);
	CloseHandle(d);
}

2 Responses to “Opening a file by ID – FILE_OPEN_BY_FILE_ID”

  1. LEV ELBERT says:

    Is it possible to do the same, open file/directory by MFT’s FRN, but using CreateFile (not NtXXX)?

  2. Peter says:

    Did you find a solution lev? What i have does is to use OpenFileById since we can use NtCreateFile on Windows XP. On windows 7 ntcreatefile will give you access denied. My solution was to load a unmanaged dll in c# that calls OpenFileById. This works fine on Windows Vista and up (x86 and x64). But i’d love to see a working solution in c# in regards of the file descriptor struct. I’ve spent days trying to make viable solution in c#, but it seems hopeless to get it working.

Leave a Reply