Is there way to convert PFILE_OBJECT x86 pointer to x64?

In the various solutions to getting open file handles you have the easy way all in user mode with nothing special; unfortunately it hangs on certain handles. one solution for that is to create a separate thread with timeout and force thread termination if doesn’t respond (rather not). The other is to have a driver use ObQueryNameString with the DeviceObject member of FILE_OBJECT (ok fine). The x86 app uses the system handle information and its Object member, which all looked to have been converted/thunked by WOW64, to provide the FILE_OBJECT (Object) pointer to the x64 driver via a DeviceIOControl request. But it appears that even the actual FILE_OBJECT structure itself has also been thunked (PFILE_OBJECT->DeviceObject)? So how can you get the x64 version of that FILE_OJBECT? Would it be okay to just also pull the device object pointer typecast to the pointer 32bit pointer size (DeviceObject sits right after two CSHORT member so could still use the PFILE_OBJECT->DeviceObject to reference it)

But considering x86 may not be able to get all handle information, would it just be better to move all the requests to the driver so x86 app will always get a full list of open handles? Or does the thunking actually handle the transitions of values that won’t fit in 32bit pointers/values by moving where it’s at?

TIA!!

Well it appears that the thunking only chops off the 64bit pointer to be 32bits. So appears that it needs to be done in x64. e.g. x64 version of of NtQuerySystemInformation gives object pointer fffff0800f580d10 (good), x86 version f580d10 (access violation). So there you go.

What bigger problem are you trying to solve? Why do you need PFILE_OBJECT in user mode?

To properly pass pointers in both x64 and x86, your IOCTL structure needs to use 64 bit size for pointers, no matter what address size the machine and application is.
Use PVOID64 type.

xxxxx@terabyteunlimited.com wrote:

Well it appears that the thunking only chops off the 64bit pointer to be 32bits. So appears that it needs to be done in x64. e.g. x64 version of of NtQuerySystemInformation gives object pointer fffff0800f580d10 (good), x86 version f580d10 (access violation). So there you go.

True. The 32-bit version of NtQuerySystemInformation gives you a 32-bit
object pointer. The 32-bit version of NtQueryObject knows how to
tramslate that back out to a 64-bit pointer. Probably, the API knows
that all FILE_OBJECTs will be allocated in the same 4GB region, and so
it just adds a known value. Your driver doesn’t know that value
(although you could figure it out).


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Why this is needed, I need to know all open files within a reasonable point in time (including access, if read-only or writable). Based on all the research, I’ve built three different ways to do this (controlled with a conditional define).

One, all user mode, this doesn’t work because the important open files can’t be received because due to user mode openprocess rejects opening some processes, particularly system (or whatever would be owning the registry files).

Second, do most of the processing in the app, send a request to get the file name information from the PFILE_OBJECT and its PDEVICE_OBJECT. Work with x64 app, but the 32bit app on x64 system/driver has the issue with the passed pointer and get access violation (trapped in try/except).

Third, do it all in the driver, this works, but I’d prefer to move as much as I can to the app since those handles/pfile_object may not be valid by the time used and I’d presume in user mode it would just reject them through the api if used which could reduce the window where the driver may have an invalid object.

I’m not sure how the kernel mode would handle the no longer valid pointers, if it would get an access violation trapped by try/except or would it be worse (just looks at the object type to ensure as expected, then gets the device object, checks its type, then just reads the name fields of those two different objects).

So I guess there are a couple questions.

1 - What is the actual answer to the 32bit object pointer from NtQuerySystemInformation in the x64 driver “(although you could figure it out)”

2 - If doing all in the driver, those object pointers given in the ZwQuerySystemInformation may have been released by the time used, in that case, is the access to the type/name members of the structure always just going to be caught in try/except or would it just maybe be outdated or wrong information, or would it bsod ?

TIA!!

How do you get FILE_OBJECT pointers with ZwQuerySystemInformation ?

Why do you want to access a kernel mode addeess from user mode ? This is not possible.

J. S.

xxxxx@terabyteunlimited.com wrote:

So I guess there are a couple questions.

1 - What is the actual answer to the 32bit object pointer from NtQuerySystemInformation in the x64 driver “(although you could figure it out)”

If you can get ANY legitimate PFILE_OBJECT in your driver (including the
one that submitted the request, maybe), the upper 32-bits are going to
be the same. Just replace the lower.

The better answer, of course, is to compile your application as a 64-bit
app.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>If you can get ANY legitimate PFILE_OBJECT in your driver (including the one that submitted the

request, maybe), the upper 32-bits are going to be the same. Just replace the lower.

Which one do you suggest. I tried the iostack FileObject which gave me 0xFFFC0C00 in the upper 32 bits, but access violation. The x64 version can see it should be 0xFFFFFA80

>Which one do you suggest. I tried the iostack FileObject which gave me 0xFFFC0C00 in the upper

32 bits, but access violation. The x64 version can see it should be 0xFFFFFA80

Well in a wth, dumping that via %p shows it should be FFFFFA80, not sure why:

pfileobject=((UINT_PTR)(pstack->FileObject) & 0xFFFFFFFF00000000)+pfileobject;

doesn’t work, but I’ll have to check in to what’s going on. Must be right in front of my face…

So this fixes whatever the compiler was doing before:
UINT_PTR full64=(((UINT_PTR) pstack->FileObject) & ~(0xFFFFFFFFULL))+(UINT_PTR) pfileobject;
pfileobject=(PFILE_OBJECT) full64;

But now, it gets part way through and bug check:
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except,
it must be protected by a Probe. Typically the address is just plain bad or it
is pointing at freed memory.

