public uint Create(
            uint treeId,
            string fileName,
            CreateOptions_Values createOptions,
            out FILEID fileId,
            out Smb2CreateContextResponse[] serverCreateContexts,
            RequestedOplockLevel_Values requestedOplockLevel_Values = RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
            Smb2CreateContextRequest[] createContexts = null,
            Packet_Header_Flags_Values headerFlag     = Packet_Header_Flags_Values.FLAGS_SIGNED,
            AccessMask accessMask                     = AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE,
            ShareAccess_Values shareAccess            = ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
            ResponseChecker <CREATE_Response> checker = null,
            ushort creditRequest = 64)
        {
            Packet_Header   header;
            CREATE_Response createResponse;

            uint status = client.Create(
                1,
                creditRequest,
                headerFlag,
                messageId++,
                sessionId,
                treeId,
                fileName,
                accessMask,
                shareAccess,
                createOptions,
                CreateDisposition_Values.FILE_OPEN_IF,
                File_Attributes.NONE,
                ImpersonationLevel_Values.Impersonation,
                SecurityFlags_Values.NONE,
                requestedOplockLevel_Values,
                createContexts,
                out fileId,
                out serverCreateContexts,
                out header,
                out createResponse);

            InnerResponseChecker(checker, header, createResponse);

            grantedCredit = header.CreditRequestResponse;

            return(status);
        }
        public DetectResult[] CheckIOCTL_IntegrityInfo(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL IntegrityInfo =====");
            logWriter.AddLog(LogLevel.Information, "Share name: " + sharename);

            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);

                #region Create

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileId;
                CREATE_Response createResponse;
                Packet_Header header;
                logWriter.AddLog(LogLevel.Information, "Client opens a file");
                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 fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("CREATE", header.Status);
                    throw new Exception("CREATE failed with with " + Smb2Status.GetStatusCode(header.Status));
                }

                #endregion

                #region IOCTL GET IntegrityInfo

                logWriter.AddLog(LogLevel.Information, "Client sends IOCTL request with FSCTL_GET_INTEGRITY_INFORMATION.");
                FSCTL_GET_INTEGRITY_INFO_OUTPUT getIntegrityInfo;
                IOCTL_Response ioCtlResponse;
                byte[] buffer = new byte[1024];
                byte[] respInput = new byte[1024];
                byte[] respOutput = new byte[1024];

                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_GET_INTEGRITY_INFORMATION,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult[] result = { DetectResult.UnSupported, DetectResult.UnSupported };

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    // Get_Integrity is not supported
                    // Set_Integrity cannot be tested.
                    LogFailedStatus("GET_INTEGRITY_INFORMATION", header.Status);
                    return result;
                }

                getIntegrityInfo = TypeMarshal.ToStruct<FSCTL_GET_INTEGRITY_INFO_OUTPUT>(respOutput);

                result[0] = DetectResult.Supported;
                logWriter.AddLog(LogLevel.Information, "FSCTL_GET_INTEGRITY_INFORMATION is supported");

                #endregion

                #region IOCTL SET IntegrityInfo

                logWriter.AddLog(LogLevel.Information,
                    "Client sends IOCTL request with FSCTL_SET_INTEGRITY_INFORMATION after changed the value of the following fields in FSCTL_SET_INTEGRIY_INFO_INPUT: "
                    + "ChecksumAlgorithm, Flags, Reserved.");
                FSCTL_SET_INTEGRIY_INFO_INPUT setIntegrityInfo;
                setIntegrityInfo.ChecksumAlgorithm = FSCTL_SET_INTEGRITY_INFO_INPUT_CHECKSUMALGORITHM.CHECKSUM_TYPE_CRC64;
                setIntegrityInfo.Flags = FSCTL_SET_INTEGRITY_INFO_INPUT_FLAGS.FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF;
                setIntegrityInfo.Reserved = FSCTL_SET_INTEGRITY_INFO_INPUT_RESERVED.V1;
                buffer = TypeMarshal.ToBytes<FSCTL_SET_INTEGRIY_INFO_INPUT>(setIntegrityInfo);

                respInput = new byte[1024];
                respOutput = new byte[1024];

                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_SET_INTEGRITY_INFORMATION,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                #endregion

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("SET_INTEGRITY_INFORMATION", header.Status);
                }
                else
                {
                    #region IOCTL GET IntegrityInfo

                    buffer = new byte[1024];
                    respInput = new byte[1024];
                    respOutput = new byte[1024];
                    logWriter.AddLog(LogLevel.Information, "Client sends second FSCTL_GET_INTEGRITY_INFORMATION.");
                    client.IoCtl(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        CtlCode_Values.FSCTL_GET_INTEGRITY_INFORMATION,
                        fileId,
                        0,
                        buffer,
                        64 * 1024,
                        IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                        out respInput,
                        out respOutput,
                        out header,
                        out ioCtlResponse,
                        0);

                    getIntegrityInfo = TypeMarshal.ToStruct<FSCTL_GET_INTEGRITY_INFO_OUTPUT>(respOutput);

                    if (header.Status != Smb2Status.STATUS_SUCCESS)
                    {
                        LogFailedStatus("Second GET_INTEGRITY_INFORMATION", header.Status);
                    }

                    if ((ushort)setIntegrityInfo.ChecksumAlgorithm != (ushort)getIntegrityInfo.ChecksumAlgorithm)
                    {
                        logWriter.AddLog(LogLevel.Information, "Failed to set the ChecksumAlgorithm field to value " + setIntegrityInfo.ChecksumAlgorithm);
                    }

                    result[1] = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_SET_INTEGRITY_INFORMATION is supported");

                    #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,
                    fileId,
                    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_FileLevelTrim(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting FSCTL_FILE_LEVEL_TRIM =====");
            string content = Smb2Utility.CreateRandomString(32);

            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);

                #region Create
                logWriter.AddLog(LogLevel.Information, "Client creates a file to prepare for the trimming");
                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileId;
                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 fileId,
                    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,
                    fileId,
                    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 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,
                    fileId,
                    Flags_Values.NONE,
                    out header,
                    out closeResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("CLOSE", header.Status);
                    throw new Exception("CLOSE failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                #endregion

                #region Create

                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 fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("CREATE", header.Status);
                    throw new Exception("Second CREATE failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                #endregion

                #region IOCTL FileLevelTrim

                FSCTL_FILE_LEVEL_TRIM_RANGE fileLevelTrimRange;
                Random random = new Random();
                uint offset = (uint)random.Next(0, 32 * 1024);
                uint length = (uint)random.Next(0, (int)(32 * 1024 - offset));
                fileLevelTrimRange.Offset = offset;
                fileLevelTrimRange.Length = length;

                FSCTL_FILE_LEVEL_TRIM_INPUT fileLevelTrimInput;
                fileLevelTrimInput.Key = 0;
                fileLevelTrimInput.NumRanges = 1;
                fileLevelTrimInput.Ranges = new FSCTL_FILE_LEVEL_TRIM_RANGE[] { fileLevelTrimRange };

                byte[] buffer = TypeMarshal.ToBytes<FSCTL_FILE_LEVEL_TRIM_INPUT>(fileLevelTrimInput);
                byte[] respOutput;

                IOCTL_Response ioCtlResponse;
                byte[] respInput = new byte[1024];
                logWriter.AddLog(LogLevel.Information, "Client sends FSCTL_FILE_LEVEL_TRIM to server");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_FILE_LEVEL_TRIM,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                #endregion

                DetectResult result = DetectResult.UnSupported;
                if (header.Status == Smb2Status.STATUS_SUCCESS)
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_FILE_LEVEL_TRIM is supported");
                }
                else
                {
                    LogFailedStatus("FSCTL_FILE_LEVEL_TRIM", header.Status);
                }

                #region Close

                client.Close(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileId,
                    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));
                    }

                    // 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 CheckCreateContexts_LeaseV2(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context LeaseV2 =====");
            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);

                Packet_Header header;

                #region Create

                FILEID fileId;
                Smb2CreateContextResponse[] serverCreateContexts = null;
                string fileName = "LeaseV2_" + Guid.NewGuid() + ".txt";
                CREATE_Response createResponse;
                logWriter.AddLog(LogLevel.Information, "Client opens file with a leaseV2 context");
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                    new Smb2CreateContextRequest[]
                    {
                        new Smb2CreateRequestLeaseV2
                        {
                            LeaseKey = Guid.NewGuid(),
                            LeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING,
                        }
                    },
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create with lease v2", header.Status);
                    return DetectResult.UnSupported;
                }

                #endregion

                if (serverCreateContexts != null)
                {
                    foreach (Smb2CreateContextResponse ctx in serverCreateContexts)
                    {
                        if (ctx is Smb2CreateResponseLeaseV2)
                        {
                            logWriter.AddLog(LogLevel.Information, "Create context LeaseV2 is supported");
                            return DetectResult.Supported;
                        }
                    }
                }

                logWriter.AddLog(LogLevel.Information, "The returned Create response doesn't contain lease v2 context. So Create context LeaseV2 is not supported");
                return DetectResult.UnSupported;
            }
        }
        public DetectResult CheckCreateContexts_HandleV2BatchOplock(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context HandleV2 with Batch oplock =====");
            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);

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileId;
                Guid leaseKey = Guid.NewGuid();
                Guid createGuid = Guid.NewGuid();
                CREATE_Response createResponse;
                Packet_Header header;
                string fileName = "DurableHandleV2WithBatchOplock_" + Guid.NewGuid() + ".txt";
                logWriter.AddLog(LogLevel.Information, "Client opens file with a durable handle v2 and Batch oplock");
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH,
                    new Smb2CreateContextRequest[]
                    {
                        new Smb2CreateDurableHandleRequestV2
                        {
                             CreateGuid = createGuid,
                             Timeout = 0,
                        }
                    },
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create durable handle v2 with Batch oplock", header.Status);
                    return DetectResult.UnSupported;
                }

                if (serverCreateContexts != null)
                {
                    foreach (Smb2CreateContextResponse ctx in serverCreateContexts)
                    {
                        if (ctx is Smb2CreateDurableHandleResponseV2)
                        {
                            logWriter.AddLog(LogLevel.Information, "Create context HandleV2 with Batch oplock is supported");
                            return DetectResult.Supported;
                        }
                    }
                }

                logWriter.AddLog(LogLevel.Information,
                    "The returned Create response doesn't contain durable handle v2 response. So Create context HandleV2 with Batch oplock is not supported");
                return DetectResult.UnSupported;
            }
        }
