SMBServer v1.0.5

This commit is contained in:
Tal Aloni 2016-12-22 20:51:16 +02:00
parent b75820452d
commit bd1006cb81
400 changed files with 28062 additions and 0 deletions

View file

@ -0,0 +1,74 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.Authentication
{
public class AVPairUtils
{
public static byte[] GetAVPairSequence(string domainName, string computerName)
{
KeyValuePairList<AVPairKey, byte[]> pairs = new KeyValuePairList<AVPairKey, byte[]>();
pairs.Add(AVPairKey.NbDomainName, UnicodeEncoding.Unicode.GetBytes(domainName));
pairs.Add(AVPairKey.NbComputerName, UnicodeEncoding.Unicode.GetBytes(computerName));
return AVPairUtils.GetAVPairSequenceBytes(pairs);
}
public static byte[] GetAVPairSequenceBytes(KeyValuePairList<AVPairKey, byte[]> pairs)
{
int length = 0;
foreach (KeyValuePair<AVPairKey, byte[]> pair in pairs)
{
length += 4 + pair.Value.Length;
}
length += 4;
byte[] result = new byte[length];
int offset = 0;
foreach (KeyValuePair<AVPairKey, byte[]> pair in pairs)
{
WriteAVPair(result, ref offset, pair.Key, pair.Value);
}
LittleEndianWriter.WriteUInt16(result, ref offset, (ushort)AVPairKey.EOL);
LittleEndianWriter.WriteUInt16(result, ref offset, 0);
return result;
}
public static void WriteAVPair(byte[] buffer, ref int offset, AVPairKey key, byte[] value)
{
LittleEndianWriter.WriteUInt16(buffer, ref offset, (ushort)key);
LittleEndianWriter.WriteUInt16(buffer, ref offset, (ushort)value.Length);
ByteWriter.WriteBytes(buffer, ref offset, value);
}
public static KeyValuePairList<AVPairKey, byte[]> ReadAVPairSequence(byte[] buffer, int offset)
{
KeyValuePairList<AVPairKey, byte[]> result = new KeyValuePairList<AVPairKey,byte[]>();
AVPairKey key = (AVPairKey)LittleEndianConverter.ToUInt16(buffer, offset);
while (key != AVPairKey.EOL)
{
KeyValuePair<AVPairKey, byte[]> pair = ReadAVPair(buffer, ref offset);
result.Add(pair);
key = (AVPairKey)LittleEndianConverter.ToUInt16(buffer, offset);
}
return result;
}
public static KeyValuePair<AVPairKey, byte[]> ReadAVPair(byte[] buffer, ref int offset)
{
AVPairKey key = (AVPairKey)LittleEndianReader.ReadUInt16(buffer, ref offset);
ushort length = LittleEndianReader.ReadUInt16(buffer, ref offset);
byte[] value = ByteReader.ReadBytes(buffer, ref offset, length);
return new KeyValuePair<AVPairKey, byte[]>(key, value);
}
}
}

View file

@ -0,0 +1,94 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.Authentication
{
/// <summary>
/// [MS-NLMP] AUTHENTICATE_MESSAGE (Type 3 Message)
/// </summary>
public class AuthenticateMessage
{
public string Signature; // 8 bytes
public MessageTypeName MessageType;
public byte[] LmChallengeResponse;
public byte[] NtChallengeResponse;
public string DomainName;
public string UserName;
public string WorkStation;
public byte[] EncryptedRandomSessionKey;
public NegotiateFlags NegotiateFlags;
public Version Version;
// 16-byte MIC field is omitted for Windows NT / 2000 / XP / Server 2003
public AuthenticateMessage()
{
Signature = AuthenticationMessageUtils.ValidSignature;
MessageType = MessageTypeName.Authenticate;
DomainName = String.Empty;
UserName = String.Empty;
WorkStation = String.Empty;
EncryptedRandomSessionKey = new byte[0];
}
public AuthenticateMessage(byte[] buffer)
{
Signature = ByteReader.ReadAnsiString(buffer, 0, 8);
MessageType = (MessageTypeName)LittleEndianConverter.ToUInt32(buffer, 8);
LmChallengeResponse = AuthenticationMessageUtils.ReadBufferPointer(buffer, 12);
NtChallengeResponse = AuthenticationMessageUtils.ReadBufferPointer(buffer, 20);
DomainName = AuthenticationMessageUtils.ReadUnicodeStringBufferPointer(buffer, 28);
UserName = AuthenticationMessageUtils.ReadUnicodeStringBufferPointer(buffer, 36);
WorkStation = AuthenticationMessageUtils.ReadUnicodeStringBufferPointer(buffer, 44);
EncryptedRandomSessionKey = AuthenticationMessageUtils.ReadBufferPointer(buffer, 52);
NegotiateFlags = (NegotiateFlags)LittleEndianConverter.ToUInt32(buffer, 60);
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
Version = new Version(buffer, 64);
}
}
public byte[] GetBytes()
{
int fixedLength = 64;
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
fixedLength += 8;
}
int payloadLength = LmChallengeResponse.Length + NtChallengeResponse.Length + DomainName.Length * 2 + UserName.Length * 2 + WorkStation.Length * 2 + EncryptedRandomSessionKey.Length;
byte[] buffer = new byte[fixedLength + payloadLength];
ByteWriter.WriteAnsiString(buffer, 0, AuthenticationMessageUtils.ValidSignature, 8);
LittleEndianWriter.WriteUInt32(buffer, 8, (uint)MessageType);
LittleEndianWriter.WriteUInt32(buffer, 60, (uint)NegotiateFlags);
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
Version.WriteBytes(buffer, 64);
}
int offset = fixedLength;
AuthenticationMessageUtils.WriteBufferPointer(buffer, 12, (ushort)LmChallengeResponse.Length, (uint)offset);
ByteWriter.WriteBytes(buffer, ref offset, LmChallengeResponse);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 20, (ushort)NtChallengeResponse.Length, (uint)offset);
ByteWriter.WriteBytes(buffer, ref offset, NtChallengeResponse);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 28, (ushort)(DomainName.Length * 2), (uint)offset);
ByteWriter.WriteUTF16String(buffer, ref offset, DomainName);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 36, (ushort)(UserName.Length * 2), (uint)offset);
ByteWriter.WriteUTF16String(buffer, ref offset, UserName);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 44, (ushort)(WorkStation.Length * 2), (uint)offset);
ByteWriter.WriteUTF16String(buffer, ref offset, WorkStation);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 52, (ushort)EncryptedRandomSessionKey.Length, (uint)offset);
ByteWriter.WriteBytes(buffer, ref offset, EncryptedRandomSessionKey);
return buffer;
}
}
}

View file

@ -0,0 +1,64 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.Authentication
{
public class AuthenticationMessageUtils
{
public const string ValidSignature = "NTLMSSP\0";
public static string ReadAnsiStringBufferPointer(byte[] buffer, int offset)
{
byte[] bytes = ReadBufferPointer(buffer, offset);
return ASCIIEncoding.Default.GetString(bytes);
}
public static string ReadUnicodeStringBufferPointer(byte[] buffer, int offset)
{
byte[] bytes = ReadBufferPointer(buffer, offset);
return UnicodeEncoding.Unicode.GetString(bytes);
}
public static byte[] ReadBufferPointer(byte[] buffer, int offset)
{
ushort length = LittleEndianConverter.ToUInt16(buffer, offset);
ushort maxLength = LittleEndianConverter.ToUInt16(buffer, offset + 2);
uint bufferOffset = LittleEndianConverter.ToUInt32(buffer, offset + 4);
if (length == 0)
{
return new byte[0];
}
else
{
return ByteReader.ReadBytes(buffer, (int)bufferOffset, length);
}
}
public static void WriteBufferPointer(byte[] buffer, int offset, ushort bufferLength, uint bufferOffset)
{
LittleEndianWriter.WriteUInt16(buffer, offset, bufferLength);
LittleEndianWriter.WriteUInt16(buffer, offset + 2, bufferLength);
LittleEndianWriter.WriteUInt32(buffer, offset + 4, bufferOffset);
}
public static bool IsSignatureValid(byte[] messageBytes)
{
string signature = ByteReader.ReadAnsiString(messageBytes, 0, 8);
return (signature == ValidSignature);
}
public static MessageTypeName GetMessageType(byte[] messageBytes)
{
return (MessageTypeName)LittleEndianConverter.ToUInt32(messageBytes, 8);
}
}
}

View file

@ -0,0 +1,77 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.Authentication
{
/// <summary>
/// [MS-NLMP] CHALLENGE_MESSAGE (Type 2 Message)
/// </summary>
public class ChallengeMessage
{
public string Signature; // 8 bytes
public MessageTypeName MessageType;
public string TargetName;
public NegotiateFlags NegotiateFlags;
public byte[] ServerChallenge; // 8 bytes
// Reserved - 8 bytes
public byte[] TargetInfo; // sequence of AV_PAIR structures
public Version Version;
public ChallengeMessage()
{
Signature = AuthenticationMessageUtils.ValidSignature;
MessageType = MessageTypeName.Challenge;
}
public ChallengeMessage(byte[] buffer)
{
Signature = ByteReader.ReadAnsiString(buffer, 0, 8);
MessageType = (MessageTypeName)LittleEndianConverter.ToUInt32(buffer, 8);
TargetName = AuthenticationMessageUtils.ReadUnicodeStringBufferPointer(buffer, 12);
NegotiateFlags = (NegotiateFlags)LittleEndianConverter.ToUInt32(buffer, 20);
ServerChallenge = ByteReader.ReadBytes(buffer, 24, 8);
// Reserved
TargetInfo = AuthenticationMessageUtils.ReadBufferPointer(buffer, 40);
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
Version = new Version(buffer, 48);
}
}
public byte[] GetBytes()
{
int fixedLength = 48;
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
fixedLength += 8;
}
int payloadLength = TargetName.Length * 2 + TargetInfo.Length;
byte[] buffer = new byte[fixedLength + payloadLength];
ByteWriter.WriteAnsiString(buffer, 0, AuthenticationMessageUtils.ValidSignature, 8);
LittleEndianWriter.WriteUInt32(buffer, 8, (uint)MessageType);
LittleEndianWriter.WriteUInt32(buffer, 20, (uint)NegotiateFlags);
ByteWriter.WriteBytes(buffer, 24, ServerChallenge);
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
Version.WriteBytes(buffer, 48);
}
int offset = fixedLength;
AuthenticationMessageUtils.WriteBufferPointer(buffer, 12, (ushort)(TargetName.Length * 2), (uint)offset);
ByteWriter.WriteUTF16String(buffer, ref offset, TargetName);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 40, (ushort)TargetInfo.Length, (uint)offset);
ByteWriter.WriteBytes(buffer, ref offset, TargetInfo);
return buffer;
}
}
}

View file

@ -0,0 +1,18 @@
namespace SMBLibrary.Authentication
{
public enum AVPairKey : ushort
{
EOL = 0x0000,
NbComputerName = 0x0001, // Unicode
NbDomainName = 0x0002, // Unicode
DnsComputerName = 0x0003, // Unicode
DnsDomainName = 0x0004, // Unicode
DnsTreeName = 0x0005, // Unicode
Flags = 0x0006, // UInt32
Timestamp = 0x0006, // Filetime
SingleHost = 0x0008, // platform-specific BLOB
TargetName = 0x0009, // Unicode
ChannelBindings = 0x000A, // MD5 Hash
}
}

View file

@ -0,0 +1,10 @@
namespace SMBLibrary.Authentication
{
public enum MessageTypeName : uint
{
Negotiate = 0x01,
Challenge = 0x02,
Authenticate = 0x03,
}
}

View file

@ -0,0 +1,48 @@
using System;
namespace SMBLibrary.Authentication
{
[Flags]
public enum NegotiateFlags : uint
{
NegotiateUnicode = 0x01, // NTLMSSP_NEGOTIATE_UNICODE
NegotiateOEM = 0x02, // NTLM_NEGOTIATE_OEM
RequestTarget = 0x04, // NTLMSSP_REQUEST_TARGET
NegotiateSign = 0x10, // NTLMSSP_NEGOTIATE_SIGN
NegotiateSeal = 0x20, // NTLMSSP_NEGOTIATE_SEAL
NegotiateDatagram = 0x40, // NTLMSSP_NEGOTIATE_DATAGRAM
/// <summary>
/// NegotiateLanManagerKey and NegotiateExtendedSecurity are mutually exclusive
/// If both are set then NegotiateLanManagerKey must be ignored
/// </summary>
NegotiateLanManagerKey = 0x80, // NTLMSSP_NEGOTIATE_LM_KEY
NegotiateNTLMKey = 0x200, // NTLMSSP_NEGOTIATE_NTLM
//NegotiateNTOnly = 0x400, // Unused, must be clear
/// <summary>
/// If set, the connection SHOULD be anonymous
/// </summary>
NegotiateAnonymous = 0x800,
NegotiateOEMDomainSupplied = 0x1000, // NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
NegotiateOEMWorkstationSupplied = 0x2000, // NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
NegotiateAlwaysSign = 0x8000, // NTLMSSP_NEGOTIATE_ALWAYS_SIGN
NegotiateTargetTypeDomain = 0x10000, // NTLMSSP_TARGET_TYPE_DOMAIN
NegotiateTargetTypeServer = 0x20000, // NTLMSSP_TARGET_TYPE_SERVER
NegotiateTargetTypeShare = 0x40000, // Unused, must be clear
/// <summary>
/// NegotiateLanManagerKey and NegotiateExtendedSecurity are mutually exclusive
/// If both are set then NegotiateLanManagerKey must be ignored
/// </summary>
NegotiateExtendedSecurity = 0x80000, // NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
NegotiateIdentify = 0x100000, // NTLMSSP_NEGOTIATE_IDENTIFY
RequestNonNTSession = 0x400000, // NTLMSSP_REQUEST_NON_NT_SESSION_KEY
NegotiateTargetInfo = 0x800000, // NTLMSSP_NEGOTIATE_TARGET_INFO
NegotiateVersion = 0x2000000, // NTLMSSP_NEGOTIATE_VERSION
Negotiate128 = 0x20000000, // NTLMSSP_NEGOTIATE_128
NegotiateKeyExchange = 0x40000000, // NTLMSSP_NEGOTIATE_KEY_EXCH
Negotiate56 = 0x80000000, // NTLMSSP_NEGOTIATE_56
}
}

View file

@ -0,0 +1,79 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.Authentication
{
/// <summary>
/// NTLMv2_CLIENT_CHALLENGE
/// </summary>
public class NTLMv2ClientChallengeStructure
{
public static readonly DateTime EpochTime = DateTime.FromFileTimeUtc(0);
public byte ResponseVersion;
public byte ResponseVersionHigh;
public DateTime Time;
public byte[] ClientChallenge;
public KeyValuePairList<AVPairKey, byte[]> AVPairs;
public NTLMv2ClientChallengeStructure()
{
}
public NTLMv2ClientChallengeStructure(DateTime time, byte[] clientChallenge, string domainName, string computerName)
{
ResponseVersion = 1;
ResponseVersionHigh = 1;
Time = time;
ClientChallenge = clientChallenge;
AVPairs = new KeyValuePairList<AVPairKey, byte[]>();
AVPairs.Add(AVPairKey.NbDomainName, UnicodeEncoding.Unicode.GetBytes(domainName));
AVPairs.Add(AVPairKey.NbComputerName, UnicodeEncoding.Unicode.GetBytes(computerName));
}
public NTLMv2ClientChallengeStructure(byte[] buffer) : this(buffer, 0)
{
}
public NTLMv2ClientChallengeStructure(byte[] buffer, int offset)
{
ResponseVersion = ByteReader.ReadByte(buffer, offset + 0);
ResponseVersionHigh = ByteReader.ReadByte(buffer, offset + 1);
long temp = LittleEndianConverter.ToInt64(buffer, offset + 8);
Time = DateTime.FromFileTimeUtc(temp);
ClientChallenge = ByteReader.ReadBytes(buffer, offset + 16, 8);
AVPairs = AVPairUtils.ReadAVPairSequence(buffer, offset + 28);
}
public byte[] GetBytes()
{
byte[] sequenceBytes = AVPairUtils.GetAVPairSequenceBytes(AVPairs);
byte[] timeBytes = LittleEndianConverter.GetBytes((ulong)Time.ToFileTimeUtc());
byte[] buffer = new byte[28 + sequenceBytes.Length];
ByteWriter.WriteByte(buffer, 0, ResponseVersion);
ByteWriter.WriteByte(buffer, 1, ResponseVersionHigh);
ByteWriter.WriteBytes(buffer, 8, timeBytes);
ByteWriter.WriteBytes(buffer, 16, ClientChallenge, 8);
ByteWriter.WriteBytes(buffer, 28, sequenceBytes);
return buffer;
}
/// <summary>
/// [MS-NLMP] Page 60, Response key calculation algorithm:
/// To create 'temp', 4 zero bytes will be appended to NTLMv2_CLIENT_CHALLENGE
/// </summary>
public byte[] GetBytesPadded()
{
return ByteUtils.Concatenate(GetBytes(), new byte[4]);
}
}
}

View file