I didn’t see any problem using the x64 app, nor the driver doing everything itself. But consistently have the bug check on the x86 app requesting the iocontrol.

So what “Probe” must I do to prevent that?

So now I can get the x64 app version to crash as well. Before running it, opened up a few browsers, some editors with a bunch of files. Ran app that loaded driver then at the deviceiocontrol call stopped it via break point. Then went off doing a bunch of stuff, browsing around the Internet, closing the other editors and files, closing browsers, opening again, etc… Then go back to the app and let it run. Boom. So still wondering what this “Probe” that needs to be done to ensure all okay and can capture in a try/except block?

Is there something I can do with this “probe” that validates the memory and if valid keeps it valid until I say I’m done with it? Again these are the objects returned by ZwQuerySystemInformation. Is there any other way to get a list of all open files on the system or per volume?

I thought about doing ZwOpenProcess, ZwDuplicateObject, then ObReferenceObjectByHandle but on every call of ZwOpenProcess(&hprocess, PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, &processid) it’s caught as an access violation in the except part of the try except block. hresult is local variable as is processid with uniquethread set to zero, uniqueprocess set to the value the app got from the system_handle_ex uniqueprocessid.

Once ZwQuerySystemInformation has returned, you can’t access the provided object pointers because you have no guaranty that they are still there. They may have been freed.

Kernel objects structures are allocated in nonpaged area and touching a bad address in nonpaged area causes bugcheck 0x50 PAGE_FAULT_IN_NONPAGED_AREA.

And even if the address is valid, the memory may have been attributed to someone else and the content may not be usable. Worse, writing to this address will corrupt the system pool.

Try to be a minifilter, you will be in the file opening/closing path.

J. S.

It just seems like such overkill to have to install a minifilter that sits there all the time just to track what files are opened (if that’s what it took, surprised MS doesn’t provide one so you don’t get 15 different filter drivers on the system). I was hoping the zwduplicateobject would validate the handle and then i’d get the pfile_object from the ObReferenceObjectByHandle, but can’t even get there since zwopenprocess gets caught in the try/except block with access violation for any id given to it (yet openprocess in user mode works). This is the correct prototype?

NTSYSAPI NTSTATUS NTAPI ZwOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId);

#define PROCESS_TERMINATE (0x0001)
#define PROCESS_CREATE_THREAD (0x0002)
#define PROCESS_SET_SESSIONID (0x0004)
#define PROCESS_VM_OPERATION (0x0008)
#define PROCESS_VM_READ (0x0010)
#define PROCESS_VM_WRITE (0x0020)
#define PROCESS_DUP_HANDLE (0x0040)
#define PROCESS_CREATE_PROCESS (0x0080)
#define PROCESS_SET_QUOTA (0x0100)
#define PROCESS_SET_INFORMATION (0x0200)
#define PROCESS_QUERY_INFORMATION (0x0400)
#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
0xFFF)

ZwOpenProcess is documented and is available in the WDK.

Where do you get the parameters ? Are you using user mode buffers ?

If that is the case, try to use buffered I/O.

W. N.

Well, I moved this over to a vm so I can see what is up, and it looks like it’s because the uniquethread is 0, but how do I get the thread I’m supposed to use for the ZwOpenProcess call?

No, a thread ID is not a pointer, it is not dereferenced.

W. N.

Well, digging deeper, it’s not uniquethread that is the problem (was referenced in windbg as being in NtSetInformationThread, so I -assumed- it was that being zero), but the 3rd parameter ObjectAttributes has to be provided. Misread the docs saying it has to be NULL in Vista or later, but it’s talking about the “objectname” “member” not the parameter itself.

“In Windows Vista and later versions of Windows, the ObjectName field of this structure must be set to NULL” argh.

Okay so now it’s doing it’s thing to a point. Does a bunch of things just fine and hit’s a point where you get bug check:

INVALID_KERNEL_HANDLE (93)
This message occurs if kernel code (server, redirector, other driver, etc.)
attempts to close a handle that is not a valid handle.
Arguments:
Arg1: 0000006c, The handle that NtClose was called with.
Arg2: 00000000, means a protected handle was closed.
Arg3: 00000000
Arg4: 00000000

That handle 6C was from the zwduplicateobject call of a processid opened of 4 and handle 2fc.

!handles for 6c shows:

006c: Object: ffbda458 GrantedAccess: 00000003 (Locked) (Protected) Entry: e10840d8
Object: ffbda458 Type: (81278560) File
ObjectHeader: ffbda440 (old version)
HandleCount: 2 PointerCount: 2
Directory Object: 00000000 Name: \WINDOWS\system32\config\SAM.LOG {HarddiskVolume2}

For the 2fc handle in processid 4 it shows:

kd> !handle 2fc f 4

Searching for Process with Cid == 4
PROCESS 8128e2c0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 00039000 ObjectTable: e1000b58 HandleCount: 232.
Image: System

Kernel handle table at e1002000 with 232 entries in use

02fc: Object: ffbda458 GrantedAccess: 00000003 (Protected) Entry: e10025f8
Object: ffbda458 Type: (81278560) File
ObjectHeader: ffbda440 (old version)
HandleCount: 2 PointerCount: 2
Directory Object: 00000000 Name: \WINDOWS\system32\config\SAM.LOG {HarddiskVolume2}

So why is it bombing out? Is it a trap in WinDbg or is there something really wrong that needs to be addressed? What would it be?

TIA!!!

So fixed that issue by doing the duplicate object with only OBJ_CASE_INSENSITIVE instead of DUPLICATE_SAME_ATTRIBUTES.