예제 #7
0
        private void DeleteTestVHDByClient(DetectionInfo info, string vhdName)
        {
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong  messageId = default;
                ulong  sessionId = default;
                uint   treeId    = default;
                FILEID fileId    = default;

                try
                {
                    logWriter.AddLog(DetectLogLevel.Information, string.Format("Try to connect share {0}.", info.BasicShareName));
                    ConnectToShare(info.BasicShareName, info, client, out messageId, out sessionId, out treeId);
                }
                catch
                {
                    // Show error to user.
                    logWriter.AddLog(DetectLogLevel.Error, "Did not find shares on SUT. Please check the share setting and SUT password.");
                }

                var packetHeader = (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE;

                try
                {
                    var status = client.Create(
                        1,
                        1,
                        packetHeader,
                        messageId++,
                        sessionId,
                        treeId,
                        vhdName,
                        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 | CreateOptions_Values.FILE_DELETE_ON_CLOSE,
                        CreateDisposition_Values.FILE_OPEN_IF,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                        null,
                        out fileId,
                        out _,
                        out _,
                        out _);

                    if (status != Smb2Status.STATUS_SUCCESS)
                    {
                        LogFailedStatus("CREATE", status);
                        throw new Exception("CREATE failed with " + Smb2Status.GetStatusCode(status));
                    }
                }
                finally
                {
                    try
                    {
                        LogOffSession(client, packetHeader, messageId, sessionId, treeId, fileId);
                    }
                    catch (Exception ex)
                    {
                        logWriter.AddLog(DetectLogLevel.Information, string.Format("Exception thrown when logging off the share, reason {0}.", ex.Message));
                    }
                }
            }
        }
        /// <summary>
        /// To check the create contexts.
        /// </summary>
        /// <param name="sharename">The share name</param>
        /// <param name="info">The detection information</param>
        /// <returns>Returns a DetectResult instance</returns>
        public DetectResult CheckCreateContexts_AppInstanceId(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context AppInstanceId =====");
            using (Smb2Client clientForInitialOpen = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)),
                   clientForReOpen = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageIdInitial;
                ulong sessionIdInitial;
                uint  treeIdInitial;
                logWriter.AddLog(LogLevel.Information, "Start first client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
                ConnectToShare(sharename, info, clientForInitialOpen, out messageIdInitial, out sessionIdInitial, out treeIdInitial);

                #region client 1 connect to server
                Guid                        appInstanceId = Guid.NewGuid();
                FILEID                      fileIdInitial;
                CREATE_Response             createResponse;
                Packet_Header               header;
                Smb2CreateContextResponse[] serverCreateContexts;
                string                      fileName = "AppInstanceId_" + Guid.NewGuid() + ".txt";
                logWriter.AddLog(LogLevel.Information, "The first client opens a file with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 and SMB2_CREATE_APP_INSTANCE_ID.");
                uint status = clientForInitialOpen.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageIdInitial++,
                    sessionIdInitial,
                    treeIdInitial,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    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,
                    new Smb2CreateContextRequest[] {
                    new Smb2CreateDurableHandleRequestV2
                    {
                        CreateGuid = Guid.NewGuid()
                    },
                    new Smb2CreateAppInstanceId
                    {
                        AppInstanceId = appInstanceId
                    }
                },
                    out fileIdInitial,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create", header.Status);
                    return(DetectResult.UnSupported);
                }
                #endregion

                #region client 2 connect to server

                ulong messageId;
                ulong sessionId;
                uint  treeId;
                logWriter.AddLog(LogLevel.Information, "Start second client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
                ConnectToShare(sharename, info, clientForReOpen, out messageId, out sessionId, out treeId);

                try
                {
                    // Test if a second client can close the previous open.
                    FILEID fileId;
                    logWriter.AddLog(LogLevel.Information, "The second client opens the same file with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 and same AppInstanceId.");
                    status = clientForReOpen.Create(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        fileName,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.NONE,
                        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,
                        new Smb2CreateContextRequest[] {
                        new Smb2CreateDurableHandleRequestV2
                        {
                            CreateGuid = Guid.NewGuid()
                        },
                        new Smb2CreateAppInstanceId
                        {
                            AppInstanceId = appInstanceId
                        }
                    },
                        out fileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse,
                        0);
                }
                catch (Exception ex)
                {
                    logWriter.AddLog(LogLevel.Information, "Create failed, reason: " + ex.Message);
                    return(DetectResult.UnSupported);
                }

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create", header.Status);
                    return(DetectResult.UnSupported);
                }
                #endregion

                // Write data using the first client
                // If AppInstanceId is supported, then the open should be closed.
                WRITE_Response writeResponse;
                logWriter.AddLog(LogLevel.Information, "The first client writes to the file to check if the open is closed");
                status = clientForInitialOpen.Write(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageIdInitial++,
                    sessionIdInitial,
                    treeIdInitial,
                    0,
                    fileIdInitial,
                    Channel_Values.CHANNEL_NONE,
                    WRITE_Request_Flags_Values.None,
                    new byte[0],
                    Encoding.ASCII.GetBytes("AppInstanceId"),
                    out header,
                    out writeResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (status == Smb2Status.STATUS_FILE_CLOSED)
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "The open is closed. So Create context AppInstanceId is supported");
                }
                else
                {
                    logWriter.AddLog(LogLevel.Information, "The open is not closed. So Create context AppInstanceId is not supported");
                }
                return(result);
            }
        }
        public DetectResult[] CheckIOCTL_IntegrityInfo(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL IntegrityInfo =====");
            logWriter.AddLog(LogLevel.Information, "Share name: " + sharename);

            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);

                #region Create

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID          fileId;
                CREATE_Response createResponse;
                Packet_Header   header;
                logWriter.AddLog(LogLevel.Information, "Client opens a file");
                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 fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("CREATE", header.Status);
                    throw new Exception("CREATE failed with with " + Smb2Status.GetStatusCode(header.Status));
                }

                #endregion

                #region IOCTL GET IntegrityInfo

                logWriter.AddLog(LogLevel.Information, "Client sends IOCTL request with FSCTL_GET_INTEGRITY_INFORMATION.");
                FSCTL_GET_INTEGRITY_INFO_OUTPUT getIntegrityInfo;
                IOCTL_Response ioCtlResponse;
                byte[]         buffer     = new byte[1024];
                byte[]         respInput  = new byte[1024];
                byte[]         respOutput = new byte[1024];

                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_GET_INTEGRITY_INFORMATION,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult[] result = { DetectResult.UnSupported, DetectResult.UnSupported };

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    // Get_Integrity is not supported
                    // Set_Integrity cannot be tested.
                    LogFailedStatus("GET_INTEGRITY_INFORMATION", header.Status);
                    return(result);
                }

                getIntegrityInfo = TypeMarshal.ToStruct <FSCTL_GET_INTEGRITY_INFO_OUTPUT>(respOutput);

                result[0] = DetectResult.Supported;
                logWriter.AddLog(LogLevel.Information, "FSCTL_GET_INTEGRITY_INFORMATION is supported");

                #endregion

                #region IOCTL SET IntegrityInfo

                logWriter.AddLog(LogLevel.Information,
                                 "Client sends IOCTL request with FSCTL_SET_INTEGRITY_INFORMATION after changed the value of the following fields in FSCTL_SET_INTEGRIY_INFO_INPUT: "
                                 + "ChecksumAlgorithm, Flags, Reserved.");
                FSCTL_SET_INTEGRIY_INFO_INPUT setIntegrityInfo;
                setIntegrityInfo.ChecksumAlgorithm = FSCTL_SET_INTEGRITY_INFO_INPUT_CHECKSUMALGORITHM.CHECKSUM_TYPE_CRC64;
                setIntegrityInfo.Flags             = FSCTL_SET_INTEGRITY_INFO_INPUT_FLAGS.FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF;
                setIntegrityInfo.Reserved          = FSCTL_SET_INTEGRITY_INFO_INPUT_RESERVED.V1;
                buffer = TypeMarshal.ToBytes <FSCTL_SET_INTEGRIY_INFO_INPUT>(setIntegrityInfo);

                respInput  = new byte[1024];
                respOutput = new byte[1024];

                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_SET_INTEGRITY_INFORMATION,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                #endregion

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("SET_INTEGRITY_INFORMATION", header.Status);
                }
                else
                {
                    #region IOCTL GET IntegrityInfo

                    buffer     = new byte[1024];
                    respInput  = new byte[1024];
                    respOutput = new byte[1024];
                    logWriter.AddLog(LogLevel.Information, "Client sends second FSCTL_GET_INTEGRITY_INFORMATION.");
                    client.IoCtl(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        CtlCode_Values.FSCTL_GET_INTEGRITY_INFORMATION,
                        fileId,
                        0,
                        buffer,
                        64 * 1024,
                        IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                        out respInput,
                        out respOutput,
                        out header,
                        out ioCtlResponse,
                        0);

                    getIntegrityInfo = TypeMarshal.ToStruct <FSCTL_GET_INTEGRITY_INFO_OUTPUT>(respOutput);

                    if (header.Status != Smb2Status.STATUS_SUCCESS)
                    {
                        LogFailedStatus("Second GET_INTEGRITY_INFORMATION", header.Status);
                    }

                    if ((ushort)setIntegrityInfo.ChecksumAlgorithm != (ushort)getIntegrityInfo.ChecksumAlgorithm)
                    {
                        logWriter.AddLog(LogLevel.Information, "Failed to set the ChecksumAlgorithm field to value " + setIntegrityInfo.ChecksumAlgorithm);
                    }

                    result[1] = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_SET_INTEGRITY_INFORMATION is supported");

                    #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,
                    fileId,
                    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_ResilientHandle(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ResilientHandle =====");

            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);

                #region Create

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID          fileId;
                CREATE_Response createResponse;
                Packet_Header   header;
                logWriter.AddLog(LogLevel.Information, "Client opens a file");
                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 fileId,
                    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 IOCTL ResilientHandle

                IOCTL_Response             ioCtlResponse;
                byte[]                     inputInResponse;
                byte[]                     outputInResponse;
                uint                       inputCount       = (uint)Marshal.SizeOf(typeof(NETWORK_RESILIENCY_Request));
                NETWORK_RESILIENCY_Request resilientRequest = new NETWORK_RESILIENCY_Request()
                {
                    Timeout = 120
                };

                byte[] resiliencyRequestBytes = TypeMarshal.ToBytes <NETWORK_RESILIENCY_Request>(resilientRequest);
                byte[] buffer = resiliencyRequestBytes;
                if (inputCount < resiliencyRequestBytes.Length)
                {
                    buffer = new byte[inputCount];
                    Array.Copy(resiliencyRequestBytes, buffer, buffer.Length);
                }
                else if (inputCount > resiliencyRequestBytes.Length)
                {
                    buffer = new byte[inputCount];
                    Array.Copy(resiliencyRequestBytes, buffer, resiliencyRequestBytes.Length);
                }

                logWriter.AddLog(LogLevel.Information, "Client sends an IOCTL FSCTL_LMR_REQUEST_RESILLIENCY request.");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_LMR_REQUEST_RESILIENCY,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out inputInResponse,
                    out outputInResponse,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("FSCTL_LMR_REQUEST_RESILIENCY", header.Status);
                }
                else
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_LMR_REQUEST_RESILIENCY is supported");
                }

                #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,
                    fileId,
                    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_FileLevelTrim(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting FSCTL_FILE_LEVEL_TRIM =====");
            string content = Smb2Utility.CreateRandomString(32);

            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);

                #region Create
                logWriter.AddLog(LogLevel.Information, "Client creates a file to prepare for the trimming");
                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID          fileId;
                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 fileId,
                    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,
                    fileId,
                    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 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,
                    fileId,
                    Flags_Values.NONE,
                    out header,
                    out closeResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("CLOSE", header.Status);
                    throw new Exception("CLOSE failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                #endregion

                #region Create

                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 fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("CREATE", header.Status);
                    throw new Exception("Second CREATE failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                #endregion

                #region IOCTL FileLevelTrim

                FSCTL_FILE_LEVEL_TRIM_RANGE fileLevelTrimRange;
                Random random = new Random();
                uint   offset = (uint)random.Next(0, 32 * 1024);
                uint   length = (uint)random.Next(0, (int)(32 * 1024 - offset));
                fileLevelTrimRange.Offset = offset;
                fileLevelTrimRange.Length = length;

                FSCTL_FILE_LEVEL_TRIM_INPUT fileLevelTrimInput;
                fileLevelTrimInput.Key       = 0;
                fileLevelTrimInput.NumRanges = 1;
                fileLevelTrimInput.Ranges    = new FSCTL_FILE_LEVEL_TRIM_RANGE[] { fileLevelTrimRange };

                byte[] buffer = TypeMarshal.ToBytes <FSCTL_FILE_LEVEL_TRIM_INPUT>(fileLevelTrimInput);
                byte[] respOutput;


                IOCTL_Response ioCtlResponse;
                byte[]         respInput = new byte[1024];
                logWriter.AddLog(LogLevel.Information, "Client sends FSCTL_FILE_LEVEL_TRIM to server");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_FILE_LEVEL_TRIM,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                #endregion

                DetectResult result = DetectResult.UnSupported;
                if (header.Status == Smb2Status.STATUS_SUCCESS)
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_FILE_LEVEL_TRIM is supported");
                }
                else
                {
                    LogFailedStatus("FSCTL_FILE_LEVEL_TRIM", header.Status);
                }

                #region Close

                client.Close(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileId,
                    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);
            }
        }