@ -0,0 +1,74 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.Authentication
{
/// <summary>
/// [MS-NLMP] NEGOTIATE_MESSAGE (Type 1 Message)
/// </summary>
public class NegotiateMessage
{
public string Signature; // 8 bytes
public MessageTypeName MessageType;
public NegotiateFlags NegotiateFlags;
public string DomainName;
public string Workstation;
public Version Version;
public NegotiateMessage()
{
Signature = AuthenticationMessageUtils.ValidSignature;
MessageType = MessageTypeName.Negotiate;
DomainName = String.Empty;
Workstation = String.Empty;
}
public NegotiateMessage(byte[] buffer)
{
Signature = ByteReader.ReadAnsiString(buffer, 0, 8);
MessageType = (MessageTypeName)LittleEndianConverter.ToUInt32(buffer, 8);
NegotiateFlags = (NegotiateFlags)LittleEndianConverter.ToUInt32(buffer, 12);
DomainName = AuthenticationMessageUtils.ReadAnsiStringBufferPointer(buffer, 16);
Workstation = AuthenticationMessageUtils.ReadAnsiStringBufferPointer(buffer, 24);
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
Version = new Version(buffer, 32);
}
}
public byte[] GetBytes()
{
int fixedLength = 32;
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
fixedLength += 8;
}
int payloadLength = DomainName.Length * 2 + Workstation.Length * 2;
byte[] buffer = new byte[fixedLength + payloadLength];
ByteWriter.WriteAnsiString(buffer, 0, AuthenticationMessageUtils.ValidSignature, 8);
LittleEndianWriter.WriteUInt32(buffer, 8, (uint)MessageType);
LittleEndianWriter.WriteUInt32(buffer, 12, (uint)NegotiateFlags);
if ((NegotiateFlags & NegotiateFlags.NegotiateVersion) > 0)
{
Version.WriteBytes(buffer, 32);
}
int offset = fixedLength;
AuthenticationMessageUtils.WriteBufferPointer(buffer, 16, (ushort)(DomainName.Length * 2), (uint)offset);
ByteWriter.WriteUTF16String(buffer, ref offset, DomainName);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 16, (ushort)(Workstation.Length * 2), (uint)offset);
ByteWriter.WriteUTF16String(buffer, ref offset, Workstation);
return buffer;
}
}
}

View file

@ -0,0 +1,64 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.Authentication
{
public class Version
{
public const byte NTLMSSP_REVISION_W2K3 = 0x0F;
public byte ProductMajorVersion;
public byte ProductMinorVersion;
public ushort ProductBuild;
// Reserved - 3 bytes
public byte NTLMRevisionCurrent;
public Version(byte majorVersion, byte minorVersion, ushort build, byte ntlmRevisionCurrent)
{
ProductMajorVersion = majorVersion;
ProductMinorVersion = minorVersion;
ProductBuild = build;
NTLMRevisionCurrent = ntlmRevisionCurrent;
}
public Version(byte[] buffer, int offset)
{
ProductMajorVersion = ByteReader.ReadByte(buffer, offset + 0);
ProductMinorVersion = ByteReader.ReadByte(buffer, offset + 1);
ProductBuild = LittleEndianConverter.ToUInt16(buffer, offset + 2);
NTLMRevisionCurrent = ByteReader.ReadByte(buffer, offset + 7);
}
public void WriteBytes(byte[] buffer, int offset)
{
ByteWriter.WriteByte(buffer, offset + 0, ProductMajorVersion);
ByteWriter.WriteByte(buffer, offset + 1, ProductMinorVersion);
LittleEndianWriter.WriteUInt16(buffer, offset + 2, ProductBuild);
ByteWriter.WriteByte(buffer, offset + 7, NTLMRevisionCurrent);
}
public static Version WindowsXP
{
get
{
return new Version(5, 1, 2600, NTLMSSP_REVISION_W2K3);
}
}
public static Version Server2003
{
get
{
return new Version(5, 2, 3790, NTLMSSP_REVISION_W2K3);
}
}
}
}

View file

@ -0,0 +1,418 @@
/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD4 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD4 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
--------------------------------------------------------------
Ported from Norbert Hranitzky's (norbert.hranitzky@mchp.siemens.de)
Java version by Oren Novotny (osn@po.cwru.edu)
--------------------------------------------------------------
Adapted to C# 2.0 By Tal Aloni
--------------------------------------------------------------
*/
using System.Text;
namespace System.Security.Cryptography
{
using System;
/// <summary>
/// Implements the MD4 message digest algorithm in C#
/// </summary>
/// <remarks>
/// <p>
/// <b>References:</b>
/// <ol>
/// <li> Ronald L. Rivest,
/// "<a href = "http://www.roxen.com/rfc/rfc1320.html">
/// The MD4 Message-Digest Algorithm</a>",
/// IETF RFC-1320 (informational).
/// </li>
/// </ol>
/// </p>
/// </remarks>
internal class MD4
{
// MD4 specific object variables
//-----------------------------------------------------------------------
/// <summary>
/// The size in bytes of the input block to the transformation algorithm
/// </summary>
private const int BLOCK_LENGTH = 64; // = 512 / 8
/// <summary>
/// 512-bit work buffer = 16 x 32-bit words
/// </summary>
private readonly uint[] X = new uint[16];
/// <summary>
/// 4 32-bit words (interim result)
/// </summary>
private readonly uint[] context = new uint[4];
/// <summary>
/// 512-bit input buffer = 16 x 32-bit words holds until it reaches 512 bits
/// </summary>
private byte[] buffer = new byte[BLOCK_LENGTH];
/// <summary>
/// Number of bytes procesed so far mod. 2 power of 64.
/// </summary>
private long count;
// Constructors
//------------------------------------------------------------------------
public MD4()
{
EngineReset();
}
/// <summary>
/// This constructor is here to implement the clonability of this class
/// </summary>
/// <param name = "md"> </param>
private MD4(MD4 md)
: this()
{
//this();
context = (uint[])md.context.Clone();
buffer = (byte[])md.buffer.Clone();
count = md.count;
}
// Clonable method implementation
//-------------------------------------------------------------------------
public object Clone()
{
return new MD4(this);
}
// JCE methods
//-------------------------------------------------------------------------
/// <summary>
/// Resets this object disregarding any temporary data present at the
/// time of the invocation of this call.
/// </summary>
private void EngineReset()
{
// initial values of MD4 i.e. A, B, C, D
// as per rfc-1320; they are low-order byte first
context[0] = 0x67452301;
context[1] = 0xEFCDAB89;
context[2] = 0x98BADCFE;
context[3] = 0x10325476;
count = 0L;
for (int i = 0; i < BLOCK_LENGTH; i++)
buffer[i] = 0;
}
/// <summary>
/// Continues an MD4 message digest using the input byte
/// </summary>
/// <param name = "b">byte to input</param>
private void EngineUpdate(byte b)
{
// compute number of bytes still unhashed; ie. present in buffer
int i = (int)(count % BLOCK_LENGTH);
count++; // update number of bytes
buffer[i] = b;
if (i == BLOCK_LENGTH - 1)
Transform(ref buffer, 0);
}
/// <summary>
/// MD4 block update operation
/// </summary>
/// <remarks>
/// Continues an MD4 message digest operation by filling the buffer,
/// transform(ing) data in 512-bit message block(s), updating the variables
/// context and count, and leaving (buffering) the remaining bytes in buffer
/// for the next update or finish.
/// </remarks>
/// <param name = "input">input block</param>
/// <param name = "offset">start of meaningful bytes in input</param>
/// <param name = "len">count of bytes in input blcok to consider</param>
private void EngineUpdate(byte[] input, int offset, int len)
{
// make sure we don't exceed input's allocated size/length
if (offset < 0 || len < 0 || (long)offset + len > input.Length)
throw new ArgumentOutOfRangeException();
// compute number of bytes still unhashed; ie. present in buffer
int bufferNdx = (int)(count % BLOCK_LENGTH);
count += len; // update number of bytes
int partLen = BLOCK_LENGTH - bufferNdx;
int i = 0;
if (len >= partLen)
{
Array.Copy(input, offset + i, buffer, bufferNdx, partLen);
Transform(ref buffer, 0);
for (i = partLen; i + BLOCK_LENGTH - 1 < len; i += BLOCK_LENGTH)
Transform(ref input, offset + i);
bufferNdx = 0;
}
// buffer remaining input
if (i < len)
Array.Copy(input, offset + i, buffer, bufferNdx, len - i);
}
/// <summary>
/// Completes the hash computation by performing final operations such
/// as padding. At the return of this engineDigest, the MD engine is
/// reset.
/// </summary>
/// <returns>the array of bytes for the resulting hash value.</returns>
private byte[] EngineDigest()
{
// pad output to 56 mod 64; as RFC1320 puts it: congruent to 448 mod 512
int bufferNdx = (int)(count % BLOCK_LENGTH);
int padLen = (bufferNdx < 56) ? (56 - bufferNdx) : (120 - bufferNdx);
// padding is always binary 1 followed by binary 0's
byte[] tail = new byte[padLen + 8];
tail[0] = 0x80;
// append length before final transform
// save number of bits, casting the long to an array of 8 bytes
// save low-order byte first.
for (int i = 0; i < 8; i++)
tail[padLen + i] = (byte)((count * 8) >> (8 * i));
EngineUpdate(tail, 0, tail.Length);
byte[] result = new byte[16];
// cast this MD4's context (array of 4 uints) into an array of 16 bytes.
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
result[i * 4 + j] = (byte)(context[i] >> (8 * j));
// reset the engine
EngineReset();
return result;
}
/// <summary>
/// Returns a byte hash from a string
/// </summary>
/// <param name = "s">string to hash</param>
/// <returns>byte-array that contains the hash</returns>
public byte[] GetByteHashFromString(string s)
{
byte[] b = Encoding.UTF8.GetBytes(s);
MD4 md4 = new MD4();
md4.EngineUpdate(b, 0, b.Length);
return md4.EngineDigest();
}
/// <summary>
/// Returns a binary hash from an input byte array
/// </summary>
/// <param name = "b">byte-array to hash</param>
/// <returns>binary hash of input</returns>
public byte[] GetByteHashFromBytes(byte[] b)
{
MD4 md4 = new MD4();
md4.EngineUpdate(b, 0, b.Length);
return md4.EngineDigest();
}
/// <summary>
/// Returns a string that contains the hexadecimal hash
/// </summary>
/// <param name = "b">byte-array to input</param>
/// <returns>String that contains the hex of the hash</returns>
public string GetHexHashFromBytes(byte[] b)
{
byte[] e = GetByteHashFromBytes(b);
return BytesToHex(e, e.Length);
}
/// <summary>
/// Returns a byte hash from the input byte
/// </summary>
/// <param name = "b">byte to hash</param>
/// <returns>binary hash of the input byte</returns>
public byte[] GetByteHashFromByte(byte b)
{
MD4 md4 = new MD4();
md4.EngineUpdate(b);
return md4.EngineDigest();
}
/// <summary>
/// Returns a string that contains the hexadecimal hash
/// </summary>
/// <param name = "b">byte to hash</param>
/// <returns>String that contains the hex of the hash</returns>
public string GetHexHashFromByte(byte b)
{
byte[] e = GetByteHashFromByte(b);
return BytesToHex(e, e.Length);
}
/// <summary>
/// Returns a string that contains the hexadecimal hash
/// </summary>
/// <param name = "s">string to hash</param>
/// <returns>String that contains the hex of the hash</returns>
public string GetHexHashFromString(string s)
{
byte[] b = GetByteHashFromString(s);
return BytesToHex(b, b.Length);
}
private static string BytesToHex(byte[] a, int len)
{
string temp = BitConverter.ToString(a);
// We need to remove the dashes that come from the BitConverter
StringBuilder sb = new StringBuilder((len - 2) / 2); // This should be the final size
for (int i = 0; i < temp.Length; i++)
if (temp[i] != '-')
sb.Append(temp[i]);
return sb.ToString();
}
// own methods
//-----------------------------------------------------------------------------------
/// <summary>
/// MD4 basic transformation
/// </summary>
/// <remarks>
/// Transforms context based on 512 bits from input block starting
/// from the offset'th byte.
/// </remarks>
/// <param name = "block">input sub-array</param>
/// <param name = "offset">starting position of sub-array</param>
private void Transform(ref byte[] block, int offset)
{
// decodes 64 bytes from input block into an array of 16 32-bit
// entities. Use A as a temp var.
for (int i = 0; i < 16; i++)
X[i] = ((uint)block[offset++] & 0xFF) |
(((uint)block[offset++] & 0xFF) << 8) |
(((uint)block[offset++] & 0xFF) << 16) |
(((uint)block[offset++] & 0xFF) << 24);
uint A = context[0];
uint B = context[1];
uint C = context[2];
uint D = context[3];
A = FF(A, B, C, D, X[0], 3);
D = FF(D, A, B, C, X[1], 7);
C = FF(C, D, A, B, X[2], 11);
B = FF(B, C, D, A, X[3], 19);
A = FF(A, B, C, D, X[4], 3);
D = FF(D, A, B, C, X[5], 7);
C = FF(C, D, A, B, X[6], 11);
B = FF(B, C, D, A, X[7], 19);
A = FF(A, B, C, D, X[8], 3);
D = FF(D, A, B, C, X[9], 7);
C = FF(C, D, A, B, X[10], 11);
B = FF(B, C, D, A, X[11], 19);
A = FF(A, B, C, D, X[12], 3);
D = FF(D, A, B, C, X[13], 7);
C = FF(C, D, A, B, X[14], 11);
B = FF(B, C, D, A, X[15], 19);
A = GG(A, B, C, D, X[0], 3);
D = GG(D, A, B, C, X[4], 5);
C = GG(C, D, A, B, X[8], 9);
B = GG(B, C, D, A, X[12], 13);
A = GG(A, B, C, D, X[1], 3);
D = GG(D, A, B, C, X[5], 5);
C = GG(C, D, A, B, X[9], 9);
B = GG(B, C, D, A, X[13], 13);
A = GG(A, B, C, D, X[2], 3);
D = GG(D, A, B, C, X[6], 5);
C = GG(C, D, A, B, X[10], 9);
B = GG(B, C, D, A, X[14], 13);
A = GG(A, B, C, D, X[3], 3);
D = GG(D, A, B, C, X[7], 5);
C = GG(C, D, A, B, X[11], 9);
B = GG(B, C, D, A, X[15], 13);
A = HH(A, B, C, D, X[0], 3);
D = HH(D, A, B, C, X[8], 9);
C = HH(C, D, A, B, X[4], 11);
B = HH(B, C, D, A, X[12], 15);
A = HH(A, B, C, D, X[2], 3);
D = HH(D, A, B, C, X[10], 9);
C = HH(C, D, A, B, X[6], 11);
B = HH(B, C, D, A, X[14], 15);
A = HH(A, B, C, D, X[1], 3);
D = HH(D, A, B, C, X[9], 9);
C = HH(C, D, A, B, X[5], 11);
B = HH(B, C, D, A, X[13], 15);
A = HH(A, B, C, D, X[3], 3);
D = HH(D, A, B, C, X[11], 9);
C = HH(C, D, A, B, X[7], 11);
B = HH(B, C, D, A, X[15], 15);
context[0] += A;
context[1] += B;
context[2] += C;
context[3] += D;
}
// The basic MD4 atomic functions.
private uint FF(uint a, uint b, uint c, uint d, uint x, int s)
{
uint t = a + ((b & c) | (~b & d)) + x;
return t << s | t >> (32 - s);
}
private uint GG(uint a, uint b, uint c, uint d, uint x, int s)
{
uint t = a + ((b & (c | d)) | (c & d)) + x + 0x5A827999;
return t << s | t >> (32 - s);
}
private uint HH(uint a, uint b, uint c, uint d, uint x, int s)
{
uint t = a + (b ^ c ^ d) + x + 0x6ED9EBA1;
return t << s | t >> (32 - s);
}
}
// class MD4
}
// namespace MD4Hash

View file

