/* OpenIDA - Outil d'analyse de fichiers binaires * helper_x86.c - gestion auxiliaire de l'architecture x86 * * Copyright (C) 2009 Cyrille Bagard * * This file is part of OpenIDA. * * OpenIDA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * OpenIDA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "helper_x86.h" #include #include #include #include "elf-int.h" #include "../symbol.h" #include "../../arch/immediate.h" #include "../../arch/processor.h" #include "../../arch/x86/instruction.h" /* symbols.c : Récupère la désignation d'un symbole donné. */ extern const char *get_elf_symbol_name(GElfFormat *, const elf_shdr *, const elf_shdr *, off_t); /* Décode les instructions liées à la relocalisation. */ GArchInstruction **decode_elf_relocations(GElfFormat *, const elf_shdr *, size_t *); /* Déduit les adresses effectives des relocalisations. */ void translate_elf_relocations(GElfFormat *, GArchInstruction **, size_t); /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * relxxx = section .rel.xxx trouvée (zone à traiter). * * dynsym = section .dynsym trouvée (info. dynamiques). * * dynstr = section .dynstr trouvée (chaînes de caractères). * * * * Description : Charge en mémoire la liste des symboles dynamiques. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool load_elf_x86_relocated_symbols(GElfFormat *format, const elf_shdr *relxxx, const elf_shdr *dynsym, const elf_shdr *dynstr) { bool result; /* Bilan à retourner */ off_t rel_start; /* Début de la zone à traiter */ off_t rel_size; /* Taille de cette même zone */ off_t iter; /* Boucle de parcours */ elf_rel reloc; /* Infos de relocalisation */ off_t index; /* Indice de la portion visée */ const char *name; /* Nom du symbole trouvé */ GBinSymbol *symbol; /* Nouveau symbole construit */ result = true; get_elf_section_content(format, relxxx, &rel_start, &rel_size, NULL); printf("rel :: %d -> %d\n", rel_start, rel_start + rel_size); for (iter = rel_start; iter < (rel_start + rel_size); ) { result = read_elf_relocation(format, &iter, &reloc); if (!result) break; switch (ELF_REL_TYPE(format, reloc)) { case R_386_NONE: break; case R_386_JMP_SLOT: index = ELF_REL_SYM(format, reloc); name = get_elf_symbol_name(format, dynsym, dynstr, index); printf("got a jump ! >> %d - %s\n", index, name); if (name == NULL) { /* FIXME */ name = "unknown"; } symbol = g_binary_symbol_new(STP_FUNCTION, name, ELF_REL(format, reloc, r_offset)); g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol); break; default: printf("Relocation not supported (%lld) !\n", ELF_REL_TYPE(format, reloc)); break; } } return result; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * plt = section .plt trouvée (points d'entrées dynamiques). * * * * Description : Déduit les adresses effectives des appels externes. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool find_elf_x86_dynamic_symbols(GElfFormat *format, const elf_shdr *plt) { GArchInstruction **instructions; /* Instructions décodées */ size_t count; /* Quantité d'instructions */ size_t i; /* Boucle de parcours */ instructions = decode_elf_relocations(format, plt, &count); translate_elf_relocations(format, instructions, count); for (i = 0; i < count; i++) /* TODO : free instructions[i] */; if (instructions != NULL) free(instructions); return true; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * plt = section .plt trouvée (points d'entrées dynamiques). * * count = nombre d'instructions lues. [OUT] * * * * Description : Décode les instructions liées à la relocalisation. * * * * Retour : Liste des instructions décodées ou NULL. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction **decode_elf_relocations(GElfFormat *format, const elf_shdr *plt, size_t *count) { GArchInstruction **result; /* Liste à renvoyer */ off_t plt_start; /* Début de section */ off_t plt_size; /* Taille de section */ vmpa_t plt_address; /* Adresse virtuelle associée */ GArchProcessor *proc; /* Processeur pour le décodage */ off_t pos; /* Tête de lecture */ vmpa_t address; /* Adresse virtuelle courante */ GArchInstruction *instr; /* Instruction décodée */ result = NULL; *count = 0; get_elf_section_content(format, plt, &plt_start, &plt_size, &plt_address); proc = get_arch_processor_for_type(APT_386); for (pos = 0; pos < plt_size; ) { address = plt_address + pos; instr = g_arch_processor_decode_instruction(proc, &G_BIN_FORMAT(format)->content[plt_start], &pos, plt_size, 0/* FIXME*/, address); result = (GArchInstruction **)realloc(result, ++(*count) * sizeof(GArchInstruction *)); result[*count - 1] = instr; } return result; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * instructions = listes des instructions à interpréter. * * count = nombre d'instructions lues. * * * * Description : Déduit les adresses effectives des relocalisations. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void translate_elf_relocations(GElfFormat *format, GArchInstruction **instructions, size_t count) { size_t i; /* Boucle de parcours #1 */ X86Opcodes opcode_n0; /* Opcode de l'instruction n */ X86Opcodes opcode_n1; /* Opcode de l'instruction n+1 */ X86Opcodes opcode_n2; /* Opcode de l'instruction n+2 */ const GArchOperand *operand; /* Valeur du saut */ vmpa_t address; /* Adresse virtuelle finale */ GBinSymbol **symbols; /* Liste des symboles existants*/ size_t symbols_count; /* Taille de cette liste */ size_t j; /* Boucle de parcours #2 */ size_t new_len; /* Taille du nouveau nom */ char *new_name; /* Nom avec suffixe @plt */ GBinRoutine *routine; /* Nouvelle routine déduite */ GBinSymbol *symbol; /* Nouveau symbole construit */ for (i = 0; (i + 2) < count; ) { opcode_n0 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i])); opcode_n1 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i + 1])); opcode_n2 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i + 2])); if (opcode_n0 == XOP_JMP_RM1632 && opcode_n1 == XOP_PUSH_IMM1632 && opcode_n2 == XOP_JMP_REL1632) { operand = g_arch_instruction_get_operand(instructions[i], 0); g_imm_operand_to_vmpa_t(G_IMM_OPERAND(operand), &address); if (g_imm_operand_to_vmpa_t(G_IMM_OPERAND(operand), &address)) { symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &symbols_count); for (j = 0; j < symbols_count; j++) if (g_binary_symbol_get_address(symbols[j]) == address) { new_len = strlen(g_binary_symbol_to_string(symbols[j])) + 4 + 1; new_name = calloc(new_len, sizeof(char)); snprintf(new_name, new_len, "%s@plt", g_binary_symbol_to_string(symbols[j])); g_arch_instruction_get_location(instructions[i], NULL, NULL, &address); /* Routine */ routine = g_binary_routine_new(); g_binary_routine_set_name(routine, new_name); g_binary_routine_set_address(routine, address); g_binary_format_add_routine(G_BIN_FORMAT(format), routine); /* Symbole uniquement */ symbol = g_binary_symbol_new(STP_FUNCTION, new_name, address); g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol); } } i += 3; } else i++; } }