Packet Class - C++

Started by Dark_Side, 30 de December , 2007, 09:29:27 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dark_Side

Hi,

Vim aqui apenas pra dizer que dia 31/12 eu completo mais um ano de vida e que eu estou esperando presentes :)

Pois bem, embora seja verdade, vejamos o real propósito do tópico.

Como outras classes C++ que eu escrevo e disponibilizo no fórum, farei o mesmo com uma outra.

Esta classe permite a criação, manipulação e envio de pacotes IP/ICMP, IP/TCP e IP/UDP no Windows.

É possível criar pacotes com diferentes características. Alguns exemplos são pacotes com IP's de origem e destino forjados, código e tipo de ICMP customizados, números de identificação e seqüência pré-definidos, etc.

Para enviar tais pacotes sem restrições impostas pelo sistema operacional, a classe depende de uma biblioteca não-nativa chamada Winpcap. Tal biblioteca consiste em um driver que permite o acesso às camadas de rede num nível bem baixo, que torna possível a captura e o envio de pacotes de rede sem os típicos obstáculos oferecidos pela API nativa do Windows.

Portanto, antes de mais nada, é necessário baixar e instalar o driver + pacote para desenvolvimento de aplicações inclusos na biblioteca:


Informações:

http://www.winpcap.org/default.htm

Driver (instalador automático):

http://www.winpcap.org/install/default.htm

Pacote para desenvolvimento:

http://www.winpcap.org/devel.htm  


Após instalar o driver, deve-se extrair os arquivos contidos na pasta "include" do pacote, para a pasta "include" do compilador. O mesmo deve ser feito com os arquivos contidos no diretório "lib" do pacote, salvando-os no local correspondente.


Antes de efetivamente postar o código da classe, farei uma breve descrição sobre a mesma.

Funções membro da classe:

int  ListarInterfaces(std::string * buffer);
Lista as interfaces disponíveis para uso no computador. O ponteiro "buffer", quando diferente de ZERO, armazena na variável do tipo "string" referenciada, a lista das interfaces. A função retorna o número de interfaces encontradas.


    
void AbrirInterface(int num);
Abre uma interface para uso. Onde "num" é a identificação da mesma.


void FecharInterface();
Fecha uma interface previamente aberta.



void CriarPacote(unsigned char protocolo, unsigned short tam_dados);  

Função utilizada para criar um pacote. Onde "protocolo" é o tipo de protocolo do pacote, podendo ser: IPPROTO_ICMP, IPPROTO_TCP ou IPPROTO_UDP. O argumento "tam_dados" especifica o tamanho, em bytes, dos dados que serão anexados ao pacote.
Se o valor de "tam_dados" for passado como ZERO, um pacote sem payload(dados) será criado.

void DeletarPacote();
Deleta um pacote previamente criado.
    
void PreencherEthernet(const char * mac_origem, const char * mac_destino);
Especifica endereços MAC de origem e destino do pacote.
Macros: MAC_ORIGEM_PADRAO e MAC_DESTINO_PADRAO.


void PreencherIP(unsigned char  ip_tos,  unsigned short ip_id,
                 unsigned short ip_off,  unsigned char  ip_ttl,
                 const char *   ip_src,  const char *   ip_dst);


Preenche o cabeçalho IP com os valores correspondentes aos argumentos.



void PreencherICMP(unsigned char ih_code, unsigned char  ih_type,
                   unsigned short ih_id,  unsigned short ih_seq,
                   const char * dados,    unsigned short tam_dados);


Preenche o cabeçalho ICMP com os valores correspondentes aos argumentos.


void PreencherTCP(unsigned short th_sport, unsigned short th_dport,
                  unsigned int   th_seq,   unsigned int   th_ack,
                  unsigned char  th_off,   unsigned char  th_flags,
                  unsigned short th_win,   unsigned short th_urp,
                  const char *   dados,    unsigned short tam_dados);


Preenche o cabeçalho TCP com os valores correspondentes aos argumentos.



void PreencherUDP(unsigned short uh_sport, unsigned short uh_dport,
                  const char *    dados,   unsigned short tam_dados);


Preenche o cabeçalho UDP com os valores correspondentes aos argumentos.
      
                
        
bool EnviarPacote();
Envia um pacote criado e montando. Retorno: 1 quando não ocorrem erros; 0 do contrário.


Informações sobre os campos dos protocolos:

http://www.networksorcery.com/enp/protocol/ip.htm
http://www.networksorcery.com/enp/protocol/icmp.htm
http://www.networksorcery.com/enp/protocol/tcp.htm
http://www.networksorcery.com/enp/protocol/udp.htm

