Hi,
Sem idéias para meus últimos tópicos, desta vez irei postar um programinha, escrito em C, que utiliza a DLL ICMP.DLL para executar um ping em um host.
Basicamente, o programa obtém, externamente, os endereços das funções dentro da DLL: IcmpCreateFile, IcmpCloseHandle e IcmpSendEcho.
Com a função IcmpCreateFile, iniciamos o serviço PING, após preenchermos as estruturas e parâmetros que cada função externa exige, chamamos, através de ponteiros, a função IcmpSendEcho - que irá executar efetivamente o ping.
Após executado, devemos utilizar a função IcmpCloseHandle para finalizar o serviço.
Para facilitar, mative alguns parâmetros encontrados no ping do Windows:
Quote-t = envia pacotes constatemente;
-l tamanho = especifica o tamanho dos pacotes: 0 a 65500 bytes;
-n num = define o número de pacotes
-i TTL = define o tempo de vida: 0 a 255;
-s TOS = define o tipo de serviço: 1 a 4.
Segue abaixo o source (compile-o linkando a lib "wsock32"):
ping.c#include <stdio.h> // Entrada e saída padronizadas
#include <stdlib.h> // Alocação dinâmica, conversões, etc
#include <windows.h> // Constantes e funções da API do Windows
#include <winsock.h> // Header do winsock
#include "funcoes.h" // Header com funções, constantes, variáveis e estruturas do código
// Declaração de funções
void pingar(struct ping_args *);
int enviar_pacote(void);
void envia_infinitos(void);
void envia_num(unsigned long);
// Função principal
int main(int argn, char * arg[]){
system("cls"); // Limpa a tela
if(argn < 2) // Verifica argumentos
{
puts("Uso: ping HOST [-t] [-l tamanho] [-n numero] [-i TTL] [-s TOS]\n");
puts("Opcoes");
puts(" -t \t Envia pacotes infinitos.");
puts(" -l tamanho \t Define o tamanho dos pacotes.");
puts(" -n numero \t Define a quantidade de pacotes.");
puts(" -i TTL \t Define o tempo de vida.");
puts(" -s TOS \t Define o tipo de servico.\n");
system("pause");
return 1;
}
// Limpa estrutura
memset(&ping_arg,0x0,sizeof(struct ping_args));
// Define parâmetros iniciais
ping_arg.infinitos = FALSE; // NÃO enviar pacotes infinitamente
ping_arg.tam = 256; // Tamanho do buffer a enviar
ping_arg.num = 4; // Número de pacotes
ping_arg.tos = 1; // Tipo de serviço
ping_arg.ttl = 128; // Tempo de vida
obter_parametros(argn,arg); // Obtém argumentos e atualiza os parâmetros acima
if(WSAStartup(0x101,&wsa) ==-1){ // Tenta inicializar winsock -> usar gethostbyname()
puts("Erro ao inicializar Winsock");
exit(1);}
// Tenta resolver host
host = gethostbyname(HOST_ARG);
if(!host){
printf("Ocorreu um erro ao resolver o host: %s",HOST_ARG);
exit(1);}
addr = *(unsigned long*)host->h_addr; // Transforma-o em network byte
inicializar(); // Inicializa ICMP
if(ping_arg.tam > 65500) // Verifica se o tamanho do pacote ultrapassa 65.500 Bytes
ping_arg.tam = 256; // Reinicia o valor inicial
cria_buffer(ping_arg.tam); // Cria buffer do pacote
pingar(&ping_arg); // Inicia o ping
FecharICMP(PING_ID); // Termina o ping
free(ping_buffer); // Libera buffer alocado
free(PingResp); // Libera estrutura alocada
FreeLibrary(icmp_dll); // Libera DLL
WSACleanup(); // Finaliza Winsock
return 0;
}
// Função para pingar
void pingar(struct ping_args * parametros)
{
ip_host = inet_ntoa(*(struct in_addr*)&addr); // Obtém IP do host
nome_host = host->h_name; // Obtém hostname
system("cls"); // Limpa a tela
if(parametros->tos > 4) // Se TOS for maior do que 4 (inválido) -> reinicia-o
parametros->tos = 1;
if(parametros->ttl > 255) // Se TTL for maior do que 255 (inválido) -> reinicia-o
parametros->tos = 128;
// Ajusta parâmetros
PingResp->opcoes.tos = parametros->tos;
PingResp->opcoes.ttl = parametros->ttl;
if(parametros->infinitos == TRUE) // Verifica se a opção -t foi utilizada
envia_infinitos();
else
envia_num(parametros->num); // Se -t não foi utilizada, envia o número de pacotes (-n numero)
}
void envia_infinitos()
{
while(1){
Sleep(600);
if(!enviar_pacote()) // Envia o pacote
puts("Tempo limite esgotado."); // Retorno 0 = erro
else{ // Retorno 1 = resposta recebida
printf("Resposta de %s [%s]:\n\n",ip_host,nome_host); // Mostra IP e HostName
printf("tempo(sec) = %lu\n",(PingResp->tempo / 1000)); // Mostra tempo de resposta (segundos)
printf("TTL = %lu\n",PingResp->opcoes.ttl); // Mostra tempo de vida
printf("Bytes = %lu\n\n",PingResp->tam_data); // Mostra número de bytes
}
}
}
void envia_num(unsigned long num)
{
int i=0;
while(i < num){ // Enquanto o número de pacotes definido não for atingido
Sleep(600);
// Envia o pacote e filtra retorno
if(!enviar_pacote())
puts("Tempo limite esgotado.");
else{
printf("Resposta de %s [%s]:\n\n",ip_host,nome_host); // Mostra IP e HostName
printf("tempo(sec) = %lu\n",(PingResp->tempo / 1000)); // Mostra tempo de resposta (segundos)
printf("TTL = %lu\n",PingResp->opcoes.ttl); // Mostra tempo de vida
printf("Bytes = %lu\n\n",PingResp->tam_data); // Mostra número de bytes
}
i++; // Incrementa número de pacotes
}
}
int enviar_pacote()
{
// Envia o pacote ICMP retornando o valor da função externa
return EnviarICMP(PING_ID,addr,ping_buffer,ping_arg.tam,NULL,PingResp,PingResp_Tam + ping_arg.tam,1);
}
[b]funcoes.h[/b]
// Abaixo temos estruturas, constantes, variáveis e funções globais
// Opções do pacote
struct ping_opt{
unsigned char ttl; // Tempo de vida
unsigned char tos; // Tipo de serviço
unsigned char flags; // IP header flags
unsigned char op_tam; // Tamanho do buffer de dados opcionais
unsigned char * op_dados; // Dados opcionais
};
// Resposta do Ping
struct ping_resp{
unsigned long addr; // Endereço de resposta
unsigned long status; // Reply status
unsigned long tempo; // Tempo de resposta
unsigned short tam_data; // Tamanho do buffer -> enviar no ping
unsigned short reservado; // Reservado para o sistema
char * buffer; // Ponteiro para o buffer
struct ping_opt opcoes; // Estrutura ping_opt -> opções do pacote
};
// Argumentos
struct ping_args{
BOOL infinitos; // Pacotes infinitos
unsigned long tam; // Tamanho do buffer
unsigned long num; // Número de pacotes
unsigned short tos; // Tipo de serviço
unsigned short ttl; // Tempo de vida
};
// Tamanho da estrutura ping_resp
#define PingResp_Tam sizeof(struct ping_resp)
// Declaração de estruturas
struct ping_opt PingOp;
struct ping_resp * PingResp;
struct ping_args ping_arg;
// Define ponteiros para funções
typedef HANDLE (WINAPI* pfnCriar) (void);
typedef BOOL (WINAPI* pfnFechar)(HANDLE);
typedef DWORD (WINAPI* pfnEnviar)(HANDLE, DWORD, LPVOID, WORD,struct ping_opt*, LPVOID, DWORD, DWORD);
// Declaração dos ponteiros
pfnCriar CriarICMP;
pfnFechar FecharICMP;
pfnEnviar EnviarICMP;
HINSTANCE icmp_dll; // Handle para a DLL
HANDLE PING_ID; // ID do ping
// Variáveis do winsock
WSADATA wsa;
struct hostent * host = NULL;
// Ponteiros para char
char * ip_host;
char * nome_host;
char * ping_buffer;
char * HOST_ARG;
unsigned long addr; // Endereço alvo em network byte
// Declaração de funções
void inicializar(void);
void cria_buffer(unsigned long);
void obter_parametros(int,char**);
void erro_arg(const char*);
// Inicialização
void inicializar()
{
// Carrega dinamicamente a DLL
icmp_dll = LoadLibrary("ICMP.DLL");
if(!icmp_dll){
puts("Ocorreu um erro ao abrir a dll "ICMP.DLL".");
exit(1);}
// Obtém endereços remotos de cada função da DLL
CriarICMP = (pfnCriar)GetProcAddress(icmp_dll,"IcmpCreateFile");
FecharICMP = (pfnFechar)GetProcAddress(icmp_dll,"IcmpCloseHandle");
EnviarICMP = (pfnEnviar)GetProcAddress(icmp_dll,"IcmpSendEcho");
// Verifica validade dos endereços
if(!CriarICMP || !FecharICMP || !EnviarICMP) {
puts("Ocorreu um erro ao obter as funcoes externas.");
exit(1);}
PING_ID = CriarICMP(); // Cria um novo ping (lolz)
if(PING_ID == (HANDLE)-1){ // Verifica
puts("Ocorreu um erro ao inicializar o ping.");
exit(1);}
}
void cria_buffer(unsigned long tam) // Aloca buffer utilizado no pacote
{
ping_buffer = (char*)malloc(tam); // Aloca espaço no buffer
memset(ping_buffer,0x61,tam); // Preenche-o com o caractere 'A'
PingResp = (struct ping_resp*)malloc(PingResp_Tam + tam); // Aloca estrutura
if(!PingResp){
puts("Erro ao alocar espaco na estrutura PingResp");
exit(1);}
// Ajusta parâmetros
PingResp->buffer = ping_buffer; // Ponteiro para o buffer
PingResp->tam_data = tam; // Tamanho do buffer
}
// Verifica argumentos
void obter_parametros(int argn, char ** argumento)
{
int i,x;
char * arg;
char arg_lista[5][3] = {"-t","-l","-n","-i","-s"}; // Lista de argumentos
// Primeiro argumento = alvo do ping
HOST_ARG = argumento[1];
for(i=1;i<argn;i++) // Pecorre os argumentos
{
arg = argumento[i];
for(x=0;x<5;x++){
if(!strcmp(arg,arg_lista[x])){ // Verifica se o argumento coincide com um parâmetro
if(i==1) // Valida alvo
erro_arg("Especifique um Host!");
switch(x){
case 0: // -t
ping_arg.infinitos = TRUE;
break;
case 1: // -l tamanho
if(i+1 > argn || argumento[i+1] == NULL)
erro_arg("Digite um tamanho valido!");
else
ping_arg.tam = atol(argumento[i+1]);
break;
case 2: // -n numero
if(i+1 > argn || argumento[i+1] == NULL)
erro_arg("Digite um numero valido!");
else
ping_arg.num = atol(argumento[i+1]);
break;
case 3: // -i TTL
if(i+1 > argn || argumento[i+1] == NULL)
erro_arg("Digite um TTL valido!");
else
ping_arg.ttl = (u_short)atol(argumento[i+1]);
break;
case 4: // -s TOS
if(i+1 > argn || argumento[i+1] == NULL)
erro_arg("Digite um TOS valido!");
else
ping_arg.tos = (u_short)atol(argumento[i+1]);
break;
}
break;
}}}
}
// Erro de argumento
void erro_arg(const char* msg)
{
printf("%s\n",msg);
exit(1);
}
Para finalizar, seguem o código e o executável:
Arquivo em Anexo - Security Ðarkers - wWw.darkers.com.br (http://www.darkers.com.br)Bye