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 (http://www.winpcap.org/default.htm)
Driver (instalador automático):
http://www.winpcap.org/install/default.htm (http://www.winpcap.org/install/default.htm)
Pacote para desenvolvimento:
http://www.winpcap.org/devel.htm (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/ip.htm)
http://www.networksorcery.com/enp/protocol/icmp.htm (http://www.networksorcery.com/enp/protocol/icmp.htm)
http://www.networksorcery.com/enp/protocol/tcp.htm (http://www.networksorcery.com/enp/protocol/tcp.htm)
http://www.networksorcery.com/enp/protocol/udp.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:
(//http://one.xthost.info/darkside17/projetos/c-cpp/packetclass/screenwire.jpg)
O programa pode ser obtido gratuitamente em:
http://www.wireshark.org/ (http://www.wireshark.org/)
Download dos sources + executável utilizados:
http://one.xthost.info/darkside17/proje ... tclass.rar (http://one.xthost.info/darkside17/projetos/c-cpp/packetclass/packetclass.rar)
É isso...
Aguardo meus presentes ahauhuahua
Bye.
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..
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