@ -0,0 +1,220 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using Utilities;
namespace SMBLibrary.Authentication
{
public class NTAuthentication
{
public static byte[] ComputeLMv1Response(byte[] challenge, string password)
{
byte[] hash = LMOWFv1(password);
return DesLongEncrypt(hash, challenge);
}
public static byte[] ComputeNTLMv1Response(byte[] challenge, string password)
{
byte[] hash = NTOWFv1(password);
return DesLongEncrypt(hash, challenge);
}
public static byte[] ComputeNTLMv1ExtendedSecurityResponse(byte[] serverChallenge, byte[] clientChallenge, string password)
{
byte[] passwordHash = NTOWFv1(password);
byte[] challengeHash = MD5.Create().ComputeHash(ByteUtils.Concatenate(serverChallenge, clientChallenge));
byte[] challengeHashShort = new byte[8];
Array.Copy(challengeHash, 0, challengeHashShort, 0, 8);
return DesLongEncrypt(passwordHash, challengeHashShort);
}
public static byte[] ComputeLMv2Response(byte[] serverChallenge, byte[] clientChallenge, string password, string user, string domain)
{
byte[] key = LMOWFv2(password, user, domain);
byte[] bytes = ByteUtils.Concatenate(serverChallenge, clientChallenge);
HMACMD5 hmac = new HMACMD5(key);
byte[] hash = hmac.ComputeHash(bytes, 0, bytes.Length);
return ByteUtils.Concatenate(hash, clientChallenge);
}
/// <summary>
/// [MS-NLMP] page 60
/// 'temp' is the same as ClientChallengeStructure with 4 zero bytes padding
/// </summary>
public static byte[] ComputeNTLMv2Response(byte[] serverChallenge, byte[] clientChallengeStructurePadded, string password, string user, string domain)
{
byte[] key = NTOWFv2(password, user, domain);
byte[] temp = clientChallengeStructurePadded;
HMACMD5 hmac = new HMACMD5(key);
byte[] _NTProof = hmac.ComputeHash(ByteUtils.Concatenate(serverChallenge, temp), 0, serverChallenge.Length + temp.Length);
return ByteUtils.Concatenate(_NTProof, temp);
}
/// <summary>
/// NTLMv2_CLIENT_CHALLENGE
/// </summary>
[Obsolete]
public static byte[] GetNTLMv2ClientChallengeStructure(byte[] clientChallenge, byte responseVersion, byte responseVersionHigh, byte[] time, byte[] serverAVPair)
{
byte[] temp = new byte[28 + serverAVPair.Length];
temp[0] = responseVersion;
temp[1] = responseVersionHigh;
Array.Copy(time, 0, temp, 8, 8);
Array.Copy(clientChallenge, 0, temp, 16, 8);
Array.Copy(serverAVPair, 0, temp, 28, serverAVPair.Length);
return temp;
}
public static byte[] DesEncrypt(byte[] key, byte[] plainText)
{
return DesEncrypt(key, plainText, 0, plainText.Length);
}
public static byte[] DesEncrypt(byte[] key, byte[] plainText, int inputOffset, int inputCount)
{
ICryptoTransform encryptor = CreateWeakDesEncryptor(CipherMode.ECB, key, new byte[key.Length]);
byte[] result = new byte[inputCount];
encryptor.TransformBlock(plainText, inputOffset, inputCount, result, 0);
return result;
}
public static ICryptoTransform CreateWeakDesEncryptor(CipherMode mode, byte[] rgbKey, byte[] rgbIV)
{
DES des = DES.Create();
des.Mode = mode;
DESCryptoServiceProvider sm = des as DESCryptoServiceProvider;
MethodInfo mi = sm.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
object[] Par = { rgbKey, mode, rgbIV, sm.FeedbackSize, 0 };
ICryptoTransform trans = mi.Invoke(sm, Par) as ICryptoTransform;
return trans;
}
/// <summary>
/// DESL()
/// </summary>
public static byte[] DesLongEncrypt(byte[] key, byte[] plainText)
{
if (key.Length != 16)
{
throw new ArgumentException("Invalid key length");
}
if (plainText.Length != 8)
{
throw new ArgumentException("Invalid plain-text length");
}
byte[] padded = new byte[21];
Array.Copy(key, padded, key.Length);
byte[] k1 = new byte[7];
byte[] k2 = new byte[7];
byte[] k3 = new byte[7];
Array.Copy(padded, 0, k1, 0, 7);
Array.Copy(padded, 7, k2, 0, 7);
Array.Copy(padded, 14, k3, 0, 7);
byte[] r1 = DesEncrypt(ExtendDESKey(k1), plainText);
byte[] r2 = DesEncrypt(ExtendDESKey(k2), plainText);
byte[] r3 = DesEncrypt(ExtendDESKey(k3), plainText);
byte[] result = new byte[24];
Array.Copy(r1, 0, result, 0, 8);
Array.Copy(r2, 0, result, 8, 8);
Array.Copy(r3, 0, result, 16, 8);
return result;
}
public static Encoding GetOEMEncoding()
{
return Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage);
}
/// <summary>
/// LM Hash
/// </summary>
public static byte[] LMOWFv1(string password)
{
byte[] plainText = ASCIIEncoding.ASCII.GetBytes("KGS!@#$%");
byte[] passwordBytes = GetOEMEncoding().GetBytes(password.ToUpper());
byte[] key = new byte[14];
Array.Copy(passwordBytes, key, Math.Min(passwordBytes.Length, 14));
byte[] k1 = new byte[7];
byte[] k2 = new byte[7];
Array.Copy(key, 0, k1, 0, 7);
Array.Copy(key, 7, k2, 0, 7);
byte[] part1 = DesEncrypt(ExtendDESKey(k1), plainText);
byte[] part2 = DesEncrypt(ExtendDESKey(k2), plainText);
return ByteUtils.Concatenate(part1, part2);
}
/// <summary>
/// NTLM hash (NT hash)
/// </summary>
public static byte[] NTOWFv1(string password)
{
byte[] passwordBytes = UnicodeEncoding.Unicode.GetBytes(password);
return new MD4().GetByteHashFromBytes(passwordBytes);
}
/// <summary>
/// LMOWFv2 is identical to NTOWFv2
/// </summary>
public static byte[] LMOWFv2(string password, string user, string domain)
{
return NTOWFv2(password, user, domain);
}
public static byte[] NTOWFv2(string password, string user, string domain)
{
byte[] passwordBytes = UnicodeEncoding.Unicode.GetBytes(password);
byte[] key = new MD4().GetByteHashFromBytes(passwordBytes);
string text = user.ToUpper() + domain;
byte[] bytes = UnicodeEncoding.Unicode.GetBytes(text);
HMACMD5 hmac = new HMACMD5(key);
return hmac.ComputeHash(bytes, 0, bytes.Length);
}
/// <summary>
/// Extends a 7-byte key into an 8-byte key.
/// Note: The DES key ostensibly consists of 64 bits, however, only 56 of these are actually used by the algorithm.
/// Eight bits are used solely for checking parity, and are thereafter discarded
/// </summary>
private static byte[] ExtendDESKey(byte[] key)
{
byte[] result = new byte[8];
int i;
result[0] = (byte)((key[0] >> 1) & 0xff);
result[1] = (byte)((((key[0] & 0x01) << 6) | (((key[1] & 0xff) >> 2) & 0xff)) & 0xff);
result[2] = (byte)((((key[1] & 0x03) << 5) | (((key[2] & 0xff) >> 3) & 0xff)) & 0xff);
result[3] = (byte)((((key[2] & 0x07) << 4) | (((key[3] & 0xff) >> 4) & 0xff)) & 0xff);
result[4] = (byte)((((key[3] & 0x0F) << 3) | (((key[4] & 0xff) >> 5) & 0xff)) & 0xff);
result[5] = (byte)((((key[4] & 0x1F) << 2) | (((key[5] & 0xff) >> 6) & 0xff)) & 0xff);
result[6] = (byte)((((key[5] & 0x3F) << 1) | (((key[6] & 0xff) >> 7) & 0xff)) & 0xff);
result[7] = (byte)(key[6] & 0x7F);
for (i = 0; i < 8; i++)
{
result[i] = (byte)(result[i] << 1);
}
return result;
}
}
}

View file

@ -0,0 +1,69 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using SMBLibrary.NetBios;
using SMBLibrary.SMB1;
using Utilities;
namespace SMBLibrary.Client
{
public class SMBClient
{
public const int NetBiosOverTCPPort = 139;
public const int DirectTCPPort = 445;
public const string NTLanManagerDialect = "NT LM 0.12";
public SMBClient(IPAddress serverAddress, SMBTransportType transport)
{
NegotiateRequest request = new NegotiateRequest();
request.Dialects.Add(NTLanManagerDialect);
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
if (transport == SMBTransportType.DirectTCPTransport)
{
serverSocket.Connect(serverAddress, DirectTCPPort);
}
else
{
serverSocket.Connect(serverAddress, NetBiosOverTCPPort);
}
TrySendMessage(serverSocket, request);
}
public static void TrySendMessage(Socket serverSocket, SMBCommand request)
{
SMBMessage message = new SMBMessage();
message.Commands.Add(request);
TrySendMessage(serverSocket, message);
}
public static void TrySendMessage(Socket serverSocket, SMBMessage message)
{
SessionMessagePacket packet = new SessionMessagePacket();
packet.Trailer = message.GetBytes();
TrySendPacket(serverSocket, packet);
}
public static void TrySendPacket(Socket serverSocket, SessionPacket response)
{
try
{
serverSocket.Send(response.GetBytes());
}
catch (SocketException)
{
}
catch (ObjectDisposedException)
{
}
}
}
}

View file

@ -0,0 +1,101 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary
{
/// <summary>
/// [MS-SMB] 2.2.1.4.1 - File_Pipe_Printer_Access_Mask
/// </summary>
[Flags]
public enum FileAccessMask : uint
{
FILE_READ_DATA = 0x00000001,
FILE_WRITE_DATA = 0x00000002,
FILE_APPEND_DATA = 0x00000004,
FILE_READ_EA = 0x00000008,
FILE_WRITE_EA = 0x00000010,
FILE_EXECUTE = 0x00000020,
FILE_READ_ATTRIBUTES = 0x00000080,
FILE_WRITE_ATTRIBUTES = 0x00000100,
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_ALL = 0x20000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_WRITE = 0x40000000,
GENERIC_READ = 0x80000000,
}
/// <summary>
/// [MS-SMB] 2.2.1.4.2 - Directory_Access_Mask
/// </summary>
[Flags]
public enum DirectoryAccessMask : uint
{
FILE_LIST_DIRECTORY = 0x00000001,
FILE_ADD_FILE = 0x00000002,
FILE_ADD_SUBDIRECTORY = 0x00000004,
FILE_READ_EA = 0x00000008,
FILE_WRITE_EA = 0x00000010,
FILE_TRAVERSE = 0x00000020,
FILE_DELETE_CHILD = 0x00000040,
FILE_READ_ATTRIBUTES = 0x00000080,
FILE_WRITE_ATTRIBUTES = 0x00000100,
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_ALL = 0x20000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_WRITE = 0x40000000,
GENERIC_READ = 0x80000000,
}
/// <summary>
/// [MS-DTYP] 2.4.3 - ACCESS_MASK
/// </summary>
public struct AccessMask // uint
{
public FileAccessMask File;
public FileAccessMask Directory;
public AccessMask(byte[] buffer, ref int offset) : this(buffer, offset)
{
offset += 4;
}
public AccessMask(byte[] buffer, int offset)
{
uint value = LittleEndianConverter.ToUInt32(buffer, offset);
File = (FileAccessMask)value;
Directory = (FileAccessMask)value;
}
public void WriteBytes(byte[] buffer, int offset)
{
uint value = (uint)(this.File | this.Directory);
LittleEndianWriter.WriteUInt32(buffer, offset, value);
}
public void WriteBytes(byte[] buffer, ref int offset)
{
WriteBytes(buffer, offset);
offset += 4;
}
}
}

View file

@ -0,0 +1,36 @@
namespace SMBLibrary
{
public enum NTStatus : uint
{
STATUS_SUCCESS = 0x00000000,
STATUS_NOT_IMPLEMENTED = 0xC0000002,
STATUS_INVALID_HANDLE = 0xC0000008,
STATUS_INVALID_PARAMETER = 0xC000000D,
STATUS_NO_SUCH_DEVICE = 0xC000000E,
STATUS_NO_SUCH_FILE = 0xC000000F,
STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016,
STATUS_ACCESS_DENIED = 0xC0000022, // The user is not authorized to access the resource.
STATUS_OBJECT_NAME_INVALID = 0xC0000033,
STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
STATUS_OBJECT_NAME_COLLISION = 0xC0000035, // The file already exists
STATUS_OBJECT_PATH_INVALID = 0xC0000039,
STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A, // The share path does not reference a valid resource.
STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B,
STATUS_DATA_ERROR = 0xC000003E, // IO error
STATUS_SHARING_VIOLATION = 0xC0000043,
STATUS_FILE_LOCK_CONFLICT = 0xC0000054,
STATUS_LOGON_FAILURE = 0xC000006D, // Authentication failure.
STATUS_ACCOUNT_RESTRICTION = 0xC000006E, // The user has an empty password, which is not allowed
STATUS_DISK_FULL = 0xC000007F,
STATUS_MEDIA_WRITE_PROTECTED = 0xC00000A2,
STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA,
STATUS_CANNOT_DELETE = 0xC0000121,
STATUS_INVALID_SMB = 0x00010002, // CIFS/SMB1: A corrupt or invalid SMB request was received
STATUS_SMB_BAD_COMMAND = 0x00160002, // CIFS/SMB1: An unknown SMB command code was received by the server
STATUS_SMB_BAD_FID = 0x00060001, // CIFS/SMB1
STATUS_SMB_BAD_TID = 0x00050002, // CIFS/SMB1
STATUS_OS2_NO_MORE_SIDS = 0x00710001, // CIFS/SMB1
}
}

View file

@ -0,0 +1,9 @@
namespace SMBLibrary
{
public enum SMBTransportType
{
NetBiosOverTCP, // Port 139
DirectTCPTransport, // Port 445
}
}

View file

@ -0,0 +1,16 @@
namespace SMBLibrary
{
// All Win32 error codes MUST be in the range 0x0000 to 0xFFFF
public enum Win32Error : ushort
{
ERROR_SUCCESS = 0x0000,
ERROR_ACCESS_DENIED = 0x0005,
ERROR_SHARING_VIOLATION = 0x0020,
ERROR_DISK_FULL = 0x0070,
ERROR_LOGON_FAILURE = 0x0000052E,
ERROR_ACCOUNT_RESTRICTION = 0x0000052F,
ERROR_LOGON_TYPE_NOT_GRANTED = 0x00000569,
NERR_NetNameNotFound = 0x00000906
}
}

View file

@ -0,0 +1,60 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary
{
/// <summary>
/// [MS-FSCC] FILE_FULL_EA_INFORMATION data element
/// </summary>
public class FileFullEAInformation
{
public uint NextEntryOffset;
public byte Flags;
//byte EaNameLength;
//ushort EaValueLength;
public string EaName; // ASCII
public string EaValue; // ASCII
public FileFullEAInformation()
{
}
public FileFullEAInformation(byte[] buffer, int offset)
{
NextEntryOffset = LittleEndianReader.ReadUInt32(buffer, ref offset);
Flags = ByteReader.ReadByte(buffer, ref offset);
byte eaNameLength = ByteReader.ReadByte(buffer, ref offset);
ushort eaValueLength = LittleEndianReader.ReadUInt16(buffer, ref offset);
EaName = ByteReader.ReadAnsiString(buffer, ref offset, eaNameLength);
EaValue = ByteReader.ReadAnsiString(buffer, ref offset, eaValueLength);
}
public void WriteBytes(byte[] buffer, int offset)
{
byte eaNameLength = (byte)EaName.Length;
ushort eaValueLength = (ushort)EaValue.Length;
LittleEndianWriter.WriteUInt32(buffer, ref offset, NextEntryOffset);
ByteWriter.WriteByte(buffer, ref offset, Flags);
ByteWriter.WriteByte(buffer, ref offset, eaNameLength);
LittleEndianWriter.WriteUInt16(buffer, ref offset, eaValueLength);
ByteWriter.WriteAnsiString(buffer, ref offset, EaName);
ByteWriter.WriteAnsiString(buffer, ref offset, EaValue);
}
public int Length
{
get
{
return 8 + EaName.Length + EaValue.Length;
}
}
}
}

View file

@ -0,0 +1,67 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace SMBLibrary
{
/// <summary>
/// [MS-FSCC] FILE_FULL_EA_INFORMATION buffer
/// </summary>
public class FileFullEAInformationList : List<FileFullEAInformation>
{
public FileFullEAInformationList()
{
}
public FileFullEAInformationList(byte[] buffer, int offset)
{
FileFullEAInformation entry = new FileFullEAInformation(buffer, offset);
this.Add(entry);
while (entry.NextEntryOffset != 0)
{
entry = new FileFullEAInformation(buffer, (int)entry.NextEntryOffset);
this.Add(entry);
}
}
public void WriteBytes(byte[] buffer, int offset)
{
// When multiple FILE_FULL_EA_INFORMATION data elements are present in the buffer, each MUST be aligned on a 4-byte boundary
for (int index = 0; index < this.Count; index++)
{
this[index].WriteBytes(buffer, offset);
offset += this[index].Length;
if (index < this.Count - 1)
{
int padding = (4 - (offset % 4)) % 4;
offset += padding;
}
}
}
public int Length
{
get
{
// When multiple FILE_FULL_EA_INFORMATION data elements are present in the buffer, each MUST be aligned on a 4-byte boundary
int length = 0;
for(int index = 0; index < this.Count; index++)
{
length += this[index].Length;
if (index < this.Count - 1)
{
int padding = (4 - (length % 4)) % 4;
length += padding;
}
}
return length;
}
}
}
}

View file

@ -0,0 +1,48 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary
{
/// <summary>
/// [MS-FSCC] FILE_OBJECTID_BUFFER Type 1
/// </summary>
public class ObjectIDBufferType1
{
public const int Length = 64;
public Guid ObjectId;
public Guid BirthVolumeId;
public Guid BirthObjectId;
public Guid DomainId;
public ObjectIDBufferType1()
{
}
public ObjectIDBufferType1(byte[] buffer)
{
ObjectId = LittleEndianConverter.ToGuid(buffer, 0);
BirthVolumeId = LittleEndianConverter.ToGuid(buffer, 16);
BirthObjectId = LittleEndianConverter.ToGuid(buffer, 32);
DomainId = LittleEndianConverter.ToGuid(buffer, 48);
}
public byte[] GetBytes()
{
byte[] buffer = new byte[Length];
LittleEndianWriter.WriteGuidBytes(buffer, 0, ObjectId);
LittleEndianWriter.WriteGuidBytes(buffer, 16, BirthVolumeId);
LittleEndianWriter.WriteGuidBytes(buffer, 32, BirthObjectId);
LittleEndianWriter.WriteGuidBytes(buffer, 48, DomainId);
return buffer;
}
}
}

View file

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public enum OwnerNodeType : byte
{
BNode = 0x00,
PNode = 0x01,
MNode = 0x10,
}
public struct NameFlags // ushort
{
public const int Length = 2;
public OwnerNodeType NodeType;
public bool WorkGroup;
public ushort Value
{
get
{
ushort value = (ushort)(((byte)NodeType) << 13);
if (WorkGroup)
{
value |= 0x8000;
}
return value;
}
}
}
}

View file

@ -0,0 +1,9 @@
namespace SMBLibrary.NetBios
{
public enum NameRecordType : ushort
{
NB = 0x0020,
NBStat = 0x0021,
}
}

View file

