在Windows底下要實現Sniffer有很多種方法,如用SIP、Hook或是寫一張虛擬網卡出來。但最簡單的方法還是直接用Winsock2中的raw socket。
先將網路卡設為混亂模式,好接收到所有的封包,再使用Raw socket的方式直接抓取IP層的原始資料。接著只要照TCP/IP的協定去分析所抓到的資料就可以了。
首先定義一個Struct來表示IP的表頭
[StructLayout(LayoutKind.Explicit)]
public struct IpHeader
{
[FieldOffset(0)] public byte ip_version_headerlen; // IP 協定版本和表頭長度
[FieldOffset(1)] public byte ip_tos; // 服務類型
[FieldOffset(2)] public ushort ip_totallength; // 封包長度
[FieldOffset(4)] public ushort ip_id; //識別碼
[FieldOffset(6)] public ushort ip_flags_offset; // 旗標和fragment位移
[FieldOffset(8)] public byte ip_ttl; // 存活時間
[FieldOffset(9)] public byte ip_protocol; // 協定種類
[FieldOffset(10)] public ushort ip_checksum; //IP表頭檢查碼
[FieldOffset(12)] public uint ip_srcaddr; //來源IP位址
[FieldOffset(16)] public uint ip_destaddr;//目的地IP位址
}
Version (4)
Internet Header Length (4)
Type of Service (8)
Total Length (16)
Identification (16)
Flags (3)
Fragment Offset (13)
Time To Live (8)
Protocol (8)
Header checksum (16)
Source Address (32)
Destination Address (32)
Options (Variable)
Padding (0-24)
Data
......
接著設定好Raw socket和網卡的混亂模式
socket = new Socket(AddressFamily.InterNetwork,SocketType.Raw,ProtocolType.IP); //Raw socket
socket.Blocking = false;
socket.Bind(new IPEndPoint(IPAddress.Parse(IP),0));
socket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.HeaderIncluded, 1); //接收IP層封包
byte []IN = new byte[4]{1, 0, 0, 0};
byte []OUT = new byte[4];
int SIO_RCVALL = unchecked((int)0x98000001);
socket.IOControl(SIO_RCVALL, IN, OUT); //設定網卡成為混亂模式
便可以用Socket的BeginReceive方法來接收一個封包了
IAsyncResult ar = socket.BeginReceive(receive_buf, 0, receive_buf.Length,SocketFlags.None, null, this);
socket.EndReceive(ar);
收到的原始資料將會存在receive_buf中,所以直接用unsafe的方法將receive_buf轉成IpHeader(不喜歡unsafe的話,也可以用BitConverter慢慢地轉型)
fixed(byte *fixed_buf = receive_buf)
{
IpHeader* header = (IpHeader *)fixed_buf;
msg.source_ip = new IPAddress(header->ip_srcaddr).ToString();
……
}
最後記得要將Socket給關閉
socket.Shutdown(SocketShutdown.Both);
socket.Close();
整個Sniffer便大功告成了。
//转入地址:http://www.techblog.idv.tw/Blog/zion/archive/147.aspx