/* 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 "elf-int.h" #include "section.h" #include "../../arch/immediate.h" #include "../../arch/processor.h" #include "../../arch/x86/instruction.h" #include "../../panel/log.h" #define _(str) (str) /* Décode les instructions liées à la relocalisation. */ GArchInstruction **decode_elf_relocations(elf_format *, size_t *); /* Déduit les adresses effectives des relocalisations. */ void translate_elf_relocations(elf_format *, GArchInstruction **, size_t); /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * dyn_start = début des informations dynamiques associées. * * dyn_size = taille de la zone associée. * * str_start = début de la zone de chaîne de caractères. * * str_size = taille de la zone de chaînes de caractères. * * * * Description : Déduit les adresses effectives des appels externes. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_elf_format_find_x86_dynamic_symbols(elf_format *format, off_t dyn_start, off_t dyn_size, off_t str_start, off_t str_size) { GArchInstruction **instructions; /* Instructions décodées */ size_t count; /* Quantité d'instructions */ size_t i; /* Boucle de parcours */ instructions = decode_elf_relocations(format, &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. * * 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(elf_format *format, 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 */ Elf_Shdr *sections; /* Groupe de sections trouvées */ size_t sec_count; /* Quantité de données */ size_t i; /* Boucle de parcours */ 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; if (!find_elf_section_content_by_name(format, ".plt", &plt_start, &plt_size, &plt_address)) { log_simple_message(LMT_BAD_BINARY, _("No .plt section found ! Trying to guess it...")); /* FIXME : 64 bits ! */ find_elf_section_by_type(format, SHT_PROGBITS, §ions, &sec_count); for (i = 0; i < sec_count; i++) if (ELF_SHDR(format, §ions[i], sh_entsize) > 0) { get_elf_section_content(format, §ions[i], &plt_start, &plt_size, &plt_address); break; } free(sections); if (i == sec_count) return NULL; } 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, &EXE_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(elf_format *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 */ GArchOperand *operand; /* Valeur du saut */ vmpa_t address; /* Adresse virtuelle finale */ 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 */ 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)) for (j = 0; j < format->rel_count; j++) if (format->relocations[j].address == address) { new_len = strlen(format->relocations[j].name) + 4 + 1; new_name = calloc(new_len, sizeof(char)); snprintf(new_name, new_len, "%s@plt", format->relocations[j].name); g_arch_instruction_get_location(instructions[i], NULL, NULL, &address); routine = g_binary_routine_new(); g_binary_routine_set_name(routine, new_name); g_binary_routine_set_address(routine, address); format->routines = (GBinRoutine **)realloc(format->routines, ++format->routines_count * sizeof(GBinRoutine *)); format->routines[format->routines_count - 1] = routine; } i += 3; } else i++; } }