trying to hook ntSetInfomationFile, but explorer is crashing

c++ / delphi package - dll injection and api hooking
Post Reply
unclepauly
Posts: 5
Joined: Thu Jul 30, 2009 11:18 am

trying to hook ntSetInfomationFile, but explorer is crashing

Post by unclepauly »

hello,

im having a problem with hooking ntSetInformationFile. Im trying to prevent certain files from being deleted. im on Vista 32 bit.

so im doing this:

Code: Select all

HookAPI("ntdll.dll","NtSetInformationFile",NtSetInformationFileCallback,(PVOID*)&NtSetInformationFileNext);
NtSetInformationFileNext is defined as:

Code: Select all

ULONG (WINAPI *NtSetInformationFileNext)  (HANDLE  FileHandle,  PIO_STATUS_BLOCK  IoStatusBlock, PVOID FileInformation, ULONG  Length, FILE_INFORMATION_CLASS  FileInformationClass);
then all my callback does (for now) is:

Code: Select all

ULONG NtSetInformationFileCallback(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass)
{		
      ULONG ret = NtSetInformationFileNext(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass);

      return ret;
}
then when i inject and try to delted a file from the desktop, explorer crashes.

the only thing in my code that needs to be mentioned is that i dont have the DDK, so things like FILE_INFORMATION_CLASS and IO_STATUS_BLOCK are not in any win32 header file, i have had to create them myself. but i got them from MSDN so these should be correct. also, the function returns NTSTATUS, but this is also in the DDK somewhere. but this is defined as ULONG so i have declared it as ULONG in my code.

other than that im just forwarding on the function call. but explorer.exe crashes (access violation).

has anyone successfully managed to hook this function in vista ? and if so can you see anything wrong with my code ?
unclepauly
Posts: 5
Joined: Thu Jul 30, 2009 11:18 am

Post by unclepauly »

more info :

i downloaded the DDK to get my hands on the structs and defines that ntSeInformationFile requires. however, you cant use the DDK headers along with windows.h, due to "multiple define" errors. so, i cut the bits out of the DDK that i need and put them in my app:

Code: Select all

typedef __success(return >= 0) LONG NTSTATUS;
and

Code: Select all

typedef struct _IO_STATUS_BLOCK {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    } DUMMYUNIONNAME;

    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
now i can use these to define the function :

Code: Select all

NTSTATUS		(WINAPI *NtSetInformationFileNext)  (HANDLE  FileHandle,  PIO_STATUS_BLOCK  IoStatusBlock, PVOID FileInformation, ULONG  Length, FILE_INFORMATION_CLASS  FileInformationClass);
FILE_INFORMATION_CLASS is just an enum that i wont paste here because its quite big. again, all my function is doing is forwarding onto the original function:

Code: Select all

NTSTATUS NtSetInformationFileCallback(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass)
{		
      NTSTATUS ret = NtSetInformationFileNext(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass);	
      return ret;
}
but still i get the exception. any ideas anyone ?
mikec
Posts: 166
Joined: Sun Jul 16, 2006 9:01 pm
Location: UK

Post by mikec »

Hay unclepauly...

First off, I had the same problem that you’re facing - it turned out to be an issue with the FILE_INFORMATION_CLASS enumeration. If I remember correctly, there was some sort of issue with different data types being used by the compiler to represent the underlying enum. I guess you’re using C++ which is what I was using originally - have a look at the compile options that change the way BCB treats enum values.

Second point - if you search for posts that I made previously, you'll see that between myself and madshi, we could not get a pure, non-VCL C++ DLL to compile with the mad libraries - this means that VCL / RTL is always compiled into the DLL - which is not great and can potentially cause issues. Based on this problem, I opted to code my injection library in Delphi / Pascal. It was a pain but only took about a week to port over.

Finally, I'd see if you can find an alternative way to achieve what you are trying to do. I was basically trying to do the same thing and couldn’t find a satisfactory solution. Granted, NtSetInformationFile is used in most file transactions, but I found that other native API's could be used to delete files in certain situations. The general problem that I found is that because the native API's are so generic, they can be used in a variety of different situations to achieve the same results. I can't remember off the top of my head which others were used but I spent nearly 2 months testing and designing and abandoned it in the end. Any example of what I'm taking about is process termination - everyone hooks NtTerminateProcess but NtOpenProcess can also be used to terminate a process depending on the flags provided.

HTH

Mike C
unclepauly
Posts: 5
Joined: Thu Jul 30, 2009 11:18 am

Post by unclepauly »

hello mikec and thanks for the reply.

im sorry if ive misunderstood but i think your replies were based on a Borland world (BCB = Borland C++ Builder ?). im using Win32 c++ in Visual Studio.NET 2009.
...there was some sort of issue with different data types being used by the compiler to represent the underlying enum. I guess you’re using C++ which is what I was using originally - have a look at the compile options that change the way BCB treats enum values.
my code is acutally bog standard C, not C++ because it needs to be as lightweight as possible. an enum is just an enum and the data type is always an int, and in addition i am usuing the FILE_INFORMATION_CLASS directly from the DDK :

