Figuring our RootObject

Hi everyone,

I’ve been trying to figure out how to decipher the RootObject on XP RegNtPostCreateKey. Based on what I’ve read here, it seems that I’m suppose to use ObOpenObjectByPointer but I’m getting an 0xC0000005 calling it.

Can someone see the error in my ways?

NTSTATUS HandleRegNtPostCreateOpenKey(IN PVOID pCallbackContext, IN PVOID Argument1, IN PVOID pArgument2)
{
NTSTATUS status = STATUS_SUCCESS;
__try
{
REG_CREATE_KEY_INFORMATION * pRS = (REG_CREATE_KEY_INFORMATION *) pArgument2;
BOOLEAN bDeny = FALSE;

if ((pRS->CompleteName->Length > 0) && (pRS->CompleteName->Buffer[0] == ‘\’))
{
DbgPrint(“Full key %wZ\n”, pRS->CompleteName);
return STATUS_SUCCESS;
}

if (pRS->RootObject != 0)
{
HANDLE keyHandle;

DbgPrint(“0\n”);
status = ObOpenObjectByPointer(pRS->RootObject, 0, NULL, 0, NULL, KernelMode, &keyHandle);
DbgPrint(“1\n”);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
NTSTATUS exStatus = GetExceptionCode();
DbgPrint(“HandleRegNtPostCreateOpenKey Exception 0x%X\n”, exStatus);
}

Output:
Full key \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Print\Providers
Full key \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Print\Providers
0
HandleRegNtPostCreateOpenKey Exception 0xC0000005
0
HandleRegNtPostCreateOpenKey Exception 0xC0000005

I’ve also tried to use ObQueryNameString directly, but that bugchecks.

While I would LOVE to use the newer structures, 72% of our customer base is running XP.

Any help would be greatly appreciated.

thanks,

Gene

On 9/20/2010 7:04 PM, xxxxx@bystormsoftware.com wrote:

if (pRS->RootObject != 0)
{
HANDLE keyHandle;

DbgPrint(“0\n”);
status = ObOpenObjectByPointer(pRS->RootObject, 0, NULL, 0, NULL, KernelMode,&keyHandle);
DbgPrint(“1\n”);
}

Try specifying OBJ_KERNEL_HANDLE as the second parameter.

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

Structure “REG_CREATE_KEY_INFORMATION”, that you are using, is not
available on XP. The structure that belongs to callback “RegNtPostCreateKey”
is “REG_POST_CREATE_KEY_INFORMATION”, which has no support for root object:

typedef struct _REG_POST_CREATE_KEY_INFORMATION {
PUNICODE_STRING CompleteName;
PVOID Object;
NTSTATUS Status;
} REG_POST_CREATE_KEY_INFORMATION, *PREG_POST_CREATE_KEY_INFORMATION;

Unfortunately, registry callbacks are *very* limited on XP.

wrote news:xxxxx@ntdev…
> Hi everyone,
>
> I’ve been trying to figure out how to decipher the RootObject on XP
> RegNtPostCreateKey. Based on what I’ve read here, it seems that I’m
> suppose to use ObOpenObjectByPointer but I’m getting an 0xC0000005 calling
> it.
>
> Can someone see the error in my ways?
>
> NTSTATUS HandleRegNtPostCreateOpenKey(IN PVOID pCallbackContext, IN PVOID
> Argument1, IN PVOID pArgument2)
> {
> NTSTATUS status = STATUS_SUCCESS;
> __try
> {
> REG_CREATE_KEY_INFORMATION * pRS = (REG_CREATE_KEY_INFORMATION *)
> pArgument2;
> BOOLEAN bDeny = FALSE;
>
> if ((pRS->CompleteName->Length > 0) && (pRS->CompleteName->Buffer[0] ==
> ‘\’))
> {
> DbgPrint(“Full key %wZ\n”, pRS->CompleteName);
> return STATUS_SUCCESS;
> }
>
> if (pRS->RootObject != 0)
> {
> HANDLE keyHandle;
>
> DbgPrint(“0\n”);
> status = ObOpenObjectByPointer(pRS->RootObject, 0, NULL, 0, NULL,
> KernelMode, &keyHandle);
> DbgPrint(“1\n”);
> }
>__except(EXCEPTION_EXECUTE_HANDLER)
> {
> NTSTATUS exStatus = GetExceptionCode();
> DbgPrint(“HandleRegNtPostCreateOpenKey Exception 0x%X\n”, exStatus);
> }
>
> Output:
> Full key \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Print\Providers
> Full key \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Print\Providers
> 0
> HandleRegNtPostCreateOpenKey Exception 0xC0000005
> 0
> HandleRegNtPostCreateOpenKey Exception 0xC0000005
>
> I’ve also tried to use ObQueryNameString directly, but that bugchecks.
>
> While I would LOVE to use the newer structures, 72% of our customer base
> is running XP.
>
>
> Any help would be greatly appreciated.
>
> thanks,
>
> Gene
>

Thanks Frank, I switched the structure and tried to use the Object instead of RootObject.

Both ObQueryNameString and ObOpenObjectByPointer and both bugcheck.

According to http://www.osronline.com/ShowThread.cfm?link=150144 it appears that the recommend way on XP is to patch the ZwXXXX apis, which I don’t want to do (never done that at the kernel level)

I’m picking up the Pre-Open operation, which has the full path but it appears that the registry context operations didn’t show up until 2003 or Vista.

The post_Create doesn’t seem to be of much value if you can’t figure out what registry key is being operated on.

Any other advice?

On 9/21/2010 6:32 AM, xxxxx@bystormsoftware.com wrote:

Thanks Frank, I switched the structure and tried to use the Object instead of RootObject.

Both ObQueryNameString and ObOpenObjectByPointer and both bugcheck.

Using ObOpenObjectByPointer in post-create/open and specifying
OBJ_KERNEL_HANDLE and KernelMode works fine, this is exactly what I
implement in several implementations. In the pre operation just use the
full path.

According to http://www.osronline.com/ShowThread.cfm?link=150144 it appears that the recommend way on XP is to patch the ZwXXXX apis, which I don’t want to do (never done that at the kernel level)

Right, in XP you have minimal control and, I hate saying this, the best
way to implement registry filtering is to patch the Zw API set for
registry access.

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

Still no joy.

HANDLE keyHandle;
DbgPrint(“0\n”);
status = ObOpenObjectByPointer(pRS->Object, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &keyHandle);
DbgPrint(“1\n”);

I never see the ‘1’ and the exception catch reports a 0XC0000005.

I tried to dereference the pRS->Object based on the 150144 thread, but that BugChecked on me.

I suppose I’m going to have to figure out how to patch the routines…which seem like overkill for a single call on an old OS.

Gene, small pitfall I should have mentioned: you’ll have to deref the
Object-Pointer. Try it like this:

status = ObOpenObjectByPointer((void*)(*(PUINT_PTR)pRS->Object), …

wrote news:xxxxx@ntdev…
> Still no joy.
>
> HANDLE keyHandle;
> DbgPrint(“0\n”);
> status = ObOpenObjectByPointer(pRS->Object, OBJ_KERNEL_HANDLE, NULL,
> 0, NULL, KernelMode, &keyHandle);
> DbgPrint(“1\n”);
>
> I never see the ‘1’ and the exception catch reports a 0XC0000005.
>
> I tried to dereference the pRS->Object based on the 150144 thread, but
> that BugChecked on me.
>
> I suppose I’m going to have to figure out how to patch the
> routines…which seem like overkill for a single call on an old OS.
>

Thank you Frank…your magic dereference code did the trick.
Now, to see how it works on the other OSs.

Hello again,

I’ve moved on to 2003 and trying to get the key string in the PostOpenCreateEx.

I’m getting a status of 0xC0000008 (STATUS_INVALID_HANDLE) when I query the passed in object.

I’m guessing the problem is that I’m using ZWQueryKey and the object is in user mode so I should be using NtQueryKey instead…but for the life of me I can’t find a NtQueryKey prototype that the compiler likes.

Here is the prototype that I’m trying to use:
NTSYSAPI NTSTATUS NtQueryKey(HANDLE, KEY_INFORMATION_CLASS, PVOID, ULONG, ULONG *);

If it isn’t a user space problem, does my ZwQueryKey look right?

REG_POST_OPERATION_INFORMATION * pPOI = (PREG_POST_OPERATION_INFORMATION) pArgument2;
REG_CREATE_KEY_INFORMATION * pRS = (PREG_CREATE_KEY_INFORMATION) pPOI->Object;
KEY_NAME_INFORMATION kni;
ULONG retLen = 0;
HANDLE h = 0;
if (FAILED(pPOI->Status))
{…}
h = *((PHANDLE) pPOI->Object);
status = ZwQueryKey(h, KeyNameInformation, &kni, sizeof(kni), &retLen);

Sorry for asking such a simple question, but sometime it’s like I fight the tool more than actually write code.

Thank you again,

Gene

wrote in message news:xxxxx@ntdev…
> Hello again,
>
> I’ve moved on to 2003 and trying to get the key string in the
> PostOpenCreateEx.
>
> I’m getting a status of 0xC0000008 (STATUS_INVALID_HANDLE) when I query
> the passed in object.
>
> I’m guessing the problem is that I’m using ZWQueryKey and the object is in
> user mode so I should be using NtQueryKey instead…but for the life of
> me I can’t find a NtQueryKey prototype that the compiler likes.
>
> Here is the prototype that I’m trying to use:
> NTSYSAPI NTSTATUS NtQueryKey(HANDLE, KEY_INFORMATION_CLASS, PVOID, ULONG,
> ULONG *);
>
> If it isn’t a user space problem, does my ZwQueryKey look right?
>
> REG_POST_OPERATION_INFORMATION * pPOI =
> (PREG_POST_OPERATION_INFORMATION) pArgument2;
> REG_CREATE_KEY_INFORMATION * pRS = (PREG_CREATE_KEY_INFORMATION)
> pPOI->Object;
> KEY_NAME_INFORMATION kni;
> ULONG retLen = 0;
> HANDLE h = 0;
> if (FAILED(pPOI->Status))
> {…}
> h = *((PHANDLE) pPOI->Object);
> status = ZwQueryKey(h, KeyNameInformation, &kni, sizeof(kni), &retLen);

In the code above:[h = *((PHANDLE) pPOI->Object);]
Object pointers are not handles. To use a function that needs a handle,
get the handle
using ObOpenObjectByPointer. Then, you can get a kernel mode handle (by
specifying AccessMode = KernelMode)
so ZwQueryKey will work.

– pa

>
> Sorry for asking such a simple question, but sometime it’s like I fight
> the tool more than actually write code.
>
> Thank you again,
>
> Gene
>

Thank you Pavel, but I’m getting a STATUS_ACCESS_DENIED for a while then a page fault BSOD.

Is my ObOpenObjectByPointer wrong?

here is the new code.

status = ObOpenObjectByPointer(pPOI->Object, OBJ_KERNEL_HANDLE , NULL, 0, 0, KernelMode, &h);
if((!NT_SUCCESS(status)) || (!h))
{
ObDereferenceObject(pPOI->Object);
DbgPrint(“ObOpenObjectByPointer failed pPOI->Status 0x%X Status 0x%X\n”, pPOI->Status, status);
return STATUS_SUCCESS;
}

pKni = (PKEY_NAME_INFORMATION) ExAllocatePoolWithTag(NonPagedPool, 1024, ‘HKEY’);
status = ZwQueryKey(h, KeyNameInformation, pKni, sizeof(1024), &retLen);
ZwClose(h);
ExFreePoolWithTag(pKni, ‘HKEY’);

Hmm. sizeof(1024) ?
When you get BSOD, what it is?
No pass again. Go learn C. Sorry :frowning:
–pa

opps! I’m going to go sit in the corner now.
I’m getting a PAGE_FAULT_IN_NONPAGED_AREA;

I’ve tracked it down to somewhere in here…
status = ObOpenObjectByPointer(pPOI->Object, OBJ_KERNEL_HANDLE , NULL, 0, 0, KernelMode, &h);
if (FAILED(status))
{
DbgPrint(“ObOpenObjectByPointer failed pPOI->Status 0x%X Status 0x%X\n”, pPOI->Status, status);
return STATUS_SUCCESS;
}
ZwClose(h);
return STATUS_SUCCESS;

I’m guessing that the pPOI->Object isn’t valid or something, but the status isn’t failing.

Pavel, thank you for all your help with my attempts to get this working.

I found the error in my ways.
REG_POST_OPERATION_INFORMATION * pPOI = (PREG_POST_OPERATION_INFORMATION)
–> if (FAILED(pPOI->Status))

I ASSUMED that if the Status wasn’t a failed code, the pointer was good. Bad assumption.
A simple test of a non-null object and all is good.

Thank you again for help. :slight_smile:

wrote in message news:xxxxx@ntdev…
> I found the error in my ways.
> REG_POST_OPERATION_INFORMATION * pPOI =
> (PREG_POST_OPERATION_INFORMATION)
> –> if (FAILED(pPOI->Status))
>
> I ASSUMED that if the Status wasn’t a failed code, the pointer was good.
> Bad assumption.
> A simple test of a non-null object and all is good.
>
> Thank you again for help. :slight_smile:

Great, but next time when you get a BSOD be sure to include
a relevant portion of !analyse decode, at very least, the parameters of the
bugcheck. Ok?
– pa

Yes sir!
I didn’t want to bother anyone with a bugcheck when I’m sure that I was just doing things wrong.

What I need is on Windows 2003, the full key in the PostCreateOpenKeyEx, if I do

status = ZwQueryKey(h, KeyBasicInformation, pKi, 1024, &retLen);

everything works but I get the relative key name (e.g. ‘TPAutoConnect’) instead of the full key (e.g. ‘HKEY_CURRENT_USER\Software\ThinPrint\TPAutoConnect’)

if I use
status = ZwQueryKey(h, KeyFullInformation, pKi, 1024, &retLen);
all I get is STATUS_ACCESS_DENIED for a status.

With your help I was able to get the PostOpen to work on XP and on Vista and later things, are MUCH nicer, but 2003 only gives me the REG_POST_OPERATION_INFORMATION with only has 2 fields on Windows 2003.

Any guidance on why I getting a STATUS_ACCESS_DENIED while trying to do KeyFullInformation, but no problems when using KeyBasicInformation?

My own registry monitoring work on NT5.x systems was based on SSDT hooking (ugh!) , so I do not know whether the object that you get in PostCreateOpenKey callback works well with ZwQueryKey(h, KeyFullInformation …). Maybe others can comment on this.
But on Vista SP2 and Win7 KeyFullInformation definitely used to work.
Check your code, there may still be errors; it happens.

Good luck.
– pa