Código da classe:

protohdr.h


#pragma pack(push,1)

// Cabeçalho ETHERNET
struct ethhdr
{
unsigned char  eth_dst[6];
unsigned char  eth_src[6];
unsigned short eth_type;
};


// Cabeçalho IP
struct iphdr
{
    unsigned char  ip_hl:4, ip_v:4;
    unsigned char  ip_tos;
    unsigned short ip_len;
    unsigned short ip_id;
    unsigned short ip_off;
    unsigned char  ip_ttl;
    unsigned char  ip_p;
    unsigned short ip_sum;
    unsigned long  ip_src;
    unsigned long  ip_dst;
};


// Cabeçalho PSEUDO
struct psdhdr
{
    unsigned long  saddr, daddr;
    unsigned char  zero, protocol;
    unsigned short len;
};


// Cabeçalho TCP
struct tcphdr
 {
    unsigned short th_sport;
    unsigned short th_dport;
    unsigned int   th_seq;
    unsigned int   th_ack;
    unsigned char  th_x2:4, th_off:4;
    unsigned char  th_flags;
    unsigned short th_win;
    unsigned short th_sum;
    unsigned short th_urp;
};


// Cabeçalho UDP
struct udphdr
{
    unsigned short uh_sport;
    unsigned short uh_dport;
    unsigned short uh_len;
    unsigned short uh_sum;
};


// Cabeçalho ICMP
struct icmphdr
{
    unsigned char  ih_code;
    unsigned char  ih_type;
    unsigned short ih_sum;
    unsigned short ih_id;
    unsigned short ih_seq;
};


#pragma pack(pop)

#define IPTYPE htons(0x0800);

#define ETHTAM  sizeof(struct ethhdr)   // Tamanho da estrutura ETHERNET
#define IPTAM   sizeof(struct iphdr)    // Tamanho da estrutura IP
#define PSTAM   sizeof(struct psdhdr)   // Tamanho da estrutura PSEUDO
#define ICMPTAM sizeof(struct icmphdr)  // Tamanho da estrutura ICMP
#define TCPTAM  sizeof(struct tcphdr)   // Tamanho da estrutura TCP
#define UDPTAM  sizeof(struct udphdr)   // Tamanho da estrutura UDP
 

#define MAC_ORIGEM_PADRAO   "\x00\x00\x00\x00\x00\x00"
#define MAC_DESTINO_PADRAO  "\xFF\xFF\xFF\xFF\xFF\xFF"

// Função para cálculo de checksum
unsigned short cksum(unsigned short * buffer,int len)
{
 unsigned long cksum = 0;
 
    while(len > 1)
    {
        cksum += *buffer++;
        len   -= sizeof(unsigned short);
    }
 
    if(len)
      cksum += *(unsigned char*)buffer;

    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);

 return (unsigned short)(~cksum);

}


PacketClass.h



#ifndef _PacketClass_
#define _PacketClass_

#include "pcap.h"
#include "protohdr.h"


static char ErroSemInterfaces[]     = "Nenhuma interface foi especificada.";
static char ErroSemPacotes[]        = "Não existe pacote disponível.";
static char ErroInterfaceInvalida[] = "A interface selecionada é inválida";
static char ErroAbrirInterface[]    = "Erro ao abrir a interface selecionada.";
static char ErroProtocoloInvalido[] = "O protocolo especificado não é suportado.";
static char ErroAlocarPacote[]      = "Erro ao alocar pacote.";
static char ErroSemPacoteICMP[]     = "Não existe um pacote ICMP criado.";
static char ErroSemPacoteTCP[]      = "Não existe um pacote TCP criado.";
static char ErroSemPacoteUDP[]      = "Não existe um pacote TCP criado.";

class Packet
 {
   private:
    
     pcap_t    * fp;
     pcap_if_t * alldevs;
     pcap_if_t * d;
  
     char errbuf[PCAP_ERRBUF_SIZE];
     bool ManterLista;

     struct ethhdr  * eth;
     struct iphdr   * ip;
     struct psdhdr  * psd;
     struct icmphdr * icmp;
     struct tcphdr  * tcp;
     struct udphdr  * udp;

     unsigned char  * pacote;
     unsigned short   TAMANHO_PACOTE;
     unsigned char    tipo_protocolo;
    
   public:
      
      Packet();
      ~Packet();
      
      int  ListarInterfaces(std::string * buffer);
      
      void AbrirInterface(int num);

      void FecharInterface();

      void CriarPacote(unsigned char protocolo, unsigned short tam_dados);  

      void DeletarPacote();
    
      void PreencherEthernet(const char * mac_origem, const char * mac_destino);

      void PreencherIP(unsigned char  ip_tos,  unsigned short ip_id,
                       unsigned short ip_off,  unsigned char  ip_ttl,
                       const char *   ip_src,  const char *   ip_dst);
      
      void PreencherICMP(unsigned char ih_code, unsigned char  ih_type,
                         unsigned short ih_id,  unsigned short ih_seq,
                         const char * dados,    unsigned short tam_dados);

      void PreencherTCP(unsigned short th_sport, unsigned short th_dport,
                        unsigned int   th_seq,   unsigned int   th_ack,
                        unsigned char  th_off,   unsigned char  th_flags,
                        unsigned short th_win,   unsigned short th_urp,
                        const char *   dados,    unsigned short tam_dados);

      void PreencherUDP(unsigned short uh_sport, unsigned short uh_dport,
                        const char *    dados,   unsigned short tam_dados);
                        
      bool EnviarPacote();

      

};
    