예제 #13
0
        /// <summary>
        /// Connect to the Server and establish the named pipe transport.
        /// </summary>
        private void ConnectToServer()
        {
            smb2Client = new Smb2Client(smb2ClientTimeout);

            if (IPAddress.TryParse(serverName, out var serverIp))
            {
                smb2Client.ConnectOverTCP(serverIp);
            }
            else
            {
                var serverHostEntry = Dns.GetHostEntry(serverName);
                smb2Client.ConnectOverTCP(serverHostEntry.AddressList[0]);
            }

            var validDialects = new DialectRevision[]
            {
                DialectRevision.Smb2002,
                DialectRevision.Smb21,
                DialectRevision.Smb30,
                DialectRevision.Smb302,
                DialectRevision.Smb311
            };

            var preauthIntegrityHashIDs = new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 };
            var encryptionAlgorithms    = new EncryptionAlgorithm[] { EncryptionAlgorithm.ENCRYPTION_AES128_GCM, EncryptionAlgorithm.ENCRYPTION_AES128_CCM };
            var status = smb2Client.Negotiate(
                creditCharge: 1,
                creditRequest: 1,
                flags: defaultFlags,
                messageId: messageId++,
                // Will negotiate highest dialect server supports
                dialects: validDialects,
                securityMode: SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                capabilities: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_ENCRYPTION | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_LARGE_MTU,
                clientGuid: Guid.NewGuid(),
                out var selectedDialect,
                out var serverGssToken,
                out Packet_Header _,
                out var negotiateResponse,
                preauthHashAlgs: preauthIntegrityHashIDs,
                encryptionAlgs: encryptionAlgorithms);

            CheckStatusCode(status, nameof(Smb2Client.Negotiate));

            var sessionSiginingRequired = negotiateResponse.SecurityMode.HasFlag(NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED);

            if (sessionSiginingRequired)
            {
                defaultFlags |= Packet_Header_Flags_Values.FLAGS_SIGNED;
            }

            var usedSecurityPackageType = (SecurityPackageType)Enum.Parse(typeof(SecurityPackageType), securityPackage);
            var sspiClientGss           = new SspiClientSecurityContext(
                usedSecurityPackageType,
                new AccountCredential(domainName, userName, password),
                Smb2Utility.GetCifsServicePrincipalName(serverName),
                ClientSecurityContextAttribute.None,
                SecurityTargetDataRepresentation.SecurityNativeDrep);

            if (usedSecurityPackageType == SecurityPackageType.Negotiate && useServerGssToken)
            {
                sspiClientGss.Initialize(serverGssToken);
            }
            else
            {
                sspiClientGss.Initialize(null);
            }

            do
            {
                status = smb2Client.SessionSetup(
                    creditCharge: 1,
                    creditRequest: 1,
                    flags: Packet_Header_Flags_Values.NONE,
                    messageId: messageId++,
                    sessionId: sessionId,
                    sessionSetupFlags: SESSION_SETUP_Request_Flags.NONE,
                    securityMode: SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    capabilities: SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                    previousSessionId: 0,
                    clientGssToken: sspiClientGss.Token,
                    out sessionId,
                    out serverGssToken,
                    out _,
                    out _);
                CheckStatusCode(status, nameof(Smb2Client.SessionSetup));

                if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) &&
                    serverGssToken != null && serverGssToken.Length > 0)
                {
                    sspiClientGss.Initialize(serverGssToken);
                }
            } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

            var treeConnectSigningRequired = sessionSiginingRequired || (selectedDialect >= DialectRevision.Smb311);

            smb2Client.GenerateCryptoKeys(
                sessionId,
                sspiClientGss.SessionKey,
                treeConnectSigningRequired,
                false);

            status = smb2Client.TreeConnect(
                creditCharge: 1,
                creditRequest: 1,
                flags: treeConnectSigningRequired ? defaultFlags | Packet_Header_Flags_Values.FLAGS_SIGNED : defaultFlags,
                messageId: messageId++,
                sessionId: sessionId,
                $"\\\\{serverName}\\IPC$",
                out treeId,
                out _,
                out _);
            CheckStatusCode(status, nameof(Smb2Client.TreeConnect));

            smb2Client.EnableSessionSigningAndEncryption(sessionId, sessionSiginingRequired, false);

            status = smb2Client.Create(
                creditCharge: 1,
                creditRequest: 1,
                flags: defaultFlags,
                messageId: messageId++,
                sessionId: sessionId,
                treeId: treeId,
                path: pipeName,
                desiredAccess: AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE,
                shareAccess: ShareAccess_Values.FILE_SHARE_READ,
                createOptions: CreateOptions_Values.NONE,
                createDispositions: CreateDisposition_Values.FILE_OPEN_IF,
                fileAttributes: File_Attributes.NONE,
                impersonationLevel: ImpersonationLevel_Values.Impersonation,
                securityFlag: SecurityFlags_Values.NONE,
                requestedOplockLevel: RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                createContexts: null,
                out fileId,
                out _,
                out _,
                out _);
            CheckStatusCode(status, nameof(Smb2Client.Create));
        }
