Problems with ObReferenceObject and ObDerefenceObject

I have the following problem:

Given an object handle, an object pointer (pointer and handle refer to the same object), and the pid of the process that owns the handle, I want to be able to access the object pointer safely. Note that the object handle and pointer come from a call to ZwQuerySystemInformation(SystemHandleInformation), therefore they may refer to an object that does not exist anymore and the process with the given pid may not exist either.

My current solution is as follows:

  1. Get a handle to the owner process
  2. Duplicate the handle into the current process
  3. Call ObReferenceObjectByPointer using the originally supplied object pointer

If all 3 steps succeed I assume that it is OK to use the object file pointer. Once I am done with the file pointer I clean by:

  1. ObDereferenceObject on the object pointer
  2. Close the duplicated handle (I have to play some tricks to make sure the handle can be closed)
  3. Close the owner process handle

This code ran successfully for several weeks until today. I got SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (STATUS_ACCESS_VIOLATION) when trying to perform step 1 of the dereferencing sequence. Here is the stack trace (obtained by “!analyze -v”):

nt!ObpRemoveObjectRoutine+0xc4
nt!ObfDereferenceObject+0x67
nt!VerifierObfDereferenceObject+0xa
mydriver!DereferenceObject+0x15
mydriver!MakeWrappers+0x5dc
mydriver!DiscoverObjectsAndMakeWrappers+0x30b
mydriver!DriverEntry+0x3af
nt!IopLoadDriver+0x689
nt!IopLoadUnloadDriver+0x45
nt!ExpWorkerThread+0xeb
nt!PspSystemThreadStartup+0x2e
nt!KiThreadStartup+0x16

The actual exception seems to be thrown on a different thread . Its stack trace is (obtained by “k”):
nt!KeBugCheckEx+0x1b
nt!PspUnhandledExceptionInSystemThread+0x1a
nt!PspSystemThreadStartup+0x56
nt!KiThreadStartup+0x16

The exception details are:

EXCEPTION_RECORD: f78f6a24 – (.exr 0xfffffffff78f6a24)
ExceptionAddress: 80929979 (nt!ObpRemoveObjectRoutine+0x000000c4)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000098
Attempt to read from address 00000098

My questions are:

  1. What is wrong with my approach? I have my handles to the process and the object and managed to increment the refcount on the file object. Why would decrementing the refcount on the file object cause this error?

  2. Are there another approache to achieve what I am trying to do?

Thank you in advance,
–aydan

I’m not sure if it is related to your current problem but I’d say you
have race conditions in the first part. If the handle got using
ZwQuerySystemInformation() is closed before step 3, you can reference
non-existing object. You may not get an error in step 2 if the target
process opens another handle in the meantime. Handles are just indexes
to handle table. Handle close frees the slot there and new open utilizes
it. In turn, you can have valid handle pointing to different object.

I’d say the exception is caused by NULL pointer dereference. You should
check what the code at ObpRemoveObjectRoutine+0xc4 does (others can’t
because you didn’t say OS version). Maybe it’ll give a hint what is
wrong. Alternatively, you could simulate above scenario to see what
happens.

What exactly are you trying to achieve?

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Wednesday, October 01, 2008 10:49 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Problems with ObReferenceObject and ObDerefenceObject

I have the following problem:

Given an object handle, an object pointer (pointer and handle
refer to the same object), and the pid of the process that
owns the handle, I want to be able to access the object
pointer safely. Note that the object handle and pointer come
from a call to
ZwQuerySystemInformation(SystemHandleInformation), therefore
they may refer to an object that does not exist anymore and
the process with the given pid may not exist either.

My current solution is as follows:

  1. Get a handle to the owner process
  2. Duplicate the handle into the current process
  3. Call ObReferenceObjectByPointer using the originally
    supplied object pointer

If all 3 steps succeed I assume that it is OK to use the
object file pointer. Once I am done with the file pointer I clean by:

  1. ObDereferenceObject on the object pointer
  2. Close the duplicated handle (I have to play some tricks to
    make sure the handle can be closed)
  3. Close the owner process handle

This code ran successfully for several weeks until today. I
got SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
(STATUS_ACCESS_VIOLATION) when trying to perform step 1 of
the dereferencing sequence. Here is the stack trace (obtained
by “!analyze -v”):

