public DetectResult[] CheckIOCTL_CopyOffload(string sharename, ref DetectionInfo info) { logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL CopyOffload ====="); #region Initialization int contentLength = 32; string content = Smb2Utility.CreateRandomString(contentLength); using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds))) { ulong messageId; ulong sessionId; uint treeId; ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId); #endregion #region Create logWriter.AddLog(LogLevel.Information, "Client creates a file with specified length as for offload copy."); Smb2CreateContextResponse[] serverCreateContexts; FILEID fileIdSrc; CREATE_Response createResponse; Packet_Header header; client.Create( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, Guid.NewGuid().ToString(), AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN_IF, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, null, out fileIdSrc, out serverCreateContexts, out header, out createResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("CREATE", header.Status); throw new Exception("CREATE failed with " + Smb2Status.GetStatusCode(header.Status)); } #endregion #region Write WRITE_Response writeResponse; client.Write( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, 0, fileIdSrc, Channel_Values.CHANNEL_NONE, WRITE_Request_Flags_Values.None, new byte[0], Encoding.ASCII.GetBytes(content), out header, out writeResponse, 0); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("WRITE", header.Status); throw new Exception("WRITE failed with " + Smb2Status.GetStatusCode(header.Status)); } #endregion #region Flush FLUSH_Response flushResponse; client.Flush( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, fileIdSrc, out header, out flushResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("FLUSH", header.Status); throw new Exception("FLUSH failed with " + Smb2Status.GetStatusCode(header.Status)); } #endregion #region IOCTL OFFLOAD_READ logWriter.AddLog(LogLevel.Information, "Client sends IOCTL request with FSCTL_OFFLOAD_READ to ask server to generate the token of the content for offload copy."); STORAGE_OFFLOAD_TOKEN token; ulong fileOffsetToRead = 0; //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong copyLengthToRead = (ulong)contentLength / 2 * 1024; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong transferLength; // Request hardware to generate a token that represents a range of file to be copied FSCTL_OFFLOAD_READ_INPUT offloadReadInput = new FSCTL_OFFLOAD_READ_INPUT(); offloadReadInput.Size = 32; offloadReadInput.FileOffset = fileOffsetToRead; offloadReadInput.CopyLength = copyLengthToRead; byte[] requestInputOffloadRead = TypeMarshal.ToBytes(offloadReadInput); byte[] responseInput; byte[] responseOutput; IOCTL_Response ioCtlResponse; client.IoCtl( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, CtlCode_Values.FSCTL_OFFLOAD_READ, fileIdSrc, 0, requestInputOffloadRead, 32000, IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL, out responseInput, out responseOutput, out header, out ioCtlResponse); #endregion DetectResult[] result = { DetectResult.UnSupported, DetectResult.UnSupported }; if (Smb2Status.STATUS_SUCCESS != header.Status) { LogFailedStatus("FSCTL_OFFLOAD_READ", header.Status); } else { result[0] = DetectResult.Supported; logWriter.AddLog(LogLevel.Information, "FSCTL_OFFLOAD_READ is supported"); #region IOCTL OFFLOAD_WRITE logWriter.AddLog(LogLevel.Information, "Client creates another file as the destination of offload copy."); // Create another file as the destination of offload copy. FILEID fileIdDes; client.Create( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, Guid.NewGuid().ToString(), AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN_IF, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, null, out fileIdDes, out serverCreateContexts, out header, out createResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("CREATE", header.Status); throw new Exception("CREATE failed with " + Smb2Status.GetStatusCode(header.Status)); } // Bug 8016334 // The destination file of CopyOffload Write should not be zero, it should be at least 512 bytes, which is the sector size. client.Write( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, 0, fileIdDes, Channel_Values.CHANNEL_NONE, WRITE_Request_Flags_Values.None, new byte[0], Smb2Utility.CreateRandomByteArray(512), out header, out writeResponse, 0); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("WRITE", header.Status); throw new Exception("WRITE failed with " + Smb2Status.GetStatusCode(header.Status)); } client.Flush( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, fileIdDes, out header, out flushResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("FLUSH", header.Status); throw new Exception("FLUSH failed with " + Smb2Status.GetStatusCode(header.Status)); } if (responseOutput != null) { var offloadReadOutput = TypeMarshal.ToStruct<FSCTL_OFFLOAD_READ_OUTPUT>(responseOutput); transferLength = offloadReadOutput.TransferLength; token = offloadReadOutput.Token; } else { transferLength = 0; token = new STORAGE_OFFLOAD_TOKEN(); } logWriter.AddLog(LogLevel.Information, "Client sends IOCTL request with FSCTL_OFFLOAD_WRITE to ask server to copy the content from source to destination."); ulong fileOffsetToWrite = (ulong)contentLength / 2 * 1024; //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong copyLengthToWrite = transferLength; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong transferOffset = 0; //TransferOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes FSCTL_OFFLOAD_WRITE_INPUT offloadWriteInput = new FSCTL_OFFLOAD_WRITE_INPUT(); offloadWriteInput.Size = 544; offloadWriteInput.FileOffset = fileOffsetToWrite; offloadWriteInput.CopyLength = copyLengthToWrite; offloadWriteInput.TransferOffset = transferOffset; offloadWriteInput.Token = token; byte[] requestInputOffloadWrite = TypeMarshal.ToBytes(offloadWriteInput); // Client sends IOCTL request with FSCTL_OFFLOAD_WRITE to ask server to copy the content from source to destination. client.IoCtl( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, CtlCode_Values.FSCTL_OFFLOAD_WRITE, fileIdDes, 0, requestInputOffloadWrite, 32000, IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL, out responseInput, out responseOutput, out header, out ioCtlResponse); if (Smb2Status.STATUS_SUCCESS == header.Status) { result[1] = DetectResult.Supported; logWriter.AddLog(LogLevel.Information, "FSCTL_OFFLOAD_WRITE is supported"); } else { LogFailedStatus("FSCTL_OFFLOAD_WRITE", header.Status); } #endregion } #region Close CLOSE_Response closeResponse; client.Close( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, fileIdSrc, Flags_Values.NONE, out header, out closeResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("CLOSE", header.Status); } #endregion #region Tree Disconnect TREE_DISCONNECT_Response treeDisconnectResponse; client.TreeDisconnect( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, out header, out treeDisconnectResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("TREEDISCONNECT", header.Status); } #endregion return result; } }
public DetectResult[] CheckIOCTL_CopyOffload(string sharename, ref DetectionInfo info) { logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL CopyOffload ====="); #region Initialization int contentLength = 32; string content = Smb2Utility.CreateRandomString(contentLength); using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds))) { ulong messageId; ulong sessionId; uint treeId; ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId); #endregion #region Create logWriter.AddLog(LogLevel.Information, "Client creates a file with specified length as for offload copy."); Smb2CreateContextResponse[] serverCreateContexts; FILEID fileIdSrc; CREATE_Response createResponse; Packet_Header header; client.Create( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, Guid.NewGuid().ToString(), AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN_IF, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, null, out fileIdSrc, out serverCreateContexts, out header, out createResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("CREATE", header.Status); throw new Exception("CREATE failed with " + Smb2Status.GetStatusCode(header.Status)); } #endregion #region Write WRITE_Response writeResponse; client.Write( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, 0, fileIdSrc, Channel_Values.CHANNEL_NONE, WRITE_Request_Flags_Values.None, new byte[0], Encoding.ASCII.GetBytes(content), out header, out writeResponse, 0); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("WRITE", header.Status); throw new Exception("WRITE failed with " + Smb2Status.GetStatusCode(header.Status)); } #endregion #region Flush FLUSH_Response flushResponse; client.Flush( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, fileIdSrc, out header, out flushResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("FLUSH", header.Status); throw new Exception("FLUSH failed with " + Smb2Status.GetStatusCode(header.Status)); } #endregion #region IOCTL OFFLOAD_READ logWriter.AddLog(LogLevel.Information, "Client sends IOCTL request with FSCTL_OFFLOAD_READ to ask server to generate the token of the content for offload copy."); STORAGE_OFFLOAD_TOKEN token; ulong fileOffsetToRead = 0; //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong copyLengthToRead = (ulong)contentLength / 2 * 1024; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong transferLength; // Request hardware to generate a token that represents a range of file to be copied FSCTL_OFFLOAD_READ_INPUT offloadReadInput = new FSCTL_OFFLOAD_READ_INPUT(); offloadReadInput.Size = 32; offloadReadInput.FileOffset = fileOffsetToRead; offloadReadInput.CopyLength = copyLengthToRead; byte[] requestInputOffloadRead = TypeMarshal.ToBytes(offloadReadInput); byte[] responseInput; byte[] responseOutput; IOCTL_Response ioCtlResponse; client.IoCtl( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, CtlCode_Values.FSCTL_OFFLOAD_READ, fileIdSrc, 0, requestInputOffloadRead, 32000, IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL, out responseInput, out responseOutput, out header, out ioCtlResponse); #endregion DetectResult[] result = { DetectResult.UnSupported, DetectResult.UnSupported }; if (Smb2Status.STATUS_SUCCESS != header.Status) { LogFailedStatus("FSCTL_OFFLOAD_READ", header.Status); } else { result[0] = DetectResult.Supported; logWriter.AddLog(LogLevel.Information, "FSCTL_OFFLOAD_READ is supported"); #region IOCTL OFFLOAD_WRITE logWriter.AddLog(LogLevel.Information, "Client creates another file as the destination of offload copy."); // Create another file as the destination of offload copy. FILEID fileIdDes; client.Create( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, Guid.NewGuid().ToString(), AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN_IF, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, null, out fileIdDes, out serverCreateContexts, out header, out createResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("CREATE", header.Status); throw new Exception("CREATE failed with " + Smb2Status.GetStatusCode(header.Status)); } if (responseOutput != null) { var offloadReadOutput = TypeMarshal.ToStruct <FSCTL_OFFLOAD_READ_OUTPUT>(responseOutput); transferLength = offloadReadOutput.TransferLength; token = offloadReadOutput.Token; } else { transferLength = 0; token = new STORAGE_OFFLOAD_TOKEN(); } logWriter.AddLog(LogLevel.Information, "Client sends IOCTL request with FSCTL_OFFLOAD_WRITE to ask server to copy the content from source to destination."); ulong fileOffsetToWrite = (ulong)contentLength / 2 * 1024; //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong copyLengthToWrite = transferLength; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong transferOffset = 0; //TransferOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes FSCTL_OFFLOAD_WRITE_INPUT offloadWriteInput = new FSCTL_OFFLOAD_WRITE_INPUT(); offloadWriteInput.Size = 544; offloadWriteInput.FileOffset = fileOffsetToWrite; offloadWriteInput.CopyLength = copyLengthToWrite; offloadWriteInput.TransferOffset = transferOffset; offloadWriteInput.Token = token; byte[] requestInputOffloadWrite = TypeMarshal.ToBytes(offloadWriteInput); // Client sends IOCTL request with FSCTL_OFFLOAD_WRITE to ask server to copy the content from source to destination. client.IoCtl( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, CtlCode_Values.FSCTL_OFFLOAD_WRITE, fileIdDes, 0, requestInputOffloadWrite, 32000, IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL, out responseInput, out responseOutput, out header, out ioCtlResponse); if (Smb2Status.STATUS_SUCCESS == header.Status) { result[1] = DetectResult.Supported; logWriter.AddLog(LogLevel.Information, "FSCTL_OFFLOAD_WRITE is supported"); } else { LogFailedStatus("FSCTL_OFFLOAD_WRITE", header.Status); } #endregion } #region Close CLOSE_Response closeResponse; client.Close( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, fileIdSrc, Flags_Values.NONE, out header, out closeResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("CLOSE", header.Status); } #endregion #region Tree Disconnect TREE_DISCONNECT_Response treeDisconnectResponse; client.TreeDisconnect( 1, 1, info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE, messageId++, sessionId, treeId, out header, out treeDisconnectResponse); if (header.Status != Smb2Status.STATUS_SUCCESS) { LogFailedStatus("TREEDISCONNECT", header.Status); } #endregion return(result); } }