public static bool AuthorizeFileAccess(FilterAPI.MessageSendData messageSend, ref FilterAPI.MessageReplyData messageReply) { bool ret = true; try { messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; // //here you can control all the registered IO requests,block the access or modify the I/O data base on the file IO information from MessageSend struture // // //if you don't want to change anything to this IO request, just let it pass through as below setting: //messageReply.FilterStatus = 0; //messageReply.ReturnStatus = (uint)NtStatus.Status.Success; //if you want to block the access this IO request before it goes down to the file system, you can return the status as below, //it is only for pre IO requests, it means the user IO reuqests will be completed here instead of going down to the file system. //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; //if you want to modify the IO data and complete the pre IO with your own data, you can return status as below: // messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; // messageReply.DataBufferLength = the return data buffer length. // messageReply.DataBuffer = the data you want to return. // messageReply.ReturnStatus = (uint)NtStatus.Status.Success; FilterAPI.MessageType messageType = (FilterAPI.MessageType)messageSend.MessageType; WinData.FileInfomationClass infoClass = (WinData.FileInfomationClass)messageSend.InfoClass; uint dataLength = messageSend.DataBufferLength; byte[] data = messageSend.DataBuffer; //here is some IO information for your reference: if ((messageSend.CreateOptions & (uint)WinData.CreateOptions.FO_REMOTE_ORIGIN) > 0) { //this is file access request comes from remote network server } //you can check the file create option with this data: //"DesiredAccess: messageSend.DesiredAccess //"Disposition:" + ((WinData.Disposition)messageSend.Disposition).ToString(); //"ShareAccess:" + ((WinData.ShareAccess)messageSend.SharedAccess).ToString(); //"CreateOptions:"messageSend.CreateOptions //Here is the demo to copy file content before it was deleted.----------------------------------------------- bool isFileDeleting = false; if (messageSend.Status == (uint)NtStatus.Status.Success) { if (messageType == FilterAPI.MessageType.POST_CREATE) { if ((messageSend.CreateOptions & (uint)WinData.CreateOptions.FILE_DELETE_ON_CLOSE) > 0) { isFileDeleting = true; } } else if (messageType == FilterAPI.MessageType.PRE_SET_INFORMATION) { if (infoClass == WinData.FileInfomationClass.FileDispositionInformation) { isFileDeleting = true; } } if (isFileDeleting) { //IntPtr fileHandle = IntPtr.Zero; //bool retVal = FilterAPI.GetFileHandleInFilter(messageSend.FileName,(uint)FileAccess.Read, ref fileHandle); //if (retVal) //{ // SafeFileHandle sHandle = new SafeFileHandle(fileHandle, true); // FileStream fileStream = new FileStream(sHandle, FileAccess.Read); // //copy your data here... // fileStream.Close(); //} } } //End ----------------------------------------------- switch (messageType) { case FilterAPI.MessageType.PRE_CREATE: { //here you reparse the file open to another new file name //string newReparseFileName = "\\??\\c:\\myNewFile.txt"; //byte[] returnData = Encoding.Unicode.GetBytes(newReparseFileName); //Array.Copy(returnData, messageReply.DataBuffer, returnData.Length); //messageReply.DataBufferLength = (uint)returnData.Length; //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.Reparse; break; } case FilterAPI.MessageType.PRE_CACHE_READ: case FilterAPI.MessageType.POST_CACHE_READ: case FilterAPI.MessageType.PRE_NOCACHE_READ: case FilterAPI.MessageType.POST_NOCACHE_READ: case FilterAPI.MessageType.PRE_PAGING_IO_READ: case FilterAPI.MessageType.POST_PAGING_IO_READ: case FilterAPI.MessageType.PRE_CACHE_WRITE: case FilterAPI.MessageType.POST_CACHE_WRITE: case FilterAPI.MessageType.PRE_NOCACHE_WRITE: case FilterAPI.MessageType.POST_NOCACHE_WRITE: case FilterAPI.MessageType.PRE_PAGING_IO_WRITE: case FilterAPI.MessageType.POST_PAGING_IO_WRITE: { //byte[] returnData = //new data you want to modify the read/write data; //Array.Copy(returnData, messageReply.DataBuffer, returnData.Length); //messageReply.DataBufferLength = (uint)returnData.Length; ////for pre IO,use this one //// messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; // messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; // messageReply.ReturnStatus = (uint)NtStatus.Status.Success; break; } case FilterAPI.MessageType.PRE_SET_INFORMATION: case FilterAPI.MessageType.POST_SET_INFORMATION: case FilterAPI.MessageType.PRE_QUERY_INFORMATION: case FilterAPI.MessageType.POST_QUERY_INFORMATION: { switch (infoClass) { case WinData.FileInfomationClass.FileRenameInformation: { if (FilterAPI.MessageType.PRE_SET_INFORMATION == messageType) { string blockFileName = @"c:\filterTest\blockRename.txt"; //test block rename to blockFileName, it needs to register PRE_SET_INFORMATION; if (string.Compare(messageSend.FileName, blockFileName, true) == 0) { EventManager.WriteMessage(179, "IOAccessControl", EventLevel.Warning, "Block rename for file:" + messageSend.FileName); ret = false; break; } } //you can block file rename as below //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; break; } case WinData.FileInfomationClass.FileDispositionInformation: { //you can block file delete as below //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; break; } case WinData.FileInfomationClass.FileEndOfFileInformation: { //change file size break; } case WinData.FileInfomationClass.FileBasicInformation: { //file basic information break; } case WinData.FileInfomationClass.FileStandardInformation: { //file standard information break; } case WinData.FileInfomationClass.FileNetworkOpenInformation: { //file network information break; } case WinData.FileInfomationClass.FileInternalInformation: { //file internal inofrmation break; } default: { break; } } break; } } } catch (Exception ex) { EventManager.WriteMessage(174, "IOAccessControl", EventLevel.Error, "IOAccessControl failed." + ex.Message); } return(ret); }
public static bool AuthorizeRegistryAccess(FilterAPI.MessageSendData messageSend, ref FilterAPI.MessageReplyData messageReply) { bool ret = true; try { messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; // //here you can control registry request,block the access or modify the registry data. // // //if you don't want to change anything to this registry request, just let it pass through as below setting: //messageReply.FilterStatus = 0; //messageReply.ReturnStatus = (uint)NtStatus.Status.Success; //if you want to block the access this registry request, you can return the status as below, //it is only for pre callback requests. //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; //if you want to modify the registry data and complete the pre IO with your own data, you can return status as below: // messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; // messageReply.DataBufferLength = the return data buffer length. // messageReply.DataBuffer = the data you want to return. // messageReply.ReturnStatus = (uint)NtStatus.Status.Success; FilterAPI.RegCallbackClass regCallbackClass = (FilterAPI.RegCallbackClass)messageSend.Offset; uint dataLength = messageSend.DataBufferLength; byte[] data = messageSend.DataBuffer; switch (regCallbackClass) { case FilterAPI.RegCallbackClass.Reg_Pre_Query_Value_Key: { KEY_VALUE_INFORMATION_CLASS keyValuseInformationClass = (KEY_VALUE_INFORMATION_CLASS)messageSend.InfoClass; IntPtr keyValueInfoPtr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0); if (messageSend.FileName.IndexOf("EaseFilter") <= 0) { //this is not our unit test key break; } //below code is for unit test to demo how to complete pre-callback registry call with our own data. EventManager.WriteMessage(400, "AuthorizeRegistryAccess", EventLevel.Error, "Reg_Pre_Query_Value_Key keyValuseInformationClass:" + keyValuseInformationClass.ToString()); switch (keyValuseInformationClass) { case KEY_VALUE_INFORMATION_CLASS.KeyValueBasicInformation: { //public struct KEY_VALUE_BASIC_INFORMATION // { // public uint TitleIndex; // public uint Type; // public uint NameLength; // public byte[] Name; // } uint titleIndex = 0; uint type = (uint)VALUE_DATA_TYPE.REG_DWORD; byte[] valueName = Encoding.Unicode.GetBytes("value1"); uint valueNameLength = (uint)valueName.Length; MemoryStream ms = new MemoryStream(messageReply.DataBuffer); BinaryWriter bw = new BinaryWriter(ms); bw.Write(titleIndex); bw.Write(type); bw.Write(valueNameLength); bw.Write(valueName); messageReply.DataBufferLength = (uint)ms.Position; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; break; } case KEY_VALUE_INFORMATION_CLASS.KeyValueFullInformation: { //KeyValueFullInformation class structure //public uint TitleIndex; //public uint Type; //public uint DataOffset; //public uint DataLength; //public uint NameLength; //public byte[] Name; uint titleIndex = 0; uint type = (uint)VALUE_DATA_TYPE.REG_DWORD; uint testData = 12345; uint testDataLength = sizeof(uint); byte[] valueName = Encoding.Unicode.GetBytes("value1"); uint valueNameLength = (uint)valueName.Length; uint dataOffset = 5 * sizeof(uint) + valueNameLength; MemoryStream ms = new MemoryStream(messageReply.DataBuffer); BinaryWriter bw = new BinaryWriter(ms); bw.Write(titleIndex); bw.Write(type); bw.Write(dataOffset); bw.Write(testDataLength); bw.Write(valueNameLength); bw.Write(valueName); bw.Write(testData); messageReply.DataBufferLength = (uint)ms.Position; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; break; } case KEY_VALUE_INFORMATION_CLASS.KeyValuePartialInformation: { // public struct KEY_VALUE_PARTIAL_INFORMATION //{ // public uint TitleIndex; // public uint Type; // public uint DataLength; // public byte[] Data; //} uint titleIndex = 0; uint type = (uint)VALUE_DATA_TYPE.REG_DWORD; uint testData = 12345; uint testDataLength = sizeof(uint); MemoryStream ms = new MemoryStream(messageReply.DataBuffer); BinaryWriter bw = new BinaryWriter(ms); bw.Write(titleIndex); bw.Write(type); bw.Write(testDataLength); bw.Write(testData); messageReply.DataBufferLength = (uint)ms.Position; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; break; } default: break; } break; } case FilterAPI.RegCallbackClass.Reg_Pre_Create_KeyEx: case FilterAPI.RegCallbackClass.Reg_Pre_Open_KeyEx: { //this is our unit test key if (messageSend.FileName.IndexOf("EaseFilter") > 0) { //NOT allow to create new registry key. messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; } break; } default: break; } } catch (Exception ex) { EventManager.WriteMessage(400, "AuthorizeRegistryAccess", EventLevel.Error, "AuthorizeRegistryAccess exception:" + ex.Message); } return(ret); }