nt!ObpRemoveObjectRoutine+0xc4
nt!ObfDereferenceObject+0x67
nt!VerifierObfDereferenceObject+0xa
mydriver!DereferenceObject+0x15
mydriver!MakeWrappers+0x5dc
mydriver!DiscoverObjectsAndMakeWrappers+0x30b
mydriver!DriverEntry+0x3af
nt!IopLoadDriver+0x689
nt!IopLoadUnloadDriver+0x45
nt!ExpWorkerThread+0xeb
nt!PspSystemThreadStartup+0x2e
nt!KiThreadStartup+0x16

The actual exception seems to be thrown on a different thread
. Its stack trace is (obtained by “k”):
nt!KeBugCheckEx+0x1b
nt!PspUnhandledExceptionInSystemThread+0x1a
nt!PspSystemThreadStartup+0x56
nt!KiThreadStartup+0x16

The exception details are:

EXCEPTION_RECORD: f78f6a24 – (.exr 0xfffffffff78f6a24)
ExceptionAddress: 80929979 (nt!ObpRemoveObjectRoutine+0x000000c4)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000098
Attempt to read from address 00000098

My questions are:

  1. What is wrong with my approach? I have my handles to the
    process and the object and managed to increment the refcount
    on the file object. Why would decrementing the refcount on
    the file object cause this error?

  2. Are there another approache to achieve what I am trying to do?

Thank you in advance,
–aydan


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online
at http://www.osronline.com/page.cfm?name=ListServer

You should not try to close a user mode handle (not OBJ_KERNEL_HANDLE) from kernel mode as a general rule. There are a number of situations (user mode closing or protecting said handle) that you cannot really protect against with such a model.

You might be able to attach to the process and attempt the handle reference (be sure to specify AccessMode == UserMode, and specify a POBJECT_TYPE).

However, that is not a particularly good thing to do without extreme care, as you can very easily break things when attaching a thread to a process (and I’m certain that it will not be listed as a blessed thing for your usage, and as such may have unintended consequences).

Why do you believe that you must do such an estoric operation? There may be a (much) safer and easier way.

  • S

-----Original Message-----
From: xxxxx@gmail.com
Sent: Wednesday, October 01, 2008 15:50
To: Windows System Software Devs Interest List
Subject: [ntdev] Problems with ObReferenceObject and ObDerefenceObject

I have the following problem:

Given an object handle, an object pointer (pointer and handle refer to the same object), and the pid of the process that owns the handle, I want to be able to access the object pointer safely. Note that the object handle and pointer come from a call to ZwQuerySystemInformation(SystemHandleInformation), therefore they may refer to an object that does not exist anymore and the process with the given pid may not exist either.

My current solution is as follows:

1. Get a handle to the owner process
2. Duplicate the handle into the current process
3. Call ObReferenceObjectByPointer using the originally supplied object pointer

If all 3 steps succeed I assume that it is OK to use the object file pointer. Once I am done with the file pointer I clean by:

1. ObDereferenceObject on the object pointer
2. Close the duplicated handle (I have to play some tricks to make sure the handle can be closed)
3. Close the owner process handle

This code ran successfully for several weeks until today. I got SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (STATUS_ACCESS_VIOLATION) when trying to perform step 1 of the dereferencing sequence. Here is the stack trace (obtained by “!analyze -v”):

nt!ObpRemoveObjectRoutine+0xc4
nt!ObfDereferenceObject+0x67
nt!VerifierObfDereferenceObject+0xa
mydriver!DereferenceObject+0x15
mydriver!MakeWrappers+0x5dc
mydriver!DiscoverObjectsAndMakeWrappers+0x30b
mydriver!DriverEntry+0x3af
nt!IopLoadDriver+0x689
nt!IopLoadUnloadDriver+0x45
nt!ExpWorkerThread+0xeb
nt!PspSystemThreadStartup+0x2e
nt!KiThreadStartup+0x16

The actual exception seems to be thrown on a different thread . Its stack trace is (obtained by “k”):
nt!KeBugCheckEx+0x1b
nt!PspUnhandledExceptionInSystemThread+0x1a
nt!PspSystemThreadStartup+0x56
nt!KiThreadStartup+0x16

The exception details are:

EXCEPTION_RECORD: f78f6a24 – (.exr 0xfffffffff78f6a24)
ExceptionAddress: 80929979 (nt!ObpRemoveObjectRoutine+0x000000c4)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000098
Attempt to read from address 00000098
----