Code: Select all

typedef enum _FILE_INFORMATION_CLASS {
    FileDirectoryInformation         = 1,
    FileFullDirectoryInformation,   // 2
    FileBothDirectoryInformation,   // 3
    FileBasicInformation,           // 4
    FileStandardInformation,        // 5

etc etc etc

FileIdGlobalTxDirectoryInformation,      // 50
    FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
Second point - if you search for posts that I made previously, you'll see that between myself and madshi, we could not get a pure, non-VCL C++ DLL to compile with the mad libraries - this means that VCL / RTL is always compiled into the DLL
VCL / RTL - this again is Borland lingo and im not using that. the Mad Libraries are built in C++ and ive got my library compiling fine and hooking other functions no problem - its just this one (for now!).
Finally, I'd see if you can find an alternative way to achieve what you are trying to do. I was basically trying to do the same thing and couldn’t find a satisfactory solution. Granted, NtSetInformationFile is used in most file transactions, but I found that other native API's could be used to delete files in certain situations.
my application must be able to detect when any file or folder has been deleted, and act on it accordingly. i understand that there is not one common API that is eventually called, and that there are various ways to do this, ntSetInformationFile being one, so i need to be able to hook them all. so i really need to get this working.
mikec
Posts: 166
Joined: Sun Jul 16, 2006 9:01 pm
Location: UK

Post by mikec »

All I can really say is that I had the same issue and it was problem with the enum values.

Firstly, you say that your enum is being interpreted as an int - are you sure? Some compilers do code optimisation which can change this to a signed integer or even shorten it.

Secondly, although you are assigning the first value in your enum list, you are assuming that all the other values will have a logically incremented value.

I have found that different versions of Windows have different _FILE_INFORMATION_CLASS values. If you are using an alias (as an enum basically is) but you have a different value assigned to it, then this also can cause problems. I would really, really check this out.

I've done a little digging into my achieves to see if I could find anything but most of that work has gone because i couldn’t make it robust. However, I have found my _FILE_INFORMATION_CLASS definitions - it may help. I basically tried to compare and contrast all the different headers that I found...

Code: Select all

typedef enum _FILE_INFORMATION_CLASS {
FileFiller=0,
FileDirectoryInformation = 1, // 1 Y N D
FileFullDirectoryInformation, // 2 Y N D
FileBothDirectoryInformation, // 3 Y N D
FileBasicInformation, // 4 Y Y F
FileStandardInformation, // 5 Y N F
FileInternalInformation, // 6 Y N F
FileEaInformation, // 7 Y N F
FileAccessInformation, // 8 Y N F
FileNameInformation, // 9 Y N F
FileRenameInformation, // 10 N Y F
FileLinkInformation, // 11 N Y F
FileNamesInformation, // 12 Y N D
FileDispositionInformation, // 13 N Y F
FilePositionInformation, // 14 Y Y F
FileModeInformation = 16, // 16 Y Y F
FileAlignmentInformation, // 17 Y N F
FileAllInformation, // 18 Y N F
FileAllocationInformation, // 19 N Y F
FileEndOfFileInformation, // 20 N Y F
FileAlternateNameInformation, // 21 Y N F
FileStreamInformation, // 22 Y N F
FilePipeInformation, // 23 Y Y F
FilePipeLocalInformation, // 24 Y N F
FilePipeRemoteInformation, // 25 Y Y F
FileMailslotQueryInformation, // 26 Y N F
FileMailslotSetInformation, // 27 N Y F
FileCompressionInformation, // 28 Y N F
FileObjectIdInformation, // 29 Y Y F
FileCompletionInformation, // 30 N Y F
FileMoveClusterInformation, // 31 N Y F
FileQuotaInformation, // 32 Y Y F
FileReparsePointInformation, // 33 Y N F
FileNetworkOpenInformation, // 34 Y N F
FileAttributeTagInformation, // 35 Y N F
FileTrackingInformation // 36 N Y F
FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

_FILE_INFORMATION_CLASS = ( 
     
    FileDirectoryInformation, // 1 
    FileFullDirectoryInformation, // 2 
    FileBothDirectoryInformation, // 3 
    FileBasicInformation, // 4  wdm 
    FileStandardInformation, // 5  wdm 
    FileInternalInformation, // 6 
    FileEaInformation, // 7 
    FileAccessInformation, // 8 
    FileNameInformation, // 9 
    FileRenameInformation, // 10 
    FileLinkInformation, // 11 
    FileNamesInformation, // 12 
    FileDispositionInformation, // 13 
    FilePositionInformation, // 14 wdm 
    FileFullEaInformation, // 15 
    FileModeInformation, // 16 
    FileAlignmentInformation, // 17 
    FileAllInformation, // 18 
    FileAllocationInformation, // 19 
    FileEndOfFileInformation, // 20 wdm 
    FileAlternateNameInformation, // 21 
    FileStreamInformation, // 22 
    FilePipeInformation, // 23 
    FilePipeLocalInformation, // 24 
    FilePipeRemoteInformation, // 25 
    FileMailslotQueryInformation, // 26 
    FileMailslotSetInformation, // 27 
    FileCompressionInformation, // 28 
    FileObjectIdInformation, // 29 
    FileCompletionInformation, // 30 
    FileMoveClusterInformation, // 31 
    FileQuotaInformation, // 32 
    FileReparsePointInformation, // 33 
    FileNetworkOpenInformation, // 34 
    FileAttributeTagInformation, // 35 
    FileTrackingInformation, // 36 
    ); 
Finally, does you hook fail on all OS? Does it fail if you simply relay the call straight through to the real API?

HTH

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

Post by madshi »

You forgot to define NtSetInformationFileCallback as "WINAPI".

Besides, I'd suggest to redefine enumerations as DWORD, just to be safe.
unclepauly
Posts: 5
Joined: Thu Jul 30, 2009 11:18 am

Post by unclepauly »

madshi - thanks for pointing out the WINAPI ommision.

ive added this and...still it crashes explorer. well actually it hangs now instead of crashing so maybe this is a litle bit better ;)

the other thing you say - make the FILE_INFORMATION_CLASS enum an emumeration of DWORDS. as far as i understand, an enum is just an enum, which is an emumeration of type int. how can i define an enumeration of DWORDS ? i do not know of such a way. by the way, im using Visual Studio.NET 2009, not Borland.

so, just to go over what i am doing:

1) define NTSTATUS, the enum and struct used in the ntSetInformationFile function (all copy/paste from the DDK header files):

