计算机系统应用教程网站

网站首页 > 技术文章 正文

DELPHI学习之「原始套接字 和 封包数据头」

btikc 2024-10-12 11:08:47 技术文章 14 ℃ 0 评论

截获IP数据包, 原始套接字 和 封包数据头




流式套接字(SOCK_STREAM)和数据包套接字(SOCK_DGRAM)。知道了面向连接的套接字,对应于 TCP 应用程序。而无连接的套接字,对应于UDP 应用程序。相对于这两种套接字之外,还有一种更加强大的套接字类型,原始套接字。

一、原始套接字

1、什么是原始套接字:

原始套接字(SOCK_RAW),是可以对原始网络报文进行处理的套接字,可以直接访问网络底层协议,包括IP协议,ICMP协议(即Internet控制报文协议)等。

2、原始套接字的作用:网络协议属于分层结构,各个层级相互配合,完成数据报文的发送。而底层协议对于数据报文的发送起着决定性作用。由于原始套接字可以访问底层协议,处理底层报文,因而也就取得了对整个网络的控制权。要控制其它协议发送的数据,就必须使用原始套接字。

因此,原始套接字可以用来控制包括网络层和传输层应用在内的多种网络协议,可以接收底层协议包,自定义IP包,接收和处理TCP/IP栈不能处理的IP包。也可以基于原始套接字,来实现我们自己的网络协议。

原始套接字有很多特殊功能,比如:

1)发送自定义的IP 数据报

2)发送ICMP 网编控制数据报

3)监听网络上的数据包。

4)伪装IP地址。

5)实现自定义网络协议。

  更进一步的,原始套接字也是很多网络黑客技术实现的必备手段。比如:网络嗅探器、拒绝服务(DoS)、网络欺骗等等。

3、原始套接字的创建:

使用API函数Socket来创建,只是第二个参数要使用 SOCK_RAW 标识,以标明要创建原始套接字。

int rawsock = socket(AF_INET, SOCK_RAW, protocol);

  第三个参数,常用协议的类型如下:

IPPROTO_IP: IP协议, 处理IP数据包。

IPPROTO_ICMP: ICMP协议, 处理ICMP的数据包。

IPPROTO_TCP: TCP协议,处理TCP数据包

IPPROTO_UDP: UDP协议,处理UDP数据包

IPPROTO_RAW: 原始IP包

注:

ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递网络控制消息。网络控制消息是指网络是否畅通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

二、设置套接字工作模式,接收所有IP数据包

我们使用API函数 WSAIoctl来设置套接字工作模式,

该函数在MSDN中的C语言原型如下:

int WSAAPI WSAIoctl(

SOCKET s, //一个套接口的句柄。

DWORD dwIoControlCode, //将进行的操作的控制代码

LPVOID lpvInBuffer, //输入缓冲区的地址

DWORD cbInBuffer, //输出缓冲区的地址

LPVOID lpvOutBuffer, //输入缓冲区的大小

DWORD cbOutBuffer, //输出缓冲区的大小

LPDWORD lpcbBytesReturned, //输出实际字节数的地址

LPWSAOVERLAPPED lpOverlapped, //WSAOVERLAPPED结构的地址

LPWSAOVERLAPPED lpCompletionRoutine //一个指向操作结束后调用的例程指针

);

WSAIoctl函数实现在ws2_32.dll中,在WinSock中没有公开,正式定义在WinSock2中。由于不想再麻烦使用WinSock2单元,所以,我们使用了另一种方法。 加载ws2_32.dll,定义指向WSAIoctl函数指针,进而用这个函数指针来调用WSAIoctl函数。这也是一种常用的方法。

函数中有一个关键的参数,就是dwIoControlCode,它的定义比较特殊。而这个参数,是我们使用WSAIoctl函数的关键。

MSDN中这样定义:

#define SIO_RCVALL _WSAIOW(IOC_VENDOR, 1)

即:0x80000000 | 0x18000000 | 0x00000001 = 0x98000001

其中IOC_VENDOR 实际上是IOC_WS2|IOC_PROTOCOL,

转换到Delphi中,则是这样使用:$0x80000000 or $0x18000000 or $0x00000001 = $0x98000001

我们教程中的完整使用方法:

const

IOC_IN =$80000000;

IOC_VENDOR =$18000000;

IOC_out =$40000000;


SIO_RCVALL =IOC_IN or IOC_VENDOR or 1;// 即$0x98000001

三、定义封包数据头

当有封包到达时,我们把包中的数据流强制转换成为相应的数据头结构,就可以得到其中的数据

1、IP数据头

type

_iphdr = record

h_lenver :byte;//4位首部长度+4位IP版本号

tos :char;//8位服务类型TOS

total_len :char;//8位总长度(字节)

ident :word;//16位标识

frag_and_flags :word; //3位标志位

ttl :byte; //8位生存时间 TTL

proto :byte; //8位协议 (TCP, UDP 或其他)

checksum :word;//16位IP首部校验和

sourceIP :Longword;//32位源IP地址

destIP :Longword;//32位目的IP地址

end;

IP_HEADER=_iphdr;

2、TCP数据头

type

_tcphdr = record //定义TCP首部

TCP_Sport :word; //16位源端口

TCP_Dport :word; //16位目的端口

th_seq :longword;//32位序列号

th_ack :longword;//32位确认号

th_lenres :byte; //4位首部长度/6位保留字

th_flag :char; //6位标志位

th_win :word; //16位窗口大小

th_sum :word; //16位校验和

th_urp :word; //16位紧急数据偏移量

end;

TCP_HEADER = _tcphdr

3、UDP数据头

type

_udphdr = record //定义UDP首部

uh_sport :word; //16位源端口

uh_dport :word; //16位目的端口

uh_len :word; //16位长度

uh_sum :word; //16位校验和

end;

UDP_HEADER =_udphdr;

4、ICMP数据头

type

_icmphdr = record //定义ICMP首部

i_type :byte; //8位类型

i_code :byte; //8位代码

i_cksum :word; //16位校验和

i_id :word; //识别号(一般用进程号作为识别号)

//i_seq :word; //报文序列号

timestamp :word; //时间戳

end;

ICMP_HEADER=_icmphdr;


5、子协议映射表

type

_protomap = record//定义子协议映射表

ProtoNum :integer;//子协议个数

ProtoText :array[0..MAX_PROTO_TEXT_LEN] of char;//子协议内容

end;

TPROTOMAP=_protomap;

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表