/* 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++;
}
}