Socket編程--用C#製作Sniffer

来源:互联网 发布:3k党 知乎 编辑:程序博客网 时间:2024/06/03 12:55

Socket編程--用C#製作Sniffer

/*
調試說明:在vs2003下調試通過,但在vs2005下調試不能通過,主要是多線程的問題.使用BackGroundWorker處理後,只能接收幾個封包然後就停止接收了,可能還要再學一下多線程編程,還望高手指教.

*/

代碼已改進,現在可用了.接下來的問題是完善對各种協議的分析.還有個問題,我的計算机在局域网里面,但沒有加入域,如何才能嗅探到在域里傳遞的數据啊?

以下是源代碼:
1.枚舉常用的變量
        public enum Precedence
 {
  Routine = 0,
  Priority = 1,
  Immediate = 2,
  Flash = 3,
  FlashOverride = 4,
  CRITICECP = 5,
  InternetworkControl = 6,
  NetworkControl = 7
 }
 public enum Delay
 {
  NormalDelay = 0,
  LowDelay = 1
 }
 public enum Throughput
 {
  NormalThroughput = 0,
  HighThroughput = 1
 }
 public enum Reliability
 {
  NormalReliability = 0,
  HighReliability = 1
 }
 public enum Protocol
 {
  Ggp = 3,
  Icmp = 1,
  Idp = 22,
  Igmp = 2,
  IP = 4,
  ND = 77,
  Pup = 12,
  Tcp = 6,
  Udp = 17,
  Other = -1
 }

2.將封包封裝成類
public class Packet
 {
  private byte[] m_Raw;//保存原始封包數據
  private DateTime m_Time;//時間
  private int m_Version;//4位,版本
  private int m_HeaderLength;//4位,ip頭的長度,一般都是20字節長
  private Precedence m_Precedence;//優先級
  private Delay m_Delay;//延時
  private Throughput m_Throughput;//
  private Reliability m_Reliability;//
  private int m_TotalLength;//16位,封包總長度
  private int m_Identification;//16位,ip包標識
  private int m_TimeToLive;//8位,數據包在網絡上的存活時間
  private Protocol m_Protocol;//8位,協議號
  private byte[] m_Checksum;//校驗值
  private string m_SourceAddress;//源地址
  private string m_DestinationAddress;//目標地址
  private int m_SourcePort;//源端口
  private int m_DestinationPort;//目標端口
  private byte[] m_data;//保存接收到的用戶數據

  public Packet()
  {
  }

  public Packet(byte[] raw, DateTime time)
  {
   if (raw==null)
   {
    throw new ArgumentNullException();
   }
   if (raw.Length<20)
   {
    throw new ArgumentException();
   }
   this.m_Raw = raw;//取原始數據包
   this.m_Time = time;//取接收時間
   this.m_HeaderLength = (raw[0] & 0xF) * 4;//取ip頭長度
   if ((raw[0] & 0xF) < 5) {throw new ArgumentException();}//包長太短
   this.m_Precedence = (Precedence)((raw[1] & 0xE0) >> 5);//取優先級
   this.m_Delay = (Delay)((raw[1] & 0x10) >> 4);//取延時
   this.m_Throughput = (Throughput)((raw[1] & 0x8) >> 3);//
   this.m_Reliability = (Reliability)((raw[1] & 0x4) >> 2);//
   this.m_TotalLength = raw[2] * 256 + raw[3];//取總長度
   if ( ! (this.m_TotalLength == raw.Length)) { throw new ArgumentException();} //封包長度不正確
   this.m_Identification = raw[4] * 256 + raw[5];//取標識值
   this.m_TimeToLive = raw[8];//取存活時間
   m_Protocol = (Protocol)raw[9];//取服務類型
   m_Checksum = new byte[2];//取校驗值
   m_Checksum[0] = raw[11];
   m_Checksum[1] = raw[10];

   
   //此處只對tcp,udp取正確的用戶數據,其余用戶數據都不正確.
   switch(m_Protocol)
   {
    case Protocol.Tcp://tcp頭長20
     m_data=new byte[m_TotalLength-m_HeaderLength-20];
     Array.Copy(raw,m_HeaderLength+20,m_data, 0,m_TotalLength-m_HeaderLength-20);
     break;
    case Protocol.Udp://udp頭長8
     m_data=new byte[m_TotalLength-m_HeaderLength-8];
     Array.Copy(raw,m_HeaderLength+8,m_data, 0,m_TotalLength-m_HeaderLength-8);
     break;
    default:
     m_data=new byte[m_TotalLength-m_HeaderLength];
     Array.Copy(raw,m_HeaderLength,m_data, 0,m_TotalLength-m_HeaderLength);
     break;
   }
   

   //取目錄地址及源地址
   try
   {
    m_SourceAddress = GetIPAddress(raw, 12);
    m_DestinationAddress = GetIPAddress(raw, 16);
   }
   catch (Exception e)
   {
    throw;
   }
   //取目標端口及源端口
   if (m_Protocol == Protocol.Tcp || m_Protocol == Protocol.Udp)
   {
    m_SourcePort = raw[m_HeaderLength] * 256 + raw[m_HeaderLength + 1];
    m_DestinationPort = raw[m_HeaderLength + 2] * 256 + raw[m_HeaderLength + 3];
   }
   else
   {
               
    m_SourcePort = -1;
    m_DestinationPort = -1;
   }
  }

  public int HeaderLength
  {
   get
   {
    return m_HeaderLength;
   }
  }
  public string Data
  {
   get
   {
    string result="";
    System.Text.ASCIIEncoding ac=new ASCIIEncoding();
    result = ac.GetString(m_data);
    return result;
   }
  }
  public string GetIPAddress(byte[] bArray, int nStart)
  {
   byte[] tmp = new byte[4];
   if (bArray.Length > nStart + 2)
   {
    tmp[0] = bArray[nStart];
    tmp[1] = bArray[nStart + 1];
    tmp[2] = bArray[nStart + 2];
    tmp[3] = bArray[nStart + 3];
   }
   return tmp[0] + "." + tmp[1] + "." + tmp[2] + "." + tmp[3];
  }
  public int TotalLength
  {
   get { return m_TotalLength; }
  }
  public DateTime Time
  {
   get { return this.m_Time; }
  }
  public Protocol Protocol
  {
   get { return this.m_Protocol; }
  }
  public string SourceAddress
  {
   get { return this.m_SourceAddress; }
  }
  public string Source
  {
   get
   {
    if ( m_SourcePort != -1 )
    {
     return SourceAddress.ToString() + ":" + m_SourcePort.ToString();
    }
    else
    {
     return SourceAddress.ToString();
    }
   }
  }
  public string Destination
  {
   get
   {
    if (this.m_DestinationPort != -1)
    {
     return DestinationAddress.ToString() + ":" + m_DestinationPort.ToString();
    }
    else
    {
     return DestinationAddress.ToString();
    }
   }
  }
  public string DestinationAddress
  {
   get
   {
    return m_DestinationAddress;
   }
  }
 }