////////////////////////////////////////////////////////////////////////////////

Packet::Packet()
{
    fp = NULL;
    pacote = NULL;
    tipo_protocolo =  0;
ManterLista = FALSE;
}

////////////////////////////////////////////////////////////////////////////////
    
Packet::~Packet()
{

    delete [] pacote;
      
    if(fp)
      pcap_close(fp);

}

////////////////////////////////////////////////////////////////////////////////

int Packet::ListarInterfaces(std::string * buffer)
{

 int i;

    memset(errbuf,0x0,sizeof(errbuf));
    
    if(buffer)
     *buffer = "";
    
    if(pcap_findalldevs(&alldevs, errbuf) == -1)
     throw (const char*)errbuf;
    
    for(i = 1, d=alldevs; d != NULL; d=d->next, i++)
     if(buffer != NULL)
     {
      
       buffer->append(d->name);
       buffer->append(" -> ");
      
       if(d->description)
        buffer->append(d->description);
       else
        buffer->append("(sem descrição)");
        
       buffer->append("\n\n");
        
     }
  

    if(!ManterLista)
     pcap_freealldevs(alldevs);
 
    i--;

    if(i == 0)
     throw ErroSemInterfaces;
    
    
  return i;
}

////////////////////////////////////////////////////////////////////////////////
          
void Packet::AbrirInterface(int num)
{
  
   ManterLista = TRUE;

   int i = ListarInterfaces(NULL);
  
    if(num < 1 || num > i)
     {
        pcap_freealldevs(alldevs);
        throw ErroInterfaceInvalida;
     }

    for(d = alldevs, i = 0; i < num-1 ; d = d->next, i++);

    if(fp != NULL)
      pcap_close(fp);
    
    fp = pcap_open_live(d->name,65536,1,1000,errbuf);

pcap_freealldevs(alldevs);
    
    if(!fp)
      throw ErroAbrirInterface;

}

////////////////////////////////////////////////////////////////////////////////

void Packet::FecharInterface()
{
 
 if(fp)
  {
    pcap_close(fp);
    fp = NULL;
  }
}

////////////////////////////////////////////////////////////////////////////////
    
void Packet::CriarPacote(unsigned char protocolo, unsigned short tam_dados)
{
  
   if(tipo_protocolo != 0)
     DeletarPacote();
  
  switch(protocolo)
    {
      case IPPROTO_ICMP:
        TAMANHO_PACOTE  = ETHTAM + IPTAM + ICMPTAM + tam_dados;
      break;                        

      case IPPROTO_TCP:
        TAMANHO_PACOTE  = ETHTAM + IPTAM + PSTAM + TCPTAM + tam_dados;
      break;                        

      case IPPROTO_UDP:
        TAMANHO_PACOTE  = ETHTAM + IPTAM + PSTAM + UDPTAM + tam_dados;
      break;                        

      default:
        throw ErroProtocoloInvalido;
    }      
  
  
  pacote = new (std::nothrow) unsigned char[TAMANHO_PACOTE];
  if(!pacote)
   throw ErroAlocarPacote;

  tipo_protocolo = protocolo;
  
}

////////////////////////////////////////////////////////////////////////////////

void Packet::DeletarPacote()
{
     delete [] pacote;

     pacote = NULL;
     tipo_protocolo = 0;
}

////////////////////////////////////////////////////////////////////////////////


void Packet::PreencherEthernet(const char * mac_origem, const char * mac_destino)
{
    
      if(!pacote)
        throw ErroSemPacotes;

      eth   = (struct ethhdr*)(pacote);

      memcpy(eth->eth_dst,mac_destino,sizeof(eth->eth_dst));
      memcpy(eth->eth_src,mac_origem,sizeof(eth->eth_dst));

      eth->eth_type = IPTYPE;
    
}

