2008年5月8日星期四

[Tips]使用winpcap定制TCP包发送

by: 云舒
2008-05-08
http://www.ph4nt0m.org

前些时候做DOS方面的测试,由于协议学得不够好,有些回应不记得,所以就首先想到用hping来定制一些包,看看远程主机的回应。结果下载的hping死活都不发包,换了多个不同版本的winpcap都不行。一怒之下,决定自己写个简单的。首先想到的是perl来做,最后觉得一样要安装 winpcap还有很多别的模块,不如直接c来实现一下,来得更痛快。

需要说明一下的是,在以太网头那里我故意偷懒了,没有获取本机的MAC地址而是写了个错误的。所以给内网用户发包的话,能发出去,只是你收不到回应了,发给外网就没这个问题,这是因为同交换机下面靠MAC地址来定位的。

最后一点,这里所有的包,目的MAC地址都是写的MAC,通过网关把数据转发出去的。虽然同交换机下面可以直接通过MAC定位,但是我懒得判断,直接发送给网关再转发会比较简单。

/* Code By yunshu, 2008-05-08, Make tcp packet to send to remote server
* I don't know which version of winpcap needed by hping, so I wrote this code.
* Under winpcap 4.0.2, Dev-CPP 4.9.9.2, windows xp professional sp2
*/

#include 
<stdio.h>
#include 
<string.h>
#include 
<winsock2.h>
#include 
<iphlpapi.h>
#include 
<unistd.h>
#include 
<pcap.h>
#include 
<remote-ext.h>

#define IP_PROTO    0x0800

