Вступление
Надеюсь мне не придется объяснять, что такое сниффер и каково его предназначение по этому перейду сразу к сути. В данном руководстве я расскажу вам, как можно сделать простой сниффер без особых усилий всего за 15 минут(особо ленивые сделают за 15 секунд обычным копипастом).
Сразу отмечу, что я чисто из принципов не буду отвечать на вопросы типа "У МИНЯ АШИБКА ЧТО ДЕЛАТЬ!!??!" и "У МЕНЯ %SUBJECT% ПОМОГИТЕ".
Часть I. Формострой.
Для начала нам понадобится: Label - x1 ComboBox - x1 TextBox/RichTextBox - x1 Button - x1 CheckBox с свойством Appearance в положении Button - x1
Накидаем это все на форму, я сделал так:
[Ссылки могут видеть только зарегистрированные пользователи. ] В правом нижнем углу формы находится не кнопка, а CheckBox
Часть II. Капля теории.
Если не сильно вдаваться в подробности то мы пишем клиент-серверное приложение предварительно покурив мануалов по Raw Socket'ам.
На самом деле сложного тут ничего нет, мы просто "слушаем" весь трафик проходящий через определенное устройство.
Часть III. Вперед под танки!
Если вы выдержали две предыдущих части значит вы еще(а может даже "уже") не совсем потеряны, давайте я отведу вас к вашему "танку".
В первой части вы создали приложение, разместили все элементы, значит настал час, нажимаем ПКМ по нашей форму и кликаем Перейти к коду или просто нажимаете клавишу F7. И так что же мы видим? А видим мы конструктор(не путать с лего) класса и имя ему ЛегионForm1 если вы конечно ничего не меняли.
Давайте добавим в него следующие строки
Код:
IPHostEntry HosyEntry = Dns.GetHostEntry((Dns.GetHostName()));
if (HosyEntry.AddressList.Length > 0)
{
foreach (IPAddress ip in HosyEntry.AddressList)
comboBox1.Items.Add(ip.ToString());
}
Вышеприведенное "чудо" при создании формы добавит в ComboBox все возможные устройства для прослушивания. Можете запустить приложение и посмотреть на результат.
Следующим шагом будет добавление 2-х полей в наш класс, перед конструктором класса, я назвал их socket и buffer, но вы можете назвать их по-другому.
Код:
private Socket socket; //собственно это и есть наше прослушивающее устройство
private byte[] buffer; //а сюда мы будем записывать полученные пакеты
Давайте теперь перейдем к конструктору формы(не путать с конструктором класса) и два раза кликнем по нашему CheckBox'у тем самым подписав его на событие CheckedChanged которое вызывается всякий раз когда свойство Checked меняет свое значение.
Давайте вставим туда следующий код
Код:
if((sender as CheckBox).Checked)
{
(sender as CheckBox).Text = "&Stop me";
socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
socket.Bind(new IPEndPoint(IPAddress.Parse(comboBox1.SelectedItem.ToString()), 0));
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
byte[] byInc = new byte[] { 1, 0, 0, 0 };
byte[] byOut = new byte[4];
buffer = new byte[4096];
socket.IOControl(IOControlCode.ReceiveAll, byInc, byOut);
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnReceive, null);
}
else
{
socket.Close();
(sender as CheckBox).Text = "&Start me";
}
Здесь мы начинаем прослушку, но делегат OnReceive подчеркивает красным, это потому что мы его еще не добавили, сам Адмирал Ясен...ну вы поняли, намекает.
Ну так давайте добавим этот делегат, чего мелочится то.
Вот собственно и он, давайте я вам вкратце объясню, что же это такое. Метод socket.BeginReceive асинхронно вызывает делегат AsyncCallback при каждом получении данных, а в самом методе мы уже выполняем все необходимые преобразования.
Давайте добавим два последних метода первый это Print, выводящий в текстбокс полученный пакет и Parse, парсящий из полученного пакета IP Header'ы
Вроде бы мы все сделали, но что-то здесь не так. А ведь точно, C# не имеет в своих библиотеках класса IPHeader, я в этом случае поступил очень лениво, зашел в гугл и взял первый попавшийся мне класс описывающий структуру хедера, вот он, под спойлером
Код:
public class IPHeader
{
//IP Header fields
private byte byVersionAndHeaderLength; //Eight bits for version and header length
private byte byDifferentiatedServices; //Eight bits for differentiated services (TOS)
private ushort usTotalLength; //Sixteen bits for total length of the datagram (header + message)
private ushort usIdentification; //Sixteen bits for identification
private ushort usFlagsAndOffset; //Eight bits for flags and fragmentation offset
private byte byTTL; //Eight bits for TTL (Time To Live)
private byte byProtocol; //Eight bits for the underlying protocol
private short sChecksum; //Sixteen bits containing the checksum of the header
//(checksum can be negative so taken as short)
private uint uiSourceIPAddress; //Thirty two bit source IP Address
private uint uiDestinationIPAddress; //Thirty two bit destination IP Address
//End IP Header fields
private byte byHeaderLength; //Header length
private byte[] byIPData = new byte[4096]; //Data carried by the datagram
public IPHeader(byte[] byBuffer, int nReceived)
{
try
{
//Create MemoryStream out of the received bytes
MemoryStream memoryStream = new MemoryStream(byBuffer, 0, nReceived);
//Next we create a BinaryReader out of the MemoryStream
BinaryReader binaryReader = new BinaryReader(memoryStream);
//The first eight bits of the IP header contain the version and
//header length so we read them
byVersionAndHeaderLength = binaryReader.ReadByte();
//The next eight bits contain the Differentiated services
byDifferentiatedServices = binaryReader.ReadByte();
//Next eight bits hold the total length of the datagram
usTotalLength = (ushort)IPAddress.NetworkToHostOrder(binaryReader.ReadInt16());
//Next sixteen have the identification bytes
usIdentification = (ushort)IPAddress.NetworkToHostOrder(binaryReader.ReadInt16());
//Next sixteen bits contain the flags and fragmentation offset
usFlagsAndOffset = (ushort)IPAddress.NetworkToHostOrder(binaryReader.ReadInt16());
//Next eight bits have the TTL value
byTTL = binaryReader.ReadByte();
//Next eight represnts the protocol encapsulated in the datagram
byProtocol = binaryReader.ReadByte();
//Next sixteen bits contain the checksum of the header
sChecksum = IPAddress.NetworkToHostOrder(binaryReader.ReadInt16());
//Next thirty two bits have the source IP address
uiSourceIPAddress = (uint)(binaryReader.ReadInt32());
//Next thirty two hold the destination IP address
uiDestinationIPAddress = (uint)(binaryReader.ReadInt32());
//Now we calculate the header length
byHeaderLength = byVersionAndHeaderLength;
//The last four bits of the version and header length field contain the
//header length, we perform some simple binary airthmatic operations to
//extract them
byHeaderLength <<= 4;
byHeaderLength >>= 4;
//Multiply by four to get the exact header length
byHeaderLength *= 4;
//Copy the data carried by the data gram into another array so that
//according to the protocol being carried in the IP datagram
Array.Copy(byBuffer,
byHeaderLength, //start copying from the end of the header
byIPData, 0,
usTotalLength - byHeaderLength);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "MJsniffer", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
public string Version
{
get
{
//Calculate the IP version
//The four bits of the IP header contain the IP version
if ((byVersionAndHeaderLength >> 4) == 4)
{
return "IP v4";
}
else if ((byVersionAndHeaderLength >> 4) == 6)
{
return "IP v6";
}
else
{
return "Unknown";
}
}
}
public string HeaderLength
{
get
{
return byHeaderLength.ToString();
}
}
public ushort MessageLength
{
get
{
//MessageLength = Total length of the datagram - Header length
return (ushort)(usTotalLength - byHeaderLength);
}
}
public string DifferentiatedServices
{
get
{
//Returns the differentiated services in hexadecimal format
return string.Format ("0x{0:x2} ({1})", byDifferentiatedServices,
byDifferentiatedServices);
}
}
public string Flags
{
get
{
//The first three bits of the flags and fragmentation field
//represent the flags (which indicate whether the data is
//fragmented or not)
int nFlags = usFlagsAndOffset >> 13;
if (nFlags == 2)
{
return "Don't fragment";
}
else if (nFlags == 1)
{
return "More fragments to come";
}
else
{
return nFlags.ToString();
}
}
}
public string FragmentationOffset
{
get
{
//The last thirteen bits of the flags and fragmentation field
//contain the fragmentation offset
int nOffset = usFlagsAndOffset << 3;
nOffset >>= 3;
return nOffset.ToString();
}
}
public string TTL
{
get
{
return byTTL.ToString();
}
}
public Protocol ProtocolType
{
get
{
//The protocol field represents the protocol in the data portion
//of the datagram
if (byProtocol == 6) //A value of six represents the TCP protocol
{
return Protocol.TCP;
}
else if (byProtocol == 17) //Seventeen for UDP
{
return Protocol.UDP;
}
else
{
return Protocol.Unknown;
}
}
}
public string Checksum
{
get
{
//Returns the checksum in hexadecimal format
return string.Format ("0x{0:x2}", sChecksum);
}
}
public IPAddress SourceAddress
{
get
{
return new IPAddress(uiSourceIPAddress);
}
}
public IPAddress DestinationAddress
{
get
{
return new IPAddress(uiDestinationIPAddress);
}
}
public string TotalLength
{
get
{
return usTotalLength.ToString();
}
}
public string Identification
{
get
{
return usIdentification.ToString();
}
}
public byte[] Data
{
get
{
return byIPData;
}
}
}
, просто добавьте его в свой проект и дело в шляпе.
Чуть не забыл, у нас же осталась последняя "безпризорная" кнопка, давайте добавим ей следующий код
Спс за статью - познавательная. Особенно для такого нуба в сокетах, как я.
Yukikaze, несмотря на Ваше предупреждение, прошу послать меня в нужном направлении: Вопрос 1: Пакеты не кратные 16 не полностью представляются в ASCII, либо-же пакеты обрезаются по длине - решил самостоятельно. Вопрос 2: Если сравнивать полученные данные с другим сниффером
Код:
0000 f4 6d 04 8c ea bc 00 1b 9e 6a e0 db 08 00 45 00
0010 00 28 79 55 40 00 80 06 6e 21 c0 a8 01 03 c1 6a
0020 90 43 c7 64 0e 8c 82 6f 52 4f 63 29 79 e3 50 10
0030 01 d2 12 ed 00 00
выделенный фрагмент в Вашем не отлавливается - в общем не принципиально (поковырялся и понял, что мне он не нужен). Вопрос 3: Наиболее критичен
Ваш Сниффер не видит входящие пакеты от игрового сервера.
Сторонний сниффер эти-же пакеты видит и определяет как Tcp...
Подскажите, пожалуйста, как лечить или где копать?
Последний раз редактировалось Zizipuza; 23.06.2012 в 11:09.
Zizipuza, это пример самого простого сниффера, более сложные реализации делаются на основе WinPcap, под .NET есть неплохие обертки, например SharpPcap.
[Ссылки могут видеть только зарегистрированные пользователи. ] наваял простенький TCP сниффер, только для него нужен установленный WinPcap драйвер, я положил его в архив.
ЗЫ
Цитата:
Yukikaze, несмотря на Ваше предупреждение, прошу послать меня в нужном направлении:
Это относиться только к школьникам которые копипастят и при этом даже не пытаются понять написанное, а иногда даже не знают как создать метод и что его надо размещать в теле класса, а не в обработчик события button_Click
ЗЫЫ То что выделено красным это Ethernet хедер, первые 14 байт, затем следующие 20 это IP header
________________
Talk is cheap. Show me the code
— Linus Torvalds
Последний раз редактировалось Yukikaze; 24.06.2012 в 06:07.
Если можешь, помоги разобраться с несколькими проблемами которые возникли во время запуска программы по твоему исходнику.
Смог добиться того что бы запускалась без ошибок, но после выбора доступных для прослушивания устройств я выбираю к примеру:
[Ссылки могут видеть только зарегистрированные пользователи. ]
Возникает ошибка:
[Ссылки могут видеть только зарегистрированные пользователи. ]
У меня нет опыта программирования в С# и в создании различных сетевых приложений, просто поставлена такая задача для расчетной работы по не профильному предмету.