标题:
[讨论] 关于使用半开扫描探测端口的程序
[打印本页]
作者:
richy
时间:
2008-7-20 23:22
标题:
[讨论] 关于使用半开扫描探测端口的程序
[讨论] 关于使用半开扫描探测端口的程序
议题作者: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
晶莹剔透§烈日灼然
作者:
caio
时间:
2008-7-20 23:22
提醒一下
xp sp2之后是不能用SYN扫描的
2003才可以
代码米看...
帖子4 精华
0
积分8 阅读权限40 在线时间5 小时 注册时间2005-11-22 最后登录2008-6-14
查看详细资料
引用
报告
回复
TOP
让女孩一夜变的更有女人味
sunwear
团队执行官
作者:
原野
时间:
2008-7-20 23:22
to 楼上
严格来说是不能支持原始套接字.... -_-!
帖子3776 精华
70
积分18704 阅读权限200 性别男 来自天津 在线时间1645 小时 注册时间2004-8-16 最后登录2008-7-18
查看个人网站
查看详细资料
引用
报告
回复
TOP
软件项目外包
冰邪
晶莹剔透§烈日灼然
欢迎光临 【3.A.S.T】网络安全爱好者 (http://3ast.com/)
Powered by Discuz! 7.2