Mac Library Externalcommandfilter

A file system filter for Mac OS X

License

Mac library external command filter location

The license model is a BSD Open Source License. This is a non-viral license, only asking that if you use it, you acknowledge the authors, in this case Slava Imameev.

The project uses the distorm disassembler https://github.com/gdabah/distorm which is now released under BSD license.

However, if you have MAC address filtering enabled, the hacker can bypass all that trouble and simply grab your MAC address, spoof it, disconnect you or another device on your network from the router and connect freely. Once they are in, they can do all kinds of damage and access everything on your network. Other Solutions to the Problem. Firstly, I want to thank you as finally I found IP addresses that were connected to my modem. I found out all 5 devices that were connected to my modem using nmap, while it was showing only 2 devices before scanning. I want to find their mac address and remove those devices from my Wi-Fi using Gnome-Terminal. Oct 07, 2017  I found things returned to normal when I right clicked on AMF and selected 'Show Search Criteria', cleared any spurious search parameters,and then Hid the Search Parameters again. I also had to select 'This Mac' rather than All My Files. After that it displayed my files. You can also use the search parameters to limit what is displayed in AMF.

Design

Mac OS X doesn't support a full fledged file system filtering like Windows as Apple believes that BSD stackable file system doesn't fit Mac OS X. The available kernel authorization subsystem ( kauth ) allows only filtering open requests and a limited number of operations on file/directory. It doesn't allow filtering read and write operations and provides a limited control over file system operations as a vnode is already created at the moment of kauth callback invoking. In Windows parlance a kauth callback is a postoperation callback for create/open request ( IRP_MJ_CREATE for Windows ), that is all you have for Mac OS X. Not much really.

The filtering can also be implemented by registering MAC ( Mandatory Access Control ) layer. But MAC has limited functionality and not consistent in relation to file system filtering as it was not designed as a file system filter layer. Instead of being called by VFS layer MAC registered callbacks are scattered through the kernel code. They are called from system calls and other kernel subsystems, so MAC doesn't provide a consistent interface for VFS filter and if I remember correctly MAC was declared as deprecated for usage by third party developers.

To summarize the above, there is no official support from Apple if you need to filter read or/and write requests, filter and modify VFS vnode operation.

Mac Library External Command Filter Location

The lack of a stackable file system support by Mac OS X VFS required to find a way to place a filter between VFS invoking vnode operations via VNOP_* functions and a file system driver implementing these vnode operations. I developed a hooking technique for VFS layer that emulates a stackable file system by replacing vnode operations in array. This technique allows to place a filter between VFS and file system driver and supports sophisticated filtering such as isolation file system filter when a filter creates vnodes instead of a file system driver thus gaining a full control over file data. I used this technique in two projects to implement filtering for lookup, create, read and write requests and to implement an isolation file system.

FltFakeFSD.h and FltFakeFSD.cpp are optional files that helps to infer the vnode and vnodeop_desc structures layout that are not declared in SDK. This is achieved by registering a dummy file system, creating a vnode and inspecting it to find required offsets. All you need to do is to call FltGetVnodeLayout() in a filter initialization code.

Alternatively you can extract declarations from XNU code at opensource.apple.com. An alternative implementation without using the fake FSD can be found in VersionDependent.h and VersionDependent.cpp files, where struct vnodeop_desc_Yosemite was borrowed from Apple's open source code for Yosemite(10.10), it happened that vnode and vnodeop_desc structures haven't change in all latest kernel versions so this code works for Mavericks(10.9) and El Capitan(10.11). With Sierra(10.12) release the field offsets changed for vnode structure and the project was changed to be compiled with FltFakeFSD.cpp to infer vnode layout. If you want to switch back then remove USE_FAKE_FSD preprocessor definition from project settings and replace vnode_Yosemite structure definition.

The filter registers a kauth callback FltIOKitKAuthVnodeGate::VnodeAuthorizeCallback which in turn calls FltHookVnodeVopAndParent that hooks vnode related operations. The kauth callback is used only to trigger filtering for a file system. When an application opens a file FileX in a directory DirX a vnode for a DirX is provided as a parameter for VnodeAuthorizeCallback so the following calls to file system's lookup or create operations for FileX will be visible for file system filter. When an original lookup or create returns a filter calls FltHookVnodeVopAndParent for a returned vnode or does this in a kauth callback which is nearly the same as kauth callback is a postoperation callback called after VNOP_LOOKUP or VNOP_CREATE. In case of lookup vnode operation do not forget about name cache, so lookup is not always called when an application calls open( FileX ), but if you need to see all lookup operations it is possible to disable name caching for a vnode. You can devise your own way of finding vnodes to hook depending on your requirements, for my purposes a kauth callback worked well as I was filtering vnodes of VREG type so I can use VDIR vnode as an anchor that started filtering for VREG vnodes. Also in most file systems vnode operations array is shared between all vnodes of VREG and VDIR type.

The filter registers operations it wants to intercept in gFltVnodeVopHookEntries array. The skeleton filter immediately calls an original function from a hook but if you want to see a filter in action look at DldVNodeHook.cpp ( https://github.com/slavaim/MacOSX-Kernel-Filter/blob/master/DLDriver/DldVNodeHook.cpp ) which is a more advanced implementation at MacOSX-Kernel-Filter that also implements an isolation filter for read and write operations on a file by redirecting read and write to a sparse file on another volume. The isolation filter is implemented at DldCoveringVnode.cpp and a sparse file at DldSparseFile.cpp

Application

You can find a real world filter application in MacOSX-VFS-redirector( https://github.com/slavaim/MacOSX-VFS-redirector ) and a file system isolation filter( https://github.com/slavaim/MacOSX-Kernel-Filter/blob/master/DLDriver/DldVNodeHook.cpp , it is a part of a bigger project).

Dos Internal And External Commands

Example of call stacks when a filter is loaded

FYI a set of call stacks when hooks are active

Lookup hook

Pagein hook

Close hook

Inactive hook

Mac Library External Command Filter System

Mac library external command filter location

Ms-dos External Command

Some words on unloading implementation

The module has been made non-unloadable by taking a reference to IOKit com_FsdFilter class in com_FsdFilter::start routine. The reason is that unload for a hooking file system filter driver is a dangerous operation as it is hard to implement it correctly to avoid race conditions and preserve data consistency. To process unload correctly you need to process the following cases

  • unhook all vnode tables
  • check that there is no return to the hooking code in any call stack or else unloading a module results in a panic as control returns to unloaded code
  • check that there is no hooking code being called, i.e. there is no a processor with IP register pointing to any function in a driver
  • ensure that data changed by a filter will not crash the system or damage user or system data, for example if the driver implements any data modification it should guarantee data consistency on unload

Ms-dos Internal Command

The only feasible way to implement this is dividing a driver in two parts - one part can be unloaded and another part is never unloaded. Unloading complicates the code as you have to synchronize the code with unloading procedure, this increases complexity and as a result of this complexity and nondeterminism in the system state it's never implemented correctly