////////////////////////////////////////////////////////////////////////////////

void Packet::PreencherIP(unsigned char  ip_tos,  unsigned short ip_id,
                         unsigned short ip_off,  unsigned char  ip_ttl,
                         const char *   ip_src,  const char *   ip_dst)
{

      
      if(!pacote)
        throw ErroSemPacotes;

      ip = (struct iphdr*)(pacote + ETHTAM);
      
      ip->ip_hl   =  5;
      ip->ip_v    =  4;
      ip->ip_tos  =  ip_tos;
      
      if(tipo_protocolo == IPPROTO_ICMP)
         ip->ip_len  =  htons(TAMANHO_PACOTE - ETHTAM);
      else
         ip->ip_len  =  htons(TAMANHO_PACOTE - ETHTAM - PSTAM);
      
      ip->ip_id   =  htons(ip_id);
      ip->ip_off  =  ip_off;
      ip->ip_ttl  =  ip_ttl;
      ip->ip_p    =  tipo_protocolo;
      ip->ip_sum  =  0;
      ip->ip_src  =  inet_addr(ip_src);
      ip->ip_dst  =  inet_addr(ip_dst);
  
      ip->ip_sum    =  cksum((unsigned short *)ip, IPTAM);  
 

}

////////////////////////////////////////////////////////////////////////////////

void Packet::PreencherICMP(unsigned char ih_code, unsigned char ih_type,
                           unsigned short ih_id, unsigned short ih_seq,
                           const char * dados,   unsigned short tam_dados)

{

     if(tipo_protocolo != IPPROTO_ICMP)
       throw ErroSemPacoteICMP;
      
     if(!dados && tam_dados)
       tam_dados = 0;

      icmp  = (struct icmphdr* )(pacote + ETHTAM + IPTAM);
      
      memset(icmp,0x0,TAMANHO_PACOTE - ETHTAM - IPTAM);

      if(dados && tam_dados)
        memcpy((char*)(icmp) + ICMPTAM, dados, tam_dados);
      
      icmp->ih_code = ih_code;
      icmp->ih_type = ih_type;
      icmp->ih_id   = htons(ih_id);
      icmp->ih_seq  = htons(ih_seq);
      icmp->ih_sum  = cksum((unsigned short *)icmp,ICMPTAM + tam_dados);

}

////////////////////////////////////////////////////////////////////////////////

void Packet::PreencherTCP(unsigned short th_sport, unsigned short th_dport,
                          unsigned int   th_seq,   unsigned int   th_ack,
                          unsigned char  th_off,   unsigned char  th_flags,
                          unsigned short th_win,   unsigned short th_urp,
                          const char *   dados,    unsigned short tam_dados)
{

     if(tipo_protocolo != IPPROTO_TCP)
       throw ErroSemPacoteTCP;
      
     if(!dados && tam_dados)
       tam_dados = 0;

      psd   = (struct psdhdr* )(pacote + ETHTAM + IPTAM);
      tcp   = (struct tcphdr* )(pacote + ETHTAM + IPTAM + PSTAM);
      
      memset(psd,0x0,TAMANHO_PACOTE - ETHTAM - IPTAM);

      if(dados && tam_dados)
        memcpy((char*)(tcp) + TCPTAM, dados, tam_dados);
  
      psd->saddr    =  ip->ip_src;
      psd->daddr    =  ip->ip_dst;
      psd->zero     =  0;                    
      psd->protocol =  IPPROTO_TCP;          
      psd->len      =  htons(TCPTAM + tam_dados);
  
      tcp->th_sport =  htons(th_sport);
      tcp->th_dport =  htons(th_dport);
      tcp->th_seq   =  htonl(th_seq);
      tcp->th_ack   =  th_ack;
      tcp->th_x2    =  0;
      tcp->th_off   =  th_off;
      tcp->th_flags =  th_flags;
      tcp->th_win   =  htons(th_win);
      tcp->th_urp   =  th_urp;
      tcp->th_sum   =  cksum((unsigned short *)psd,PSTAM + TCPTAM + tam_dados);
      
      memcpy(psd, tcp, TCPTAM + tam_dados);
 
}
 
////////////////////////////////////////////////////////////////////////////////