예제 #14
0
        /// <summary>
        /// Get branchcache version supported information, which version SUT supports depends on the IOCTL_READ_HASH response code
        /// </summary>
        /// <param name="info">The detection information</param>
        /// <returns></returns>
        public VersionInfo FetchVersionInfo(DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detect Version Info =====");

            Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds));

            AddToClientList(client);
            Packet_Header      header;
            Guid               clientGuid;
            NEGOTIATE_Response negotiateResp;
            ulong              messageId = 1;
            ulong              sessionId = 0;
            uint               treeId    = 0;

            try
            {
                UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResp);
            }
            catch (Exception ex)
            {
                logWriter.AddLog(LogLevel.Warning, "Failed", false, Detector.LogStyle.StepFailed);
                logWriter.AddLineToLog(LogLevel.Information);
                logWriter.AddLog(LogLevel.Error, string.Format("User log on failed: {0}", ex.Message));
            }

            detectionInfo.ResetDetectResult();

            #region TreeConnect

            TREE_CONNECT_Response treeConnectResp;
            string uncSharePath = Smb2Utility.GetUncPath(info.ContentServerName, defaultShare);
            client.TreeConnect(
                1,
                1,
                Packet_Header_Flags_Values.FLAGS_SIGNED,
                messageId++,
                sessionId,
                uncSharePath,
                out treeId,
                out header,
                out treeConnectResp);

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("TREECONNECT", header.Status);
                throw new Exception("TREECONNECT failed with " + Smb2Status.GetStatusCode(header.Status));
            }
            #endregion

            CREATE_Response             createResp;
            FILEID                      fileId;
            Smb2CreateContextResponse[] serverCreateContexts = null;
            VersionInfo                 versionInfo          = new VersionInfo();
            versionInfo.branchCacheVersion = BranchCacheVersion.NotSupported;
            string fileName = "MultipleBlocks.txt";
            client.Create(
                1,
                1,
                Packet_Header_Flags_Values.FLAGS_SIGNED,
                messageId++,
                sessionId,
                treeId,
                fileName,
                AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE,
                ShareAccess_Values.NONE,
                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 fileId,
                out serverCreateContexts,
                out header,
                out createResp);

            HASH_HEADER hashHeader;
            byte[]      hashData = null;

            // Trigger to generate Content Information V1
            uint status = 0;
            status = ReadHash(
                client,
                Packet_Header_Flags_Values.FLAGS_SIGNED,
                messageId++,
                treeId,
                sessionId,
                fileId,
                SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST,
                SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_1,
                SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_HASH_BASED,
                0,
                uint.MaxValue,
                out hashHeader,
                out hashData);

            // Retrieve Content Information V1
            status = ReadHash(
                client,
                Packet_Header_Flags_Values.FLAGS_SIGNED,
                messageId++,
                treeId,
                sessionId,
                fileId,
                SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST,
                SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_1,
                SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_HASH_BASED,
                0,
                uint.MaxValue,
                out hashHeader,
                out hashData);

            if (status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("READ_HASH_V1", header.Status);
            }
            else
            {
                versionInfo.branchCacheVersion = BranchCacheVersion.BranchCacheVersion1;
            }

            // Trigger to generate Content Information V2
            status = ReadHash(
                client,
                Packet_Header_Flags_Values.FLAGS_SIGNED,
                messageId++,
                treeId,
                sessionId,
                fileId,
                SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST,
                SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_2,
                SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_FILE_BASED,
                0,
                uint.MaxValue,
                out hashHeader,
                out hashData);

            status = ReadHash(
                client,
                Packet_Header_Flags_Values.FLAGS_SIGNED,
                messageId++,
                treeId,
                sessionId,
                fileId,
                SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST,
                SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_2,
                SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_FILE_BASED,
                0,
                uint.MaxValue,
                out hashHeader,
                out hashData);

            if (status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("READ_HASH_V2", header.Status);
            }
            else
            {
                versionInfo.branchCacheVersion |= BranchCacheVersion.BranchCacheVersion2;
            }

            try
            {
                LOGOFF_Response logoffResponse;
                client.LogOff(1, 1, Packet_Header_Flags_Values.FLAGS_SIGNED, messageId++, sessionId, out header, out logoffResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("LOGOFF", header.Status);
                }
            }
            catch (Exception e)
            {
                logWriter.AddLog(LogLevel.Information, "Exception in Cleanup: " + e.Message);
            }

            return(versionInfo);
        }
        public DetectResult CheckIOCTL_ResilientHandle(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ResilientHandle =====");

            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);

                #region Create

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileId;
                CREATE_Response createResponse;
                Packet_Header header;
                logWriter.AddLog(LogLevel.Information, "Client opens a file");
                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 fileId,
                    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 IOCTL ResilientHandle

                IOCTL_Response ioCtlResponse;
                byte[] inputInResponse;
                byte[] outputInResponse;
                uint inputCount = (uint)Marshal.SizeOf(typeof(NETWORK_RESILIENCY_Request));
                NETWORK_RESILIENCY_Request resilientRequest = new NETWORK_RESILIENCY_Request()
                {
                    Timeout = 120
                };

                byte[] resiliencyRequestBytes = TypeMarshal.ToBytes<NETWORK_RESILIENCY_Request>(resilientRequest);
                byte[] buffer = resiliencyRequestBytes;
                if (inputCount < resiliencyRequestBytes.Length)
                {
                    buffer = new byte[inputCount];
                    Array.Copy(resiliencyRequestBytes, buffer, buffer.Length);
                }
                else if (inputCount > resiliencyRequestBytes.Length)
                {
                    buffer = new byte[inputCount];
                    Array.Copy(resiliencyRequestBytes, buffer, resiliencyRequestBytes.Length);
                }

                logWriter.AddLog(LogLevel.Information, "Client sends an IOCTL FSCTL_LMR_REQUEST_RESILLIENCY request.");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_LMR_REQUEST_RESILIENCY,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out inputInResponse,
                    out outputInResponse,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("FSCTL_LMR_REQUEST_RESILIENCY", header.Status);
                }
                else
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_LMR_REQUEST_RESILIENCY is supported");
                }

                #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,
                    fileId,
                    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 CheckCreateContexts_HandleV1BatchOplock(string sharename, DialectRevision smb2Dialect, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context HandleV1 with Batch oplock =====");
            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);

                Packet_Header header;

                #region Create
                FILEID fileId;
                Smb2CreateContextResponse[] serverCreateContexts = null;
                string          fileName = "DurableHandleV1BatchOplock_" + Guid.NewGuid() + ".txt";
                CREATE_Response createResponse;
                logWriter.AddLog(LogLevel.Information, "Client opens file with a durable handle v1 and batch oplock");
                uint status = client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH,
                    new Smb2CreateContextRequest[]
                {
                    new Smb2CreateDurableHandleRequest
                    {
                        DurableRequest = Guid.Empty,
                    },
                },
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create durable handle v1 with batch oplock", header.Status);
                    return(DetectResult.UnSupported);
                }

                #endregion

                if (serverCreateContexts != null)
                {
                    foreach (Smb2CreateContextResponse ctx in serverCreateContexts)
                    {
                        if (ctx is Smb2CreateDurableHandleResponse)
                        {
                            logWriter.AddLog(LogLevel.Information, "Create context HandleV1 with Batch oplock is supported");
                            return(DetectResult.Supported);
                        }
                    }
                }

                logWriter.AddLog(LogLevel.Information,
                                 "The returned Create response doesn't contain handle v1 context. So Create context HandleV1 with Batch oplock is not supported");
                return(DetectResult.UnSupported);
            }
        }
        /// <summary>
        /// To check the create contexts.
        /// </summary>
        /// <param name="sharename">The share name</param>
        /// <param name="info">The detection information</param>
        /// <returns>Returns a DetectResult instance</returns>
        public DetectResult CheckCreateContexts_AppInstanceId(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context AppInstanceId =====");
            using (Smb2Client clientForInitialOpen = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)),
                clientForReOpen = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageIdInitial;
                ulong sessionIdInitial;
                uint treeIdInitial;
                logWriter.AddLog(LogLevel.Information, "Start first client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
                ConnectToShare(sharename, info, clientForInitialOpen, out messageIdInitial, out sessionIdInitial, out treeIdInitial);

                #region client 1 connect to server
                Guid appInstanceId = Guid.NewGuid();
                FILEID fileIdInitial;
                CREATE_Response createResponse;
                Packet_Header header;
                Smb2CreateContextResponse[] serverCreateContexts;
                string fileName = "AppInstanceId_" + Guid.NewGuid() + ".txt";
                logWriter.AddLog(LogLevel.Information, "The first client opens a file with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 and SMB2_CREATE_APP_INSTANCE_ID.");
                uint status = clientForInitialOpen.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageIdInitial++,
                    sessionIdInitial,
                    treeIdInitial,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    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,
                    new Smb2CreateContextRequest[] {
                        new Smb2CreateDurableHandleRequestV2
                        {
                             CreateGuid = Guid.NewGuid()
                        },
                        new Smb2CreateAppInstanceId
                        {
                             AppInstanceId = appInstanceId
                        }
                    },
                    out fileIdInitial,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create", header.Status);
                    return DetectResult.UnSupported;
                }
                #endregion

                #region client 2 connect to server

                ulong messageId;
                ulong sessionId;
                uint treeId;
                logWriter.AddLog(LogLevel.Information, "Start second client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
                ConnectToShare(sharename, info, clientForReOpen, out messageId, out sessionId, out treeId);

                try
                {
                    // Test if a second client can close the previous open.
                    FILEID fileId;
                    logWriter.AddLog(LogLevel.Information, "The second client opens the same file with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 and same AppInstanceId.");
                    status = clientForReOpen.Create(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        fileName,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.NONE,
                        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,
                        new Smb2CreateContextRequest[] {
                            new Smb2CreateDurableHandleRequestV2
                            {
                                 CreateGuid = Guid.NewGuid()
                            },
                            new Smb2CreateAppInstanceId
                            {
                                 AppInstanceId = appInstanceId
                            }
                        },
                        out fileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse,
                        0);
                }
                catch (Exception ex)
                {
                    logWriter.AddLog(LogLevel.Information, "Create failed, reason: " + ex.Message);
                    return DetectResult.UnSupported;
                }

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create", header.Status);
                    return DetectResult.UnSupported;
                }
                #endregion

                // Write data using the first client
                // If AppInstanceId is supported, then the open should be closed.
                WRITE_Response writeResponse;
                logWriter.AddLog(LogLevel.Information, "The first client writes to the file to check if the open is closed");
                status = clientForInitialOpen.Write(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageIdInitial++,
                    sessionIdInitial,
                    treeIdInitial,
                    0,
                    fileIdInitial,
                    Channel_Values.CHANNEL_NONE,
                    WRITE_Request_Flags_Values.None,
                    new byte[0],
                    Encoding.ASCII.GetBytes("AppInstanceId"),
                    out header,
                    out writeResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (status == Smb2Status.STATUS_FILE_CLOSED)
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "The open is closed. So Create context AppInstanceId is supported");
                }
                else
                {
                    logWriter.AddLog(LogLevel.Information, "The open is not closed. So Create context AppInstanceId is not supported");
                }
                return result;
            }
        }
        public DetectResult CheckCreateContexts_HandleV2LeaseV2(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context HandleV2 with LeaseV2 =====");
            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);

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID          fileId;
                Guid            leaseKey   = Guid.NewGuid();
                Guid            createGuid = Guid.NewGuid();
                CREATE_Response createResponse;
                Packet_Header   header;
                string          fileName = "DurableHandleV2LeaseV2_" + Guid.NewGuid() + ".txt";
                logWriter.AddLog(LogLevel.Information, "Client opens file with a durable handle v2 and lease v2 context");
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                    new Smb2CreateContextRequest[]
                {
                    new Smb2CreateDurableHandleRequestV2
                    {
                        CreateGuid = createGuid,
                        Timeout    = 0,
                    },
                    new Smb2CreateRequestLeaseV2
                    {
                        LeaseKey   = Guid.NewGuid(),
                        LeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING,
                    }
                },
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create with lease v2", header.Status);
                    return(DetectResult.UnSupported);
                }

                if (serverCreateContexts != null)
                {
                    foreach (Smb2CreateContextResponse ctx in serverCreateContexts)
                    {
                        if (ctx is Smb2CreateDurableHandleResponseV2)
                        {
                            logWriter.AddLog(LogLevel.Information, "Create context HandleV2 with LeaseV2 is supported");
                            return(DetectResult.Supported);
                        }
                    }
                }

                logWriter.AddLog(LogLevel.Information,
                                 "The returned Create response doesn't contain durable handle v2 response. So Create context HandleV2 with LeaseV2 is not supported");
                return(DetectResult.UnSupported);
            }
        }