@ -0,0 +1,17 @@
namespace SMBLibrary.NetBios
{
public enum NameServiceOperation : byte
{
QueryRequest = 0x00,
RegistrationRequest = 0x05,
ReleaseRequest = 0x06,
WackRequest = 0x07,
RefreshRequest = 0x08,
QueryResponse = 0x10,
RegistrationResponse = 0x15,
ReleaseResponse = 0x16,
WackResponse = 0x17,
RefreshResponse = 0x18,
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SMBLibrary.NetBios
{
/// <summary>
/// 16th character suffix for netbios name.
/// see http://support.microsoft.com/kb/163409/en-us
/// </summary>
public enum NetBiosSuffix : byte
{
WorkstationService = 0x00,
MessengerService = 0x03,
DomainMasterBrowser = 0x1B,
MasterBrowser = 0x1D,
BrowserServiceElections = 0x1E,
FileServiceService = 0x20,
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.1.1. HEADER
/// </summary>
[Flags]
public enum OperationFlags : byte
{
Broadcast = 0x01,
RecursionAvailable = 0x08,
RecursionDesired = 0x10,
Truncated = 0x20,
AuthoritativeAnswer = 0x40,
}
}

View file

@ -0,0 +1,45 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.12. NAME QUERY REQUEST
/// </summary>
public class NameQueryRequest
{
public NameServicePacketHeader Header;
public QuestionSection Question;
public NameQueryRequest()
{
Header = new NameServicePacketHeader();
Header.OpCode = NameServiceOperation.QueryRequest;
Header.ARCount = 1;
Question = new QuestionSection();
}
public NameQueryRequest(byte[] buffer, int offset)
{
Header = new NameServicePacketHeader(buffer, ref offset);
Question = new QuestionSection(buffer, ref offset);
}
public byte[] GetBytes()
{
MemoryStream stream = new MemoryStream();
Header.WriteBytes(stream);
Question.WriteBytes(stream);
return stream.ToArray();
}
}
}

View file

@ -0,0 +1,66 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.2. NAME REGISTRATION REQUEST
/// </summary>
public class NameRegistrationRequest
{
public const int DataLength = 6;
public NameServicePacketHeader Header;
public QuestionSection Question;
public ResourceRecord Resource;
public NameFlags NameFlags;
public byte[] Address; // IPv4 address
public NameRegistrationRequest()
{
Header = new NameServicePacketHeader();
Header.OpCode = NameServiceOperation.RegistrationRequest;
Header.QDCount = 1;
Header.ARCount = 1;
Header.Flags = OperationFlags.Broadcast | OperationFlags.RecursionDesired;
Question = new QuestionSection();
Resource = new ResourceRecord();
Address = new byte[4];
}
public NameRegistrationRequest(string machineName, NetBiosSuffix suffix, IPAddress address) : this()
{
Question.Name = NetBiosUtils.GetMSNetBiosName(machineName, suffix);
Address = address.GetAddressBytes();
}
public byte[] GetBytes()
{
Resource.Data = GetData();
MemoryStream stream = new MemoryStream();
Header.WriteBytes(stream);
Question.WriteBytes(stream);
Resource.WriteBytes(stream, NameServicePacketHeader.Length);
return stream.ToArray();
}
public byte[] GetData()
{
byte[] data = new byte[DataLength];
BigEndianWriter.WriteUInt16(data, 0, NameFlags.Value);
ByteWriter.WriteBytes(data, 2, Address, 4);
return data;
}
}
}

View file

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.1.1. HEADER
/// </summary>
public class NameServicePacketHeader
{
public const int Length = 12;
public ushort TransactionID;
public NameServiceOperation OpCode;
public OperationFlags Flags;
public byte ResultCode;
public ushort QDCount;
public ushort ANCount;
public ushort NSCount;
public ushort ARCount;
public NameServicePacketHeader()
{
}
public NameServicePacketHeader(byte[] buffer, ref int offset) : this(buffer, offset)
{
offset += Length;
}
public NameServicePacketHeader(byte[] buffer, int offset)
{
TransactionID = BigEndianConverter.ToUInt16(buffer, offset + 0);
ushort temp = BigEndianConverter.ToUInt16(buffer, offset + 2);
ResultCode = (byte)(temp & 0xF);
Flags = (OperationFlags)((temp >> 4) & 0x7F);
OpCode = (NameServiceOperation)((temp >> 11) & 0x1F);
QDCount = BigEndianConverter.ToUInt16(buffer, offset + 4);
ANCount = BigEndianConverter.ToUInt16(buffer, offset + 6);
NSCount = BigEndianConverter.ToUInt16(buffer, offset + 8);
ARCount = BigEndianConverter.ToUInt16(buffer, offset + 10);
}
public void WriteBytes(Stream stream)
{
BigEndianWriter.WriteUInt16(stream, TransactionID);
ushort temp = (ushort)(ResultCode & (0xF));
temp |= (ushort)((byte)Flags << 4);
temp |= (ushort)((byte)OpCode << 11);
BigEndianWriter.WriteUInt16(stream, temp);
BigEndianWriter.WriteUInt16(stream, QDCount);
BigEndianWriter.WriteUInt16(stream, ANCount);
BigEndianWriter.WriteUInt16(stream, NSCount);
BigEndianWriter.WriteUInt16(stream, ARCount);
}
}
}

View file

@ -0,0 +1,64 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.18. NODE STATUS RESPONSE
/// </summary>
public class NodeStatusResponse
{
public NameServicePacketHeader Header;
public ResourceRecord Resource;
// byte NumberOfNames;
public KeyValuePairList<string, NameFlags> Names = new KeyValuePairList<string, NameFlags>();
public NodeStatistics Statistics;
public NodeStatusResponse()
{
Header = new NameServicePacketHeader();
Header.OpCode = NameServiceOperation.QueryResponse;
Header.Flags = OperationFlags.AuthoritativeAnswer | OperationFlags.RecursionAvailable;
Header.ANCount = 1;
Resource = new ResourceRecord();
Resource.Type = NameRecordType.NBStat;
Statistics = new NodeStatistics();
}
public byte[] GetBytes()
{
Resource.Data = GetData();
MemoryStream stream = new MemoryStream();
Header.WriteBytes(stream);
Resource.WriteBytes(stream);
return stream.ToArray();
}
public byte[] GetData()
{
MemoryStream stream = new MemoryStream();
stream.WriteByte((byte)Names.Count);
foreach (KeyValuePair<string, NameFlags> entry in Names)
{
ByteWriter.WriteAnsiString(stream, entry.Key);
//byte[] encodedName = NetBiosUtils.EncodeName(entry.Key, String.Empty);
//ByteWriter.WriteBytes(stream, encodedName);
BigEndianWriter.WriteUInt16(stream, entry.Value.Value);
}
ByteWriter.WriteBytes(stream, Statistics.GetBytes());
return stream.ToArray();
}
}
}

View file

@ -0,0 +1,57 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.13. POSITIVE NAME QUERY RESPONSE
/// </summary>
public class PositiveNameQueryResponse
{
public const int EntryLength = 6;
public NameServicePacketHeader Header;
public ResourceRecord Resource;
public KeyValuePairList<byte[], NameFlags> Addresses = new KeyValuePairList<byte[], NameFlags>();
public PositiveNameQueryResponse()
{
Header = new NameServicePacketHeader();
Header.Flags = OperationFlags.AuthoritativeAnswer | OperationFlags.RecursionDesired;
Header.OpCode = NameServiceOperation.QueryResponse;
Header.ANCount = 1;
Resource = new ResourceRecord();
}
public byte[] GetBytes()
{
Resource.Data = GetData();
MemoryStream stream = new MemoryStream();
Header.WriteBytes(stream);
Resource.WriteBytes(stream);
return stream.ToArray();
}
public byte[] GetData()
{
byte[] data = new byte[EntryLength * Addresses.Count];
int offset = 0;
foreach (KeyValuePair<byte[], NameFlags> entry in Addresses)
{
BigEndianWriter.WriteUInt16(data, ref offset, entry.Value.Value);
ByteWriter.WriteBytes(data, ref offset, entry.Key, 4);
}
return data;
}
}
}

View file

@ -0,0 +1,75 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public class NodeStatistics
{
public const int Length = 46;
public byte[] UnitID; // MAC address, 6 bytes;
public byte Jumpers;
public byte TestResult;
public ushort VersionNumber;
public ushort PeriodOfStatistics;
public ushort NumberOfCRCs;
public ushort NumberOfAlignmentErrors;
public ushort NumberOfCollisions;
public ushort NumberOfSendAborts;
public uint NumberOfGoodSends;
public uint NumberOfGoodReceives;
public ushort NumberOfRetransmits;
public ushort NumberOfNoResourceConditions;
public ushort NumberOfFreeCommandBlocks;
public ushort TotalNumberOfCommandBlocks;
public ushort MaxTotalNumberOfCommandBlocks;
public ushort NumberOfPendingSessions;
public ushort MaxNumberOfPendingSessions;
public ushort MaxTotalsSessionsPossible;
public ushort SessionDataPacketSize;
public NodeStatistics()
{
UnitID = new byte[6];
}
public void WriteBytes(byte[] buffer, int offset)
{
ByteWriter.WriteBytes(buffer, ref offset, UnitID, 6);
ByteWriter.WriteByte(buffer, ref offset, Jumpers);
ByteWriter.WriteByte(buffer, ref offset, TestResult);
BigEndianWriter.WriteUInt16(buffer, ref offset, VersionNumber);
BigEndianWriter.WriteUInt16(buffer, ref offset, PeriodOfStatistics);
BigEndianWriter.WriteUInt16(buffer, ref offset, NumberOfCRCs);
BigEndianWriter.WriteUInt16(buffer, ref offset, NumberOfAlignmentErrors);
BigEndianWriter.WriteUInt16(buffer, ref offset, NumberOfCollisions);
BigEndianWriter.WriteUInt16(buffer, ref offset, NumberOfSendAborts);
BigEndianWriter.WriteUInt32(buffer, ref offset, NumberOfGoodSends);
BigEndianWriter.WriteUInt32(buffer, ref offset, NumberOfGoodReceives);
BigEndianWriter.WriteUInt16(buffer, ref offset, NumberOfRetransmits);
BigEndianWriter.WriteUInt16(buffer, ref offset, NumberOfNoResourceConditions);
BigEndianWriter.WriteUInt16(buffer, ref offset, NumberOfFreeCommandBlocks);
BigEndianWriter.WriteUInt16(buffer, ref offset, TotalNumberOfCommandBlocks);
BigEndianWriter.WriteUInt16(buffer, ref offset, MaxTotalNumberOfCommandBlocks);
BigEndianWriter.WriteUInt16(buffer, ref offset, NumberOfPendingSessions);
BigEndianWriter.WriteUInt16(buffer, ref offset, MaxNumberOfPendingSessions);
BigEndianWriter.WriteUInt16(buffer, ref offset, MaxTotalsSessionsPossible);
BigEndianWriter.WriteUInt16(buffer, ref offset, SessionDataPacketSize);
}
public byte[] GetBytes()
{
byte[] buffer = new byte[Length];
WriteBytes(buffer, 0);
return buffer;
}
}
}

View file

@ -0,0 +1,43 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.1.2. QUESTION SECTION
/// </summary>
public class QuestionSection
{
public string Name;
public NameRecordType Type = NameRecordType.NB; // NB
public ushort Class = 0x0001; // IN
public QuestionSection()
{
}
public QuestionSection(byte[] buffer, ref int offset)
{
Name = NetBiosUtils.DecodeName(buffer, ref offset);
Type = (NameRecordType)BigEndianReader.ReadUInt16(buffer, ref offset);
Class = BigEndianReader.ReadUInt16(buffer, ref offset);
}
public void WriteBytes(Stream stream)
{
byte[] encodedName = NetBiosUtils.EncodeName(Name, String.Empty);
ByteWriter.WriteBytes(stream, encodedName);
BigEndianWriter.WriteUInt16(stream, (ushort)Type);
BigEndianWriter.WriteUInt16(stream, Class);
}
}
}

View file

@ -0,0 +1,57 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.1.3. RESOURCE RECORD
/// </summary>
public class ResourceRecord
{
public string Name;
public NameRecordType Type = NameRecordType.NB; // NB
public ushort Class = 0x0001; // IN
public uint TTL;
// ushort DataLength
public byte[] Data;
public ResourceRecord()
{
Name = String.Empty;
TTL = (uint)new TimeSpan(7, 0, 0, 0).TotalSeconds;
Data = new byte[0];
}
public void WriteBytes(Stream stream)
{
WriteBytes(stream, null);
}
public void WriteBytes(Stream stream, int? nameOffset)
{
if (nameOffset.HasValue)
{
NetBiosUtils.WriteNamePointer(stream, nameOffset.Value);
}
else
{
byte[] encodedName = NetBiosUtils.EncodeName(Name, String.Empty);
ByteWriter.WriteBytes(stream, encodedName);
}
BigEndianWriter.WriteUInt16(stream, (ushort)Type);
BigEndianWriter.WriteUInt16(stream, Class);
BigEndianWriter.WriteUInt32(stream, TTL);
BigEndianWriter.WriteUInt16(stream, (ushort)Data.Length);
ByteWriter.WriteBytes(stream, Data);
}
}
}

View file

@ -0,0 +1,207 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public class NetBiosUtils
{
/// <summary>
/// The NetBIOS naming convention allows for 16 characters in a NetBIOS name.
/// Microsoft, however, limits NetBIOS names to 15 characters and uses the 16th character as a NetBIOS suffix
/// See http://support.microsoft.com/kb/163409/en-us
/// </summary>
public static string GetMSNetBiosName(string name, NetBiosSuffix suffix)
{
if (name.Length > 15)
{
name = name.Substring(0, 15);
}
else if (name.Length < 15)
{
name = name.PadRight(15);
}
return name + (char)suffix;
}
public static string GetNameFromMSNetBiosName(string netBiosName)
{
if (netBiosName.Length != 16)
{
throw new ArgumentException("Invalid MS NetBIOS name");
}
netBiosName = netBiosName.Substring(0, 15);
return netBiosName.TrimEnd(' ');
}
public static byte[] EncodeName(string name, NetBiosSuffix suffix, string scopeID)
{
string netBiosName = GetMSNetBiosName(name, suffix);
return EncodeName(netBiosName, scopeID);
}
/// <param name="name">NetBIOS name</param>
/// <param name="scopeID">dot-separated labels, formatted per DNS naming rules</param>
public static byte[] EncodeName(string netBiosName, string scopeID)
{
string domainName = FirstLevelEncoding(netBiosName, scopeID);
return SecondLevelEncoding(domainName);
}
// The conversion of a NetBIOS name to a format complying with DNS "best practices".
// NetBIOS names may contain characters which are not considered valid for use in DNS names,
// yet RFC 1001 and RFC 1002 attempted to map the NetBIOS name space into the DNS name space.
// To work around this conflict, NetBIOS names are encoded by splitting each byte of the name
// into two nibbles and then adding the value of 'A' (0x41).
// Thus, the '&' character (0x26) would be encoded as "CG".
// NetBIOS names are usually padded with spaces before being encoded.
/// <param name="name">NetBIOS name</param>
/// <param name="scopeID">dot-separated labels, formatted per DNS naming rules</param>
public static string FirstLevelEncoding(string netBiosName, string scopeID)
{
// RFC 1001: NetBIOS names as seen across the client interface to NetBIOS are exactly 16 bytes long
if (netBiosName.Length != 16)
{
throw new ArgumentException("Invalid MS NetBIOS name");
}
StringBuilder builder = new StringBuilder();
for (int index = 0; index < netBiosName.Length; index++)
{
byte c = (byte)netBiosName[index];
byte high = (byte)(0x41 + (c >> 4));
byte low = (byte)(0x41 + (c & 0x0F));
builder.Append((char)high);
builder.Append((char)low);
}
if (scopeID.Length > 0)
{
builder.Append(".");
builder.Append(scopeID);
}
return builder.ToString();
}
// Domain names messages are expressed in terms of a sequence
// of labels. Each label is represented as a one octet length
// field followed by that number of octets. Since every domain
// name ends with the null label of the root, a compressed
// domain name is terminated by a length byte of zero
/// <summary>
/// The on-the-wire format of an NBT name. The encoding scheme replaces the familiar dot characters
/// used in DNS names with a byte containing the length of the next label.
/// </summary>
public static byte[] SecondLevelEncoding(string domainName)
{
string[] labels = domainName.Split('.');
int length = 1; // null terminator
for (int index = 0; index < labels.Length; index++)
{
length += 1 + labels[index].Length;
if (labels[index].Length > 63)
{
throw new ArgumentException("Invalid NetBIOS label length");
}
}
byte[] result = new byte[length];
int offset = 0;
foreach(string label in labels)
{
result[offset] = (byte)label.Length;
offset++;
ByteWriter.WriteAnsiString(result, offset, label, label.Length);
offset += label.Length;
}
result[offset] = 0; // null termination
return result;
}
public static string DecodeName(byte[] buffer, ref int offset)
{
string domainName = SecondLevelDecoding(buffer, ref offset);
string name = domainName.Split('.')[0];
return FirstLevelDecoding(name);
}
public static string SecondLevelDecoding(byte[] buffer, ref int offset)
{
StringBuilder builder = new StringBuilder();
byte labelLength = ByteReader.ReadByte(buffer, ref offset);
while (labelLength > 0)
{
if (builder.Length > 0)
{
builder.Append(".");
}
// The high order two bits of the length field must be zero
if (labelLength > 63)
{
throw new ArgumentException("Invalid NetBIOS label length");
}
string label = ByteReader.ReadAnsiString(buffer, offset, labelLength);
builder.Append(label);
offset += labelLength;
labelLength = ByteReader.ReadByte(buffer, ref offset);
}
return builder.ToString();
}
public static string FirstLevelDecoding(string name)
{
StringBuilder builder = new StringBuilder();
for(int index = 0; index < name.Length; index += 2)
{
byte c0 = (byte)name[index];
byte c1 = (byte)name[index + 1];
byte high = (byte)(((c0 - 0x41) & 0xF) << 4);
byte low = (byte)((c1 - 0x41) & 0xF);
byte c = (byte)(high | low);
builder.Append((char)c);
}
return builder.ToString();
}
public static void WriteNamePointer(byte[] buffer, ref int offset, int nameOffset)
{
WriteNamePointer(buffer, offset, nameOffset);
offset += 2;
}
/// <summary>
/// Will write a 2 bytes pointer to a name
/// Note: NetBIOS implementations can only use label string pointers in Name Service packets
/// </summary>
public static void WriteNamePointer(byte[] buffer, int offset, int nameOffset)
{
ushort pointer = (ushort)(0xC000 | (nameOffset & 0x3FFF));
BigEndianWriter.WriteUInt16(buffer, offset, pointer);
}
public static void WriteNamePointer(Stream stream, int nameOffset)
{
ushort pointer = (ushort)(0xC000 | (nameOffset & 0x3FFF));
BigEndianWriter.WriteUInt16(stream, pointer);
}
}
}