My questions are:

1. What is wrong with my approach? I have my handles to the process and the object and managed to increment the refcount on the file object. Why would decrementing the refcount on the file object cause this error?

2. Are there another approache to achieve what I am trying to do?

Thank you in advance,
–aydan


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

What I am trying to achieve is to enumerate all TDI address/connection objects at the time my TDI filter driver is installed. I need to establish some state about TDI address objects and doing this allows my driver to provide some functionality without requiring a system reboot or application restart. I also need to find out all processes that have handle to a TDI connection/address object so that I can start monitoring them, e.g., report process utilization, etc. In addition, on windows 2000 machines this technique also allows me to associate PIDs with extant connections (connections that existed at the time the driver was installed).

Michal, I can see the race condition you mentioned. Would changing 3 to: ObReferenceObjectByHandle(duplicated object handle) fix the problem? Also, in my case, it seems that the referencing part succeeded, it was the dereferencing part that failed.

Ken, would you give me a pointer as to how I could attach to a given process from within a driver? I am not sure I know how to do that.

Thank you very much,
–aydan

> how I could attach to a given process from within a driver

KeStackAttachProcess(), but this is not going to help either - just consider what happens if the target process closes the handle. I am afraid you are totally out of luck here - this is the situation when you are playing with someone else’s resource without its owner’s knowledge, and it just cannot be done safely…

What I am trying to achieve is to enumerate all TDI address/connection objects at the time
my TDI filter driver is installed.

It cannot be reliably done for the reasons mentioned above. All info that you get is valid at the moment it is being collected, but there is no guarantee it will still be valid by the time you decide to make any use of it… This is why you should not make any use of this info - it is meant to be used only for the statistical purposes…

Anton Bassov

xxxxx@gmail.com wrote:

I have the following problem:

Given an object handle, an object pointer (pointer and handle refer to the same object), and the pid of the process that owns the handle, I want to be able to access the object pointer safely. Note that the object handle and pointer come from a call to ZwQuerySystemInformation(SystemHandleInformation), therefore they may refer to an object that does not exist anymore and the process with the given pid may not exist either.

My current solution is as follows:

  1. Get a handle to the owner process
  2. Duplicate the handle into the current process
  3. Call ObReferenceObjectByPointer using the originally supplied object pointer

If all 3 steps succeed I assume that it is OK to use the object file pointer. Once I am done with the file pointer I clean by:

  1. ObDereferenceObject on the object pointer
  2. Close the duplicated handle (I have to play some tricks to make sure the handle can be closed)
  3. Close the owner process handle

This code ran successfully for several weeks until today. I got SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (STATUS_ACCESS_VIOLATION) when trying to perform step 1 of the dereferencing sequence. Here is the stack trace (obtained by “!analyze -v”):

A safer approach is:

  1. Hook TDI so your driver will see any subsequent opens and closes.
    Be prepared for the possibility that your enumeration may encounter
    fresh connections also seen by your hooking, and the possibility that
    your hooking may see the closing of a connection seen by your enumeration.

  2. For each process other than System:
    In the System process, obtain first a handle to the process, then
    reference your handle to get a process reference. Hold on to both.
    This way you can be sure that the process object will remain AND that
    the process id will not be reused AND that your handle and reference
    refer to the same process.

  3. For each handle in the process:
    3.1. Manually check that this is not a Kernel mode handle
    3.2 Duplicate the handle to the system process
    3.3 Reference the handle in the system process to get a pointer, be sure
    to specify the interesting object type (ObFileObjectType I think).
    3.4 Close the handle in the system process, this is your handle so you
    can always close it.
    3.5 Determine if the obtained object (FILE_OBJECT if that is what you
    specified) is of interest to you and then add it to your tables of live
    connections.
    3.6 If you have no other reason to hold on to the object, DeReference it.

  4. For the system process (Where everything runs in kernel mode anyway),
    just enumerate and Reference the handles directly. Keep or release
    references to the found objects, but don’t close any handles.

This does not involve attaching to processes and gives you a reference
that is all yours. This will not tell you what permissions are
associated with the FILE_OBJECT, but you may not need that information
for your purposes.

