Hooking NtCreateKey and NtOpenKey crash explorer

c++ / delphi package - dll injection and api hooking
Post Reply
softtouch
Posts: 111
Joined: Sat Jun 20, 2009 10:08 am
Contact:

Hooking NtCreateKey and NtOpenKey crash explorer

Post by softtouch »

I hooked until now RegCreateKey and other regxxx api;s, which worked, but they can't catch all key creations, so I decided to hook NtCreateKey/NtOpenKey.

NtCreateKey send an ipc message to the main whenever it is called, but that never happen...?
No hooking issue, no freezing, but no IPC message arrives too...

NtOpenKey crash explorer when I hook it,without anything in the callback, just calling the next hook.

Can I NOT send IPC messages within them?

Hooking:
HookAPI('ntdll.dll', 'NtCreateKey',@NtCreateKeyCallback,@NtCreateKeyNext);
HookAPI('ntdll.dll', 'NtOpenKey', @NtOpenKeyCallback,@NtOpenKeyNext);

Callback:
function NtCreateKeyCallback(var KeyHandle: THandle; DesiredAccess: ULONG; var ObjectAttributes: OBJECT_ATTRIBUTES; TitleIndex: ULONG; Class_:PUNICODE_STRING; CreateOptions: ULONG; var Disposition: ULONG): NTSTATUS; stdcall;
var
pi:TRegData;
begin
lstrcpyA(pi.subkey,pchar(WideToAnsiEx(ObjectAttributes.ObjectName.Buffer)));
SendIpcMessage(pchar('ProtexProc'),@pi,sizeOf(pi),@result,sizeOf(result));
result:=NtCreateKeyNext(KeyHandle,DesiredAccess,ObjectAttributes,TitleIndex,Class_,CreateOptions,Disposition);
end;

function NtOpenKeyCallback(var KeyHandle:THandle;DesiredAccess: ULONG;var ObjectAttributes: OBJECT_ATTRIBUTES): NTSTATUS; stdcall;
begin
result:=NtOpenKeyNext(KeyHandle,DesiredAccess,ObjectAttributes);
end;
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

How does your NtOpenKeyNext definition look like?

Sending IPC messages for every NtOpenKey/NtCreateKey call is probably too much. IPC works well, but it's not really fast. You should try to filter and only send notifications about events that are really important, or else you might slow down the PC too much.
softtouch
Posts: 111
Joined: Sat Jun 20, 2009 10:08 am
Contact:

Post by softtouch »

NtOpenKeyNext:function(var KeyHandle:THandle;DesiredAccess: ULONG;var ObjectAttributes: OBJECT_ATTRIBUTES): NTSTATUS; stdcall;

is the NtOpenKeyNext definition.

I filter out important keys, I just minimized the code to figure out whats wrong, and now its just a "skeleton", and it still crash my explorer.exe.

When hooking only NtCreateKey, no crash, but nothing is send either.

When hooking only NtOpenKey, explorer.exe crash after a short time the program runs, and nothing is received too.

Explorer.exe will restart, but I can still exit my program fine.

I google and tried to figure out if any of the parameters might be wrong, but I see many times the same definition...

I am running Vista SP2 x86. I turned off all security apps I have running (prevx and defensewall), thought they might intercept something, but no success.
mikec
Posts: 166
Joined: Sun Jul 16, 2006 9:01 pm
Location: UK

Post by mikec »

Ok...

Based on my previous post and the points madshi has made...

First, by the looks of things i.e. all your posts, you are hooking far too much. As I have said time and time again, you need to hook as an absolute last resort. You are not doing this - you can keep on going the way you are, but you will never get a product that is stable, across all OS's, with so many hooks.

The point is: there are standard, architecture, methods of achieving what you want to do in Windows already. There are methods of getting notification about registry changes - why not use these instead? You can always modify the values back if they are changed to something that you don’t want to allow. This is what I'm trying to get across - look at the problem, think about it, read around the subject and then see if you can be clever with the API's available before you go down the root of hooking.

Example - we have a core service - it is protected from 90% of APT's techniques, not using hooking - just using the API's and logical flaws in the way windows works. Our injection Lib only hooks 3 API's and this is just for event logging.