View file

@ -0,0 +1,21 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
namespace SMBLibrary.NetBios
{
/// <summary>
/// [RFC 1002] 4.2.1.1. HEADER
/// </summary>
public enum SessionPacketTypeName : byte
{
SessionMessage = 0x00,
SessionRequest = 0x81,
PositiveSessionResponse = 0x82,
NegativeSessionResponse = 0x83,
RetargetSessionResponse = 0x84,
SessionKeepAlive = 0x85,
}
}

View file

@ -0,0 +1,36 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public class NegativeSessionResponsePacket : SessionPacket
{
public byte ErrorCode;
public NegativeSessionResponsePacket() : base()
{
this.Type = SessionPacketTypeName.NegativeSessionResponse;
}
public NegativeSessionResponsePacket(byte[] buffer) : base(buffer)
{
ErrorCode = ByteReader.ReadByte(this.Trailer, 0);
}
public override byte[] GetBytes()
{
this.Trailer = new byte[1];
this.Trailer[0] = ErrorCode;
return base.GetBytes();
}
}
}

View file

@ -0,0 +1,31 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public class PositiveSessionResponsePacket : SessionPacket
{
public PositiveSessionResponsePacket() : base()
{
this.Type = SessionPacketTypeName.PositiveSessionResponse;
}
public PositiveSessionResponsePacket(byte[] buffer) : base(buffer)
{
}
public override byte[] GetBytes()
{
this.Trailer = new byte[0];
return base.GetBytes();
}
}
}

View file

@ -0,0 +1,31 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public class SessionKeepAlivePacket : SessionPacket
{
public SessionKeepAlivePacket()
{
this.Type = SessionPacketTypeName.SessionKeepAlive;
}
public SessionKeepAlivePacket(byte[] buffer) : base(buffer)
{
}
public override byte[] GetBytes()
{
this.Trailer = new byte[0];
return base.GetBytes();
}
}
}

View file

@ -0,0 +1,25 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public class SessionMessagePacket : SessionPacket
{
public SessionMessagePacket() : base()
{
this.Type = SessionPacketTypeName.SessionMessage;
}
public SessionMessagePacket(byte[] buffer) : base(buffer)
{
}
}
}

View file

@ -0,0 +1,75 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public abstract class SessionPacket
{
public SessionPacketTypeName Type;
public byte Flags;
public int Length; // 2 bytes + length extension bit
public byte[] Trailer;
public SessionPacket()
{
}
public SessionPacket(byte[] buffer)
{
Type = (SessionPacketTypeName)ByteReader.ReadByte(buffer, 0);
Flags = ByteReader.ReadByte(buffer, 1);
Length = (Flags & 0x01) << 16 | BigEndianConverter.ToUInt16(buffer, 2);
this.Trailer = ByteReader.ReadBytes(buffer, 4, Length);
}
public virtual byte[] GetBytes()
{
Length = this.Trailer.Length;
if (Length > 0x1FFFF)
{
throw new ArgumentException("Invalid NBT packet length");
}
Flags = Convert.ToByte(Length > 0xFFFF);
byte[] buffer = new byte[4 + Trailer.Length];
ByteWriter.WriteByte(buffer, 0, (byte)this.Type);
ByteWriter.WriteByte(buffer, 1, Flags);
BigEndianWriter.WriteUInt16(buffer, 2, (ushort)(Length & 0xFFFF));
ByteWriter.WriteBytes(buffer, 4, this.Trailer);
return buffer;
}
public static SessionPacket GetSessionPacket(byte[] buffer)
{
SessionPacketTypeName type = (SessionPacketTypeName)ByteReader.ReadByte(buffer, 0);
switch (type)
{
case SessionPacketTypeName.SessionMessage:
return new SessionMessagePacket(buffer);
case SessionPacketTypeName.SessionRequest:
return new SessionRequestPacket(buffer);
case SessionPacketTypeName.PositiveSessionResponse:
return new PositiveSessionResponsePacket(buffer);
case SessionPacketTypeName.NegativeSessionResponse:
return new NegativeSessionResponsePacket(buffer);
case SessionPacketTypeName.RetargetSessionResponse:
return new SessionRetargetResponsePacket(buffer);
case SessionPacketTypeName.SessionKeepAlive:
return new SessionKeepAlivePacket(buffer);
default:
throw new InvalidRequestException("Invalid NetBIOS Session Packet");
}
}
}
}

View file

@ -0,0 +1,41 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public class SessionRequestPacket : SessionPacket
{
public string CalledName;
public string CallingName;
public SessionRequestPacket()
{
this.Type = SessionPacketTypeName.SessionRequest;
}
public SessionRequestPacket(byte[] buffer) : base(buffer)
{
int offset = 0;
CalledName = NetBiosUtils.DecodeName(this.Trailer, ref offset);
CallingName = NetBiosUtils.DecodeName(this.Trailer, ref offset);
}
public override byte[] GetBytes()
{
byte[] part1 = NetBiosUtils.EncodeName(CalledName, String.Empty);
byte[] part2 = NetBiosUtils.EncodeName(CallingName, String.Empty);
this.Trailer = new byte[part1.Length + part2.Length];
ByteWriter.WriteBytes(this.Trailer, 0, part1);
ByteWriter.WriteBytes(this.Trailer, part1.Length, part2);
return base.GetBytes();
}
}
}

View file

@ -0,0 +1,38 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.NetBios
{
public class SessionRetargetResponsePacket : SessionPacket
{
uint IPAddress;
ushort Port;
public SessionRetargetResponsePacket() : base()
{
this.Type = SessionPacketTypeName.RetargetSessionResponse;
}
public SessionRetargetResponsePacket(byte[] buffer) : base(buffer)
{
IPAddress = BigEndianConverter.ToUInt32(this.Trailer, 0);
Port = BigEndianConverter.ToUInt16(this.Trailer, 4);
}
public override byte[] GetBytes()
{
this.Trailer = new byte[6];
BigEndianWriter.WriteUInt32(this.Trailer, 0, IPAddress);
BigEndianWriter.WriteUInt16(this.Trailer, 4, Port);
return base.GetBytes();
}
}
}

View file

@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SMBLibrary")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Tal Aloni")]
[assembly: AssemblyProduct("SMBLibrary")]
[assembly: AssemblyCopyright("Copyright © Tal Aloni 2014-2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("301890e4-fc53-448e-8070-79d17086f922")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.5.0")]
[assembly: AssemblyFileVersion("1.0.5.0")]

View file

@ -0,0 +1,16 @@
namespace SMBLibrary.RPC
{
public enum NegotiationResult : ushort
{
Acceptance,
UserRejection,
ProviderRejection,
/// <summary>
/// Microsoft extension:
/// [MS-RPCE] 2.2.2.4 - negotiate_ack
/// </summary>
NegotiateAck
}
}

View file

@ -0,0 +1,16 @@
using System;
namespace SMBLibrary.RPC
{
[Flags]
public enum PacketFlags : byte
{
FirstFragment = 0x01, // PFC_FIRST_FRAG
LastFragment = 0x02, // PFC_LAST_FRAG
PendingCancel = 0x04, // PFC_PENDING_CANCEL
ConcurrntMultiplexing = 0x10, // PFC_CONC_MPX
DidNotExecute = 0x20, // PFC_DID_NOT_EXECUTE
Maybe = 0x40, // PFC_MAYBE
ObjectUUID = 0x80, // PFC_OBJECT_UUID
}
}

View file

@ -0,0 +1,27 @@
namespace SMBLibrary.RPC
{
// Commented out packet types are connectionless-only
public enum PacketTypeName : byte
{
Request = 0x00,
// Ping = 0x01,
Response = 0x02,
Fault = 0x03,
//Working = 0x04,
//NoCall = 0x05,
//Reject = 0x06,
//Ack = 0x07,
//CLCancel = 0x08, // cl_cancel
//FAck = 0x09,
//CancelAck = 0x0A, // cancel_ack
Bind = 0x0B,
BindAck = 0x0C,
BindNak = 0x0D, // bind_nak
AlterContext = 0x0E, // alter_context
AlterContextResponse = 0x0F, // alter_context_resp
Shutdown = 0x11,
COCancel = 0x12, // co_cancel
Orphaned = 0x13,
}
}

View file

@ -0,0 +1,11 @@
namespace SMBLibrary.RPC
{
public enum RejectionReason : ushort
{
NotSpecified,
AbstractSyntaxNotSupported,
ProposedTransferSyntaxesNotSupported,
LocalLimitExceeded,
}
}

View file

@ -0,0 +1,52 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
namespace SMBLibrary.RPC
{
// See DCE 1.1: Remote Procedure Call, Chapter 14.1 - Data Representation Format Label
public enum CharacterFormat : byte
{
ASCII = 0x00,
EBCDIC = 0x01,
}
public enum ByteOrder : byte
{
BigEndian = 0x00,
LittleEndian = 0x01,
}
public enum FloatingPointRepresentation : byte
{
IEEE = 0x00,
VAX = 0x01,
Cray = 0x02,
IBM = 0x03,
}
public struct DataRepresentationFormat // uint
{
public CharacterFormat CharacterFormat;
public ByteOrder ByteOrder;
public FloatingPointRepresentation FloatingPointRepresentation;
public DataRepresentationFormat(byte[] buffer, int offset)
{
CharacterFormat = (CharacterFormat)(buffer[offset + 0] & 0x0F);
ByteOrder = (ByteOrder)(buffer[offset + 0] >> 4);
FloatingPointRepresentation = (FloatingPointRepresentation)(buffer[offset + 1]);
}
public void WriteBytes(byte[] buffer, int offset)
{
buffer[offset + 0] = (byte)CharacterFormat;
buffer[offset + 0] |= (byte)((byte)ByteOrder << 4);
buffer[offset + 1] = (byte)FloatingPointRepresentation;
}
}
}

View file

@ -0,0 +1,21 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace SMBLibrary.RPC
{
/// <summary>
/// Serializable Structure / Union / Array
/// </summary>
public interface INDRStructure
{
void Read(NDRParser parser);
void Write(NDRWriter writer);
}
}

View file

@ -0,0 +1,45 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace SMBLibrary.RPC
{
public class NDRConformantArray<T> : List<T>, INDRStructure where T : INDRStructure, new()
{
/// <summary>
/// See DCE 1.1: Remote Procedure Call - 14.3.3.2 - Uni-dimensional Conformant Arrays
/// </summary>
/// <param name="parser"></param>
public void Read(NDRParser parser)
{
parser.BeginStructure();
uint maxCount = parser.ReadUInt32();
for (int index = 0; index < maxCount; index++)
{
T entry = new T();
entry.Read(parser);
this.Add(entry);
}
parser.EndStructure();
}
public void Write(NDRWriter writer)
{
writer.BeginStructure();
uint maxCount = (uint)this.Count;
writer.WriteUInt32(maxCount);
for (int index = 0; index < this.Count; index++)
{
this[index].Write(writer);
}
writer.EndStructure();
}
}
}

View file

@ -0,0 +1,140 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// NDR - Native Data Representation
/// See DCE 1.1: Remote Procedure Call, Chapter 14 - Transfer Syntax NDR
/// </summary>
public class NDRParser
{
private byte[] m_buffer;
private int m_offset;
private int m_depth;
private List<INDRStructure> m_deferredStructures = new List<INDRStructure>();
private Dictionary<uint, INDRStructure> m_referentToInstance = new Dictionary<uint, INDRStructure>();
public NDRParser(byte[] buffer)
{
m_buffer = buffer;
m_offset = 0;
m_depth = 0;
}
public void BeginStructure()
{
m_depth++;
}
/// <summary>
/// Add embedded pointer deferred structure (referent) parser
/// </summary>
private void AddDeferredStructure(INDRStructure structure)
{
m_deferredStructures.Add(structure);
}
public void EndStructure()
{
m_depth--;
// 14.3.12.3 - Algorithm for Deferral of Referents
// Representations of (embedded) pointer referents are ordered according to a left-to-right, depth-first traversal of the embedding construction.
// referent representations for the embedded construction are further deferred to a position in the octet stream that
// follows the representation of the embedding construction. The set of referent representations for the embedded construction
// is inserted among the referent representations for any pointers in the embedding construction, according to the order of elements or
// members in the embedding construction
if (m_depth == 0)
{
// Make a copy of all the deferred structures, additional deferred structures will be inserted to m_deferredStructures
// as we process the existing list
List<INDRStructure> deferredStructures = new List<INDRStructure>(m_deferredStructures);
m_deferredStructures.Clear();
// Read all deferred types:
foreach (INDRStructure deferredStructure in deferredStructures)
{
deferredStructure.Read(this);
}
}
}
public string ReadUnicodeString()
{
NDRUnicodeString unicodeString = new NDRUnicodeString(this);
return unicodeString.Value;
}
public void ReadStructure(INDRStructure structure)
{
structure.Read(this);
}
// 14.3.11.1 - Top-level Full Pointers
public string ReadTopLevelUnicodeStringPointer()
{
uint referentID = ReadUInt32();
if (referentID == 0)
{
return null;
}
if (m_referentToInstance.ContainsKey(referentID))
{
NDRUnicodeString unicodeString = (NDRUnicodeString)m_referentToInstance[referentID];
return unicodeString.Value;
}
else
{
NDRUnicodeString unicodeString = new NDRUnicodeString(this);
m_referentToInstance.Add(referentID, unicodeString);
return unicodeString.Value;
}
}
public void ReadEmbeddedStructureFullPointer(ref NDRUnicodeString structure)
{
ReadEmbeddedStructureFullPointer<NDRUnicodeString>(ref structure);
}
public void ReadEmbeddedStructureFullPointer<T>(ref T structure) where T : INDRStructure, new ()
{
uint referentID = ReadUInt32();
if (referentID != 0) // not null
{
if (structure == null)
{
structure = new T();
}
AddDeferredStructure(structure);
}
else
{
structure = default(T);
}
}
// 14.2.2 - Alignment of Primitive Types
public uint ReadUInt16()
{
m_offset += (2 - (m_offset % 2)) % 2;
return LittleEndianReader.ReadUInt16(m_buffer, ref m_offset);
}
// 14.2.2 - Alignment of Primitive Types
public uint ReadUInt32()
{
m_offset += (4 - (m_offset % 4)) % 4;
return LittleEndianReader.ReadUInt32(m_buffer, ref m_offset);
}
}
}

View file

@ -0,0 +1,16 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
namespace SMBLibrary.RPC
{
/// <summary>
/// Primitive and construced types
/// </summary>
public enum NDRTypeName
{
UnicodeString,
}
}

View file

@ -0,0 +1,74 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
public class NDRUnicodeString : INDRStructure
{
public string Value;
public NDRUnicodeString()
{
Value = String.Empty;
}
public NDRUnicodeString(string value)
{
Value = value;
}
public NDRUnicodeString(NDRParser parser)
{
Read(parser);
}
// 14.3.4.2 - Conformant and Varying Strings
public void Read(NDRParser parser)
{
uint maxCount = parser.ReadUInt32();
// the offset from the first index of the string to the first index of the actual subset being passed
uint index = parser.ReadUInt32();
// actualCount includes the null terminator
uint actualCount = parser.ReadUInt32();
StringBuilder builder = new StringBuilder();
for (int position = 0; position < actualCount - 1; position++)
{
builder.Append((char)parser.ReadUInt16());
}
this.Value = builder.ToString();
parser.ReadUInt16(); // null terminator
}
public void Write(NDRWriter writer)
{
int length = 0;
if (Value != null)
{
length = Value.Length;
}
// maxCount includes the null terminator
uint maxCount = (uint)(length + 1);
writer.WriteUInt32(maxCount);
// the offset from the first index of the string to the first index of the actual subset being passed
uint index = 0;
writer.WriteUInt32(index);
// actualCount includes the null terminator
uint actualCount = (uint)(length + 1);
writer.WriteUInt32(actualCount);
for (int position = 0; position < length; position++)
{
writer.WriteUInt16((ushort)Value[position]);
}
writer.WriteUInt16(0); // null terminator
}
}
}

View file

@ -0,0 +1,140 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// NDR - Native Data Representation
/// See DCE 1.1: Remote Procedure Call, Chapter 14 - Transfer Syntax NDR
/// </summary>
public class NDRWriter
{
private MemoryStream m_stream = new MemoryStream();
private int m_depth;
private List<INDRStructure> m_deferredStructures = new List<INDRStructure>();
private Dictionary<uint, INDRStructure> m_referentToInstance = new Dictionary<uint, INDRStructure>();
private uint m_nextReferentID = 0x00020000;
public void BeginStructure()
{
m_depth++;
}
/// <summary>
/// Add embedded pointer deferred structure (referent) writer
/// </summary>
private void AddDeferredStructure(INDRStructure structure)
{
m_deferredStructures.Add(structure);
}
public void EndStructure()
{
m_depth--;
// 14.3.12.3 - Algorithm for Deferral of Referents
// Representations of (embedded) pointer referents are ordered according to a left-to-right, depth-first traversal of the embedding construction.
// referent representations for the embedded construction are further deferred to a position in the octet stream that
// follows the representation of the embedding construction. The set of referent representations for the embedded construction
// is inserted among the referent representations for any pointers in the embedding construction, according to the order of elements or
// members in the embedding construction
if (m_depth == 0)
{
// Make a copy of all the deferred structures, additional deferred structures will be inserted to m_deferredStructures
// as we process the existing list
List<INDRStructure> deferredStructures = new List<INDRStructure>(m_deferredStructures);
m_deferredStructures.Clear();
// Write all deferred types:
foreach (INDRStructure deferredStructure in deferredStructures)
{
deferredStructure.Write(this);
}
}
}
public void WriteUnicodeString(string value)
{
NDRUnicodeString unicodeString = new NDRUnicodeString(value);
unicodeString.Write(this);
}
public void WriteStructure(INDRStructure structure)
{
structure.Write(this);
}
public void WriteTopLevelUnicodeStringPointer(string value)
{
if (value == null)
{
WriteUInt32(0);
return;
}
// Note: We do not bother searching for existing values
uint referentID = GetNextReferentID();
WriteUInt32(referentID);
NDRUnicodeString unicodeString = new NDRUnicodeString(value);
unicodeString.Write(this);
m_referentToInstance.Add(referentID, unicodeString);
}
// 14.3.12.1 Embedded Full Pointers
public void WriteEmbeddedStructureFullPointer(INDRStructure structure)
{
if (structure == null)
{
WriteUInt32(0); // null
return;
}
else
{
// Note: We do not bother searching for existing values
uint referentID = GetNextReferentID();
WriteUInt32(referentID);
AddDeferredStructure(structure);
m_referentToInstance.Add(referentID, structure);
}
}
// 14.2.2 - Alignment of Primitive Types
public void WriteUInt16(ushort value)
{
uint padding = (uint)(2 - (m_stream.Position % 2)) % 2;
m_stream.Position += padding;
LittleEndianWriter.WriteUInt16(m_stream, value);
}
// 14.2.2 - Alignment of Primitive Types
public void WriteUInt32(uint value)
{
uint padding = (uint)(4 - (m_stream.Position % 4)) % 4;
m_stream.Position += padding;
LittleEndianWriter.WriteUInt32(m_stream, value);
}
public byte[] GetBytes()
{
byte[] buffer = new byte[m_stream.Length];
m_stream.Seek(0, SeekOrigin.Begin);
m_stream.Read(buffer, 0, buffer.Length);
return buffer;
}
private uint GetNextReferentID()
{
uint result = m_nextReferentID;
m_nextReferentID++;
return result;
}
}
}