3.封裝一個用於接收及處理封包的類
 public class Monitor
 {
  public delegate void NewPacketEventHandler(Monitor m, Packet p);
  public event NewPacketEventHandler NewPacket;
  private Socket m_Monitor;//建立用於接收信息的Socket
  private IPAddress m_Ip;//本地ip
  private byte[] m_Buffer = new byte[65535];//保存接收數據

  private const System.Int32 IOC_VENDOR = 0x18000000;
  private const int IOC_IN = -2147483648;
  private const int SIO_RCVALL = IOC_IN ^ IOC_VENDOR ^ 1;//接收所有封包
  private const int SECURITY_BUILTIN_DOMAIN_RID = 0x20;
  private const int DOMAIN_ALIAS_RID_ADMINS = 0x220;

  public System.Net.IPAddress IP
  {
   get { return m_Ip; }
  }
  public byte[] Buffer
  {
   get { return m_Buffer; }
  }
  public Monitor()
  {
   //
   // TODO: 在此添加构造函數
   //
  }
  public Monitor(IPAddress IpAddress)
  {
   if (!(Environment.OSVersion.Platform == PlatformID.Win32NT) && Environment.OSVersion.Version.Major<5)
   {
    throw new NotSupportedException("This program requires Windows 2000, Windows XP or Windows .NET Server!");
   }
   m_Ip = IpAddress;
  }

  //開始偵聽
  public void Start()
  {
   if (m_Monitor==null)
   {
    try
    {
     // 初始化接收Socket
     m_Monitor = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
     // bind到本地端口
     m_Monitor.Bind(new IPEndPoint(IP, 0));
     // 設定Socket低階作業模式
     m_Monitor.IOControl(SIO_RCVALL, BitConverter.GetBytes(1), null);
     // 開始接收封包數據
     m_Monitor.BeginReceive(m_Buffer, 0, m_Buffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);

    }
    catch (Exception e)
    {
     m_Monitor = null;
     throw new SocketException();
    }
   }
  }

  //處理封包
  public void OnReceive(System.IAsyncResult ar)
  {
   try
   {
    // 完成接收封包數據
    int received = m_Monitor.EndReceive(ar);
    try
    {
     if (m_Monitor!=null)
     {
      byte[] pkt = new byte[received];
      // 將封包轉化為字節數組
      Array.Copy(Buffer, 0, pkt, 0, received);
      // 處理封包數據
      OnNewPacket(new Packet(pkt, DateTime.Now));
     }
    }
    catch(Exception e)
    {
     throw;
    }
    // 繼續開始接收新的封包
    m_Monitor.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None,new AsyncCallback(OnReceive), null);
   }
   catch (Exception e)
   {
    throw;
   }
  }
  //處理封包的函數
  protected void OnNewPacket(Packet p)
  {
   NewPacket(this, p);
  }

  //停止偵聽
  public void Stop()
  {
   if (m_Monitor!=null)
   {
    m_Monitor.Close();//關閉Socket
   }
   m_Monitor = null;
  }
 }

 

