More on callbacks: ObRegisterCallbacks

Today is ObRegisterCallbacks‘s turn: available since Vista SP1, permits to “register a list of callback routines for thread and process handle operations”. Together with the last blog from Zairon should cover the main callbacks.

After a few checks on the parameters passed the function iterates over the Operations array, checking that every entry (of type OB_OPERATION_REGISTRATION) satisfies these conditions:

  • at least one of the operations is not NULL
  • if one of the ops is not NULL it is checked with MmVerifyCallbackFunction. This function verifies that the address of the function belongs to a signed driver, as documented here (together with how to bypass that check :>).
  • check that the ObjectType for the operation supports the callbacks: SupportsObjectCallbacks (40h) must be set in ObjectType.TypeInfo.ObjectTypeFlags

On Windows 7 x86 I’ve checked the other nt!*ObjectType to see if there were other not officially supported object types but didn’t find any.

If all the checks have been successfully passed, a CALLBACK_ENTRY structure is filled with all the information and passed along with ObjectType to ObpInsertCallbackByAltitude.

+000 LIST_ENTRY CallbackList
+008 OB_OPERATION  Operations
+00C ULONG Active // set to 1 after all the callbacks have been successfully inserted
+010 OB_HANDLE Handle
+014 POBJECT_TYPE ObjectType
+020 ULONG unknown

ObpInsertCallbackByAltitude, as the name suggests, will link the CALLBACK_ENTRY in ObjectType.CallbackList.
When all the callbacks have been inserted a RegistrationHandle (OB_HANDLE) is returned:

+000  WORD Version
+002  WORD OperationRegistrationCount
+004  PVOID RegistrationContext
+008  UNICODE_STRING Altitude
+010  CALLBACK_ENTRY entries[1] // array of OperationRegistrationCount entries

At this point the registration is complete.

An alternative system to bypass MmVerifyCallbackFunction could be to have the pre/post function point to an address inside a signed driver (basically the address of a xor eax,eax retn 8 gadget), and changing the address back to our function after the registration.

So now we can list the callbacks for a given object type and eventually hijack them if you don’t feel like registering your own. Two more questions are left: where are the callbacks called ? and can we enable more object types ?

The first is easily answered placing a breakpoint on the pre/post function and inspecting the call stack: the callbacks are called by ObpCreateHandle and ObDuplicateHandle, as expected, respectively through ObpPreInterceptHandleCreate and ObpPreInterceptHandleDuplicate

As for the second question, we know which bit to change so let’s do it and see if it works even if that is not a definitive guarantee it will always work (meaning: use at your own risk!).

EnableObType(POBJECT_TYPE ObjectType)
	PMY_OBJECT_TYPE myobtype = (PMY_OBJECT_TYPE)ObjectType;
	myobtype->TypeInfo.SupportsObjectCallbacks = 1;

I tested it with IoFileObjectType and looks good!

[PRE] object:8CFA4220 access:100080 file:\Users\PCNAME\Desktop\obtest.sys
[PRE] object:8CFA4220 access:100080 file:\Users\PCNAME\Desktop\obtest.sys
[PRE] object:8CFA4220 access:100080 file:\Users\PCNAME\Desktop\obtest.sys
[PRE] object:8CFA4220 access:100080 file:\Users\PCNAME\Desktop\obtest.sys
[PRE] object:8BBD42C8 access:100001 file:\Windows\Temp
[PRE] object:8BBD42C8 access:100001 file:\Windows
[PRE] object:8BBD42C8 access:100001 file:\
[PRE] object:8CFA4220 access:13019F file:\Windows\Temp\TMP00000307CD5B57B5F20A8716
[PRE] object:8D321340 access:100080 file:\Users\PCNAME\Desktop\obtest.sys
[PRE] object:8D3155B8 access:120089 file:\Users\PCNAME\Desktop\obtest.sys
[PRE] object:8D29E6B8 access:120089 file:\Windows\Prefetch\
[PRE] object:8D29E6B8 access:12019F file:\Windows\Prefetch\
[PRE] object:8B591228 access:100001 file:\Users\PCNAME\AppData\Local\Opera\Opera\mail

and that’s it, here’s the code, have fun!

posted in callbacks, internals, kernel by swirl

6 Comments to "More on callbacks: ObRegisterCallbacks"

  1. s4tan wrote:

    As always great post :)

    there is a little typo in the link to

  2. swirl wrote:

    thanks and fixed :)

  3. mj0011 wrote:

    the newest version of sandboxie has already use this tech to filter file/token/section/…..

  4. swirl wrote:

    the must be stable enough to use in production :)
    Don’t know why Microsoft didn’t enable other object types..

  5. Dmitry Varshavsky wrote:

    Unknown field is EX_RUNDOWN_REF used to wait for all callback function to be finished before ObUnRegisterCallbacks returns.
    Also, callbacks can be inserted by hand without calling any api and fooling MmVerifyCallbackFunction ( DKOM : ObjectType -> CallbackList and ObjectType -> TypeLock for synchronization ).
    Reverse deeper :)
    But still nice.

  6. swirl wrote:

    thanks for the unknown field :) Sure there are several ways to bypass MmVerifyCallbackFunction, also passing the address of a xor eax, eax retn 8 gadget inside some verified driver and then changing the address in the CallbackList later to the real function.

Copyright (c) 2010-2011 InREVERSE - All Right Reserved
Büyükçekmece Evden Eve Nakliyat Esenler Evden Eve Nakliyat Gaziosmanpasa Evden Eve Nakliyat Güngören Evden Eve Nakliyat Kadiköy Evden Eve Nakliyat Kartal Evden Eve Nakliyat Küçükçekmece Evden Eve Nakliyat Maltepe EvdenEve Nakliyat Sisli Evden Eve Nakliyat Tuzla Evden Eve Nakliyat Ümraniye Evden Eve Nakliyat Üsküdar Evden Eve Nakliyat Içerenköy Evden Eve Nakliyat Erenköy Nakliyat Etiler Evden Eve Nakliyat