View file

@ -0,0 +1,68 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// rpcconn_bind_ack_hdr_t
/// </summary>
public class BindAckPDU : RPCPDU
{
public ushort MaxTransmitFragmentSize; // max_xmit_frag
public ushort MaxReceiveFragmentSize; // max_recv_frag
public uint AssociationGroupID; // assoc_group_id
public string SecondaryAddress; // sec_addr (port_any_t)
// Padding (alignment to 4 byte boundary)
public ResultList ResultList; // p_result_list
public byte[] AuthVerifier;
public BindAckPDU() : base()
{
PacketType = PacketTypeName.BindAck;
SecondaryAddress = String.Empty;
ResultList = new ResultList();
AuthVerifier = new byte[0];
}
public BindAckPDU(byte[] buffer) : base(buffer)
{
int offset = RPCPDU.CommonFieldsLength;
MaxTransmitFragmentSize = LittleEndianReader.ReadUInt16(buffer, ref offset);
MaxReceiveFragmentSize = LittleEndianReader.ReadUInt16(buffer, ref offset);
AssociationGroupID = LittleEndianReader.ReadUInt32(buffer, ref offset);
SecondaryAddress = RPCHelper.ReadPortAddress(buffer, ref offset);
int padding = (4 - (offset % 4)) % 4;
offset += padding;
ResultList = new ResultList(buffer, offset);
offset += ResultList.Length;
AuthVerifier = ByteReader.ReadBytes(buffer, offset, AuthLength);
}
public override byte[] GetBytes()
{
AuthLength = (ushort)AuthVerifier.Length;
int padding = (4 - ((SecondaryAddress.Length + 3) % 4)) % 4;
FragmentLength = (ushort)(RPCPDU.CommonFieldsLength + 8 + SecondaryAddress.Length + 3 + padding + ResultList.Length + AuthLength);
byte[] buffer = new byte[FragmentLength];
WriteCommonFieldsBytes(buffer);
int offset = RPCPDU.CommonFieldsLength;
LittleEndianWriter.WriteUInt16(buffer, ref offset, MaxTransmitFragmentSize);
LittleEndianWriter.WriteUInt16(buffer, ref offset, MaxReceiveFragmentSize);
LittleEndianWriter.WriteUInt32(buffer, ref offset, AssociationGroupID);
RPCHelper.WritePortAddress(buffer, ref offset, SecondaryAddress);
offset += padding;
ResultList.WriteBytes(buffer, ref offset);
ByteWriter.WriteBytes(buffer, offset, AuthVerifier);
return buffer;
}
}
}

View file

@ -0,0 +1,60 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// rpcconn_bind_hdr_t
/// </summary>
public class BindPDU : RPCPDU
{
public ushort MaxTransmitFragmentSize; // max_xmit_frag
public ushort MaxReceiveFragmentSize; // max_recv_frag
public uint AssociationGroupID; // assoc_group_id
public ContextList ContextList;
public byte[] AuthVerifier;
public BindPDU() : base()
{
PacketType = PacketTypeName.Bind;
ContextList = new ContextList();
AuthVerifier = new byte[0];
}
public BindPDU(byte[] buffer) : base(buffer)
{
int offset = RPCPDU.CommonFieldsLength;
MaxTransmitFragmentSize = LittleEndianReader.ReadUInt16(buffer, ref offset);
MaxReceiveFragmentSize = LittleEndianReader.ReadUInt16(buffer, ref offset);
AssociationGroupID = LittleEndianReader.ReadUInt32(buffer, ref offset);
ContextList = new ContextList(buffer, offset);
offset += ContextList.Length;
AuthVerifier = ByteReader.ReadBytes(buffer, offset, AuthLength);
}
public override byte[] GetBytes()
{
AuthLength =(ushort)AuthVerifier.Length;
FragmentLength = (ushort)(RPCPDU.CommonFieldsLength + 8 + ContextList.Length + AuthLength);
byte[] buffer = new byte[FragmentLength];
WriteCommonFieldsBytes(buffer);
int offset = RPCPDU.CommonFieldsLength;
LittleEndianWriter.WriteUInt16(buffer, ref offset, MaxTransmitFragmentSize);
LittleEndianWriter.WriteUInt16(buffer, ref offset, MaxReceiveFragmentSize);
LittleEndianWriter.WriteUInt32(buffer, ref offset, AssociationGroupID);
ContextList.WriteBytes(buffer, ref offset);
ByteWriter.WriteBytes(buffer, offset, AuthVerifier);
return buffer;
}
}
}

View file

@ -0,0 +1,66 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// rpcconn_fault_hdr_t
/// </summary>
public class FaultPDU : RPCPDU
{
public uint AllocationHint;
public ushort ContextID;
public byte CancelCount;
public byte Reserved;
public uint Status;
public uint Reserved2;
public byte[] Data;
public byte[] AuthVerifier;
public FaultPDU() : base()
{
PacketType = PacketTypeName.Fault;
AuthVerifier = new byte[0];
}
public FaultPDU(byte[] buffer) : base(buffer)
{
int offset = RPCPDU.CommonFieldsLength;
AllocationHint = LittleEndianReader.ReadUInt32(buffer, ref offset);
ContextID = LittleEndianReader.ReadUInt16(buffer, ref offset);
CancelCount = ByteReader.ReadByte(buffer, ref offset);
Reserved = ByteReader.ReadByte(buffer, ref offset);
Status = LittleEndianReader.ReadUInt32(buffer, ref offset);
Reserved2 = LittleEndianReader.ReadUInt32(buffer, ref offset);
int dataLength = FragmentLength - AuthLength - offset;
Data = ByteReader.ReadBytes(buffer, ref offset, dataLength);
AuthVerifier = ByteReader.ReadBytes(buffer, offset, AuthLength);
}
public override byte[] GetBytes()
{
AuthLength = (ushort)AuthVerifier.Length;
FragmentLength = (ushort)(RPCPDU.CommonFieldsLength + 16 + Data.Length + AuthVerifier.Length);
byte[] buffer = new byte[FragmentLength];
WriteCommonFieldsBytes(buffer);
int offset = RPCPDU.CommonFieldsLength;
LittleEndianWriter.WriteUInt32(buffer, ref offset, AllocationHint);
LittleEndianWriter.WriteUInt16(buffer, ref offset, ContextID);
ByteWriter.WriteByte(buffer, ref offset, CancelCount);
ByteWriter.WriteByte(buffer, ref offset, Reserved);
LittleEndianWriter.WriteUInt32(buffer, ref offset, Status);
LittleEndianWriter.WriteUInt32(buffer, ref offset, Reserved2);
ByteWriter.WriteBytes(buffer, ref offset, Data);
ByteWriter.WriteBytes(buffer, ref offset, AuthVerifier);
return buffer;
}
}
}

View file

@ -0,0 +1,83 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// See DCE 1.1: Remote Procedure Call, Chapter 12.6 - Connection-oriented RPC PDUs
/// </summary>
public abstract class RPCPDU
{
public const int CommonFieldsLength = 16;
// The common header fields, which appear in all (connection oriented) PDU types:
public byte VersionMajor; // rpc_vers
public byte VersionMinor; // rpc_vers_minor
public PacketTypeName PacketType;
public PacketFlags Flags;
public DataRepresentationFormat DataRepresentation;
public ushort FragmentLength;
public ushort AuthLength;
public uint CallID;
public RPCPDU()
{
VersionMajor = 5;
VersionMinor = 0;
}
public RPCPDU(byte[] buffer)
{
VersionMajor = ByteReader.ReadByte(buffer, 0);
VersionMinor = ByteReader.ReadByte(buffer, 1);
PacketType = (PacketTypeName)ByteReader.ReadByte(buffer, 2);
Flags = (PacketFlags)ByteReader.ReadByte(buffer, 3);
DataRepresentation = new DataRepresentationFormat(buffer, 4);
FragmentLength = LittleEndianConverter.ToUInt16(buffer, 8);
AuthLength = LittleEndianConverter.ToUInt16(buffer, 10);
CallID = LittleEndianConverter.ToUInt32(buffer, 12);
}
public abstract byte[] GetBytes();
public void WriteCommonFieldsBytes(byte[] buffer)
{
ByteWriter.WriteByte(buffer, 0, VersionMajor);
ByteWriter.WriteByte(buffer, 1, VersionMinor);
ByteWriter.WriteByte(buffer, 2, (byte)PacketType);
ByteWriter.WriteByte(buffer, 3, (byte)Flags);
DataRepresentation.WriteBytes(buffer, 4);
LittleEndianWriter.WriteUInt16(buffer, 8, FragmentLength);
LittleEndianWriter.WriteUInt16(buffer, 10, AuthLength);
LittleEndianWriter.WriteUInt32(buffer, 12, CallID);
}
public static RPCPDU GetPDU(byte[] buffer)
{
PacketTypeName packetType = (PacketTypeName)ByteReader.ReadByte(buffer, 2);
switch (packetType)
{
case PacketTypeName.Request:
return new RequestPDU(buffer);
case PacketTypeName.Response:
return new ResponsePDU(buffer);
case PacketTypeName.Fault:
return new FaultPDU(buffer);
case PacketTypeName.Bind:
return new BindPDU(buffer);
case PacketTypeName.BindAck:
return new BindAckPDU(buffer);
default:
throw new NotImplementedException();
}
}
}
}

View file

@ -0,0 +1,72 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// rpcconn_request_hdr_t
/// </summary>
public class RequestPDU : RPCPDU
{
public uint AllocationHint; // alloc_hint
public ushort ContextID;
public ushort OpNum;
public Guid ObjectGuid; // Optional field
public byte[] Data;
public byte[] AuthVerifier;
public RequestPDU() : base()
{
PacketType = PacketTypeName.Request;
AuthVerifier = new byte[0];
}
public RequestPDU(byte[] buffer) : base(buffer)
{
int offset = RPCPDU.CommonFieldsLength;
AllocationHint = LittleEndianReader.ReadUInt32(buffer, ref offset);
ContextID = LittleEndianReader.ReadUInt16(buffer, ref offset);
OpNum = LittleEndianReader.ReadUInt16(buffer, ref offset);
if ((Flags & PacketFlags.ObjectUUID) > 0)
{
ObjectGuid = LittleEndianReader.ReadGuid(buffer, ref offset);
}
int dataLength = FragmentLength - AuthLength - offset;
Data = ByteReader.ReadBytes(buffer, ref offset, dataLength);
AuthVerifier = ByteReader.ReadBytes(buffer, offset, AuthLength);
}
public override byte[] GetBytes()
{
AuthLength = (ushort)AuthVerifier.Length;
FragmentLength = (ushort)(RPCPDU.CommonFieldsLength + 8 + Data.Length + AuthVerifier.Length);
if ((Flags & PacketFlags.ObjectUUID) > 0)
{
FragmentLength += 16;
}
byte[] buffer = new byte[FragmentLength];
WriteCommonFieldsBytes(buffer);
int offset = RPCPDU.CommonFieldsLength;
LittleEndianWriter.WriteUInt32(buffer, ref offset, AllocationHint);
LittleEndianWriter.WriteUInt16(buffer, ref offset, ContextID);
LittleEndianWriter.WriteUInt16(buffer, ref offset, OpNum);
if ((Flags & PacketFlags.ObjectUUID) > 0)
{
LittleEndianWriter.WriteGuidBytes(buffer, ref offset, ObjectGuid);
}
ByteWriter.WriteBytes(buffer, ref offset, Data);
ByteWriter.WriteBytes(buffer, ref offset, AuthVerifier);
return buffer;
}
}
}

View file

@ -0,0 +1,62 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// rpcconn_response_hdr_t
/// </summary>
public class ResponsePDU : RPCPDU
{
private uint AllocationHint;
public ushort ContextID;
public byte CancelCount;
public byte Reserved;
public byte[] Data;
public byte[] AuthVerifier;
public ResponsePDU() : base()
{
PacketType = PacketTypeName.Response;
AuthVerifier = new byte[0];
}
public ResponsePDU(byte[] buffer) : base(buffer)
{
int offset = RPCPDU.CommonFieldsLength;
AllocationHint = LittleEndianReader.ReadUInt32(buffer, ref offset);
ContextID = LittleEndianReader.ReadUInt16(buffer, ref offset);
CancelCount = ByteReader.ReadByte(buffer, ref offset);
Reserved = ByteReader.ReadByte(buffer, ref offset);
int dataLength = FragmentLength - AuthLength - offset;
Data = ByteReader.ReadBytes(buffer, ref offset, dataLength);
AuthVerifier = ByteReader.ReadBytes(buffer, offset, AuthLength);
}
public override byte[] GetBytes()
{
AuthLength = (ushort)AuthVerifier.Length;
FragmentLength = (ushort)(RPCPDU.CommonFieldsLength + 8 + Data.Length + AuthVerifier.Length);
AllocationHint = (ushort)Data.Length;
byte[] buffer = new byte[FragmentLength];
WriteCommonFieldsBytes(buffer);
int offset = RPCPDU.CommonFieldsLength;
LittleEndianWriter.WriteUInt32(buffer, ref offset, AllocationHint);
LittleEndianWriter.WriteUInt16(buffer, ref offset, ContextID);
ByteWriter.WriteByte(buffer, ref offset, CancelCount);
ByteWriter.WriteByte(buffer, ref offset, Reserved);
ByteWriter.WriteBytes(buffer, ref offset, Data);
ByteWriter.WriteBytes(buffer, ref offset, AuthVerifier);
return buffer;
}
}
}

View file

@ -0,0 +1,46 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
public class RPCHelper
{
/// <summary>
/// Read port_any_t string structure
/// </summary>
public static string ReadPortAddress(byte[] buffer, int offset)
{
ushort length = LittleEndianConverter.ToUInt16(buffer, offset + 0);
// The length includes the C NULL string termination
return ByteReader.ReadAnsiString(buffer, offset + 2, length - 1);
}
public static string ReadPortAddress(byte[] buffer, ref int offset)
{
string result = ReadPortAddress(buffer, offset);
offset += result.Length + 3;
return result;
}
public static void WritePortAddress(byte[] buffer, int offset, string value)
{
ushort length = (ushort)(value.Length + 1);
LittleEndianWriter.WriteUInt16(buffer, offset + 0, length);
ByteWriter.WriteNullTerminatedAnsiString(buffer, offset + 2, value);
}
public static void WritePortAddress(byte[] buffer, ref int offset, string value)
{
WritePortAddress(buffer, offset, value);
offset += value.Length + 3;
}
}
}

View file

@ -0,0 +1,65 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// p_cont_elem_t
/// </summary>
public class ContextElement // Presentation Context Element
{
public ushort ContextID;
//byte NumberOfTransferSyntaxItems;
public byte Reserved;
public SyntaxID AbstractSyntax;
public List<SyntaxID> TransferSyntaxList = new List<SyntaxID>();
public ContextElement(byte[] buffer, int offset)
{
ContextID = LittleEndianConverter.ToUInt16(buffer, offset + 0);
byte numberOfTransferSyntaxItems = ByteReader.ReadByte(buffer, offset + 2);
Reserved = ByteReader.ReadByte(buffer, offset + 3);
AbstractSyntax = new SyntaxID(buffer, offset + 4);
offset += 4 + SyntaxID.Length;
for (int index = 0; index < numberOfTransferSyntaxItems; index++)
{
SyntaxID syntax = new SyntaxID(buffer, offset);
TransferSyntaxList.Add(syntax);
offset += SyntaxID.Length;
}
}
public void WriteBytes(byte[] buffer, int offset)
{
byte numberOfTransferSyntaxItems = (byte)TransferSyntaxList.Count;
LittleEndianWriter.WriteUInt16(buffer, offset + 0, ContextID);
ByteWriter.WriteByte(buffer, offset + 2, numberOfTransferSyntaxItems);
ByteWriter.WriteByte(buffer, offset + 3, Reserved);
AbstractSyntax.WriteBytes(buffer, offset + 4);
offset += 4 + SyntaxID.Length;
for (int index = 0; index < numberOfTransferSyntaxItems; index++)
{
TransferSyntaxList[index].WriteBytes(buffer, offset);
offset += SyntaxID.Length;
}
}
public int Length
{
get
{
return 4 + SyntaxID.Length * (TransferSyntaxList.Count + 1);
}
}
}
}