void Packet::PreencherUDP(unsigned short uh_sport, unsigned short uh_dport,
                          const char * dados,      unsigned short tam_dados)
{
  
     if(tipo_protocolo != IPPROTO_UDP)
       throw ErroSemPacoteUDP;
      
     if(!dados && tam_dados)
       tam_dados = 0;

      psd   = (struct psdhdr* )(pacote + ETHTAM + IPTAM);
      udp   = (struct udphdr* )(pacote + ETHTAM + IPTAM + PSTAM);
      
      memset(psd,0x0,TAMANHO_PACOTE - ETHTAM - IPTAM);

      if(dados && tam_dados)
        memcpy((char*)(udp) + UDPTAM, dados, tam_dados);
      
      psd->saddr    =  ip->ip_src;
      psd->daddr    =  ip->ip_dst;
      psd->zero     =  0;                    
      psd->protocol =  IPPROTO_UDP;          
      psd->len      =  htons(UDPTAM + tam_dados);
  
      udp->uh_sport = htons(uh_sport);
      udp->uh_dport = htons(uh_dport);
      udp->uh_len   = psd->len;
      udp->uh_sum   = cksum((unsigned short *)psd,PSTAM + UDPTAM + tam_dados);
      
      memcpy(psd, udp, UDPTAM + tam_dados);

}

////////////////////////////////////////////////////////////////////////////////


bool Packet::EnviarPacote()
{  
    
    if(!fp)
      throw ErroSemInterfaces;
    
    if(!pacote)
      throw ErroSemPacotes;
      
    if(tipo_protocolo == IPPROTO_ICMP)    
      return !pcap_sendpacket(fp, pacote, TAMANHO_PACOTE);
    else
      return !pcap_sendpacket(fp, pacote, TAMANHO_PACOTE - PSTAM);
    
}

////////////////////////////////////////////////////////////////////////////////

#endif




Exemplo de uso:

icmp.cpp


#include <iostream>
#include <cstdlib>
#include <string>
#include "PacketClass.h"

using namespace std;

int main()
{

Packet pacote; // Declara um pacote
string lista;  
int i;

try // Tentar ;)
  {
    
    i = pacote.ListarInterfaces(&lista); // Obtém a lista de interfaces

    cout << lista;
    printf("Escolha uma interface (1-%d):",i);

    cin >> i; // Armazena a entrada do usuário
    cin.ignore (INT_MAX, '\n' );

    pacote.AbrirInterface(i); // Abre a interface selecionada
    pacote.CriarPacote(IPPROTO_ICMP,0); // Cria um pacote ICMP sem dados
    pacote.PreencherEthernet(MAC_ORIGEM_PADRAO,MAC_DESTINO_PADRAO); // Preenche MAC
    
    pacote.PreencherIP(0,0,0,255,"1.2.3.4","120.0.0.1"); // Preenche IP, ttl = 255
    pacote.PreencherICMP(0x8,0x0,0,0,NULL,0); // Preenche ICMP -> Echo Request (ping)
    
    if(!pacote.EnviarPacote()) // Envia o pacote
     cout << "Erro ao enviar pacote.";
    else
     cout << "Pacote enviado!";
    
    
    pacote.DeletarPacote(); // Deleta o espaço alocado para o pacote
    pacote.FecharInterface(); // Fecha a interface
    
  }
catch(const char * str) // Tratamento de erros
 {
   cout << "Ocorreu um erro: " << str;
   cin.get();
   return 1;
 }

cin.get();
return 0;

}


Obs:: para compilar o código, é necessário incluir nas opções do linker do compilador as seguintes bibliotecas:
 
ws2_32.lib
wpcap.lib


O programa acima cria e envia um pacote ICMP do tipo Echo Request (pedido de ping). Para verificar o funcionamento do programa, podemos utilizar um sniffer. E já que estamos falando sobre o Winpcap, seria interessante mostrar outras de suas funcionalidades. Para tanto, abaixo segue um trecho de captura gerado pelo programa WireShark - sniffer que utiliza o Winpcap para captura de pacotes:





O programa pode ser obtido gratuitamente em:

http://www.wireshark.org/

Download dos sources + executável utilizados:

http://one.xthost.info/darkside17/proje ... tclass.rar


É isso...

Aguardo meus presentes ahauhuahua
Bye.

Mental_Way

Muito bom o code, explicando agora o spoofing e o sniffing em c.. heheheh

Muito bom dark_side, mais um otimo conteudo em português.


heheheheh e aew Dark_Side, tu faz aniversario no ano novo?! kkkk legal.. E o presente sabe como éh.. aceita um cartão virtual?! a grana ta curta final de ano... kkk

Se cuida..

Fuix..
[RitualistaS GrouP]

"Aquele que sabe pouco rapidamente revela isto."

rog

feliz anniversario DS, felicidade para te

sera que os admins poderiam trocar a fonte do tag codigo do forum, fica muito dificil de ler os codigos

rog
realty.sys is corrupt :  reboot the universe (Y/N)