Closing the handle used by the original Application would be needed only
if you wanted to deliberately disrupt its operation. This will always
be subject to race conditions against other code (in the application or
elsewhere) also closing that handle, then opening another unrelated
handle by the same value. But if you really, really want to close a
handle in an uncooperative application, do this:

  1. Manually check that this is a user mode handle, not a kernel mode
    handle.
  2. Duplicate the handle to the system process, specifying the
    CLOSE_ON_DUP flag to ZwDuplicateHandle.
  3. Close the handle in the system process, this is your handle so you
    can always close it.

This does not have any internal races, just the external race that
you cannot be 100% sure what user mode handle you actually closed.


Jakob B?hm, M.Sc.Eng. * xxxxx@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right.
Information in this posting may not be the official position of Danware
Data A/S, only the personal opinions of the author.

This is a true masterpiece

[begin quote]

A safer approach is:

  1. Hook TDI

[end quote]

Objectively, hooking just cannot be safer that filtering. I did a lot of hooking myself when I was writing security software for Windows, but IN THIS CONTEXT hooking is really brain-dead approach, simply because everything you have described in your post can be done by a filter, so that you get quite a few things to worry about without ANY extra benefit.

In any case, your approach does not eliminate the possibility of race conditions …

Anton Bassov

xxxxx@hotmail.com wrote:

This is a true masterpiece

[begin quote]

A safer approach is:

  1. Hook TDI

[end quote]

Objectively, hooking just cannot be safer that filtering. I did a lot
of hooking myself when I was writing security software for Windows, but
IN THIS CONTEXT hooking is really brain-dead approach, simply because
everything you have described in your post can be done by a filter, so
that you get quite a few things to worry about without ANY extra benefit.

In this context I used hook as slang for “Install yourself as a filter
driver in the way you intend to do anyway”, but do so before enumerating
handles opened before your filter driver was installed. (The
enumeration is presumably done to avoid a reboot).

In any case, your approach does not eliminate the possibility of race
> conditions …
Which race conditions remain, other than the ones I explicitly listed,
plus the following:

  1. You enumerate handles of Process X past handle 1234
  2. Process X duplicates handle 45678 to 1234 and closes handle 45678
  3. Your enumeration continues past handle 45678 (which is not there)
    Result: Your enumeration missed the handle that used to be 45678 but is
    now 1234.

Catching such wandering handles is almost impossible without either

A) Using an entirely different mechanism for enumerating all the
FILE_OBJECTS connected to a specific TDI driver.
or
B) Using undocumented (and actively sabotaged) mechanisms to watch
all calls to ZwDuplicateHandle().

Anton Bassov


Jakob B?hm, M.Sc.Eng. * xxxxx@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right.
Information in this posting may not be the official position of Danware
Data A/S, only the personal opinions of the author.

I’m not sure that the close source option is safe if the source handle is protected. Any code leading to ObpCloseHandle running with the PreviousMode argument == KernelMode, on a handle that is protected willl result in an immediate bugcheck.

A cursory inspection reveals that as NtClose, NtDuplicateObject (ObDuplicateObject) will use ExGetPreviousMode() for that argument and is thus unsafe unless you are already operating with PreviousMode == UserMode and you use the Nt flavor and not the Zw flavor.

Bottom line, however, is that this is not something which you want to do in a shipping product.

  • S

-----Original Message-----
From: Jakob Bohm
Sent: Thursday, October 02, 2008 03:56
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

xxxxx@gmail.com wrote:
> I have the following problem:
>
> Given an object handle, an object pointer (pointer and handle refer to the same object), and the pid of the process that owns the handle, I want to be able to access the object pointer safely. Note that the object handle and pointer come from a call to ZwQuerySystemInformation(SystemHandleInformation), therefore they may refer to an object that does not exist anymore and the process with the given pid may not exist either.
>
> My current solution is as follows:
>
> 1. Get a handle to the owner process
> 2. Duplicate the handle into the current process
> 3. Call ObReferenceObjectByPointer using the originally supplied object pointer
>
> If all 3 steps succeed I assume that it is OK to use the object file pointer. Once I am done with the file pointer I clean by:
>
> 1. ObDereferenceObject on the object pointer
> 2. Close the duplicated handle (I have to play some tricks to make sure the handle can be closed)
> 3. Close the owner process handle
>
> This code ran successfully for several weeks until today. I got SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (STATUS_ACCESS_VIOLATION) when trying to perform step 1 of the dereferencing sequence. Here is the stack trace (obtained by “!analyze -v”):
>