char    LocalIP[20= { 0 };
char    InterfaceName[256= { 0 };
char    GatewayIP[20= { 0 };
BYTE    GatewayMac[
6];

typedef 
struct et_header
{
    unsigned 
char   eh_dst[6];  
    unsigned 
char   eh_src[6];
    unsigned 
short  eh_type;
}ET_HEADER;

typedef 
struct ip_hdr
{
    unsigned 
char       h_verlen;
    unsigned 
char       tos;
    unsigned 
short      total_len;
    unsigned 
short      ident;
    unsigned 
short      frag_and_flags;
    unsigned 
char       ttl;
    unsigned 
char       proto;
    unsigned 
short      checksum;
    unsigned 
int        sourceIP;
    unsigned 
int        destIP;
}IP_HEADER;

typedef 
struct tcp_hdr
{
    unsigned 
short    th_sport;
    unsigned 
short    th_dport;
    unsigned 
int    th_seq;
    unsigned 
int    th_ack;
    unsigned 
char    th_lenres;
    unsigned 
char    th_flag;
    unsigned 
short    th_win;
    unsigned 
short    th_sum;
    unsigned 
short    th_urp;
}TCP_HEADER;

typedef 
struct tsd_hdr
{
    unsigned 
long    saddr;
    unsigned 
long    daddr;
    
char            mbz;
    
char            ptcl;
    unsigned 
short    tcpl;
}PSD_HEADER;

unsigned 
short CheckSum(unsigned short * buffer, int size)
{
    unsigned 
long   cksum = 0;

    
while (size > 1)
    {
        cksum 
+= *buffer++;
        size 
-= sizeof(unsigned short);
    }
    
if (size)
    {
        cksum 
+= *(unsigned char *) buffer;
    }
    cksum 
= (cksum >> 16+ (cksum & 0xffff);
    cksum 
+= (cksum >> 16);

    
return (unsigned short) (~cksum);
}

/*
void GetLocalIP( )
{
    WORD        wVersionRequested;  
    WSADATA        wsaData;  
    char        name[255];  
    PHOSTENT    hostinfo;  
    
    wVersionRequested = MAKEWORD( 2, 0 );
    
    if( WSAStartup( wVersionRequested, &wsaData ) == 0 )  
    {
        if( gethostname( name, sizeof(name) ) == 0 )  
        {  
            if( (hostinfo = gethostbyname(name) ) != NULL )  
            {
                strcpy( LocalIP, inet_ntoa( *(struct in_addr*)*hostinfo->h_addr_list ) );            
            }  
        }  
    }
    
    WSACleanup(   );  
}
*/

int GetDevices( )
{
    pcap_if_t    
*alldevs;
    pcap_if_t    
*d;
    
    
int i = 0;
    
char errbuf[PCAP_ERRBUF_SIZE];
    
    
/* 获取本地机器设备列表 */
    
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */&alldevs, errbuf) == -1)
    {
        fprintf(stderr,
"Error in pcap_findalldevs_ex: %s\n", errbuf);
        exit(
1);
    }
    
    
/* 打印列表 */
    
for( d = alldevs; d != NULL; d = d->next )
    {
        printf(
"%d. %s"++i, d->name);
        
        
if (d->description)
        {
            printf( 
" (%s)", d->description );
        }
                
        
if( d->addresses != NULL )
        {
            
if( d->addresses->addr->sa_family == AF_INET )
            {
                
                printf( 
": %s\n", inet_ntoa( ((struct sockaddr_in *)d->addresses->addr)->sin_addr ) );
            }
            
else
            {
                printf( 
"\n" );
            }
        }
        
else
        {
            printf(
" (No description available)\n");
        }
    }
    
    
if (i == 0)
    {
        printf(
"\nNo interfaces found! Make sure WinPcap is installed.\n");
        
return -1;
    }
    
    printf( 
"\nPlease choose the index of your NetAdapter:" );
    
int    AdapterIndex = 1;
    scanf( 
"%d"&AdapterIndex );
    
if( AdapterIndex > i )
    {
        printf( 
"网卡选错啦\n" );
        
return -1;
    }
    
    d 
= alldevs;
    
forint index = 1; index < AdapterIndex; index ++ )
    {
        d 
= d->next;
    }
    
    
if( d->name == NULL || d->addresses == NULL )
    {
        printf( 
"网卡选错啦\n" );
        
return -1;
    }
    
    strcpy( InterfaceName, d
->name );
    strcpy( LocalIP, inet_ntoa( ((
struct sockaddr_in *)d->addresses->addr)->sin_addr ) );
    
    
/* 不再需要设备列表了,释放它 */
    pcap_freealldevs(alldevs);
    
    
return 1;
}

int GetGateWayMac( )
{
    PIP_ADAPTER_INFO AdapterInfo;
    
    ULONG    OutBufLen 
= sizeof(IP_ADAPTER_INFO);
    AdapterInfo 
= (IP_ADAPTER_INFO *)malloc(sizeof (IP_ADAPTER_INFO));
    
if( AdapterInfo == NULL )
    {
        printf(
"Error allocating memory needed to call GetAdaptersinfo\n");
        
return -1;
    }

    
if( GetAdaptersInfo( AdapterInfo, &OutBufLen ) == ERROR_BUFFER_OVERFLOW )
    {
        free( AdapterInfo );
        AdapterInfo 
= (IP_ADAPTER_INFO *)malloc( OutBufLen );
        
if( AdapterInfo == NULL )
        {
            printf(
"Error allocating memory needed to call GetAdaptersinfo\n");
            
return -1;
        }
    }

    
if( GetAdaptersInfo( AdapterInfo, &OutBufLen ) == NO_ERROR )
    {
        PIP_ADAPTER_INFO    a 
= AdapterInfo;
        BOOL                Found 
= FALSE;
        
         
while( a )
        {
            
if( strcmp(a->IpAddressList.IpAddress.String, LocalIP) == 0 )
            {
                strcpy( GatewayIP, a
->GatewayList.IpAddress.String );
                Found 
= TRUE;
                
break;
            }
            a 
= a->Next;
        }
        
if!Found )
        {
            printf( 
"Get gateway's ip error.\n" );
            free( AdapterInfo );
            
return -1;
        }
        
else
        {
            free( AdapterInfo );
        }
    }
    
else
    {
        printf( 
"Get gateway's ip error.\n" );
        free( AdapterInfo );
        
return -1;
    }

    BYTE    Mac[
6];
    ULONG    MacLen 
= 6;
    SendARP( inet_addr(GatewayIP), 
0, (PULONG)&Mac, &MacLen );
    memcpy( GatewayMac, Mac, MacLen );
    
    
/*
    for( int index = 0; index < MacLen; index ++ )
    {
        printf( "%d: %02x\n", index, Mac[index] );
    }
    printf( "\n%d\n", MacLen );
    
*/
}

void Usage( char *me )
{
    printf( 
"Make tcp package 0.1, code by yunshu\n" );
    printf( 
"%s:   targetip  targetport [flag]\n", me );
    printf( 
"flag: \n" );
    printf( 
"      u|U     set urg flag.\n" );
    printf( 
"      a|A     set ack flag.\n" );
    printf( 
"      p|P     set push flag.\n" );
    printf( 
"      r|R     set rst flag.\n" );
    printf( 
"      s|S     set syn flag.\n" );
    printf( 
"      f|F     set fin flag.\n" );
    printf( 
"      default is syn flag, and you can use sa to set syn+ack, and more\n" );
}