View file

@ -0,0 +1,76 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// p_cont_list_t
/// Presentation Context List
/// </summary>
public class ContextList : List<ContextElement>
{
//byte NumberOfContextElements;
public byte Reserved1;
public ushort Reserved2;
public ContextList() : base()
{
}
public ContextList(byte[] buffer, int offset) : base()
{
byte numberOfContextElements = ByteReader.ReadByte(buffer, offset + 0);
Reserved1 = ByteReader.ReadByte(buffer, offset + 1);
Reserved2 = LittleEndianConverter.ToUInt16(buffer, offset + 2);
offset += 4;
for (int index = 0; index < numberOfContextElements; index++)
{
ContextElement element = new ContextElement(buffer, offset);
this.Add(element);
offset += element.Length;
}
}
public void WriteBytes(byte[] buffer, int offset)
{
byte numberOfContextElements = (byte)this.Count;
ByteWriter.WriteByte(buffer, offset + 0, numberOfContextElements);
ByteWriter.WriteByte(buffer, offset + 1, Reserved1);
LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved2);
offset += 4;
for (int index = 0; index < numberOfContextElements; index++)
{
this[index].WriteBytes(buffer, offset);
offset += this[index].Length;
}
}
public void WriteBytes(byte[] buffer, ref int offset)
{
WriteBytes(buffer, offset);
offset += this.Length;
}
public int Length
{
get
{
int length = 4;
for (int index = 0; index < this.Count; index++)
{
length += this[index].Length;
}
return length;
}
}
}
}

View file

@ -0,0 +1,39 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// p_result_t
/// </summary>
public struct ResultElement
{
public const int Length = 24;
public NegotiationResult Result;
public RejectionReason Reason;
public SyntaxID TransferSyntax;
public ResultElement(byte[] buffer, int offset)
{
Result = (NegotiationResult)LittleEndianConverter.ToUInt16(buffer, offset + 0);
Reason = (RejectionReason)LittleEndianConverter.ToUInt16(buffer, offset + 2);
TransferSyntax = new SyntaxID(buffer, offset + 4);
}
public void WriteBytes(byte[] buffer, int offset)
{
LittleEndianWriter.WriteUInt16(buffer, offset + 0, (ushort)Result);
LittleEndianWriter.WriteUInt16(buffer, offset + 2, (ushort)Reason);
TransferSyntax.WriteBytes(buffer, offset + 4);
}
}
}

View file

@ -0,0 +1,69 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// p_result_list_t
/// </summary>
public class ResultList : List<ResultElement>
{
//byte NumberOfResults;
public byte Reserved;
public ushort Reserved2;
public ResultList() : base()
{}
public ResultList(byte[] buffer, int offset) : base()
{
byte numberOfResults = ByteReader.ReadByte(buffer, offset + 0);
Reserved = ByteReader.ReadByte(buffer, offset + 1);
Reserved2 = LittleEndianConverter.ToUInt16(buffer, offset + 2);
offset += 4;
for (int index = 0; index < numberOfResults; index++)
{
ResultElement element = new ResultElement(buffer, offset);
this.Add(element);
offset += ResultElement.Length;
}
}
public void WriteBytes(byte[] buffer, int offset)
{
byte numberOfResults = (byte)this.Count;
ByteWriter.WriteByte(buffer, offset + 0, numberOfResults);
ByteWriter.WriteByte(buffer, offset + 1, Reserved);
LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved2);
offset += 4;
for (int index = 0; index < numberOfResults; index++)
{
this[index].WriteBytes(buffer, offset);
offset += ResultElement.Length;
}
}
public void WriteBytes(byte[] buffer, ref int offset)
{
WriteBytes(buffer, offset);
offset += this.Length;
}
public int Length
{
get
{
return 4 + ResultElement.Length * this.Count;
}
}
}
}

View file

@ -0,0 +1,56 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.RPC
{
/// <summary>
/// p_syntax_id_t
/// </summary>
public struct SyntaxID
{
public const int Length = 20;
public Guid InterfaceUUID; // if_uuid
public uint InterfaceVersion; // if_version
public SyntaxID(Guid interfaceUUID, uint interfaceVersion)
{
InterfaceUUID = interfaceUUID;
InterfaceVersion = interfaceVersion;
}
public SyntaxID(byte[] buffer, int offset)
{
InterfaceUUID = LittleEndianConverter.ToGuid(buffer, offset + 0);
InterfaceVersion = LittleEndianConverter.ToUInt32(buffer, offset + 16);
}
public void WriteBytes(byte[] buffer, int offset)
{
LittleEndianWriter.WriteGuidBytes(buffer, offset + 0, InterfaceUUID);
LittleEndianWriter.WriteUInt32(buffer, offset + 16, InterfaceVersion);
}
public override bool Equals(object obj)
{
if (obj is SyntaxID)
{
return this.InterfaceUUID.Equals(((SyntaxID)obj).InterfaceUUID) && this.InterfaceVersion.Equals(((SyntaxID)obj).InterfaceVersion);
}
return false;
}
public override int GetHashCode()
{
return InterfaceUUID.GetHashCode() * InterfaceVersion.GetHashCode();
}
}
}

43
SMBLibrary/Readme.txt Normal file
View file

@ -0,0 +1,43 @@
About SMBLibrary:
=================
SMBLibrary is an open-source C# SMB 1.0/CIFS 1.0 server implementation.
SMBLibrary gives .NET developers an easy way to share a directory / file system / virtual file system, with any operating system that supports the SMB protocol.
SMBLibrary shares can be accessed from any Windows version since Windows NT 4.0.
Supported SMB / CIFS transport methods:
=======================================
NetBIOS over TCP (port 139)
Direct TCP hosting (port 445)
Notes:
------
1. Windows bind port 139 on a per-adapter basis, while port 445 is bound globally.
This means that you can't use direct TCP hosting without disabling Windows File and Printer Sharing server completely.
However, NetBIOS over TCP is almost identical, and for this reason, it's recommended to use port 139.
2. To free port 139 for a given adapter, go to 'Internet Protocol (TCP/IP) Properties' > Advanced > WINS,
and select 'Disable NetBIOS over TCP/IP'. in addition you need to uncheck 'File and Printer Sharing for Microsoft Networks'.
3. It's important to note that disabling NetBIOS over TCP/IP will also disable NetBIOS name service for that adapter (a.k.a. WINS),
This service uses UDP port 137. SMBLibrary offers a name service of its own.
4. You can install a virtual network adapter driver for Windows to be used solely with SMBLibrary:
- You can install the 'Microsoft Loopback adapter' and use it for server-only communication with SMBLibrary.
- A limited alternative is 'OpenVPN TAP-Windows Adapter' that can be used for client communication with SMBLibrary,
However, you will have to configure this adapter to use a separate network segment.
The driver installation can be downloaded from: https://openvpn.net/index.php/open-source/downloads.html
To get started, go to Adapter properties > 'Advanced' and set 'Media Status' to 'Always Connected'.
5. The differences between 'Direct TCP hosting' and 'NetBIOS over TCP' are:
- A 'session request' packet is initiating the NBT connection.
- A 'keep alive' packet is sent from time to time over NBT connections.
Using SMBLibrary:
=================
Any directory / filesystem / object you wish to share must implement the IFileSystem interface.
You can share anything from actual directories to custom objects, as long as they expose a directory structure.
Contact:
========
If you have any question, feel free to contact me.
Tal Aloni <tal.aloni.il@gmail.com>

View file

@ -0,0 +1,14 @@
Revision History:
-----------------
1.0.0 - Initial release.
1.0.1 - Better handling of invalid read / write operations.
1.0.2 - Improved documentation and updated SMB_COM_TRANSACTION2 request (Technical Specifications Errata was found).
1.0.3 - Search handles (SID) are now properly closed.
1.0.4 - Added support for IPv6.
1.0.5 - bugfix: SMB_COM_OPEN_ANDX was not returning the requested response format.
File buffering logic logic was moved to a separate class.

View file

@ -0,0 +1,95 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
namespace SMBLibrary.SMB1
{
public enum ReadMode : byte
{
ByteMode = 0x00,
MessageMode = 0x01,
}
public enum NamedPipeType : byte
{
ByteNamedPipe = 0x00,
MessageNodePipe = 0x01,
}
public enum Endpoint : byte
{
ClientSideEnd = 0x00,
ServerSideEnd = 0x01,
}
public enum NonBlocking : byte
{
Block = 0x00,
DoNotBlock = 0x01,
}
/// <summary>
/// SMB_NMPIPE_STATUS
/// </summary>
public struct NamedPipeStatus // ushort
{
public byte ICount;
public ReadMode ReadMode;
public NamedPipeType NamedPipeType;
public Endpoint Endpoint;
public NonBlocking NonBlocking;
public NamedPipeStatus(byte[] buffer, int offset)
{
ICount = buffer[offset];
ReadMode = (ReadMode)(buffer[offset + 1] & 0x03);
NamedPipeType = (NamedPipeType)((buffer[offset + 1] & 0x0C) >> 2);
Endpoint = (Endpoint)((buffer[offset + 1] & 0x40) >> 6);
NonBlocking = (NonBlocking)((buffer[offset + 1] & 0x80) >> 7);
}
public NamedPipeStatus(ushort value)
{
ICount = (byte)(value & 0xFF);
ReadMode = (ReadMode)((value & 0x0300) >> 8);
NamedPipeType = (NamedPipeType)((value & 0x0C00) >> 10);
Endpoint = (Endpoint)((value & 0x4000) >> 14);
NonBlocking = (NonBlocking)((value & 0x80) >> 15);
}
public void WriteBytes(byte[] buffer, int offset)
{
buffer[offset + 0] = ICount;
buffer[offset + 1] = (byte)((byte)ReadMode & 0x03);
buffer[offset + 1] |= (byte)(((byte)NamedPipeType << 2) & 0x0C);
buffer[offset + 1] |= (byte)(((byte)Endpoint << 6) & 0x40);
buffer[offset + 1] |= (byte)(((byte)NonBlocking << 7) & 0x80);
}
public void WriteBytes(byte[] buffer, ref int offset)
{
WriteBytes(buffer, offset);
offset += 2;
}
public ushort ToUInt16()
{
ushort result = ICount;
result |= (ushort)(((byte)ReadMode << 8) & 0x0300);
result |= (ushort)(((byte)NamedPipeType << 10) & 0x0C00);
result |= (ushort)(((byte)Endpoint << 14) & 0x4000);
result |= (ushort)(((byte)NonBlocking << 15) & 0x8000);
return result;
}
public static NamedPipeStatus Read(byte[] buffer, ref int offset)
{
offset += 2;
return new NamedPipeStatus(buffer, offset - 2);
}
}
}

View file

@ -0,0 +1,50 @@
/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Utilities;
namespace SMBLibrary.SMB1
{
public struct OpenResults // 2 bytes
{
public OpenResult OpenResult;
public bool OpLockGranted;
public OpenResults(byte[] buffer, int offset)
{
OpenResult = (OpenResult)(buffer[offset] & 0x3);
OpLockGranted = (buffer[offset + 1] & 0x80) > 0;
}
public void WriteBytes(byte[] buffer, int offset)
{
buffer[0] = (byte)OpenResult;
if (OpLockGranted)
{
buffer[1] = 0x80;
}
else
{
buffer[1] = 0x00;
}
}
public void WriteBytes(byte[] buffer, ref int offset)
{
WriteBytes(buffer, offset);
offset += 2;
}
public static OpenResults Read(byte[] buffer, ref int offset)
{
offset += 2;
return new OpenResults(buffer, offset - 2);
}
}
}

View file

@ -0,0 +1,40 @@
namespace SMBLibrary.SMB1
{
public enum CommandName : byte
{
SMB_COM_CREATE_DIRECTORY = 0x00,
SMB_COM_DELETE_DIRECTORY = 0x01,
SMB_COM_CLOSE = 0x04,
SMB_COM_FLUSH = 0x05,
SMB_COM_DELETE = 0x06,
SMB_COM_RENAME = 0x07,
SMB_COM_QUERY_INFORMATION = 0x08,
SMB_COM_SET_INFORMATION = 0x09,
SMB_COM_READ = 0x0A,
SMB_COM_WRITE = 0x0B,
SMB_COM_CHECK_DIRECTORY = 0x10,
SMB_COM_WRITE_RAW = 0x1D,
SMB_COM_WRITE_COMPLETE = 0x20, // Write RAW final response
SMB_COM_SET_INFORMATION2 = 0x22,
SMB_COM_LOCKING_ANDX = 0x24,
SMB_COM_TRANSACTION = 0x25,
SMB_COM_TRANSACTION_SECONDARY = 0x26,
SMB_COM_ECHO = 0x2B,
SMB_COM_OPEN_ANDX = 0x2D,
SMB_COM_READ_ANDX = 0x2E,
SMB_COM_WRITE_ANDX = 0x2F,
SMB_COM_TRANSACTION2 = 0x32,
SMB_COM_TRANSACTION2_SECONDARY = 0x33,
SMB_COM_FIND_CLOSE2 = 0x34,
SMB_COM_TREE_DISCONNECT = 0x71,
SMB_COM_NEGOTIATE = 0x72,
SMB_COM_SESSION_SETUP_ANDX = 0x73,
SMB_COM_LOGOFF_ANDX = 0x74,
SMB_COM_TREE_CONNECT_ANDX = 0x75,
SMB_COM_NT_TRANSACT = 0xA0,
SMB_COM_NT_TRANSACT_SECONDARY = 0xA1,
SMB_COM_NT_CREATE_ANDX = 0xA2,
SMB_COM_NO_ANDX_COMMAND = 0xFF,
}
}

View file

@ -0,0 +1,36 @@
using System;
namespace SMBLibrary.SMB1
{
/// <summary>
/// SMB_EXT_FILE_ATTR
/// </summary>
[Flags]
public enum ExtendedFileAttributes : uint
{
Readonly = 0x001, // ATTR_READONLY
Hidden = 0x0002, // ATTR_HIDDEN
System = 0x0004, // ATTR_SYSTEM
Directory = 0x0010, // ATTR_DIRECTORY
Archive = 0x0020, // ATTR_ARCHIVE
/// <summary>
/// The file has no other attributes set. This attribute is valid only if used alone.
/// </summary>
Normal = 0x0080, // ATTR_NORMAL
Temporary = 0x0100, // ATTR_TEMPORARY
Sparse = 0x0200, // ATTR_SPARSE, SMB 1.0 Addition
ReparsePoint = 0x0400, // ATTR_REPARSE_POINT, SMB 1.0 Addition
Compressed = 0x0800, // ATTR_COMPRESSED
Offline = 0x1000, // ATTR_OFFLINE, SMB 1.0 Addition
NotIndexed = 0x2000, // ATTR_NOT_CONTENT_INDEXED, SMB 1.0 Addition
Encrypted = 0x4000, // ATTR_ENCRYPTED, SMB 1.0 Addition
PosixSemantics = 0x01000000, // POSIX_SEMANTICS
BackupSemantics = 0x02000000, // BACKUP_SEMANTICS
DeleteOnClose = 0x04000000, // DELETE_ON_CLOSE
SequentialScan = 0x08000000, // SEQUENTIAL_SCAN
RandomAccess = 0x10000000, // RANDOM_ACCESS
NoBuffering = 0x10000000, // NO_BUFFERING
WriteThrough = 0x80000000, // WRITE_THROUGH
}
}

View file

@ -0,0 +1,24 @@
using System;
namespace SMBLibrary.SMB1
{
/// <summary>
/// SMB_FILE_ATTRIBUTES
/// </summary>
[Flags]
public enum FileAttributes : ushort
{
Normal = 0x0000, // SMB_FILE_ATTRIBUTE_NORMAL
ReadOnly = 0x0001, // SMB_FILE_ATTRIBUTE_READONLY
Hidden = 0x0002, // SMB_FILE_ATTRIBUTE_HIDDEN
System = 0x0004, // SMB_FILE_ATTRIBUTE_SYSTEM
Volume = 0x0008, // SMB_FILE_ATTRIBUTE_VOLUME
Directory = 0x0010, // SMB_FILE_ATTRIBUTE_DIRECTORY
Archive = 0x0020, // SMB_FILE_ATTRIBUTE_ARCHIVE
SearchReadOnly = 0x0100, // SMB_SEARCH_ATTRIBUTE_READONLY
SearchHidden = 0x0200, // SMB_SEARCH_ATTRIBUTE_HIDDEN
SearchSystem = 0x0400, // SMB_SEARCH_ATTRIBUTE_SYSTEM
SearchDirectory = 0x1000, // SMB_SEARCH_ATTRIBUTE_DIRECTORY
SearchArchive = 0x2000, // SMB_SEARCH_ATTRIBUTE_ARCHIVE
}
}

View file

@ -0,0 +1,14 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum HeaderFlags : byte
{
LockAndRead = 0x01, // SMB_FLAGS_LOCK_AND_READ_OK
CaseInsensitive = 0x08, // SMB_FLAGS_CASE_INSENSITIVE
CanonicalizedPaths = 0x10, // SMB_FLAGS_CANONICALIZED_PATHS
Oplock = 0x20, // SMB_FLAGS_OPLOCK
Reply = 0x80, // SMB_FLAGS_REPLY
}
}

View file

@ -0,0 +1,25 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum HeaderFlags2 : ushort
{
LongNamesAllowed = 0x0001, // SMB_FLAGS2_LONG_NAMES
ExtendedAttributes = 0x0002, // SMB_FLAGS2_EAS
SecuritySignature = 0x0004, // SMB_FLAGS2_SMB_SECURITY_SIGNATURE
CompressedData = 0x0008, // SMB_FLAGS2_COMPRESSED
SecuritySignatureRequired = 0x0010, // SMB_FLAGS2_SMB_SECURITY_SIGNATURE_REQUIRED
LongNameUsed = 0x0040, // SMB_FLAGS2_IS_LONG_NAME
ReparsePath = 0x400, // SMB_FLAGS2_REPARSE_PATH
/// <summary>
/// Indicates that the client or server supports extended security
/// </summary>
ExtendedSecurity = 0x0800, // SMB_FLAGS2_EXTENDED_SECURITY
DFS = 0x1000, // SMB_FLAGS2_DFS
ReadIfExecute = 0x2000, // SMB_FLAGS2_PAGING_IO
NTStatusCode = 0x4000, // SMB_FLAGS2_NT_STATUS
Unicode = 0x8000, // SMB_FLAGS2_UNICODE
}
}

