Ir para conteúdo
  • Cadastre-se
  • Até onde você conhece a memória do seu computador?


    Leandro Fróes

    No dia 26 de fevereiro o usuário de nick Sai Lay publicou em seu Twitter um cheat sheet sobre segmentação de memória para o Linux :

    5a9e8e7e41679_DXBhvZ4WsAAAJdS.jpglarge.thumb.jpeg.10fa30a217f2cabce6c37d2412e4f0c2.jpeg

     

    Afinal, o que é um cheat sheet? Basicamente um “guia rápido”, uma “folha de consulta” para possíveis dúvidas que você possa ter sobre o assunto abordado. Este tipo de guia pode abordar diversos assuntos, desde comandos/scripts específicos para pentest até definições rápidas sobre registradores e alinhamento de memória (que é o nosso caso).

    A quantidade de informações disponíveis em um cheat sheet é enorme, mas não há sentido em ter tanta informação se não entendermos de fato o que é aquilo. Tendo em vista isto detalharemos um pouco mais um ponto em específico deste guia, deixando o resto para a sua curiosidade :)

    Que tal darmos uma breve olhada em uma seção? Considere o código abaixo:

    #include <stdio.h>
    
    int main(void){
    
      printf("Isto eh um teste\n");
      return 0;
    
    }

    Se utilizarmos o comando readelf --sections test veremos que a seção .data(seção de dados inicializados), por exemplo, tem apenas 16 bytes (em hexa):

     ...
    
      [22] .got              PROGBITS         0000000000200fd8  00000fd8
           0000000000000028  0000000000000008  WA       0     0     8
      [23] .got.plt          PROGBITS         0000000000201000  00001000
           0000000000000020  0000000000000008  WA       0     0     8
      [24] .data             PROGBITS         0000000000201020  00001020
           0000000000000010  0000000000000000  WA       0     0     8
      [25] .bss              NOBITS           0000000000201030  00001030
           0000000000000008  0000000000000000  WA       0     0     1
    …

    Podemos verificar o que tem nestes bytes com objdump -d -j .data test:

    test:     file format elf64-x86-64
    
    
    Disassembly of section .data:
    
    0000000000201020 <__data_start>:
    	...
    
    0000000000201028 <__dso_handle>:
      201028:	28 10 20 00 00 00 00 00                             (. .....

    Mas e se nosso código fosse da seguinte forma:

    #include <stdio.h>
    
    int a = 10;
    
    int main(void){
    
      printf("Isto eh um teste\n");
      return 0;
    
    }

    Note que o tamanho da seção aumentou em 4 bytes, que “coinscidentemente” é o tamanho de uma variável do tipo inteiro na arquitetura onde os testes foram feitos xD:

    ...
    
      [23] .got.plt          PROGBITS         0000000000201000  00001000
           0000000000000020  0000000000000008  WA       0     0     8
      [24] .data             PROGBITS         0000000000201020  00001020
           0000000000000014  0000000000000000  WA       0     0     8
      [25] .bss              NOBITS           0000000000201034  00001034
           0000000000000004  0000000000000000  WA       0     0     1
      [26] .comment          PROGBITS         0000000000000000  00001034
    
    …

    Se olharmos o que há na seção veremos o seguinte resultado:

    test:     file format elf64-x86-64
    
    
    Disassembly of section .data:
    
    0000000000201020 <__data_start>:
    	...
    
    0000000000201028 <__dso_handle>:
      201028:	28 10 20 00 00 00 00 00                             (. .....
    
    0000000000201030 <a>:
      201030:	0a 00 00 00                                         ....

    Agora temos um valor de 4 bytes disponível para nossa variável a que possui o valor 0a em hexa (ou seja, 10 como declarado anteriormente).

     

    Caso a variável fosse, por exemplo, long long a = 10 o resultado seria:

    est:     file format elf64-x86-64
    
    
    Disassembly of section .data:
    
    0000000000201020 <__data_start>:
    	...
    
    0000000000201028 <__dso_handle>:
      201028:	28 10 20 00 00 00 00 00                             (. .....
    
    0000000000201030 <a>:
      201030:	0a 00 00 00 00 00 00 00                             .....…

    8 bytes disponíveis, exatamente o valor que sizeof(long long) representa nesta arquitetura. Não ficou satisfeito ainda? Você também pode olhar as seções com o gdb(GNU Debugger) utilizando o comando maintenance info sections:

    ...
    
     [22]     0x00201000->0x00201020 at 0x00001000: .got.plt ALLOC LOAD DATA HAS_CONTE---Type <return> to continue, or q <return> to quit---
    NTS
     [23]     0x00201020->0x00201038 at 0x00001020: .data ALLOC LOAD DATA HAS_CONTENTS
     [24]     0x00201038->0x00201040 at 0x00001038: .bss ALLOC
     [25]     0x00000000->0x0000001c at 0x00001038: .comment READONLY HAS_CONTENTS
    
    ...

    É extremamente interessante ir a fundo em cheat sheets como este, mais interessante ainda é montar um você mesmo, seja para uso particular ou para disponibilizar para todos. Espera, não entendeu direito os comandos, ordenação dos bytes ou algo desta notícia? Que tal assistir ao curso do CERO? A última aula fala justamente sobre o formato ELF (executáveis Linux) e sua especificação.

    Agora que sua curiosidade foi instigada, que tal aplicar seus conhecimentos sobre arquitetura de computadores e mostrar pra gente? :ph34r:

    Editado por Leandro Fróes



    Feedback do Usuário

    Comentários Recomendados

    Não há comentários para mostrar.



    Crie uma conta ou entre para comentar

    Você precisar ser um membro para fazer um comentário

    Criar uma conta

    Crie uma nova conta em nossa comunidade. É fácil!

    Crie uma nova conta

    Entrar

    Já tem uma conta? Faça o login.

    Entrar Agora

×