int main( int argc, char *argv[] )
{
    ET_HEADER    EtHeader;
    IP_HEADER    IpHeader;
    TCP_HEADER    TcpHeader;
    PSD_HEADER    PsdHeader;
    u_char        Buffer[
sizeof(ET_HEADER) + sizeof(IP_HEADER) + sizeof(TCP_HEADER)] = { 0 };
    
    
if( (argc != 3&& (argc != 4) )
    {
        Usage( argv[
0] );
        exit( 
-1 );
    }
    
    
int    Flag = 2;
    
if( argc == 4 )
    {
        Flag 
= 0;
        
if( strchr(argv[3], 'U'|| strchr(argv[3], 'u') )
        {
            Flag 
= Flag | 32;
        }
        
if( strchr(argv[3], 'A'|| strchr(argv[3], 'a') )
        {
            Flag 
= Flag | 16;
        }
        
if( strchr(argv[3], 'P'|| strchr(argv[3], 'p') )
        {
            Flag 
= Flag | 8;
        }
        
if( strchr(argv[3], 'R'|| strchr(argv[3], 'r') )
        {
            Flag 
= Flag | 4;
        }
        
if( strchr(argv[3], 'S'|| strchr(argv[3], 's') )
        {
            Flag 
= Flag | 2;
        }
        
if( strchr(argv[3], 'F'|| strchr(argv[3], 'f') )
        {
            Flag 
= Flag | 1;
        }
    }
    
    
//GetLocalIP( );
    if-1 == GetDevices( ) )
    {
        exit( 
-1 );
    }
    
    
//printf( "Adapter is %s, ip is %s\n", InterfaceName, LocalIP );
    
    
if-1 == GetGateWayMac( ) )
    {
        exit( 
-1 );
    }
    
    
//printf( "Gateway IP is %s\n", GatewayIP );
    
//printf( "Gateway Mac is %x\n", *GatewayMac );
    
    memcpy( EtHeader.eh_dst, GatewayMac, 
6 );
    memset( EtHeader.eh_src, 
0xa6 );
    EtHeader.eh_type 
= htons( IP_PROTO );
    
    IpHeader.h_verlen 
= (4<<4 | sizeof(IpHeader)/sizeof(unsigned int));
    IpHeader.tos 
= 0;
    IpHeader.total_len 
= htons(sizeof(IpHeader)+sizeof(TcpHeader));
    IpHeader.ident 
= 1;
    IpHeader.frag_and_flags 
= 0x40;
    IpHeader.ttl 
= 128;
    IpHeader.proto 
= IPPROTO_TCP;
    IpHeader.checksum 
= 0;
    IpHeader.sourceIP 
= inet_addr( LocalIP );
    IpHeader.destIP 
= inet_addr( argv[1] );
    
    TcpHeader.th_sport 
= htons( rand()%60000 + 1024 );
    TcpHeader.th_dport 
= htons( atoi(argv[2]) );
    TcpHeader.th_seq 
= htonl( rand()%900000000 + 100000 );
    TcpHeader.th_ack 
= 0;
    TcpHeader.th_lenres 
= (sizeof(TcpHeader)/4<<4|0);
    TcpHeader.th_flag 
= Flag;
    TcpHeader.th_win 
= htons(512);
    TcpHeader.th_sum 
= 0;
    TcpHeader.th_urp 
= 0;
    
    PsdHeader.saddr 
= inet_addr( LocalIP );
    PsdHeader.daddr 
= IpHeader.destIP;
    PsdHeader.mbz 
= 0;
    PsdHeader.ptcl 
= IPPROTO_TCP;
    PsdHeader.tcpl 
= htons(sizeof(TcpHeader));
    
    memcpy( Buffer, 
&PsdHeader, sizeof(PsdHeader) );
    memcpy( Buffer 
+ sizeof(PsdHeader), &TcpHeader, sizeof(TcpHeader) );
    TcpHeader.th_sum 
= CheckSum( (unsigned short *)Buffer, sizeof(PsdHeader) + sizeof(TcpHeader) );
    
    memset( Buffer, 
0sizeof(Buffer) );
    memcpy( Buffer, 
&IpHeader, sizeof(IpHeader) );
    IpHeader.checksum 
= CheckSum( (unsigned short *)Buffer, sizeof(IpHeader) );
    
    memset( Buffer, 
0sizeof(Buffer) );
    memcpy( Buffer, (
void *)&EtHeader, sizeof(ET_HEADER) );
    memcpy( Buffer 
+ sizeof(ET_HEADER), (void *)&IpHeader, sizeof(IP_HEADER) );
    memcpy( Buffer 
+ sizeof(ET_HEADER) + sizeof(IP_HEADER), (void *)&TcpHeader, sizeof(TCP_HEADER) );
    
    
char errbuf[PCAP_ERRBUF_SIZE] = { 0 };
    pcap_t 
*fp;
    
if ( (fp= pcap_open( InterfaceName, 100, PCAP_OPENFLAG_PROMISCUOUS, 100, NULL, errbuf ) ) == NULL )
    {
        fprintf(stderr,
"\nUnable to open the adapter. %s is not supported by WinPcap\n", InterfaceName );
        
return -1;
    }
    
    
if ( pcap_sendpacket( fp, Buffer, sizeof(Buffer) ) != 0 )
    {
        fprintf(stderr,
"\nError sending the packet: \n", pcap_geterr(fp));
        
return -1;
    }
    printf( 
"send ok!\nData is:\n" );
    
    
forint i = 0; i < sizeof(Buffer); i ++ )
    {
         printf( 
"%02x ", Buffer );
    }
    
    
return 0;