View file

@ -0,0 +1,24 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum LockType : byte
{
READ_WRITE_LOCK = 0x00,
SHARED_LOCK = 0x01,
OPLOCK_RELEASE = 0x02,
CHANGE_LOCKTYPE = 0x04,
/// <summary>
/// Request to cancel all outstanding lock requests for the specified FID and PID.
/// </summary>
CANCEL_LOCK = 0x08,
/// <summary>
/// Indicates that the LOCKING_ANDX_RANGE format is the 64-bit file offset version.
/// If this flag is not set, then the LOCKING_ANDX_RANGE format is the 32-bit file offset version
/// </summary>
LARGE_FILES = 0x10,
}
}

View file

@ -0,0 +1,45 @@
namespace SMBLibrary.SMB1
{
public enum CreateDisposition : uint
{
/// <summary>
/// If the file already exists, it SHOULD be superseded (overwritten).
/// If it does not already exist, then it SHOULD be created.
/// </summary>
FILE_SUPERSEDE = 0x0000,
/// <summary>
/// If the file already exists, it SHOULD be opened rather than created.
/// If the file does not already exist, the operation MUST fail.
/// </summary>
FILE_OPEN = 0x0001,
/// <summary>
/// If the file already exists, the operation MUST fail.
/// If the file does not already exist, it SHOULD be created.
/// </summary>
FILE_CREATE = 0x0002,
/// <summary>
/// If the file already exists, it SHOULD be opened.
/// If the file does not already exist, then it SHOULD be created.
/// This value is equivalent to (FILE_OPEN | FILE_CREATE).
/// </summary>
FILE_OPEN_IF = 0x0003,
/// <summary>
/// If the file already exists, it SHOULD be opened and truncated.
/// If the file does not already exist, the operation MUST fail.
/// The client MUST open the file with at least GENERIC_WRITE access for the command to succeed.
/// </summary>
FILE_OVERWRITE = 0x0004,
/// <summary>
/// If the file already exists, it SHOULD be opened and truncated.
/// If the file does not already exist, it SHOULD be created.
/// The client MUST open the file with at least GENERIC_WRITE access.
/// </summary>
FILE_OVERWRITE_IF = 0x0005,
}
}

View file

@ -0,0 +1,101 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum CreateOptions : uint
{
/// <summary>
/// The file being created or opened is a directory file.
/// With this option, the CreateDisposition field MUST be set to FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF.
/// </summary>
FILE_DIRECTORY_FILE = 0x0001,
/// <summary>
/// Applications that write data to the file MUST actually transfer the data into the file before any write request is considered complete.
/// If FILE_NO_INTERMEDIATE_BUFFERING is set, the server MUST perform as if FILE_WRITE_THROUGH is set in the create request.
/// </summary>
FILE_WRITE_THROUGH = 0x0002,
/// <summary>
/// This option indicates that access to the file can be sequential.
/// The server can use this information to influence its caching and read-ahead strategy for this file.
/// The file MAY in fact be accessed randomly, but the server can optimize its caching and read-ahead policy for sequential access.
/// </summary>
FILE_SEQUENTIAL_ONLY = 0x0004,
/// <summary>
/// The file SHOULD NOT be cached or buffered in an internal buffer by the server.
/// This option is incompatible when the FILE_APPEND_DATA bit field is set in the DesiredAccess field.
/// </summary>
FILE_NO_INTERMEDIATE_BUFFERING = 0x0008,
FILE_SYNCHRONOUS_IO_ALERT = 0x0010,
FILE_SYNCHRONOUS_IO_NONALERT = 0x0020,
/// <summary>
/// If the file being opened is a directory, the server MUST fail the request with STATUS_FILE_IS_A_DIRECTORY
/// </summary>
FILE_NON_DIRECTORY_FILE = 0x0040,
FILE_CREATE_TREE_CONNECTION = 0x0080,
FILE_COMPLETE_IF_OPLOCKED = 0x0100,
/// <summary>
/// The application that initiated the client's request does not support extended attributes (EAs).
/// If the EAs on an existing file being opened indicate that the caller SHOULD support EAs to correctly interpret the file, the server SHOULD fail this request with STATUS_ACCESS_DENIED.
/// </summary>
FILE_NO_EA_KNOWLEDGE = 0x0200,
FILE_OPEN_FOR_RECOVERY = 0x0400,
/// <summary>
/// Indicates that access to the file can be random.
/// The server MAY use this information to influence its caching and read-ahead strategy for this file.
/// This is a hint to the server that sequential read-ahead operations might not be appropriate on the file.
/// </summary>
FILE_RANDOM_ACCESS = 0x0800,
/// <summary>
/// The file SHOULD be automatically deleted when the last open request on this file is closed.
/// When this option is set, the DesiredAccess field MUST include the DELETE flag.
/// This option is often used for temporary files.
/// </summary>
FILE_DELETE_ON_CLOSE = 0x1000,
/// <summary>
/// Opens a file based on the FileId.
/// If this option is set, the server MUST fail the request with STATUS_NOT_SUPPORTED in the Status field of the SMB Header in the server response.
/// </summary>
FILE_OPEN_BY_FILE_ID = 0x2000,
/// <summary>
/// The file is being opened or created for the purposes of either a backup or a restore operation.
/// Thus, the server can make appropriate checks to ensure that the caller is capable of overriding
/// whatever security checks have been placed on the file to allow a backup or restore operation to occur.
/// The server can check for certain access rights to the file before checking the DesiredAccess field.
/// </summary>
FILE_OPEN_FOR_BACKUP_INTENT = 0x4000,
/// <summary>
/// When a new file is created, the file MUST NOT be compressed, even if it is on a compressed volume.
/// The flag MUST be ignored when opening an existing file.
/// </summary>
FILE_NO_COMPRESSION = 0x8000,
FILE_RESERVE_OPFILTER = 0x00100000,
FILE_OPEN_REPARSE_POINT = 0x00200000,
/// <summary>
/// In a hierarchical storage management environment, this option requests that the file SHOULD NOT be recalled from tertiary storage such as tape.
/// A file recall can take up to several minutes in a hierarchical storage management environment.
/// The clients can specify this option to avoid such delays.
/// </summary>
FILE_OPEN_NO_RECALL = 0x00400000,
FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000,
}
}

View file

@ -0,0 +1,27 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum DesiredAccess : uint
{
FILE_READ_DATA = 0x0001,
FILE_WRITE_DATA = 0x0002,
FILE_APPEND_DATA = 0x0004,
FILE_READ_EA = 0x0008,
FILE_WRITE_EA = 0x0010,
FILE_EXECUTE = 0x0020,
FILE_READ_ATTRIBUTES = 0x0080,
FILE_WRITE_ATTRIBUTES = 0x0100,
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_ALL = 0x10000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_WRITE = 0x40000000,
}
}

View file

@ -0,0 +1,12 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum FileStatus : ushort
{
NO_EAS = 0x01,
NO_SUBSTREAMS = 0x02,
NO_REPARSETAG = 0x04,
}
}

View file

@ -0,0 +1,11 @@
namespace SMBLibrary.SMB1
{
public enum ImpersonationLevel : uint
{
SEC_ANONYMOUS = 0x00,
SEC_IDENTIFY = 0x01,
SEC_IMPERSONATE = 0x02,
SECURITY_DELEGATION = 0x04, // SMB 1.0 addition
}
}

View file

@ -0,0 +1,20 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum NTCreateFlags : uint
{
/// <summary>
/// If set, the client requests an exclusive OpLock.
/// </summary>
NT_CREATE_REQUEST_OPLOCK = 0x0002,
/// <summary>
/// If set, the client requests an exclusive batch OpLock.
/// </summary>
NT_CREATE_REQUEST_OPBATCH = 0x0004,
NT_CREATE_OPEN_TARGET_DIR = 0x0008,
NT_CREATE_REQUEST_EXTENDED_RESPONSE = 0x0010, // SMB 1.0 addition
}
}

View file

@ -0,0 +1,11 @@
namespace SMBLibrary.SMB1
{
public enum OpLockLevel : byte
{
NoOpLockGranted = 0x00,
ExclusiveOpLockGranted = 0x01,
BatchOpLockGranted = 0x02,
Level2OpLockGranted = 0x03,
}
}

View file

@ -0,0 +1,10 @@
using System;
namespace SMBLibrary.SMB1
{
public enum SecurityFlags : byte
{
SMB_SECURITY_CONTEXT_TRACKING = 0x01,
SMB_SECURITY_EFFECTIVE_ONLY = 0x02,
}
}

View file

@ -0,0 +1,15 @@
using System;
namespace SMBLibrary.SMB1
{
/// <summary>
/// No bits set = Prevents the file from being shared
/// </summary>
[Flags]
public enum ShareAccess : uint
{
FILE_SHARE_READ = 0x0001,
FILE_SHARE_WRITE = 0x0002,
FILE_SHARE_DELETE = 0x0004,
}
}

View file

@ -0,0 +1,23 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum SecurityMode : byte
{
/// <summary>
/// If clear, the server supports only Share Level access control.
/// If set, the server supports only User Level access control.
/// </summary>
UserSecurityMode = 0x01, // NEGOTIATE_USER_SECURITY
/// <summary>
/// If clear, the server supports only plaintext password authentication.
/// If set, the server supports challenge/response authentication.
/// Note: Windows 2000 and above do not support plain-text passwords by default.
/// </summary>
EncryptPasswords = 0x02, // NEGOTIATE_ENCRYPT_PASSWORDS
SecuritySignaturesEnabled = 0x04, // NEGOTIATE_SECURITY_SIGNATURES_ENABLED
SecuritySignaturesRequired = 0x08, // NEGOTIATE_SECURITY_SIGNATURES_REQUIRED
}
}

View file

@ -0,0 +1,31 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum ServerCapabilities : uint
{
RawMode = 0x00000001, // CAP_RAW_MODE
MPXMode = 0x00000002, // SMB_COM_READ_MPX
Unicode = 0x00000004, // CAP_UNICODE
LargeFiles = 0x00000008, // CAP_LARGE_FILES
NTSMB = 0x00000010, // CAP_NT_SMBS
RpcRemoteApi = 0x00000020, // CAP_RPC_REMOTE_APIS
NTStatusCode = 0x00000040, // CAP_STATUS32
Level2Oplocks = 0x00000080, // CAP_LEVEL_II_OPLOCKS
LockAndRead = 0x00000100, // CAP_LOCK_AND_READ
NTFind = 0x00000200, // CAP_NT_FIND
DFS = 0x00001000, // CAP_DFS
InfoLevelPassthrough = 0x00002000, // CAP_INFOLEVEL_PASSTHRU
LargeRead = 0x00004000, // CAP_LARGE_READX
LargeWrite = 0x00008000, // CAP_LARGE_WRITEX
LightWeightIO = 0x00010000, // CAP_LWIO
Unix = 0x00800000, // CAP_UNIX
DynamicReauthentication = 0x20000000, // CAP_DYNAMIC_REAUTH
/// <summary>
/// The server supports extended security for authentication
/// </summary>
ExtendedSecurity = 0x80000000, // CAP_EXTENDED_SECURITY
}
}

View file

@ -0,0 +1,10 @@
namespace SMBLibrary.SMB1
{
public enum AccessRights : ushort
{
SMB_DA_ACCESS_READ = 0x00,
SMB_DA_ACCESS_WRITE = 0x01,
SMB_DA_ACCESS_READ_WRITE = 0x02,
}
}

View file

@ -0,0 +1,31 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum OpenFlags : ushort
{
/// <summary>
/// If this bit is set, the client requests that the file attribute data in the response be populated.
/// All fields after the FID in the response are also populated. If this bit is not set,
/// all fields after the FID in the response are zero.
/// </summary>
REQ_ATTRIB = 0x0001,
/// <summary>
/// Client requests an exclusive OpLock on the file.
/// </summary>
REQ_OPLOCK = 0x0002,
/// <summary>
/// Client requests a Batch OpLock on the file.
/// </summary>
REQ_OPLOCK_BATCH = 0x0004,
/// <summary>
/// SMB 1.0 Addition.
/// If set, the client is requesting the extended format of the response.
/// </summary>
SMB_OPEN_EXTENDED_RESPONSE = 0x0010,
}
}

View file

@ -0,0 +1,11 @@
namespace SMBLibrary.SMB1
{
public enum OpenResult : byte
{
Reserved = 0x00,
FileExistedAndWasOpened = 0x01,
NotExistedAndWasCreated = 0x02,
FileExistedAndWasTruncated = 0x03,
}
}

View file

@ -0,0 +1,28 @@
namespace SMBLibrary.SMB1
{
public enum ResourceType : ushort
{
FileTypeDisk = 0x0000,
FileTypeByteModePipe = 0x0001,
FileTypeMessageModePipe = 0x0002,
FileTypePrinter = 0x0003,
/// <summary>
/// OpenAndX Response: Valid.
/// OpenAndX Extended Response: Invalid (SMB 1.0).
/// NTCreateAndX Response: Valid.
/// NTCreateAndX Extended Response: Invalid (SMB 1.0).
/// Transact2Open2: Was never valid
/// </summary>
FileTypeCommDevice = 0x0004,
/// <summary>
/// OpenAndX Response: Valid
/// NTCreateAndX Response: Invalid
/// Transact2Open2 Response: Valid
/// TransactCreate Response: Valid
/// </summary>
FileTypeUnknown = 0xFFFF,
}
}

View file

@ -0,0 +1,11 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum SessionSetupAction : ushort
{
SetupGuest = 0x01, // SMB_SETUP_GUEST
UseLanmanKey = 0x02, // SMB_SETUP_USE_LANMAN_KEY
}
}

View file

@ -0,0 +1,11 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum TransactionFlags : ushort
{
DISCONNECT_TID = 0x0001,
NO_RESPONSE = 0x0002,
}
}

View file

@ -0,0 +1,13 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum OptionalSupportFlags : ushort
{
/// <summary>
/// The server supports the use of SMB_FILE_ATTRIBUTES exclusive search attributes in client requests.
/// </summary>
SMB_SUPPORT_SEARCH_BITS = 0x01,
}
}

View file

@ -0,0 +1,16 @@
namespace SMBLibrary.SMB1
{
public enum ServiceName
{
DiskShare,
PrinterShare,
NamedPipe,
SerialCommunicationsDevice,
/// <summary>
/// Valid only for request
/// </summary>
AnyType,
}
}

View file

@ -0,0 +1,27 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum TreeConnectFlags : ushort
{
/// <summary>
/// If set and SMB_Header.TID is valid, the tree connect specified by the TID in the SMB
/// header of the request SHOULD be disconnected when the server sends the response. If this tree disconnect fails, then the error SHOULD be ignored
/// If set and TID is invalid, the server MUST ignore this bit.
/// </summary>
DisconnectTID = 0x0001, // TREE_CONNECT_ANDX_DISCONNECT_TID
/// <summary>
/// SMB 1.0 addition.
/// If set, then the client is requesting signing key protection.
/// </summary>
ExtendedSignatures = 0x0004, // TREE_CONNECT_ANDX_EXTENDED_SIGNATURES
/// <summary>
/// SMB 1.0 addition.
/// If set, then the client is requesting extended information in the SMB_COM_TREE_CONNECT_ANDX response.
/// </summary>
ExtendedResponse = 0x0008, // TREE_CONNECT_ANDX_EXTENDED_RESPONSE
}
}

View file

@ -0,0 +1,13 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum WriteMode : ushort
{
WritethroughMode = 0x0001,
ReadBytesAvailable = 0x0002,
RAW_MODE = 0x0004,
MSG_START = 0x0008,
}
}

View file

@ -0,0 +1,20 @@
namespace SMBLibrary.SMB1
{
public enum CompletionFilter : uint
{
FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001,
FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002,
FILE_NOTIFY_CHANGE_NAME = 0x00000003,
FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004,
FILE_NOTIFY_CHANGE_SIZE = 0x00000008,
FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010,
FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020,
FILE_NOTIFY_CHANGE_CREATION = 0x00000040,
FILE_NOTIFY_CHANGE_EA = 0x00000080,
FILE_NOTIFY_CHANGE_SECURITY = 0x00000100,
FILE_NOTIFY_CHANGE_STREAM_NAME = 0x00000200,
FILE_NOTIFY_CHANGE_STREAM_SIZE = 0x00000400,
FILE_NOTIFY_CHANGE_STREAM_WRITE = 0x00000800,
}
}

View file

@ -0,0 +1,16 @@
namespace SMBLibrary.SMB1
{
/// <summary>
/// This is the Function field in NTTransactRequest
/// </summary>
public enum NTTransactSubcommandName : ushort
{
NT_TRANSACT_CREATE = 0x0001,
NT_TRANSACT_IOCTL = 0x0002,
NT_TRANSACT_SET_SECURITY_DESC = 0x0003,
NT_TRANSACT_NOTIFY_CHANGE = 0x0004,
// NT_TRANSACT_RENAME = 0x0005,
NT_TRANSACT_QUERY_SECURITY_DESC = 0x0006,
}
}

View file

@ -0,0 +1,13 @@
using System;
namespace SMBLibrary.SMB1
{
[Flags]
public enum SecurityInfoFields : uint
{
OWNER_SECURITY_INFORMATION = 0x00000001,
GROUP_SECURITY_INFORMATION = 0x00000002,
DACL_SECURITY_INFORMATION = 0x00000004,
SACL_SECURITY_INFORMATION = 0x00000008,
}
}

Some files were not shown because too many files have changed in this diff Show more