Code: Select all

typedef __success(return >= 0) LONG NTSTATUS;

Code: Select all

typedef enum _FILE_INFORMATION_CLASS {
    FileDirectoryInformation         = 1,
    FileFullDirectoryInformation,   // 2
    .
    .
    .
    FileNetworkPhysicalNameInformation,      // 49 
    FileIdGlobalTxDirectoryInformation,      // 50
    FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

Code: Select all

typedef struct _IO_STATUS_BLOCK {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    } DUMMYUNIONNAME;

    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
2) define the 'next' function:

Code: Select all

NTSTATUS	(WINAPI *NtSetInformationFileNext)  (HANDLE  FileHandle,  PIO_STATUS_BLOCK  IoStatusBlock, PVOID FileInformation, ULONG  Length, FILE_INFORMATION_CLASS  FileInformationClass);
3) define the callback:

Code: Select all

NTSTATUS WINAPI NtSetInformationFileCallback(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass)
{		
                NTSTATUS ret = NtSetInformationFileNext(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass);
	
	return ret;
}
4) hook the API:

Code: Select all

BOOL WINAPI DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
{
  if (fdwReason == DLL_PROCESS_ATTACH) {

    InitializeMadCHook();

     HookAPI("ntdll.dll","NtSetInformationFile",NtSetInformationFileCallback,(PVOID*)&NtSetInformationFileNext);
}
    else if (fdwReason == DLL_PROCESS_DETACH)
    FinalizeMadCHook();

  return true;	
}
then, after injecting the dll, i delete a file on the desktop (some text file). this is when explorer crashes/hangs. im using Vista 32 bit.

can you spot anything else wrong ?
unclepauly
Posts: 5
Joined: Thu Jul 30, 2009 11:18 am

Post by unclepauly »

madshi - apologies, i have rebooted and it is working just fine now. maybe i had not uninjected the previous dll ? thanks for your help though.

anyway, i hope the above code will help someone hook the ntSetInformationFile function !

but also madshi, im still interested to know about the enum of type DWORD - is this just a Borland thing or am i missing something ?
mikec
Posts: 166
Joined: Sun Jul 16, 2006 9:01 pm
Location: UK

Post by mikec »

I think the question is: what is an integer.

Like I said before, the default enum defaults to an integer but some compilers can over-ride this for optimisation. In most code, this will make no difference but when injecting, the prototype has to match identically, the hooked API.

Integer is a bit open ended because it doesn’t really state anything - is an int always guaranteed to be a 32-bit unsigned integer. I think what madshi was getting at is that if you make a DWORD, there is less chance of complications.

But that’s just may take.

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

Post by madshi »

In win32 programming enumerations are usually supposed to be 4 byte big, but C(++) also supports 1 byte and 2 byte enumerations. So that's why I'm usually using DWORD instead of enumeration types for hooking. Just to be sure that the compiler doesn't accidently think the enumeration would be only 1 byte or 2 byte...
Post Reply