So... When you come across an issue with your hook, you need to proceed in a logical and methodical manner. Always follow this procedure, and then if it is still not working, then post. When you post, show all your code - your prototype, any typedef's that you have used, and which OS's you are having problems with.

1) Strip out everything from your DLL and just leave the hook that you’re having issues with. TEST and check results. If there is a problem simply injecting but not hooking, some process you are injecting into doesn’t like is e.g. csrss.exe - this doesn’t seem to mind the injection but doesn’t like being hooked.

2) Take all logic out of your Hook - make is a simple relay / feed-through hook. TEST and check results. If it doesn’t work here - there is a problem with your prototype. Look at the definitions for the native API's - there in C / C++ so you need to take into account things like the var key word in the prototype. From my experience, if a function prototype is specifying a pointer (as I believe NtOpenKey is i.e. a pointer to a handle), then you don’t need to use the var. Search the forum and look to see if there are prototypes available.

3) Be wary of using Delphi's native variable types i.e. THandle. I always define my own to be extras sure. Some of the variable definitions change according to compile options.

4) Write an injector that will allow you to inject on a per-process basis so you can test how each process handle's the injection and hooking stages. This will let you identify processes that don’t play well.

5) Test on multiple OS’s – what works on Windows XP may not work on Vista, and even from service pack to service pack.

6) Finally, be super careful what your doing in you hook - keep it simple, keep it small, keep it fast. Find out what the API in question actually does - hook it and see how many hits it gets - NtOpenKey gets so many hits and wouldn’t even consider hooking it unless the logic in my hook was very basic.

Just play around - this is what we all have to do. Try changing aspects of you prototype to see if it makes any difference. At the end of the day injection and hooking is complex - it is not for the faint hearted. You need to have the mind set where you can thrash these things out. I've spent 3 weeks working on one problem before, injecting, noting, restarting etc. And when your trying to hook native API's it's mostly unknown.

- Lecture over. Look at the prototype for Zw/NtOpenKey:

Code: Select all

ZwOpenKey(
OUT PHANDLE KeyHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
This is not the same as yours. var KeyHandle:THandle is basically saying you are passing in a THandle that can be modified. The prototype is showing that it wants a PHANDLE or a pointer to a HANDLE. Try:

KeyHandle : PHANDLE;

or

var KeyHandle : Cardinal

where HANDLE is defined thus:

Code: Select all

HANDLE    = {$IFDEF USE_DELPHI_TYPES} 
                  Windows.THandle
               {$ELSE}
                  Longword
               {$ENDIF};
   PHANDLE   = {$IFDEF USE_DELPHI_TYPES}
                  Windows.PHandle
               {$ELSE}
                  ^HANDLE
               {$ENDIF};
Mike
softtouch
Posts: 111
Joined: Sat Jun 20, 2009 10:08 am
Contact:

Post by softtouch »

It does not matter. Using h:PHANDLE or var h:THancle or var h:cardinal behave the same here, explorer crash.

And the code I posted IS the actual code, with everything else removed, no other hooking, just this one, and it crash explorer under my Vista, but not under XP (what I tried in VirtualBox).

I also googled about it, and I saw many times the exact same prototype I use, and there seems to be no problem.

All other hooks I made work fine as of now, JUST this one not.

Sorry for the bad English, its not my native language.
mikec
Posts: 166
Joined: Sun Jul 16, 2006 9:01 pm
Location: UK

Post by mikec »

are you injecting system wide?

try injecting into one process at a time. Just because Explorer.exe crashes, doesnt mean that that is the problem. Are you injecting into csrss.exe? If so, dont...

Let me know how you get on - you need to break it down and try injecitng and hooking one process at a time. I had exactly the same problem on Windows 7 and started re-writing all my code - it turned out csrss.exe was the problem

Mike C
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Try to define NtOpenKeyCallback and NtOpenKeyNext like this:

function NtOpenKeyCallback(keyHandle, desiredAccess, objectAttr: dword) : dword; stdcall;

If that still doesn't help, execute this code and afterwards post the clipboard contents here:

uses madDisAsm, madExcept;

var s1 : string;
begin
ParseFunction(GetProcAddress(GetModuleHandle('ntdll.dll'), 'NtOpenKey'), s1);
FillClipboard(s1);
end;

Make sure you're using the latest madCollection version before doing all of this:

http://madshi.net/madCollection.exe
Post Reply