分享
 
 
 

用 Raw Socket 实现 Sniffer

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

一. 摘要

Raw Socket: 原始套接字

可以用它来发送和接收 IP 层以上的原始数据包, 如 ICMP, TCP, UDP...

int sockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

这样我们就创建了一个 Raw Socket

Sniffer: 嗅探器

关于嗅探器的原理我想大多数人可能都知道

1. 把网卡置于混杂模式;

2. 捕获数据包;

3. 分析数据包.

但具体的实现知道的人恐怕就不是那么多了. 好, 现在让我们用 Raw Socket 的做一个自已的 Sniffer.

二. 把网卡置于混杂模式

在正常的情况下,一个网络接口应该只响应两种数据帧:

一种是与自己硬件地址相匹配的数据帧

一种是发向所有机器的广播数据帧

如果要网卡接收所有通过它的数据, 而不管是不是发给它的, 那么必须把网卡置于混杂模式. 也就是说让

它的思维混乱, 不按正常的方式工作. 用 Raw Socket 实现代码如下:

setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag); //设置 IP 头操作选项

bind(sockRaw, (PSOCKADDR)&addrLocal, sizeof(addrLocal); //把 sockRaw 绑定到本地网卡上

ioctlsocket(sockRaw, SIO_RCVALL, &dwValue); //让 sockRaw 接受所有的数据

flag 标志是用来设置 IP 头操作的, 也就是说要亲自处理 IP 头: bool flag = ture;

addrLocal 为本地地址: SOCKADDR_IN addrLocal;

dwValue 为输入输出参数, 为 1 时执行, 0 时取消: DWORD dwValue = 1;

没想到这么简单吧?

三. 捕获数据包

你的 sockRaw 现在已经在工作了, 可以在局域网内其它的电脑上用 Sniffer 检测工具检测一下, 看你的

网卡是否处于混杂模式(比如 DigitalBrain 的 ARPKiller).

不能让他白白的浪费资源啊, 抓包!

recv(sockRaw, RecvBuf, BUFFER_SIZE, 0); //接受任意数据包

#define BUFFER_SIZE 65535

char RecvBuf[BUFFER_SIZE];

越来越发现 Sniffer 原来如此的简单了, 这么一个函数就已经完成抓取数据包的任务了.

四. 分析数据包

这回抓来的包和平常用 Socket 接受的包可就不是一回事儿了, 里面包含 IP, TCP 等原始信息. 要分析它

首先得知道这些结构.

数据包的总体结构:

----------------------------------------------

| ip header | tcp header(or x header) | data |

----------------------------------------------

IP header structure:

4 8 16 32 bit

|--------|--------|----------------|--------------------------------|

| Ver | IHL |Type of service | Total length |

|--------|--------|----------------|--------------------------------|

| Identification | Flags | Fragment offset |

|--------|--------|----------------|--------------------------------|

| Time to live | Protocol | Header checksum |

|--------|--------|----------------|--------------------------------|

| Source address |

|--------|--------|----------------|--------------------------------|

| Destination address |

|--------|--------|----------------|--------------------------------|

| Option + Padding |

|--------|--------|----------------|--------------------------------|

| Data |

|--------|--------|----------------|--------------------------------|

TCP header structure:

16 32 bit

|--------------------------------|--------------------------------|

| Source port | Destination port |

|--------------------------------|--------------------------------|

| Sequence number |

|--------------------------------|--------------------------------|

| Acknowledgement number |

|--------------------------------|--------------------------------|

| Offset | Resrvd |U|A|P|R|S|F| Window |

|--------------------------------|--------------------------------|

| Checksum | Urgent pointer |

|--------------------------------|--------------------------------|

| Option + Padding |

|--------------------------------|--------------------------------|

| Data |

|--------------------------------|--------------------------------|

五. 实现 Sniffer

OK!

现在都清楚了, 还等什么.

下面是我用 BCB6 写的一个 Simple Sniffer 的代码, 仅供参考.

(需要在工程文件里加入WS2_32.LIB这个文件)

//*************************************************************************//

//* CPP File: WMain.cpp

//* Simple Sniffer by shadowstar

//* http://shadowstar.126.com/

//*************************************************************************//

#include <vcl.h>

#pragma hdrstop

#include <winsock2.h>

#include <ws2tcpip.h>

#include <mstcpip.h>

#include <netmon.h>

#include "WMain.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TMainForm *MainForm;

//---------------------------------------------------------------------------

__fastcall TMainForm::TMainForm(TComponent* Owner)

: TForm(Owner)

{

WSADATAWSAData;

BOOL flag = true;

int nTimeout = 1000;

char LocalName[16];

struct hostent *pHost;

//检查 Winsock 版本号

if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)

throw Exception("WSAStartup error!");

//初始化 Raw Socket

if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == INVALID_SOCKET)