4.主程序
  private Monitor m_Monitor;
  private ArrayList m_Packets;
  private int m_PacketsSize;

private void button1_Click(object sender, System.EventArgs e)
  {
   if(this.button1.Text=="開始監控")
   {
    this.statusBar1.Text="監控中...";

    this.richTextBox1.Text="";
    m_PacketsSize=0;

    StartMonitor() ;
    this.button1.Text="停止監控";
   }
   else
   {
    m_Monitor.Stop();
    this.button1.Text="開始監控";
    this.statusBar1.Text="已經停止監控";

   }

  }

private void StartMonitor()
  {
   IPAddress[] hosts = Dns.Resolve(Dns.GetHostName()).AddressList;
   if (hosts.Length == 0) { throw new NotSupportedException("This computer does not have non-loopback interfaces installed!");}
   
   m_Packets = new ArrayList();
   m_Monitor = new Monitor(hosts[0]);
   //添加代理,每次有新的packet到時都觸發下面那個動作
   m_Monitor.NewPacket+=new Monitor.NewPacketEventHandler(this.OnNewPacket);
   m_Monitor.Start();
  }

/*//這個方法用於把packet顯示到richTextBox1中
private void OnNewPacket(Monitor m, Packet p)
  {
   m_Packets.Add(p);
   m_PacketsSize += p.TotalLength;
   try
   {
    this.richTextBox1.AppendText(m_Packets.Count.ToString()+"/t時間:"+p.Time.ToString()+"協議:"+p.Protocol.ToString()+"/t源:"+p.Source.ToString()+" /t目標:"+p.Destination.ToString()+"/t總長:"+p.TotalLength.ToString("0000"));
    this.richTextBox1.AppendText("/r");
    this.richTextBox1.AppendText("/t內容:"+p.Data);
   }
   catch (Exception e)
   {
    MessageBox.Show(e.Message);
   }
   statusBar1.Text = String.Format("Intercepted {0} packet(s) [{1} bytes]", m_Packets.Count, m_PacketsSize);
  } */

改進: 將上面那段注釋掉的代碼改為以下內容,這個Sniffer就可以用了.在vs2005下運行成功.沒有在vs2003下做測試.但也應該可以用.

        //這個方法用於把packet顯示到richTextBox1中
        private void OnNewPacket(Monitor m, Packet p)
        {
              m_Packets.Add(p);
             m_PacketsSize += p.TotalLength;
            try
             {
                 string result = m_Packets.Count.ToString() + "/t時間:" + p.Time.ToString() + "協議:" + p.Protocol.ToString() + "/t源:" + p.Source.ToString() + " /t目標:" + p.Destination.ToString() + "/t總長:" + p.TotalLength.ToString("0000");
                 result += "/r/n";
                 result += "/t內容:" + p.Data;
                 result += "/r/n";
                 CalcFinished(result);//计算完成需要在一个文本框里显示
             }
             catch (Exception e)
             {
                 MessageBox.Show(e.Message);
             }
        }

        delegate void changeText(string result);
        private void CalcFinished(string result)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new changeText(CalcFinished), result);
            }
            else
            {
                this.richTextBox1.AppendText(result);
                statusBar1.Text = String.Format("Intercepted {0} packet(s) [{1} bytes]", m_Packets.Count, m_PacketsSize);
            }
        }

原创粉丝点击