返回列表 发帖

[讨论] 关于使用半开扫描探测端口的程序

[讨论] 关于使用半开扫描探测端口的程序
议题作者:grayfox

近来初学原始套接字,想实现以前传说中的TCP SYN扫描端口程序。网上找了好久没找到较完整的代码,只好根据一些零星的资料拼凑起来了本个程序,经过3天调试后仍未成功,问题说明如下。

1,初步判定问题应该出现在接收数据返回时。
2,刚开始时是使用recvfrom接收数据,测试127.0.0.1时总会返回40端口开放,但我仅仅探测了80端口的。而且无论要探测的端口号怎么改,返回的总是40端口开放。测试外网时,但程序运行到接收数据函数时就阻塞了。
3,后来经过多种尝试未果后改变思路,发送数据包后使用RCVALL参数捕获所有数据包,但经过分析其中似乎没有对方返回的SYN|ACK或RST包,于是猜测发送数据包时出错。
4,检查N遍后无收获,只好让各位曾经写过这种程序大牛指点迷津,感谢不尽。

测试方法,编译以下程序后在命令行下运行:scanport <IP或HostName>,不需要端口号,程序中设定探测80端口号,这只是个Demo。
复制内容到剪贴板
代码:
#include <winsock2.h>
#include <ws2tcpip.h>  
#include <stdio.h>  


#pragma comment(lib,"ws2_32")

#define  seq  0x28376839
#define SIO_RCVALL        _WSAIOW(IOC_VENDOR,1)
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
#define TCP_ACE 0x40
#define TCP_CWR 0x80

struct sockaddr_in szDest;
struct sockaddr_in szHost;

typedef struct _TCPHeader
{
        USHORT SourcePort;
        USHORT DestPort;
        ULONG  SeqNumber;
        ULONG  AckNumber;
        UCHAR  DataOffset;
        UCHAR  Flags;
        USHORT Window;
        USHORT CheckSum;
        USHORT UrgentPointer;
}TCPHeader, *PTCPHeader;

typedef struct _IPHeader
{
        UCHAR  iphVerLen;
        UCHAR  ipTOS;
        USHORT ipLength;
        USHORT ipID;
        USHORT ipFlags;
        UCHAR  ipTTL;
        UCHAR  ipProtocol;
        USHORT ipChecksum;
        ULONG  ipSource;
        ULONG  ipDestination;
}IPHeader, *PIPHeader;

/*
typedef struct _PSDHeader
{  
        ULONG  sAddr;        // 源地址  
        ULONG  dAddr;        // 目的地址  
        char   mbz;                // 保留字,为00000000
        char   pTcl;        // 协议类型,protocol = 6
        USHORT lLen;        // TCP长度  
}PSDHeader, *PPSDHeader;
*/

// 计算TCP校验和
USHORT CheckSum(USHORT *buffer,int size)
{
        ULONG  cksum=0;  
        while(size > 1)   
        {
                cksum += *buffer++;  
                size  -= sizeof(USHORT);  
        }
        if(size)   
        {
                cksum += *(UCHAR *)buffer;  
        }
        cksum =  (cksum >> 16) + (cksum & 0xffff);  
        cksum += (cksum >> 16);

        return  (USHORT)(~cksum);
}


// 计算TCP伪头部校验和
void ComputeTcpPseudoHeaderCheckum(IPHeader *pIphdr,TCPHeader *pTcphdr,char *payload,int payloadlen)   
{
        char buff[1024];
        char *ptr = buff;
        int chksumlen = 0;
        ULONG zero = 0;

        // 伪头包含源IP地址和目的IP地址
        memcpy(ptr,&pIphdr->ipSource,sizeof(pIphdr->ipSource));
        ptr += sizeof(pIphdr->ipSource);
        chksumlen += sizeof(pIphdr->ipSource);
        memcpy(ptr,&pIphdr->ipDestination,sizeof(pIphdr->ipDestination));
        ptr += sizeof(pIphdr->ipDestination);
        chksumlen += sizeof(pIphdr->ipDestination);

        // 包含8位0域
        memcpy(ptr,&zero,1);
        ptr += 1;
        chksumlen += 1;

        // 协议
        memcpy(ptr,&pIphdr->ipProtocol,sizeof(pIphdr->ipProtocol));
        ptr += sizeof(pIphdr->ipProtocol);
        chksumlen += sizeof(pIphdr->ipProtocol);

        // TCP长度
        USHORT tcp_len = htons(sizeof(TCPHeader) + payloadlen);
        memcpy(ptr,&tcp_len,sizeof(tcp_len));
        ptr += sizeof(tcp_len);
        chksumlen += sizeof(tcp_len);

        // TCP头
        memcpy(ptr,pTcphdr,sizeof(TCPHeader));
        ptr += sizeof(TCPHeader);
        chksumlen += sizeof(TCPHeader);

        // TCP数据,即净荷
        memcpy(ptr,payload,payloadlen);
        ptr += payloadlen;
        chksumlen += payloadlen;

        // 补齐到下一个16位边界
        for(int i = 0; i < payloadlen % 2; i++)
        {
                *ptr = 0;
                ptr ++;
                chksumlen ++;
        }

        //计算校验和,将结果填充到TCP头
        pTcphdr->CheckSum = CheckSum((USHORT *)buff,chksumlen);
}

