I need to develop an application that monitors, and potentially filters (rejects the calls开发者_如何学C), file operations.
It appears that developing a minifilter is the "standard" solution. another potential method is using API hooks.
are these relevant solutions? (I read in some places the an API hook may not be suitable - but no explanation was given)
are there other options?
API hooking (at least in kernel space) is essentially not supported by microsoft. On x64 (starting from Vista and up) patchguard will usually kill the machine if it detects SSDT hooking or any change whatsoever in critical components of the system. API hooking is very hard to get on a system-wide level because the synchronization primitives that windows uses are not exported so even if you manage to hook the code there is not guarantee that the machine won't crash due to a funky value of EIP at a given moment (this is especially valid when you are unloading a driver that has hooked a function).
Probably your best bet to do it - without using minifilter driver is to try and to direct memory kernel object hooking. You might want to look at OBJECT_TYPE_INITIALIZER definition structure which every object windows has (FILE, EVENT, PORT etc - google around to see them) has as its member. You are particularly interested in the *Procedure function pointers.
It all comes down to what you want/need to accomplish.
If you just need file operations (in the kernel level, file open / file close), and you need it system-wide than I would go with minifilter. It is a long, tedious and time-consuming road, but safer (check out Sysinternals procmon to see what you can get using this method).
If you need a more application-specific control, or if you would like control over the WINAPI level, go with API hooking. It is easier to develop, but there are lots of "mines" that blow up in your face during the way (check out EasyHook, its doing a pretty good job with minimum work).
good luck!
If you are preventing user access to certain resources (files) from a security perspective the correct way is a minifilter. This is because it's the only way you are sure that the user cannot access the filtered resources.
If you use API hook you can intercept calls at kernel32.dll (CreateFileW, FindFirstFile, etc., etc.) but an attacker can uses Native API (ntdll.dl). Of course, you can intercept at Native level (it's more difficult since it's undocumented) but attackers can use differents APIs at kernel switch level. At that level it's not portable to hook. It's almost impossible to prevent creative attackers to access to resources using API hook, that's why it's not recommended for security software.
In my opinion, API hooking is a good option for monitoring. If you want to see what an application is doing, it's very good to use API hook since you can intercept higher level functions than in kernel-mode.
If you can accomplish the task without the hooks - do it. Because hooking is not a supported way of developing applications. There is a lot of pitfalls and antivirus software will treat your application as more dangerous. Also you may face problems with newer/older versions of operating system.
But take into consideration that user-mode code is much easier then kernel-mode. So if user-mode hooks can satisfy your requirements then you may think about them.
I got a follow up question by mail, so i'm adding here the solution we used
The project was canceled before it wen't live, but we evaluated a product (Eldos CallbackFilter) that allows writing kernel filters using user space code.
The product has a generic kernel driver that communicates with user space code that defines the filtering logic.
I would have to contradict LordDoskias as, OBJECT_TYPE_INITIALIZER is not a documented object and this can, has and will change with OS patches and updates. Do not approach this problem this was as it will only cause more problems and not solve anything. Not to mention the patch guard which will BSOD the system if you modify system structures. If you want to restrict access to files there is no way around it than simply using a minifilter. There are several Microsoft samples here that you can draw inspiration from and also learn to implement your driver the correct and supported way. Lastly and more importantly it is illusory to think that you will be able to block everything you want by hooking techniques and I will just give you one example: mapped files. Here is a scenario involving notepad which uses mapped files to write it's data to disk.
- CreateFile -> obtains file handle -> you see this
- CreateFileMapping -> obtains mapping handle -> you don't see this
- CloseHandle(FileHandle) -> you see this
- MapViewOfFile returning a memory buffer being page backed by the file -> you don't see this
- Modify the memory buffer -> you don't see this
- Unmap and close the FileMappingHandle -> you don't see this
- Async the memory manager's system worker threads make paging writes to the file to keep it in sync. Even after all the handles have been closed or during the in-memory change of the buffer, depending when the OS wants. -> you don't see this
This is what you are missing with hooking. And this is just one scenario. There is a multitude of them, so please do things the right way. How would that change if you use a minifilter ? You would of course catch the CreateFile, CreateFileMapping as well ( check FltAcquireForSectionSynchronization callback) and then from the minifilter you will see all the PAGING_WRITE coming from the memory manager (see IoGetTopLevelIrp()) in your Write dispatch callback.
Good luck further.
精彩评论