A safer approach is:

1. Hook TDI so your driver will see any subsequent opens and closes.
Be prepared for the possibility that your enumeration may encounter
fresh connections also seen by your hooking, and the possibility that
your hooking may see the closing of a connection seen by your enumeration.

2. For each process other than System:
In the System process, obtain first a handle to the process, then
reference your handle to get a process reference. Hold on to both.
This way you can be sure that the process object will remain AND that
the process id will not be reused AND that your handle and reference
refer to the same process.

3. For each handle in the process:
3.1. Manually check that this is not a Kernel mode handle
3.2 Duplicate the handle to the system process
3.3 Reference the handle in the system process to get a pointer, be sure
to specify the interesting object type (ObFileObjectType I think).
3.4 Close the handle in the system process, this is your handle so you
can always close it.
3.5 Determine if the obtained object (FILE_OBJECT if that is what you
specified) is of interest to you and then add it to your tables of live
connections.
3.6 If you have no other reason to hold on to the object, DeReference it.

4. For the system process (Where everything runs in kernel mode anyway),
just enumerate and Reference the handles directly. Keep or release
references to the found objects, but don’t close any handles.

This does not involve attaching to processes and gives you a reference
that is all yours. This will not tell you what permissions are
associated with the FILE_OBJECT, but you may not need that information
for your purposes.

Closing the handle used by the original Application would be needed only
if you wanted to deliberately disrupt its operation. This will always
be subject to race conditions against other code (in the application or
elsewhere) also closing that handle, then opening another unrelated
handle by the same value. But if you really, really want to close a
handle in an uncooperative application, do this:

1. Manually check that this is a user mode handle, not a kernel mode
handle.
2. Duplicate the handle to the system process, specifying the
CLOSE_ON_DUP flag to ZwDuplicateHandle.
3. Close the handle in the system process, this is your handle so you
can always close it.

This does not have any internal races, just the external race that
you cannot be 100% sure what user mode handle you actually closed.


Jakob B?hm, M.Sc.Eng. * xxxxx@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right.
Information in this posting may not be the official position of Danware
Data A/S, only the personal opinions of the author.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Yes, however stack attach avoids the possibility of an immediate bugcheck at the hands of a malicious user mode app.

Regardless, this is not a production code worthy technique.

  • S

-----Original Message-----
From: xxxxx@hotmail.com
Sent: Thursday, October 02, 2008 01:29
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

> how I could attach to a given process from within a driver

KeStackAttachProcess(), but this is not going to help either - just consider what happens if the target process closes the handle. I am afraid you are totally out of luck here - this is the situation when you are playing with someone else’s resource without its owner’s knowledge, and it just cannot be done safely…

> What I am trying to achieve is to enumerate all TDI address/connection objects at the time
> my TDI filter driver is installed.

It cannot be reliably done for the reasons mentioned above. All info that you get is valid at the moment it is being collected, but there is no guarantee it will still be valid by the time you decide to make any use of it… This is why you should not make any use of this info - it is meant to be used only for the statistical purposes…

Anton Bassov


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

I should also note that even issuing these calls with PreviousMode set to UserMode is not without consequence, as attempting to reference a bad handle may result in an arrangement to raise either STATUS_HANDLE_NOT_CLOSABLE (I think), or STATUS_INVALID_HANDLE (depending on debugging flags) in the user mode caller on return to user mode. This will probably break the user mode app.

(No idea what happens if you were to cause such a situation from a system process with no full user mode context, but it is likely not going to be a desirable behavior.)

These techniques may work for lab programs or apps like ProcExp, but you really do not want to use them in a production driver.

  • S

-----Original Message-----
From: Skywing
Sent: Thursday, October 02, 2008 09:05
To: Windows System Software Devs Interest List
Subject: RE: Re:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

I’m not sure that the close source option is safe if the source handle is protected. Any code leading to ObpCloseHandle running with the PreviousMode argument == KernelMode, on a handle that is protected willl result in an immediate bugcheck.

A cursory inspection reveals that as NtClose, NtDuplicateObject (ObDuplicateObject) will use ExGetPreviousMode() for that argument and is thus unsafe unless you are already operating with PreviousMode == UserMode and you use the Nt flavor and not the Zw flavor.