// 解析IP数据包函数1
bool DecodeIPPacket(char *pData)
{
        IPHeader *pIpHdr = (IPHeader *)pData;

        if(pIpHdr->ipSource != inet_addr(inet_ntoa(szDest.sin_addr)))
                return false;

        int nHeaderLen = (pIpHdr->iphVerLen & 0xF) * sizeof(ULONG);
        switch(pIpHdr->ipProtocol)
        {
        case IPPROTO_TCP:
                {
                        TCPHeader *pTcpHdr = (TCPHeader *)(pData + nHeaderLen);
                        if((pTcpHdr->Flags & TCP_SYN) && (pTcpHdr->Flags & TCP_ACK))
                        {
                                printf("%d\tOpen!\n",pTcpHdr->DestPort);
                                return true;
                        }
                        else
                        {
                                printf("%d\tClosed!\n",pTcpHdr->DestPort);
                        }
                }
                break;
        case IPPROTO_UDP:
                break;
        case IPPROTO_ICMP:
                break;
        default:
                break;
        }
        return false;
}


// 解析IP数据包函数2
bool  DecodeIpheader(char *buffer)  
{
        IPHeader   *iphdr;  
        TCPHeader  *tcphdr;  
        USHORT  iphdrLen;  
        
        iphdr = (IPHeader *)buffer;  
        
        //是否来自目标ip  
        if(iphdr->ipSource != inet_addr(inet_ntoa(szDest.sin_addr)))
                return  false;  

        iphdrLen = sizeof(ULONG) * (iphdr->iphVerLen & 0xf);  
        tcphdr   = (TCPHeader *)(buffer + iphdrLen);

        //序列号是否正确  
//        if((ntohl(tcphdr->AckNumber) != (seq+1)) && (ntohl(tcphdr->AckNumber) != seq))
//                return  false;  
        
        //检查返回数据的码位是否为SYN + ACK
        if((tcphdr->Flags & TCP_SYN) && (tcphdr->Flags & TCP_ACK))
        {
                printf("\n\t%d\t  Open!\n",ntohs(tcphdr->DestPort));  
                return  true;  
        }
        else
        {
                printf("\n\t%d\tClosed!\n",ntohs(tcphdr->DestPort));
                return false;
        }
}