throw Exception("socket setup error!");

//设置IP头操作选项

if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)) == SOCKET_ERROR)

throw Exception("setsockopt IP_HDRINCL error!");

//获取本机名

if (gethostname((char*)LocalName, sizeof(LocalName)-1) == SOCKET_ERROR)

throw Exception("gethostname error!");

//获取本地 IP 地址

if ((pHost = gethostbyname((char*)LocalName)) == NULL)

throw Exception("gethostbyname error!");

addr_in.sin_addr = *(in_addr *)pHost->h_addr_list[0]; //IP

addr_in.sin_family = AF_INET;

addr_in.sin_port = htons(57274);

//把 sock 绑定到本地地址上

if (bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR)

throw Exception("bind error!");

iSortDirection = 1;

}

//---------------------------------------------------------------------------

__fastcall TMainForm::~TMainForm()

{

WSACleanup();

}

//---------------------------------------------------------------------------

void __fastcall TMainForm::btnCtrlClick(TObject *Sender)

{

TListItem *Item;

DWORD dwValue;

int nIndex = 0;

if (btnCtrl->Caption == "&Start")

{

dwValue = 1;

//设置 SOCK_RAW 为SIO_RCVALL,以便接收所有的IP包

if (ioctlsocket(sock, SIO_RCVALL, &dwValue) != 0)

throw Exception("ioctlsocket SIO_RCVALL error!");

bStop = false;

btnCtrl->Caption = "&Stop";

lsvPacket->Items->Clear();

}

else

{

dwValue = 0;

bStop = true;

btnCtrl->Caption = "&Start";

//设置SOCK_RAW为SIO_RCVALL,停止接收

if (ioctlsocket(sock, SIO_RCVALL, &dwValue) != 0)

throw Exception("WSAIoctl SIO_RCVALL error!");

}

while (!bStop)

{

if (recv(sock, RecvBuf, BUFFER_SIZE, 0) > 0)

{

nIndex++;

ip = *(IP*)RecvBuf;

tcp = *(TCP*)(RecvBuf + (ip.HdrLen & IP_HDRLEN_MASK));

Item = lsvPacket->Items->Add();

Item->Caption = nIndex;

Item->SubItems->Add(GetProtocolTxt(ip.Protocol));

Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip.SrcAddr));

Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip.DstAddr));

Item->SubItems->Add(tcp.SrcPort);

Item->SubItems->Add(tcp.DstPort);

Item->SubItems->Add(ntohs(ip.TotalLen));

}

Application->ProcessMessages();

}

}

//---------------------------------------------------------------------------

AnsiString __fastcall TMainForm::GetProtocolTxt(int Protocol)

{

switch (Protocol)

{

case IPPROTO_ICMP : //1 /* control message protocol */

return PROTOCOL_STRING_ICMP_TXT;

case IPPROTO_TCP : //6 /* tcp */

return PROTOCOL_STRING_TCP_TXT;

case IPPROTO_UDP : //17 /* user datagram protocol */

return PROTOCOL_STRING_UDP_TXT;

default :

return PROTOCOL_STRING_UNKNOWN_TXT;

}

}

//---------------------------------------------------------------------------

//*************************************************************************//

//* Header File: WMain.h for WMain.cpp class TMainForm

//*************************************************************************//

//---------------------------------------------------------------------------

#ifndef WMainH

#define WMainH

//---------------------------------------------------------------------------

#define BUFFER_SIZE 65535

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <ComCtrls.hpp>

#include <ExtCtrls.hpp>

#include <winsock2.h>

#include "netmon.h"

//---------------------------------------------------------------------------

class TMainForm : public TForm

