I'm trying to call NtOpenFile
, and it's failing with error:
STATUS_OBJECT_PATH_SYNTAX_BAD = NTSTATUS($C000003B);
Object Path Component was not a directory object.
The basic gist is:
//The file we'll test with
filename: UnicodeString := 'C:\Windows\Explorer.exe'; //23 characters
//Convert the filename to counted UNICODE_STRING
cs: UNICODE_STRING;
cs.Length := Length(filename) * sizeof(WideChar); //46 bytes
cs.MaximumLength := cs.Length + 2; //48 bytes
cs.Buffer := PWideChar(Filename); //"C:\Windows\Explorer.exe"
//Define the OBJECT_ATTRIBUTES
oa: OBJECT_ATTRIBUTES := Default(OBJECT_ATTRIBUTES);
oa.Length := sizeof(OBJECT_ATTRIBUTES); //24 bytes
oa.Attributes := OBJ_CASE_INSENSITIVE;
oa.ObjectName := @cs; //UNICODE_STRING
//Open the file (by Object Attributes) and get a file handle
hFile: THandle;
iosb: IO_STATUS_BLOCK;
status: NTSTATUS := NtOpenFile(@hFile, FILE_READ_ATTRIBUTES, @oa, @iosb, FILE_SHARE_READ, 0);
What am I doing wrong?
//The file we'll test with
UnicodeString filename = "C:\Windows\Explorer.exe"; //23 characters
//Convert the filename to counted UNICODE_STRING
UNICODE_STRING cs;
cs.Length = Length(filename) * sizeof(WideChar); //46 bytes
cs.MaximumLength = cs.Length + 2; //48 bytes
cs.Buffer = Filename; //"C:\Windows\Explorer.exe"
//Define the OBJECT_ATTRIBUTES
OBJECT_ATTRIBUTES oa = Default(OBJECT_ATTRIBUTES);
oa.Length = sizeof(OBJECT_ATTRIBUTES); //24 bytes
oa.Attributes = OBJ_CASE_INSENSITIVE;
oa.ObjectName = cs; //UNICODE_STRING
//Open the file (by Object Attributes) and get a file handle
THandle hFile;
IO_STATUS_BLOCK iosb;
NTSTATUS status = NtOpenFile(out hFile, FILE_READ_ATTRIBUTES, ref oa, out iosb, FILE_SHARE_READ, 0);
Filename | Result | Description |
---|---|---|
"C:\Windows\Explorer.exe" |
STATUS_OBJECT_PATH_SYNTAX_BAD |
Object Path Component was not a directory object. |
"\global??\C:\Windows\Explorer.exe" |
0xC0000033 | Object Name invalid |
"\??\C:\Windows\Explorer.exe" |
0xC0000033 | Object Name invalid |
Because there can be issues of memory layout, alignment, padding, and missing members, lets dump the raw oa
memory:
18 00 00 00 ;Length. 0x00000018 = 24 bytes (sizeof)
00 00 00 00 ;RootDirectory. 0x00000000 = NULL
28 FF 19 00 ;ObjectName. PUNICODE_STRING 0x0019FF28
40 00 00 00 ;Attributes. (0x00000040 = OBJ_CASE_INSENSITIVE)
00 00 00 00 ;SecurityDescriptor 0x0000000 = NULL
00 00 00 00 ;SecurityQualityOfService 0x00000000 = NULL
**0x0019FF28:**
3C FF 19 00 ;PUNICODE_STRING 0x0019FF3C
**0x0019FF3C**
36 00 ; String length in bytes 0x0036
38 00 ; Buffer size in bytes 0x0038
E8 B6 4E 00 ; PWideChar 0x004EB6E8 ==> "C:\Windows\Explorer.exe"
Which, now I see my problem: PUNICODE_STRING -> PUNICODE_STRING.
program NtOpenFileDemo;
{$APPTYPE CONSOLE}
{$R *.res}
{$ALIGN 8}
{$MINENUMSIZE 4}
uses
SysUtils, Windows, ComObj;
type
NTSTATUS = Cardinal;
const
STATUS_SUCCESS = 0;
type
UNICODE_STRING = packed record
Length: Word; // Length of the string, in bytes (not including the null terminator)
MaximumLength: Word; // Size of the buffer, in bytes
Buffer: PWideChar; //really a PWideChar
end;
PUNICODE_STRING = ^UNICODE_STRING;
type
IO_STATUS_BLOCK = packed record
Status: NTSTATUS;
Information: Pointer;
end;
PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;
OBJECT_ATTRIBUTES = packed record
Length: Cardinal;
RootDirectory: THandle;
ObjectName: PUNICODE_STRING;
Attributes: Cardinal;
SecurityDescriptor: Pointer;
SecurityQualityOfService: Pointer;
end;
POBJECT_ATTRIBUTES = ^OBJECT_ATTRIBUTES;
const
// Define share access rights to files and directories
FILE_SHARE_READ = $00000001;
FILE_SHARE_WRITE = $00000002;
FILE_SHARE_DELETE = $00000004;
FILE_SHARE_VALID_FLAGS = $00000007;
// Valid values for the Attributes field
const
OBJ_INHERIT = $00000002;
OBJ_PERMANENT = $00000010;
OBJ_EXCLUSIVE = $00000020;
OBJ_CASE_INSENSITIVE = $00000040;
OBJ_OPENIF = $00000080;
OBJ_OPENLINK = $00000100;
OBJ_KERNEL_HANDLE = $00000200;
OBJ_VALID_ATTRIBUTES = $000003F2;
function NtOpenFile(FileHandle: PHandle; DesiredAccess: ACCESS_MASK; ObjectAttributes: POBJECT_ATTRIBUTES;
IoStatusBlock: PIO_STATUS_BLOCK; ShareAccess: DWORD; OpenOptions: DWORD): NTSTATUS; stdcall; external 'ntdll.dll';
function NtClose(Handle: THandle): NTSTATUS; stdcall; external 'ntdll.dll';
function FormatNTStatusMessage(const NTStatusMessage: NTSTATUS): string;
var
Buffer: PChar;
Len: Integer;
hMod: HMODULE;
function MAKELANGID(p, s: WORD): WORD;
begin
Result := WORD(s shl 10) or p;
end;
begin
{
KB259693: How to translate NTSTATUS error codes to message strings
Let the OS initialize the Buffer variable. Need to LocalFree it afterward.
}
hMod := SafeLoadLibrary('ntdll.dll');
Len := FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER or
FORMAT_MESSAGE_FROM_SYSTEM or
// FORMAT_MESSAGE_IGNORE_INSERTS or
// FORMAT_MESSAGE_ARGUMENT_ARRAY or
FORMAT_MESSAGE_FROM_HMODULE,
Pointer(hMod),
NTStatusMessage,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
@Buffer, 0, nil);
try
//Remove the undesired line breaks and '.' char
while (Len > 0) and (CharInSet(Buffer[Len - 1], [#0..#32, '.'])) do Dec(Len);
//Convert to Delphi string
SetString(Result, Buffer, Len);
finally
//Free the OS allocated memory block
LocalFree(HLOCAL(Buffer));
end;
FreeLibrary(hMod);
end;
procedure TestCase;
var
filename: UnicodeString;
cs: PUNICODE_STRING;
hFile: THandle;
oa: OBJECT_ATTRIBUTES;
iosb: IO_STATUS_BLOCK;
status: NTSTATUS;
begin
filename := 'C:\Windows\Explorer.exe'; //23 characters
{
Convert the filename to an "Object Attributes" structure
OBJECT_ATTRIBUTES.Length <-- 24
OBJECT_ATTRIBUTES.Attributes <-- OBJ_CASE_INSENSITIVE
OBJECT_ATTRIBUTES.ObjectName.Length <-- 46
OBJECT_ATTRIBUTES.ObjectName.MaximumLength <-- 48
OBJECT_ATTRIBUTES.ObjectName.Buffer <-- "C:\Windows\Explorer.exe"
}
cs.Length := Length(Filename) * sizeof(WideChar);
cs.MaximumLength := cs.Length + 2; //the null terminator
cs.Buffer := PWideChar(Filename);
oa := Default(OBJECT_ATTRIBUTES);
oa.Length := sizeof(OBJECT_ATTRIBUTES);
oa.Attributes := OBJ_CASE_INSENSITIVE;
oa.ObjectName := @cs;
//Open the file (by Object Attributes) and get a file handle
status := NtOpenFile(@hFile, FILE_READ_ATTRIBUTES, @oa, @iosb, FILE_SHARE_READ, 0);
if status <> STATUS_SUCCESS then
begin
WriteLn('Error opening file "'+Filename+'": '+FormatNTStatusMessage(status)+' (0x'+IntToHex(status, 8)+')');
Exit;
end;
try
WriteLn('Successfully opened file');
finally
NtClose(hFile);
end;
end;
begin
try
TestCase;
WriteLn('Press enter to close...');
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Found it.
Two things:
"C:\Windows\Notepad.exe"
→ "\??\C:\Windows\Notepad.exe"
OBJECT_ATTRIBUTES.ObjectName
I was assigning @PUNICODE_STRING
, rather than @UNICODE_STRING
User contributions licensed under CC BY-SA 3.0