int main(int argc,char *argv[])
{
        if(argc!=2)  
        {  
                printf("Usage:ScanPort <IP Address>\n");
                return  0;  
        }  

        int DestPort   = 80;                // 目标端口
        int SourcePort = 5555;                // 源端口
        char szBuffer[1024] = {0};

        IPHeader  ip_header;  
        TCPHeader tcp_header;
        
        WSADATA ws;  
        WSAStartup(MAKEWORD(2,2),&ws);  
        
        SOCKET sRaw = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
        SOCKET sListen = socket(AF_INET,SOCK_RAW,IPPROTO_IP);

        // 设置ip头操作选项  
        bool bOpt = true;  
        setsockopt(sRaw,IPPROTO_IP,IP_HDRINCL,(char *)&bOpt,sizeof(bOpt));

        // 获取主机信息   
        UCHAR strHostName[56];
        struct  hostent  *pHost;  
        
        gethostname((char*)strHostName,56);
        pHost = gethostbyname((char *)strHostName);
        memcpy(&szHost.sin_addr.S_un.S_addr,pHost->h_addr_list[0],pHost->h_length);  
        
        szHost.sin_family = AF_INET;  
        szHost.sin_port   = htons(SourcePort);
        bind(sListen,(SOCKADDR *)&szHost,sizeof(szHost));
        
        // 将网卡设置为混杂模式
        DWORD dwValue = 1;
        ioctlsocket(sListen,SIO_RCVALL,&dwValue);

        
        //获得目标主机ip  
        memset(&szDest,0,sizeof(szDest));  
        szDest.sin_family = AF_INET;
        szDest.sin_port   = htons(DestPort);  
        if((szDest.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE)  
        {  
                if((pHost = gethostbyname(argv[1])) != NULL)
                {  
                        memcpy(&(szDest.sin_addr),pHost->h_addr_list[0],pHost->h_length);  
                        szDest.sin_family = pHost->h_addrtype;  
                }  
                else  
                {  
                        printf("Need a Dest IP Address!\n");
                        return 0;
                }  
        }
        printf("Scanning IP : %s...\n\n",inet_ntoa(szDest.sin_addr));

        // 构造并发送数据包
        ip_header.iphVerLen = (4<<4 | sizeof(ip_header)/sizeof(ULONG));
        ip_header.ipLength  = htons(sizeof(ip_header) + sizeof(tcp_header));
        ip_header.ipID = 1;
        ip_header.ipFlags = 0;
        ip_header.ipTTL = 128;
        ip_header.ipProtocol = IPPROTO_TCP;
        ip_header.ipChecksum = 0;
        ip_header.ipSource   = inet_addr(inet_ntoa(szHost.sin_addr));
        ip_header.ipDestination = (ULONG)argv[1];
        ip_header.ipChecksum    = CheckSum((USHORT *)&ip_header,sizeof(ip_header));
        memcpy(szBuffer,&ip_header,sizeof(ip_header));

        tcp_header.DestPort   = htons(DestPort);
        tcp_header.SourcePort = htons(SourcePort);
        tcp_header.SeqNumber  = seq;
        tcp_header.AckNumber  = 0;
        tcp_header.DataOffset = (sizeof(tcp_header)/4<<4 | 0);
        tcp_header.Flags      = TCP_SYN;
        tcp_header.Window     = htons(512);
        tcp_header.UrgentPointer = 0;
        tcp_header.CheckSum      = 0;

        ComputeTcpPseudoHeaderCheckum(&ip_header,&tcp_header,NULL,0);
        memcpy(&szBuffer[sizeof(ip_header)],&tcp_header,sizeof(tcp_header));

        int iError = 0;
        int nLen = sizeof(ip_header) + sizeof(tcp_header);
        if(sendto(sRaw,szBuffer,strlen(szBuffer),0,(struct sockaddr *)&szDest,sizeof(struct sockaddr)) == SOCKET_ERROR)
        {
                printf("Send Data Error!\n");
                closesocket(sRaw);

                iError = WSAGetLastError();
                printf("Error Code = %d\n",iError);

                return -1;
        }
        printf("Send Data Success!\n");

        // 接收数据
        char szRecv[1024] = {0};
        memset( szRecv, 0, sizeof( szRecv ) );
        int  szDestLen = sizeof(szDest);
        int len=0;

        while(1)
        {
                recv(sListen,szRecv,sizeof(szRecv),0);
//                if(DecodeIpheader(szRecv))
                if(DecodeIPPacket(szRecv))
                        break;
        }
        printf("Recv Data Success!\n");

        closesocket(sRaw);

        return 0;
}Welcome to My Blog :  http://www.huihu32.cn 金麟岂是池中物,一遇风云便化龙!

帖子86 精华2 积分3309 阅读权限100 性别男 来自CUIT 在线时间293 小时 注册时间2006-6-4 最后登录2008-7-8 查看个人网站
查看详细资料引用 报告 回复 TOP 良辰择日,预测咨询,公司改名,权威易经

liword
晶莹剔透§烈日灼然

提醒一下
xp sp2之后是不能用SYN扫描的
2003才可以
代码米看...
帖子4 精华0 积分8 阅读权限40 在线时间5 小时 注册时间2005-11-22 最后登录2008-6-14 查看详细资料引用 报告 回复 TOP 让女孩一夜变的更有女人味

sunwear
团队执行官

TOP

to 楼上
严格来说是不能支持原始套接字.... -_-!

帖子3776 精华70 积分18704 阅读权限200 性别男 来自天津 在线时间1645 小时 注册时间2004-8-16 最后登录2008-7-18 查看个人网站
查看详细资料引用 报告 回复 TOP 软件项目外包

冰邪
晶莹剔透§烈日灼然

TOP

返回列表