Bottom line, however, is that this is not something which you want to do in a shipping product.

- S

-----Original Message-----
From: Jakob Bohm
Sent: Thursday, October 02, 2008 03:56
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

xxxxx@gmail.com wrote:
> I have the following problem:
>
> Given an object handle, an object pointer (pointer and handle refer to the same object), and the pid of the process that owns the handle, I want to be able to access the object pointer safely. Note that the object handle and pointer come from a call to ZwQuerySystemInformation(SystemHandleInformation), therefore they may refer to an object that does not exist anymore and the process with the given pid may not exist either.
>
> My current solution is as follows:
>
> 1. Get a handle to the owner process
> 2. Duplicate the handle into the current process
> 3. Call ObReferenceObjectByPointer using the originally supplied object pointer
>
> If all 3 steps succeed I assume that it is OK to use the object file pointer. Once I am done with the file pointer I clean by:
>
> 1. ObDereferenceObject on the object pointer
> 2. Close the duplicated handle (I have to play some tricks to make sure the handle can be closed)
> 3. Close the owner process handle
>
> This code ran successfully for several weeks until today. I got SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (STATUS_ACCESS_VIOLATION) when trying to perform step 1 of the dereferencing sequence. Here is the stack trace (obtained by “!analyze -v”):
>

A safer approach is:

1. Hook TDI so your driver will see any subsequent opens and closes.
Be prepared for the possibility that your enumeration may encounter
fresh connections also seen by your hooking, and the possibility that
your hooking may see the closing of a connection seen by your enumeration.

2. For each process other than System:
In the System process, obtain first a handle to the process, then
reference your handle to get a process reference. Hold on to both.
This way you can be sure that the process object will remain AND that
the process id will not be reused AND that your handle and reference
refer to the same process.

3. For each handle in the process:
3.1. Manually check that this is not a Kernel mode handle
3.2 Duplicate the handle to the system process
3.3 Reference the handle in the system process to get a pointer, be sure
to specify the interesting object type (ObFileObjectType I think).
3.4 Close the handle in the system process, this is your handle so you
can always close it.
3.5 Determine if the obtained object (FILE_OBJECT if that is what you
specified) is of interest to you and then add it to your tables of live
connections.
3.6 If you have no other reason to hold on to the object, DeReference it.

4. For the system process (Where everything runs in kernel mode anyway),
just enumerate and Reference the handles directly. Keep or release
references to the found objects, but don’t close any handles.

This does not involve attaching to processes and gives you a reference
that is all yours. This will not tell you what permissions are
associated with the FILE_OBJECT, but you may not need that information
for your purposes.

Closing the handle used by the original Application would be needed only
if you wanted to deliberately disrupt its operation. This will always
be subject to race conditions against other code (in the application or
elsewhere) also closing that handle, then opening another unrelated
handle by the same value. But if you really, really want to close a
handle in an uncooperative application, do this:

1. Manually check that this is a user mode handle, not a kernel mode
handle.
2. Duplicate the handle to the system process, specifying the
CLOSE_ON_DUP flag to ZwDuplicateHandle.
3. Close the handle in the system process, this is your handle so you
can always close it.

This does not have any internal races, just the external race that
you cannot be 100% sure what user mode handle you actually closed.


Jakob B?hm, M.Sc.Eng. * xxxxx@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right.
Information in this posting may not be the official position of Danware
Data A/S, only the personal opinions of the author.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> stack attach avoids the possibility of an immediate bugcheck at the hands of a malicious user mode app.

Why is that??? If an app closes a handle before you try to reference it in context of a right process, you are going to reference the invalid handle anyway. Please note that the above does not mean that app’s code is malicious - it just performs its normal operations, and it has no idea of some “third party” trying to make use of handles that it had opened …

Anton Bassov

Referencing a nonexistent handle with ObReferenceObjectByHandle (or a handle of the wrong type, if you supply a POBJECT_TYPE, or of the wrong access rights, if you supply DesiredAccess and set AccessMode to UserMode) will simply result in the call failing, which can be handled gracefully. Such a failure has no other side effects other than gracefully failing. This is the normal mechanism by which a kernel mode program can accept a handle supplied from user mode.

