Hello @Benedikt Lazar ,
According to the Understanding how packaged desktop apps (MSIX) run on Windows documentation, operations in the user's AppData are dynamically redirected to a private LocalCache to prevent system rot. bindflt.sys achieves this by injecting its own kernel handle. It intentionally leaves RequestorMode as UserMode for security. As explicitly noted in the ObReferenceObjectByHandle documentation, UserMode forces the system to check the requested access against the object's granted access. If bindflt.sys elevated it to KernelMode, it would bypass Access Control List (ACL) checks, potentially allowing a restricted app to escalate privileges.
While Windows doesn't expose a public API for this, in the NT architecture, kernel handles typically have their most significant bit (MSB) set. You can see architectural evidence of this in structures like OB_PRE_OPERATION_INFORMATION, which explicitly dedicates a KernelHandle bit. Because of this MSB behavior, kernel handles evaluate to a negative number. I usually use a macro like this to perform a quick check:
#define IS_KERNEL_HANDLE(h) (((ULONG_PTR)(h) != (ULONG_PTR)-1) && ((LONG_PTR)(h) < 0))
If you strictly need to call ObReferenceObjectByHandle, the safe workaround is a try/fallback: call it with UserMode first. If it returns STATUS_INVALID_HANDLE and the macro above is true, you can safely retry with KernelMode.
If your ultimate goal is simply to construct the destination path, I suggest not manually parsing this handle. Resolving handles injected by bindflt.sys in a PreOperationCallback is notoriously prone to triggering BSODs.
Instead, the recommended alternative is to pass the handle directly into the FltGetDestinationFileNameInformation API:
NTSTATUS status;
PFLT_FILE_NAME_INFORMATION nameInfo = NULL;
status = FltGetDestinationFileNameInformation(
FltObjects->Instance,
FltObjects->FileObject,
RenameInfo->RootDirectory, // Pass the handle here directly, FltMgr will handle it
RenameInfo->FileName,
RenameInfo->FileNameLength,
FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT,
&nameInfo
);
if (NT_SUCCESS(status)) {
// FltMgr safely resolves the virtualized root directory and combines it with the file name.
FltReleaseFileNameInformation(nameInfo);
}
Hope this gives you a direction. If you found my response helpful or informative, I would greatly appreciate it if you could provide feedback by following this guide.
Thank you.