Veremos como obter informações sobre alguma seção do ELF e exibi-la
Primeira parte em:
http://oscaraleeto.wordpress.com/2007/01/14/elf-for-dummies-parte-1-de-muitas/
Segunda parte em:
http://oscaraleeto.wordpress.com/2007/01/16/%e2%80%9celf-for-dummies%e2%80%9d-parte-2-de-muitas/
elflib.c (adicionar)
************************************
/* Exibe infomacoes da secao informada
int fd: File Descriptor do ELF char *name: Nome da secao Retorna: 1 em caso de erro, 0 caso consiga exibir a secao com sucesso Veja Também: get_section get_section_idx */ int dump_section(int fd, char *name) { Elf32_Shdr *shdr; if ( (shdr = get_section(fd, name)) == NULL) { printf ("[-] Section %s not found.n", name); return 1; } printf ("[=] Section %s:n" " Name: %sn" " Type: 0x%xn" " Flags: 0x%xn" " Addr: 0x%xn" " Offset: 0x%xn" " Size: 0x%xn" " Link: 0x%xn" " Info: 0x%xn" " Align: 0x%xn" " Ent. Size: 0x%xn", name, get_section_name(fd, shdr->sh_name), shdr->sh_type, shdr->sh_flags, shdr->sh_addr, shdr->sh_offset, shdr->sh_size, shdr->sh_link, shdr->sh_info, shdr->sh_addralign, shdr->sh_entsize ); return 0; }
/* Obtem uma secao do ELF atraves do nome int fd: File Descriptor do ELF char *name: Nome da secao Retorna: NULL em caso de erro, Um ponteiro para um Elf32_Shdr, caso consiga obter Veja Também: get_section_name get_section_idx dump_section */ Elf32_Shdr * get_section(int fd, char *name) { Elf32_Ehdr ehdr; Elf32_Shdr *shdr; char *sections, *symbols, *sym; int sections_len, symbols_len, cont; if ( lseek (fd, 0, SEEK_SET) < 0 ) { perror("lseek"); return NULL; } if ( read(fd, &ehdr, sizeof(ehdr)) < 0 ) { perror("read"); return NULL; }
if ( lseek (fd, ehdr.e_shoff, SEEK_SET) < 0 ) { perror("lseek"); return NULL; } sections = (char *) malloc(sections_len = sizeof(*shdr)*ehdr.e_shnum); if (sections == NULL) { perror("malloc"); return NULL; } if ( read(fd, sections, sections_len) < sections_len) { perror("read"); return NULL; } shdr = (Elf32_Shdr *) sections; for ( cont = 0; cont < ehdr.e_shnum; cont++) { if (strncmp(name, get_section_name(fd, shdr->sh_name), sizeof(name)) == 0) return shdr; shdr++; } return NULL; }
/* Obtem o nome de uma secao do ELF, atraves do index int fd: File Descriptor do ELF int idx: Index da secao Retorna: NULL em caso de erro, Um ponteiro para o nome da secao, caso consiga obter Veja Também: get_section get_section_idx dump_section */ char * get_section_name(int fd, int idx) { Elf32_Ehdr ehdr; Elf32_Shdr *shdr; char *sections, *symbols, *sym; int sections_len, symbols_len, cont;
if ( lseek (fd, 0, SEEK_SET) < 0 ) { perror("lseek"); return NULL; } if ( read(fd, &ehdr, sizeof(ehdr)) < 0 ) { perror("read"); return NULL; } if ( lseek (fd, ehdr.e_shoff, SEEK_SET) < 0 ) { perror("lseek"); return NULL; } sections = (char *) malloc(sections_len = sizeof(*shdr)*ehdr.e_shnum); if (sections == NULL) { perror("malloc"); return NULL; } if ( read(fd, sections, sections_len) < sections_len) { perror("read"); return NULL; } shdr = (Elf32_Shdr *) sections; shdr += ehdr.e_shstrndx;
symbols = (char *) malloc(shdr->sh_size); lseek(fd, shdr->sh_offset, SEEK_SET); read(fd, symbols, shdr->sh_size);
sym = (char *) symbols; sym += idx;
free(sections); free(symbols);
if ( lseek (fd, 0, SEEK_SET) < 0 ) { perror("lseek"); return NULL; } return sym; }
************************************
Um exemplo de uso:
dumpsection.c
************************************
#include "elflib.h"
int usage(char **args) { printf ( "usage: %s <filename> <section name>n", args[0] ); exit (0); } int main (int argc, char **argv) { int fd; if (argc != 3) { usage(argv); exit (1); } if ( (fd = open(argv[1], O_RDWR)) < 0 ) { perror("open"); exit(1); } dump_section (fd, argv[2]); }
************************************
Compilando o dumpsection.c e o sample.c,
do exemplo passado:
$ gcc -o dumpsection dumpsection.c
$ gcc -o sample sample.c
Agora para verificar o funcionamento, executamos o dumpsection passando
como parâmetro o nome de um binário em formato ELF e o nome de alguma seção do ELF, como por exemplo .text, .bss, .data:
$ ./dumpsection sample .text
[=] Section .text:
Name: .text
Type: 0×1
Flags: 0×6
Addr: 0×80482d0
Offset: 0×2d0
Size: 0×210
Link: 0×0
Info: 0×0
Align: 0×10
Ent. Size: 0×0
$ ./dumpsection sample .bss
[=] Section .bss:
Name: .bss
Type: 0×8
Flags: 0×3
Addr: 0×8049624
Offset: 0×624
Size: 0×4
Link: 0×0
Info: 0×0
Align: 0×4
Ent. Size: 0×0
$ ./dumpsection sample .data
[=] Section .data:
Name: .data
Type: 0×1
Flags: 0×3
Addr: 0×8049618
Offset: 0×618
Size: 0xc
Link: 0×0
Info: 0×0
Align: 0×4
Ent. Size: 0×0
E assim podemos observar informações de algumas das seções do ELF, informação
que será útil futuramente.
Ainda precisamos evitar o “Segmentation fault” dos exemplos anteriores, ver outras
funções e começar a aplicar o conhecimento que vem sendo adquirido.

lucas machado said
Primeiramente gostaria de agradecer, pois seus códigos para acesso do cabeçalho e seções do elf foram de grande valia! Uma dica construtiva, no nosso caso, tivemos que alterar a função get_section. No loop for, no final do código, o ponteiro shdr não incrementava! É isso. Muito obrigado.