Passing an invalid or protected handle to NtClose or NtDuplicateObject (with the close source option set) will either bugcheck the system (if PreviousMode was KernelMode), or will cause a user mode exception to be raised on return to user mode (always; if the handle was protected, and sometimes; if the handle was plain invalid). These calls have side effects that are difficult to cope with, and are not designed to be used to support the case of a kernel mode caller attempting to close a user mode handle (that is, a handle not in the kernel handle table, or not in the system handle table, i.e. a handle that a user mode program could manipulate).

To summarize, though:

  • There are well defined interfaces to safely attempt to reference a user mode supplied handle and capture the object referenced by the handle, assuming you use the API correctly and do not disable the required validation.

  • As far as I know, however, there aren’t any well defined interfaces to safely close an arbitrary handle that can be manipulated on the fly by user mode, except when you are going to return to user mode afterwards and are running in response to a user mode request whose only purpose is to close a particular handle, where the user mode caller is prepared to handle an SEH exception being raised immediately upon the return to user mode.

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Thursday, October 02, 2008 10:32 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

stack attach avoids the possibility of an immediate bugcheck at the hands of a malicious user mode app.

Why is that??? If an app closes a handle before you try to reference it in context of a right process, you are going to reference the invalid handle anyway. Please note that the above does not mean that app’s code is malicious - it just performs its normal operations, and it has no idea of some “third party” trying to make use of handles that it had opened …

Anton Bassov


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> Referencing a nonexistent handle with ObReferenceObjectByHandle

(or a handle of the wrong type, if you supply a POBJECT_TYPE, or of the wrong access rights,
if you supply DesiredAccess and set AccessMode to UserMode) will simply result in the call failing,
which can be handled gracefully.

I am not so sure about that -IIRC, I bugchecked on more that one occasion because of the wrong parameters that I was passing to ObReferenceObjectByHandle() For example, IIRC, passing NULL for POBJECT_TYPE is going to the “job” just fine, although I am not sure invalid handle will cause the same results…

Anton Bassov

Think about the situation logically. If what you’re saying is true, how is any kernel mode code ever able to reference any handled supplied by an untrusted (user mode) source without risking bringing down the system in the face of a malicious user mode caller?

Certainly, you can misuse the API and bugcheck as a result of that. In order to safely “probe” a user mode handle, and “capture” the object backing the handle, you must use AccessMode == KernelMode, you must supply a valid (non-NULL) ObjectType, and you must supply a correct DesiredAccess rights mask. Otherwise, user mode can trick you into using a handle that does not match the requirements of your program.

However, if you take advantage of the API’s validation capabilities, and you use the returned object pointer correctly, then you’re fine. ObReferenceObjectByHandle will perform the necessary handle validity, granted access, and object type matching checks atomically with respect to the handle table in question.

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Thursday, October 02, 2008 11:09 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

Referencing a nonexistent handle with ObReferenceObjectByHandle
(or a handle of the wrong type, if you supply a POBJECT_TYPE, or of the wrong access rights,
if you supply DesiredAccess and set AccessMode to UserMode) will simply result in the call failing,
which can be handled gracefully.

I am not so sure about that -IIRC, I bugchecked on more that one occasion because of the wrong parameters that I was passing to ObReferenceObjectByHandle() For example, IIRC, passing NULL for POBJECT_TYPE is going to the “job” just fine, although I am not sure invalid handle will cause the same results…

Anton Bassov


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Sorry, that should read:

You must use AccessMode == UserMode.

(Insufficient caffine error.)

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Skywing
Sent: Thursday, October 02, 2008 11:14 AM
To: Windows System Software Devs Interest List
Subject: RE: RE:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

Think about the situation logically. If what you’re saying is true, how is any kernel mode code ever able to reference any handled supplied by an untrusted (user mode) source without risking bringing down the system in the face of a malicious user mode caller?

Certainly, you can misuse the API and bugcheck as a result of that. In order to safely “probe” a user mode handle, and “capture” the object backing the handle, you must use AccessMode == KernelMode, you must supply a valid (non-NULL) ObjectType, and you must supply a correct DesiredAccess rights mask. Otherwise, user mode can trick you into using a handle that does not match the requirements of your program.

However, if you take advantage of the API’s validation capabilities, and you use the returned object pointer correctly, then you’re fine. ObReferenceObjectByHandle will perform the necessary handle validity, granted access, and object type matching checks atomically with respect to the handle table in question.

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Thursday, October 02, 2008 11:09 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