{

__published:// IDE-managed Components

TPanel *Panel1;

TButton *btnCtrl;

TListView *lsvPacket;

TLabel *Label1;

void __fastcall btnCtrlClick(TObject *Sender);

void __fastcall lsvPacketColumnClick(TObject *Sender,

TListColumn *Column);

void __fastcall lsvPacketCompare(TObject *Sender, TListItem *Item1,

TListItem *Item2, int Data, int &Compare);

void __fastcall Label1Click(TObject *Sender);

private:// User declarations

AnsiString __fastcall GetProtocolTxt(int Protocol);

public:// User declarations

SOCKET sock;

SOCKADDR_IN addr_in;

IP ip;

TCP tcp;

PSUHDR psdHeader;

char RecvBuf[BUFFER_SIZE];

bool bStop;

int iSortDirection;

int iColumnToSort;

__fastcall TMainForm(TComponent* Owner);

__fastcall ~TMainForm();

};

//---------------------------------------------------------------------------

extern PACKAGE TMainForm *MainForm;

//---------------------------------------------------------------------------

#endif

偷了个懒, IP, TCP 头及一些宏定义用了 netmon.h 的头, 这个文件在 BCB6 的 include 目录下可以找得

到, 其中与本程序相关内容如下:

//*************************************************************************//

//* Header File: netmon.h

//*************************************************************************//

//

// IP Packet Structure

//

typedef struct _IP

{

union

{

BYTE Version;

BYTE HdrLen;

};

BYTE ServiceType;

WORD TotalLen;

WORD ID;

union

{

WORD Flags;

WORD FragOff;

};

BYTE TimeToLive;

BYTE Protocol;

WORD HdrChksum;

DWORD SrcAddr;

DWORD DstAddr;

BYTE Options[0];

} IP;

typedef IP * LPIP;

typedef IP UNALIGNED * ULPIP;

//

// TCP Packet Structure

//

typedef struct _TCP

{

WORD SrcPort;

WORD DstPort;

DWORD SeqNum;

DWORD AckNum;

BYTE DataOff;

BYTE Flags;

WORD Window;

WORD Chksum;

WORD UrgPtr;

} TCP;

typedef TCP *LPTCP;

typedef TCP UNALIGNED * ULPTCP;

// upper protocols

#define PROTOCOL_STRING_ICMP_TXT "ICMP"

#define PROTOCOL_STRING_TCP_TXT "TCP"

#define PROTOCOL_STRING_UDP_TXT "UDP"

#define PROTOCOL_STRING_SPX_TXT "SPX"

#define PROTOCOL_STRING_NCP_TXT "NCP"

#define PROTOCOL_STRING_UNKNOW_TXT "UNKNOW"

这个文件也有人声称没有.

//*************************************************************************//

//* Header File: mstcpip.h

//*************************************************************************//

// Copyright (c) Microsoft Corporation. All rights reserved.

#if _MSC_VER > 1000

#pragma once

#endif

/* Argument structure for SIO_KEEPALIVE_VALS */

struct tcp_keepalive {

u_long onoff;

u_long keepalivetime;

u_long keepaliveinterval;

};

// New WSAIoctl Options

#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)

#define SIO_RCVALL_MCAST _WSAIOW(IOC_VENDOR,2)

#define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)

#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)

#define SIO_ABSORB_RTRALERT _WSAIOW(IOC_VENDOR,5)

#define SIO_UCAST_IF _WSAIOW(IOC_VENDOR,6)

#define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)

#define SIO_INDEX_BIND _WSAIOW(IOC_VENDOR,8)

#define SIO_INDEX_MCASTIF _WSAIOW(IOC_VENDOR,9)

#define SIO_INDEX_ADD_MCAST _WSAIOW(IOC_VENDOR,10)

#define SIO_INDEX_DEL_MCAST _WSAIOW(IOC_VENDOR,11)

// Values for use with SIO_RCVALL* options

#define RCVALL_OFF 0

#define RCVALL_ON 1

#define RCVALL_SOCKETLEVELONLY 2

现在我们自已的 Sniffer 就做好了, Run, Start......哇, 这么多数据包, 都是从这一台机器上发出的,

它在干什么? 原来 Adminstrator 密码为空, 中了尼姆达病毒!

六. 小结

优点: 实现简单, 不需要做驱动程序就可实现抓包.

缺点: 数据包头不含帧信息, 不能接收到与 IP 同层的其它数据包, 如 ARP, RARP...

这里提供的程序仅仅是一个 Sniffer 的例子, 没有对数据包进行进一步的分析. 写此文的目的在于熟悉

Raw Socket 编程方法, 了解 TCP/IP 协议结构原理以及各协议之间的关系.

作者水平有限, 不足之处请批评指正.

http://shadowstar.126.com/

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有