论坛: 编程破解 标题: 请教关于多线程的端口扫描问题 复制本贴地址    
作者: somreht [somreht]    论坛用户   登录
我这些天一直在搞端口扫描的程序, 由于对SOCKET编程接触不够, 弄的很吃力. 现在有一些问题要请教于各位大侠.要对一个IP段内的每个IP的80端口扫描一遍, 记录下80端口开放的IP. 当然还有更多的后续处理, 这里不细说. 由于扫描痕迹要尽量少, 所以我采取构造原始SYN包,并在指定端口接收所有包, 并对每个包解析, 符合条件的就记录下来. 具体步骤如下(一些错误处理代码去掉了):
假设要扫描的目的主机IP为strDestIp(如"202.96.113.28"), 端口为iDestPort(默认为80), 本机IP为strSrcIp(如"10.0.2.113"), 端口为iSrcPort(默认为7000). sockRawSend和sockRawListen分别是用来发送SYN包和接收IP数据报的两个SOCKET.
(1) 创建和设置sockRawSend:
sockRawSend = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
setsockopt(sockRawSend,IPPROTO_IP,IP_HDRINCL,(char *)&bOpt1,sizeof(bOpt1));
(2) 创建和设置sockRawListen;
SOCKADDR_IN addrSrc;
addrSrc.sin_addr.S_un.S_addr=inet_addr(strSrcIp); //源IP地址
addrSrc.sin_family = AF_INET;
addrSrc.sin_port = htons(iSrcPort); //源端口

sockRawListen = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
bind(sockRawListen, (PSOCKADDR)&addrSrc, sizeof(addrSrc)); //绑定到addrSrc
long lret=1L;
ioctlsocket(sockRawListen, FIONBIO, (u_long FAR *) &lret);//设置为非阻塞模式
//设置sockRawListen为SIO_RCVALL,以便接收所有的IP包
unsigned long dwBufferLen[10],dwBufferInLen = 1,dwBytesReturned = 0;
WSAIoctl(sockRawListen,SIO_RCVALL,&dwBufferInLen, sizeof(dwBufferInLen),
&dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned, NULL, NULL);
(3) 用相应数据填充IP首部(结构体变量stIpHeader)和TCP首部(结构体变量stTcpHeader)以及TCP伪首部, 计算校验和等. 并填充好发送缓冲区(定义为char acSendBuf[128])
(4) 发送TCP SYN原始包:
SOCKADDR_IN addrDest;
addrDest.sin_addr.S_un.S_addr=inet_addr(strDestIp); //源IP地址
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(iDestPort); //目的端口
sendto(sockRawSend,acSendBuf,sizeof(stIpHeader)+sizeof(stTcpHeader),0,
               (struct sockaddr* )&addrDest,sizeof(sockAddrDest));
(5) 接收数据包并解析(设接收时延为ulRcvTimeout, 接收缓冲区为char acRecvBuf[65535]):
这部分代码我就不写了,主要是在设定的时延内接收所有的IP包(recv(sockRawListen, acRecvBuf, sizeof(acRecvBuf), 0)), 对每个接收到的IP包解析, 如果是发送给本机的指定端口并来自strDestIp的iDestPort端口的SYN|ACK包且满足序列号要求就表示该目的主机开放了iDestPort端口;否则达到时延还未接收到满足该条件的包就表示该目的主机未开放该端口.

对此我有几个问题要请教:
1. 发送原始SYN包给目标主机的目标端口后, 是不是一定要接收下所有数据包并解析之才能判断目标主机是否开放了目标端口? 
2. 以上程序如果在单线程中运行, 则运行很好, 对每个IP的SYN扫描最多只需要ulRcvTimeout时间(比如设定延时为2000ms). 因为我要扫描一个段或者多段IP, 显然必须采用多线程(每个线程的sockRawListen绑定一个不同的端口,每个线程用自己的接收缓冲区), 比如要扫描IP段61.28.0.0--61.28.15.255内的每个IP,采用多个线程对分别对每个IP扫描一次,以上程序段是线程函数的一部分.这样带来了两个问题: (1)不能通过时延来判断, 因为有可能线程A在发送完SYN包后被挂起一段时间(被其他线程抢占CPU)才执行recv;(2) 由于每个线程都是把所有的包都接收下来了, 所以实际上线程A接收了发送给线程B的那个端口的数据包,但是线程A的IP包解析函数却认为该包不是来自线程A的目标主机, 而当线程B接收数据包时,发送给它的响应包由于被线程A接收了, 所以线程B接收不到.

哪位大侠如能帮我讲讲如何采用多线程扫描一个IP段的每个IP的快速方法,我将感恩不尽!


[此贴被 somreht(somreht) 在 03月07日11时32分 编辑过]

地主 发表时间: 2003-03-07 11:31:32

回复: 286 [unique]   版主   登录
老弟,就SYN发送而言,我的扫描程序一秒种可以扫上万个,为什么还要用多线程呢?更何况你只扫80端口,方法非常简单。
一个方法:总只一个线程,发一个收一下,这样如果在局域网中也一个C类地址也只需要半分钟。
另一个方法:两个线程,一个发,一个收。


[此贴被 286(unique) 在 03月07日17时53分 编辑过]

B1层 发表时间: 2003-03-07 17:35:53

回复: wineggdrop [wineggdrop]   论坛用户   登录
用传统的TCP连接扫描,一般30到40秒就能完成256个IP的
扫描了,当然视乎你开多少端口,用syn连接来扫描,是
隐藏点,但很容易就漏报。

B2层 发表时间: 03/08 12:58

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号