예제 #19
0
        private void CopyTestVHDByClient(DetectionInfo info, string vhdName)
        {
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong  messageId = default;
                ulong  sessionId = default;
                uint   treeId    = default;
                FILEID fileId    = default;

                try
                {
                    logWriter.AddLog(DetectLogLevel.Information, string.Format("Try to connect share {0}.", info.BasicShareName));
                    ConnectToShare(info.BasicShareName, info, client, out messageId, out sessionId, out treeId);
                }
                catch
                {
                    // Show error to user.
                    logWriter.AddLog(DetectLogLevel.Error, "Did not find shares on SUT. Please check the share setting and SUT password.");
                }

                var packetHeader = (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE;

                try
                {
                    var status = client.Create(
                        1,
                        1,
                        packetHeader,
                        messageId++,
                        sessionId,
                        treeId,
                        vhdName,
                        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 fileId,
                        out _,
                        out _,
                        out _);

                    if (status == Smb2Status.STATUS_SUCCESS)
                    {
                        var content      = File.ReadAllBytes(GetVhdSourcePath());
                        var messageCount = content.Length % 65536 == 0 ? content.Length / 65536 : content.Length / 65536 + 1; // Simplify credit calculation.
                        var offset       = 0ul;

                        while (messageCount > 0)
                        {
                            status = client.Write(
                                1,
                                1,
                                packetHeader,
                                messageId++,
                                sessionId,
                                treeId,
                                offset,
                                fileId,
                                Channel_Values.CHANNEL_NONE,
                                WRITE_Request_Flags_Values.None,
                                new byte[0],
                                content.Skip((int)offset).Take(65536).ToArray(),
                                out _,
                                out _);

                            if (status == Smb2Status.STATUS_SUCCESS)
                            {
                                offset += 65536;
                                messageCount--;
                            }
                            else
                            {
                                break;
                            }
                        }

                        if (status != Smb2Status.STATUS_SUCCESS)
                        {
                            LogFailedStatus("WRITE", status);
                            throw new Exception("WRITE failed with " + Smb2Status.GetStatusCode(status));
                        }
                    }
                    else
                    {
                        LogFailedStatus("CREATE", status);
                        throw new Exception("CREATE failed with " + Smb2Status.GetStatusCode(status));
                    }
                }
                finally
                {
                    try
                    {
                        LogOffSession(client, packetHeader, messageId, sessionId, treeId, fileId);
                    }
                    catch (Exception ex)
                    {
                        logWriter.AddLog(DetectLogLevel.Information, string.Format("Exception thrown when logging off the share, reason {0}.", ex.Message));
                    }
                }
            }
        }