diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | src/arch/x86/op_call.c | 4 | ||||
-rw-r--r-- | src/format/elf/e_elf.c | 18 | ||||
-rw-r--r-- | src/format/elf/elf-int.h | 10 | ||||
-rw-r--r-- | src/format/elf/section.c | 186 | ||||
-rw-r--r-- | src/format/elf/section.h | 36 | ||||
-rw-r--r-- | src/format/elf/strings.c | 33 | ||||
-rw-r--r-- | src/format/elf/symbol.c | 112 |
8 files changed, 324 insertions, 94 deletions
@@ -1,3 +1,22 @@ +2008-10-29 Cyrille Bagard <nocbos@gmail.com> + + * src/arch/x86/op_call.c: + Save the type (AIT_CALL) of all kinds of 'call' instruction. + + * src/format/elf/e_elf.c: + Update calls to the functions handling the sections. + + * src/format/elf/elf-int.h: + Move the ELF section header wrapper to section.h. + + * src/format/elf/section.c: + * src/format/elf/section.h: + Rewrite the way to look for given sections. + + * src/format/elf/strings.c: + * src/format/elf/symbol.c: + Do not rely on section names anymore. + 2008-10-27 Cyrille Bagard <nocbos@gmail.com> * src/arch/x86/instruction.h: diff --git a/src/arch/x86/op_call.c b/src/arch/x86/op_call.c index 980a5e7..7641214 100644 --- a/src/arch/x86/op_call.c +++ b/src/arch/x86/op_call.c @@ -57,6 +57,8 @@ asm_x86_instr *x86_read_instr_call_rel1632(const uint8_t *data, off_t *pos, off_ ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + ASM_INSTRUCTION(result)->type = AIT_CALL; + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_REL1632, oprsize, offset)) { free(result); @@ -95,6 +97,8 @@ asm_x86_instr *x86_read_instr_call_rm1632(const uint8_t *data, off_t *pos, off_t ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + ASM_INSTRUCTION(result)->type = AIT_CALL; + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_RM1632, oprsize)) { free(result); diff --git a/src/format/elf/e_elf.c b/src/format/elf/e_elf.c index c2e49b1..a9eacea 100644 --- a/src/format/elf/e_elf.c +++ b/src/format/elf/e_elf.c @@ -71,7 +71,7 @@ elf_format *load_elf(const uint8_t *content, off_t length) EXE_FORMAT(result)->length = length; EXE_FORMAT(result)->get_def_parts = (get_def_parts_fc)get_elf_default_code_parts; - EXE_FORMAT(result)->find_section = (find_section_fc)find_elf_section; + EXE_FORMAT(result)->find_section = (find_section_fc)find_elf_section_content_by_name; EXE_FORMAT(result)->get_symbols = (get_symbols_fc)get_elf_symbols; EXE_FORMAT(result)->resolve_symbol = (resolve_symbol_fc)resolve_elf_symbol; @@ -142,7 +142,7 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count) if (format->sec_size > 0) { - if (find_elf_section(format, ".plt", &offset, &size, &voffset)) + if (find_elf_section_content_by_name(format, ".plt", &offset, &size, &voffset)) { part = create_bin_part(); @@ -154,7 +154,7 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count) } - if (find_elf_section(format, ".init", &offset, &size, &voffset)) + if (find_elf_section_content_by_name(format, ".init", &offset, &size, &voffset)) { part = create_bin_part(); @@ -166,7 +166,7 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count) } - if (find_elf_section(format, ".text", &offset, &size, &voffset)) + if (find_elf_section_content_by_name(format, ".text", &offset, &size, &voffset)) { part = create_bin_part(); @@ -178,7 +178,7 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count) } - if (find_elf_section(format, ".fini", &offset, &size, &voffset)) + if (find_elf_section_content_by_name(format, ".fini", &offset, &size, &voffset)) { part = create_bin_part(); @@ -202,15 +202,15 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count) memcpy(&shdr, &EXE_FORMAT(format)->content[offset], format->header.e_shentsize); - if (ELF_SHDR(format, shdr, sh_flags) & SHF_EXECINSTR) + if (ELF_SHDR(format, &shdr, sh_flags) & SHF_EXECINSTR) { part = create_bin_part(); /* TODO : nom */ - set_bin_part_values(part, ELF_SHDR(format, shdr, sh_offset), - ELF_SHDR(format, shdr, sh_size), - ELF_SHDR(format, shdr, sh_addr)); + set_bin_part_values(part, ELF_SHDR(format, &shdr, sh_offset), + ELF_SHDR(format, &shdr, sh_size), + ELF_SHDR(format, &shdr, sh_addr)); result = (bin_part **)realloc(result, ++(*count) * sizeof(bin_part *)); result[*count - 1] = part; diff --git a/src/format/elf/elf-int.h b/src/format/elf/elf-int.h index 02cc2dd..0931654 100644 --- a/src/format/elf/elf-int.h +++ b/src/format/elf/elf-int.h @@ -74,16 +74,6 @@ struct _elf_format -/* En-tête de section ELF */ -typedef union _Elf_Shdr -{ - Elf32_Shdr section32; /* Version 32 bits */ - Elf64_Shdr section64; /* Version 64 bits */ - -} Elf_Shdr; - -#define ELF_SHDR(fmt, sec, fld) (fmt->is_32b ? sec.section32.fld : sec.section64.fld) - /* En-tête de programme ELF */ typedef union _Elf_Phdr diff --git a/src/format/elf/section.c b/src/format/elf/section.c index f16e002..7ad8363 100644 --- a/src/format/elf/section.c +++ b/src/format/elf/section.c @@ -32,13 +32,6 @@ -/* Teste si une section correspond à celle recherchée. */ -bool find_target_elf_section(const elf_format *, const char *, Elf32_Off, Elf32_Shdr *); - - - - - /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * @@ -75,12 +68,11 @@ bool read_elf_section_names(elf_format *format) /****************************************************************************** * * -* Paramètres : format = description de l'exécutable à consulter. * -* target = nom de la section recherchée. * -* offset = position de la section à tester. * -* data = description de la section trouvée. [OUT] * +* Paramètres : format = description de l'exécutable à consulter. * +* name = nom de la section recherchée. * +* section = ensemble d'informations à faire remonter. [OUT] * * * -* Description : Teste si une section correspond à celle recherchée. * +* Description : Recherche une section donnée au sein de binaire par nom. * * * * Retour : Bilan de l'opération. * * * @@ -88,20 +80,23 @@ bool read_elf_section_names(elf_format *format) * * ******************************************************************************/ -bool find_target_elf_section(const elf_format *format, const char *target, Elf32_Off offset, Elf32_Shdr *data) +bool find_elf_section_by_name(const elf_format *format, const char *name, Elf_Shdr *section) { - bool result; /* Conclusion à retourner */ - Elf32_Shdr section; /* Section à analyser */ + bool result; /* Bilan à retourner */ + uint16_t i; /* Boucle de parcours */ - result = false; + /* Si on perd notre temps... */ + if (format->sec_size == 0) return false; - if ((offset + sizeof(Elf32_Shdr)) >= EXE_FORMAT(format)->length) return false; + result = false; - memcpy(§ion, &EXE_FORMAT(format)->content[offset], sizeof(Elf32_Shdr)); + for (i = 0; i < format->header.e_shnum && !result; i++) + { + find_elf_section_by_index(format, i, section); - result = (strcmp(target, &format->sec_names[section.sh_name]) == 0); + result = (strcmp(name, &format->sec_names[ELF_SHDR(format, section, sh_name)]) == 0); - if (result) *data = section; + } return result; @@ -110,13 +105,109 @@ bool find_target_elf_section(const elf_format *format, const char *target, Elf32 /****************************************************************************** * * +* Paramètres : format = description de l'exécutable à consulter. * +* type = type de la section recherchée. * +* sections = tableau d'informations à faire remonter. [OUT] * +* count = nombre d'éléments présents dans le tableau. [OUT] * +* * +* Description : Recherche une section donnée au sein de binaire par type. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool find_elf_section_by_type(const elf_format *format, uint16_t type, Elf_Shdr **sections, size_t *count) +{ + uint16_t i; /* Boucle de parcours */ + Elf_Shdr section; /* Section à analyser */ + + *sections = NULL; + *count = 0; + + for (i = 0; i < format->header.e_shnum; i++) + { + find_elf_section_by_index(format, i, §ion); + + if (type == ELF_SHDR(format, §ion, sh_type)) + { + *sections = (Elf_Shdr *)realloc(*sections, ++(*count) * sizeof(Elf_Shdr)); + (*sections)[*count - 1] = section; + } + + } + + return (*count > 0); + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* index = indice de la section recherchée. * +* section = ensemble d'informations à faire remonter. [OUT] * +* * +* Description : Recherche une section donnée au sein de binaire par indice. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool find_elf_section_by_index(const elf_format *format, uint16_t index, Elf_Shdr *section) +{ + off_t offset; /* Emplacement à venir lire */ + + if (index >= format->header.e_shnum) return false; + + offset = format->header.e_shoff + format->header.e_shentsize * index; + + memcpy(section, &EXE_FORMAT(format)->content[offset], ELF_SIZEOF_SHDR(format)); + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* section = section à consulter. * +* offset = position de la section trouvée. [OUT] * +* size = taille de la section trouvée. [OUT] * +* voffset = adresse virtuelle de la section trouvée. [OUT] * +* * +* Description : Fournit les adresses et taille contenues dans une section. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void get_elf_section_content(const elf_format *format, const Elf_Shdr *section, off_t *offset, off_t *size, uint64_t *voffset) +{ + *offset = ELF_SHDR(format, section, sh_offset); + *size = ELF_SHDR(format, section, sh_size); + + if (voffset != NULL) + *voffset = ELF_SHDR(format, section, sh_addr); + +} + + +/****************************************************************************** +* * * Paramètres : format = description de l'exécutable à consulter. * -* target = nom de la section recherchée. * +* name = nom de la section recherchée. * * offset = position de la section trouvée. [OUT] * * size = taille de la section trouvée. [OUT] * * voffset = adresse virtuelle de la section trouvée. [OUT] * * * -* Description : Recherche une section donnée au sein de binaire. * +* Description : Recherche une zone donnée au sein de binaire par nom. * * * * Retour : Bilan de l'opération. * * * @@ -124,35 +215,46 @@ bool find_target_elf_section(const elf_format *format, const char *target, Elf32 * * ******************************************************************************/ -bool find_elf_section(const elf_format *format, const char *target, off_t *offset, off_t *size, uint64_t *voffset) +bool find_elf_section_content_by_name(const elf_format *format, const char *name, off_t *offset, off_t *size, uint64_t *voffset) { - bool result; - Elf32_Half i; - Elf32_Shdr data; + bool result; /* Bilan à retourner */ + Elf_Shdr section; /* Section trouvée ou non */ - /* Si on perd notre temps... */ - if (format->sec_size == 0) return false; + result = find_elf_section_by_name(format, name, §ion); - result = false; + if (result) + get_elf_section_content(format, §ion, offset, size, voffset); - for (i = 0; i < format->header.e_shnum; i++) - { - if (i == format->header.e_shstrndx) continue; + return result; + +} - if (find_target_elf_section(format, target, - format->header.e_shoff + format->header.e_shentsize * i, &data)) - { - *offset = data.sh_offset; - *size = data.sh_size; - if (voffset != NULL) - *voffset = data.sh_addr; +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* index = indice de la section recherchée. * +* offset = position de la section trouvée. [OUT] * +* size = taille de la section trouvée. [OUT] * +* voffset = adresse virtuelle de la section trouvée. [OUT] * +* * +* Description : Recherche une zone donnée au sein de binaire par indice. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - result = true; +bool find_elf_section_content_by_index(const elf_format *format, uint16_t index, off_t *offset, off_t *size, uint64_t *voffset) +{ + bool result; /* Bilan à retourner */ + Elf_Shdr section; /* Section trouvée ou non */ - } + result = find_elf_section_by_index(format, index, §ion); - } + if (result) + get_elf_section_content(format, §ion, offset, size, voffset); return result; diff --git a/src/format/elf/section.h b/src/format/elf/section.h index b84fe76..6bc3a75 100644 --- a/src/format/elf/section.h +++ b/src/format/elf/section.h @@ -25,15 +25,47 @@ #define _FORMAT_ELF_SECTION_H +#include <elf.h> + + #include "e_elf.h" +/* En-tête de section ELF */ +typedef union _Elf_Shdr +{ + Elf32_Shdr section32; /* Version 32 bits */ + Elf64_Shdr section64; /* Version 64 bits */ + +} Elf_Shdr; + + +#define ELF_SIZEOF_SHDR(fmt) (fmt->is_32b ? sizeof(Elf32_Shdr) : sizeof(Elf64_Shdr)) + +#define ELF_SHDR(fmt, shdr, fld) (fmt->is_32b ? (shdr)->section32.fld : (shdr)->section64.fld) + + /* Charge en mémoire la liste humaine des sections. */ bool read_elf_section_names(elf_format *); -/* Recherche une section donnée au sein de binaire. */ -bool find_elf_section(const elf_format *, const char *, off_t *, off_t *, uint64_t *); +/* Recherche une section donnée au sein de binaire par nom. */ +bool find_elf_section_by_name(const elf_format *, const char *, Elf_Shdr *); + +/* Recherche une section donnée au sein de binaire par type. */ +bool find_elf_section_by_type(const elf_format *, uint16_t, Elf_Shdr **, size_t *); + +/* Recherche une section donnée au sein de binaire par indice. */ +bool find_elf_section_by_index(const elf_format *, uint16_t, Elf_Shdr *); + +/* Fournit les adresses et taille contenues dans une section. */ +void get_elf_section_content(const elf_format *, const Elf_Shdr *, off_t *, off_t *, uint64_t *); + +/* Recherche une zone donnée au sein de binaire par nom. */ +bool find_elf_section_content_by_name(const elf_format *, const char *, off_t *, off_t *, uint64_t *); + +/* Recherche une zone donnée au sein de binaire par indice. */ +bool find_elf_section_content_by_index(const elf_format *, uint16_t, off_t *, off_t *, uint64_t *); diff --git a/src/format/elf/strings.c b/src/format/elf/strings.c index 3d373a6..049f6d4 100644 --- a/src/format/elf/strings.c +++ b/src/format/elf/strings.c @@ -56,9 +56,38 @@ bool find_all_elf_strings(elf_format *format) off_t str_start; /* Début de section */ off_t str_size; /* Taille de section */ uint64_t str_vaddr; /* Adresse virtuelle associée */ + Elf_Shdr *sections; /* Groupe de sections trouvées */ + size_t count; /* Quantité de données */ + size_t i; /* Boucle de parcours */ + + /* Données en lecture seule */ + + if (find_elf_section_content_by_name(format, ".rodata", &str_start, &str_size, &str_vaddr)) + parse_elf_string_data(format, str_start, str_size, str_vaddr); + + else + { + find_elf_section_by_type(format, SHT_PROGBITS, §ions, &count); - if (find_elf_section(format, ".rodata", &str_start, &str_size, &str_vaddr)) + for (i = 0; i < count; i++) + if (ELF_SHDR(format, §ions[i], sh_flags) == SHF_ALLOC + || (ELF_SHDR(format, §ions[i], sh_flags) & SHF_STRINGS)) + { + get_elf_section_content(format, §ions[i], &str_start, &str_size, &str_vaddr); + parse_elf_string_data(format, str_start, str_size, str_vaddr); + } + + } + + /* Chaîne de caractères déclarées */ + + find_elf_section_by_type(format, SHT_STRTAB, §ions, &count); + + for (i = 0; i < count; i++) + { + get_elf_section_content(format, §ions[i], &str_start, &str_size, &str_vaddr); parse_elf_string_data(format, str_start, str_size, str_vaddr); + } return true; @@ -85,6 +114,8 @@ bool parse_elf_string_data(elf_format *format, const off_t start, const off_t si off_t i; /* Boucle de parcours */ off_t end; /* Position de fin de chaîne */ + if (vaddress == 0) return false; + for (i = start; i < (start + size); i++) if (isprint(EXE_FORMAT(format)->content[i])) { diff --git a/src/format/elf/symbol.c b/src/format/elf/symbol.c index 8fa5690..4b7740d 100644 --- a/src/format/elf/symbol.c +++ b/src/format/elf/symbol.c @@ -84,74 +84,105 @@ bool load_elf_symbol_table_64(elf_format *, const off_t *, const off_t *, const bool load_elf_symbols(elf_format *format) { bool result; /* Bilan à retourner */ - - + Elf_Shdr *sections; /* Groupe de sections trouvées */ + size_t count; /* Quantité de données */ + size_t i; /* Boucle de parcours */ + Elf_Shdr section; /* Section trouvée ou non */ off_t sym_start; /* Début de section */ off_t sym_size; /* Taille de section */ off_t str_start; /* Début de section */ off_t str_size; /* Taille de section */ - - - off_t plt_start; /* Début de section */ - off_t plt_size; /* Taille de section */ + off_t rel_start; /* Début de section */ + off_t rel_size; /* Taille de section */ off_t dyn_start; /* Début de section */ off_t dyn_size; /* Taille de section */ asm_instr **instructions; /* Instructions décodées */ - size_t count; /* Quantité d'instructions */ - result = find_elf_section(format, ".symtab", &sym_start, &sym_size, NULL); + result = true; - result &= find_elf_section(format, ".strtab", &str_start, &str_size, NULL); + /* Table des symboles */ - if (result) + find_elf_section_by_type(format, SHT_SYMTAB, §ions, &count); + + for (i = 0; i < count; i++) { + /* Section ".symtab" */ + get_elf_section_content(format, §ions[i], &sym_start, &sym_size, NULL); + /* Section ".strtab" */ - result = load_elf_symbol_table_32(format, &sym_start, &sym_size, &str_start, &str_size); + result &= find_elf_section_by_index(format, ELF_SHDR(format, §ions[i], sh_link), §ion); + get_elf_section_content(format, §ion, &str_start, &str_size, NULL); + if (result) + { - } + result = load_elf_symbol_table_32(format, &sym_start, &sym_size, &str_start, &str_size); + } + } - result = find_elf_section(format, ".rel.plt", &plt_start, &plt_size, NULL); + /* Relocalisations dynamiques */ - result &= find_elf_section(format, ".dynsym", &dyn_start, &dyn_size, NULL); + find_elf_section_by_type(format, SHT_REL, §ions, &count); - result &= find_elf_section(format, ".dynstr", &str_start, &str_size, NULL); + for (i = 0; i < count; i++) + { + /* Section ".rel.xxx" */ + get_elf_section_content(format, §ions[i], &rel_start, &rel_size, NULL); + /* Section ".dynsym" */ - if (result) - { + result &= find_elf_section_by_index(format, ELF_SHDR(format, §ions[i], sh_link), §ion); + + get_elf_section_content(format, §ion, &dyn_start, &dyn_size, NULL); + /* Section ".dynstr" */ + result &= find_elf_section_by_index(format, ELF_SHDR(format, §ion, sh_link), §ion); - result = load_elf_relocation_table(format, &plt_start, &plt_size, &dyn_start, &dyn_size, &str_start, &str_size); + get_elf_section_content(format, §ion, &str_start, &str_size, NULL); + /* Récupération (première partie) */ if (result) { - instructions = decode_elf_relocations(format, &count); - translate_elf_relocations(format, instructions, count); + result = load_elf_relocation_table(format, &rel_start, &rel_size, &dyn_start, &dyn_size, &str_start, &str_size); - /* TODO : free instructions */ + } + } + + free(sections); + + /* Récupération (seconde partie) */ + + if (result) + { + instructions = decode_elf_relocations(format, &count); + + translate_elf_relocations(format, instructions, count); + + /* TODO : free instructions */ } + + return result; } @@ -446,6 +477,9 @@ asm_instr **decode_elf_relocations(elf_format *format, size_t *count) off_t rel_start; /* Début de section */ off_t rel_size; /* Taille de section */ uint64_t rel_vaddress; /* Adresse virtuelle associée */ + Elf_Shdr *sections; /* Groupe de sections trouvées */ + size_t sec_count; /* Quantité de données */ + size_t i; /* Boucle de parcours */ off_t pos; /* Tête de lecture */ uint64_t offset; /* Adresse virtuelle courante */ asm_instr *instr; /* Instruction décodée */ @@ -456,17 +490,35 @@ asm_instr **decode_elf_relocations(elf_format *format, size_t *count) result = NULL; *count = 0; - if (find_elf_section(format, ".plt", &rel_start, &rel_size, &rel_vaddress)) - for (pos = 0; pos < rel_size; ) - { - offset = rel_vaddress + pos; + if (!find_elf_section_content_by_name(format, ".plt", &rel_start, &rel_size, &rel_vaddress)) + { + printf("No .plt section found ! Trying to guess it...\n"); - instr = decode_instruction(proc, &EXE_FORMAT(format)->content[rel_start], &pos, rel_size, offset); + find_elf_section_by_type(format, SHT_PROGBITS, §ions, &sec_count); - result = (asm_instr **)realloc(result, ++(*count) * sizeof(asm_instr *)); - result[*count - 1] = instr; + for (i = 0; i < sec_count; i++) + if (ELF_SHDR(format, §ions[i], sh_entsize) > 0) + { + get_elf_section_content(format, §ions[i], &rel_start, &rel_size, &rel_vaddress); + break; + } - } + free(sections); + + if (i == sec_count) return NULL; + + } + + for (pos = 0; pos < rel_size; ) + { + offset = rel_vaddress + pos; + + instr = decode_instruction(proc, &EXE_FORMAT(format)->content[rel_start], &pos, rel_size, offset); + + result = (asm_instr **)realloc(result, ++(*count) * sizeof(asm_instr *)); + result[*count - 1] = instr; + + } return result; @@ -497,7 +549,7 @@ void translate_elf_relocations(elf_format *format, asm_instr **instructions, siz for (i = 0; (i + 2) < count; ) { - if (instructions[i]->type == AIT_JUMP + if ((instructions[i]->type == AIT_JUMP || instructions[i]->type == AIT_CALL) && instructions[i + 1]->type == AIT_PUSH && instructions[i + 2]->type == AIT_JUMP) { |