Referencing a nonexistent handle with ObReferenceObjectByHandle
(or a handle of the wrong type, if you supply a POBJECT_TYPE, or of the wrong access rights,
if you supply DesiredAccess and set AccessMode to UserMode) will simply result in the call failing,
which can be handled gracefully.

I am not so sure about that -IIRC, I bugchecked on more that one occasion because of the wrong parameters that I was passing to ObReferenceObjectByHandle() For example, IIRC, passing NULL for POBJECT_TYPE is going to the “job” just fine, although I am not sure invalid handle will cause the same results…

Anton Bassov


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> Think about the situation logically. If what you’re saying is true, how is any kernel mode code

ever able to reference any handled supplied by an untrusted (user mode) source without
risking bringing down the system in the face of a malicious user mode caller?

Well, kernel code has several layers, don’t you think…

Only the topmost layer (i.e. functions exported via SSDT) is supposed to receive anything from the UM - the rest is supposed to deal already with the trusted stuff. IIRC, validation is being done by Zw… calls when PreviousMode==UserMode, but by the time execution flow reaches kernel exports that are designed for use only by kernel-level clients (i.e. like Ke, Mm. etc), all parameters are already supposed to be validated.

Your logic applies only to the topmost layer, but here we are speaking about the function that is supposed to be called only by the KM code. Therefore, I don’t exclude the possibility that ObReferenceObjectByHandle() expects everything to be validated in advance…

Anton Bassov

ObReferenceObjectByHandle is documented for use by drivers that receive their own data from an untrusted source, e.g. via IOCTLs or whatnot. For example, see the “event” sample included with the latest WDK.

The AccessMode argument makes the routine flexibly “previous-mode-agnostic”, so long as you supply the correct KPROCESSOR_MODE.

The documentation for the routine states:

“The ObReferenceObjectByHandle routine provides access validation on the object handle, and, if access can be granted, returns the corresponding pointer to the object’s body.”

Additionally, all of the internal callers that must translate an untrusted handle to an object pointer use the routine. The function is part of the validation mechanisms available to deal safely with untrusted data.

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Thursday, October 02, 2008 11:34 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Problems with ObReferenceObject and ObDerefenceObject

Think about the situation logically. If what you’re saying is true, how is any kernel mode code
ever able to reference any handled supplied by an untrusted (user mode) source without
risking bringing down the system in the face of a malicious user mode caller?

Well, kernel code has several layers, don’t you think…

Only the topmost layer (i.e. functions exported via SSDT) is supposed to receive anything from the UM - the rest is supposed to deal already with the trusted stuff. IIRC, validation is being done by Zw… calls when PreviousMode==UserMode, but by the time execution flow reaches kernel exports that are designed for use only by kernel-level clients (i.e. like Ke, Mm. etc), all parameters are already supposed to be validated.

Your logic applies only to the topmost layer, but here we are speaking about the function that is supposed to be called only by the KM code. Therefore, I don’t exclude the possibility that ObReferenceObjectByHandle() expects everything to be validated in advance…

Anton Bassov


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

xxxxx@hotmail.com wrote:

Your logic applies only to the topmost layer, but here we are speaking about the function that is supposed to be called only by the KM code. Therefore, I don’t exclude the possibility that ObReferenceObjectByHandle() expects everything to be validated in advance…

Example: usermode app passes you event handle in ioctl buffer. Then you
call KeSetEvent on that event. Who will validate the handle?

–PA

> -----Original Message-----

From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Thursday, October 02, 2008 4:11 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Problems with ObReferenceObject and
ObDerefenceObject

Michal, I can see the race condition you mentioned. Would
changing 3 to: ObReferenceObjectByHandle(duplicated object
handle) fix the problem?

It would fix the mentioned race conditions but don’t fix a problem when
app closes the original handle and opens new one. You’d reference valid
handle but different from your expectations.

If you have TDI filter driver it should be sufficient to load it before
any handle is opened. IIRC tdi.sys loads soon in boot process so it
should be possible. If the problem is your software installation, just
request reboot.

Also, in my case, it seems that the
referencing part succeeded, it was the dereferencing part that failed.

If you reference invalid object, problem can occur in deference part
which touches invalid pointer in an attempt to free it. I can’t tell if
it is the case but I saw such scenarios.

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]