From 10deb6bbbeeaacfec577f5b24c5f821492af77f3 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 19 Oct 2008 15:05:04 +0000 Subject: Registered symbols found in the PLT. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@35 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 39 ++++++ src/arch/instruction-int.h | 22 ++++ src/arch/instruction.c | 2 + src/arch/operand.c | 118 ++++++++++++++++++ src/arch/operand.h | 3 + src/arch/processor.c | 5 + src/arch/x86/instruction.h | 4 + src/arch/x86/op_add.c | 35 ++++++ src/arch/x86/op_jump.c | 86 +++++++++++++ src/arch/x86/op_push.c | 6 + src/arch/x86/opcodes.h | 9 ++ src/arch/x86/operand.c | 26 +++- src/arch/x86/processor.c | 18 ++- src/format/elf/e_elf.c | 12 ++ src/format/elf/elf-int.h | 33 +++++ src/format/elf/symbol.c | 305 +++++++++++++++++++++++++++++++++++++++++++-- 16 files changed, 703 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 917afe6..48ea906 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2008-10-19 Cyrille Bagard + + * src/arch/instruction.c: + Define a type for the 'db' instruction. + + * src/arch/instruction-int.h: + Add more information about instructions: virtual address and type. + + * src/arch/operand.c: + * src/arch/operand.h: + Add a function to get the immediate value of an operand. + + * src/arch/processor.c: + Save the virtual address of a decoded instruction. + + * src/arch/x86/instruction.h: + * src/arch/x86/op_add.c: + * src/arch/x86/opcodes.h: + Register some new instructions. + + * src/arch/x86/operand.c: + Fix a bug when reading relative addresses (16/32 bits). + + * src/arch/x86/op_jump.c: + * src/arch/x86/op_push.c: + Register some new instructions and define their type. + + * src/arch/x86/processor.c: + Register some new instructions. Fix the case of the 0x00 opcode (add). + + * src/format/elf/e_elf.c: + Load .plt as executable section. + + * src/format/elf/elf-int.h: + Try to support both 32 and 64 bits architectures (Elf_Rel and Elf_Sym). + + * src/format/elf/symbol.c: + Register symbols found in the PLT. + 2008-10-12 Cyrille Bagard * src/binary.c: diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h index 72c7914..895c29f 100644 --- a/src/arch/instruction-int.h +++ b/src/arch/instruction-int.h @@ -40,11 +40,33 @@ #define DB_OPCODE 0x00 + +/* Typage des instructions rencontrées */ +typedef enum _AsmInstrType +{ + AIT_OTHER, /* Instruction inintéressante */ + + AIT_DB, /* Instruction non décodée */ + + AIT_PUSH, /* Empilement de valeur */ + AIT_POP, /* Dépilement de valeur */ + AIT_JUMP, /* Saut à une adresse */ + + AIT_CALL /* Appel d'une fonction */ + +} AsmInstrType; + + + /* Définition générique d'une instruction */ struct _asm_instr { uint8_t opcode; + uint64_t vaddress; /* Adresse virtuelle associée */ + + AsmInstrType type; /* Type d'instruction */ + asm_operand **operands; /* Liste des opérandes */ size_t operands_count; /* Nbre. d'opérandes utilisées */ diff --git a/src/arch/instruction.c b/src/arch/instruction.c index e199dc5..ada3d58 100644 --- a/src/arch/instruction.c +++ b/src/arch/instruction.c @@ -53,6 +53,8 @@ asm_instr *create_db_instruction(const uint8_t *data, off_t *pos, off_t len) result->opcode = DB_OPCODE; + result->type = AIT_DB; + /* TODO: check result */ result->operands = (asm_operand **)calloc(1, sizeof(asm_operand *)); result->operands[0] = (asm_operand *)calloc(1, sizeof(asm_operand)); diff --git a/src/arch/operand.c b/src/arch/operand.c index 53e652c..fa43416 100644 --- a/src/arch/operand.c +++ b/src/arch/operand.c @@ -367,6 +367,124 @@ bool fill_relimm_operand(asm_operand *operand, AsmOperandSize size, const uint8_ /****************************************************************************** * * +* Paramètres : operand = structure dont le contenu est à définir. * +* size = taille de l'opérande souhaitée. * +* ... = zone d'enregistrement prévue. * +* * +* Description : Récupère la valeur d'une opérande sur x bits. * +* * +* Retour : true si l'opération s'est effectuée avec succès, false sinon.* +* * +* Remarques : - * +* * +******************************************************************************/ + +bool get_imm_operand_value(asm_operand *operand, AsmOperandSize size, ...) +{ + bool result; /* Bilan à retourner */ + va_list ap; /* Récupération d'argument */ + uint8_t *val8; /* Valeur sur 8 bits */ + uint16_t *val16; /* Valeur sur 16 bits */ + uint32_t *val32; /* Valeur sur 32 bits */ + uint64_t *val64; /* Valeur sur 64 bits */ + + result = true; + + va_start(ap, size); + + switch (size) + { + case AOS_8_BITS: + val8 = va_arg(ap, uint8_t *); + switch (operand->size) + { + case AOS_8_BITS: + *val8 = operand->value.val8; + break; + case AOS_16_BITS: + result = false; + break; + case AOS_32_BITS: + result = false; + break; + case AOS_64_BITS: + result = false; + break; + } + break; + + case AOS_16_BITS: + val16 = va_arg(ap, uint16_t *); + switch (operand->size) + { + case AOS_8_BITS: + *val16 = operand->value.val8; + break; + case AOS_16_BITS: + *val16 = operand->value.val16; + break; + case AOS_32_BITS: + result = false; + break; + case AOS_64_BITS: + result = false; + break; + } + break; + + case AOS_32_BITS: + val32 = va_arg(ap, uint32_t *); + switch (operand->size) + { + case AOS_8_BITS: + *val32 = operand->value.val8; + break; + case AOS_16_BITS: + *val32 = operand->value.val16; + break; + case AOS_32_BITS: + *val32 = operand->value.val32; + break; + case AOS_64_BITS: + result = false; + break; + } + break; + + case AOS_64_BITS: + val64 = va_arg(ap, uint64_t *); + switch (operand->size) + { + case AOS_8_BITS: + *val64 = operand->value.val8; + break; + case AOS_16_BITS: + *val64 = operand->value.val16; + break; + case AOS_32_BITS: + *val64 = operand->value.val32; + break; + case AOS_64_BITS: + *val64 = operand->value.val64; + break; + } + break; + + default: + result = false; + break; + + } + + va_end(ap); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : operand = instruction à traiter. * * buffer = tampon de sortie mis à disposition. [OUT] * * len = taille de ce tampon. * diff --git a/src/arch/operand.h b/src/arch/operand.h index a05f819..0a00d9f 100644 --- a/src/arch/operand.h +++ b/src/arch/operand.h @@ -76,6 +76,9 @@ bool fill_imm_operand_with_value(asm_operand *, AsmOperandSize, ...); /* Crée une opérande contenant une valeur relative sur x bits. */ bool fill_relimm_operand(asm_operand *, AsmOperandSize, const uint8_t *, off_t *, off_t, uint64_t); +/* Récupère la valeur d'une opérande sur x bits. */ +bool get_imm_operand_value(asm_operand *, AsmOperandSize, ...); + /* Traduit une opérande de valeur immédiate en texte. */ void print_imm_operand(const asm_operand *, char *, size_t, AsmSyntax); diff --git a/src/arch/processor.c b/src/arch/processor.c index 373222f..fc9f773 100644 --- a/src/arch/processor.c +++ b/src/arch/processor.c @@ -24,12 +24,14 @@ #include "processor.h" +#include "instruction-int.h" #include "processor-int.h" + /****************************************************************************** * * * Paramètres : proc = architecture visée par la procédure. * @@ -66,6 +68,9 @@ asm_instr *decode_instruction(const asm_processor *proc, const uint8_t *data, of } + result->vaddress = offset; + + return result; diff --git a/src/arch/x86/instruction.h b/src/arch/x86/instruction.h index 8ef603f..baf911d 100644 --- a/src/arch/x86/instruction.h +++ b/src/arch/x86/instruction.h @@ -38,6 +38,8 @@ typedef struct _asm_x86_instr asm_x86_instr; /* Enumération de tous les opcodes */ typedef enum _X86Opcodes { + X86_OP_ADD_RM8_R8, /* add (0x00) */ + X86_OP_SUB_R1632_RM1632, /* sub ([0x66] 0x29) */ X86_OP_XOR_RM8_R8, /* xor (0x30) */ @@ -145,12 +147,14 @@ typedef enum _X86Opcodes X86_OP_INT, /* int (0xcd) */ X86_OP_CALL_REL1632, /* call ([0x66] 0xe8) */ + X86_OP_JMP_REL1632, /* jmp ([0x66] 0xe9) */ X86_OP_JMP_8, /* jmp (0xeb) */ X86_OP_HLT, /* hlt (0xf4) */ X86_OP_CALL_RM1632, /* call ([0x66] 0xff 2) */ + X86_OP_JMP_RM1632, /* jmp ([0x66] 0xff 4) */ X86_OP_PUSH_RM1632, /* push ([0x66] 0xff 6) */ X86_OP_COUNT diff --git a/src/arch/x86/op_add.c b/src/arch/x86/op_add.c index 52b998f..f42c8f9 100644 --- a/src/arch/x86/op_add.c +++ b/src/arch/x86/op_add.c @@ -104,3 +104,38 @@ asm_x86_instr *x86_read_instr_add_imm1632_to_rm1632(const uint8_t *data, off_t * return result; } + + +/****************************************************************************** +* * +* Paramètres : data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* offset = adresse virtuelle de l'instruction. * +* proc = architecture ciblée par le désassemblage. * +* * +* Description : Décode une instruction de type 'add' (8 bits). * +* * +* Retour : Instruction mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_instr *x86_read_instr_add_rm8_r8(const uint8_t *data, off_t *pos, off_t len, uint64_t offset, const asm_x86_processor *proc) +{ + asm_x86_instr *result; /* Instruction à retourner */ + + result = (asm_x86_instr *)calloc(1, sizeof(asm_x86_instr)); + + ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + + if (!x86_read_two_operands(result, data, pos, len, X86_OTP_RM8, X86_OTP_R8)) + { + free(result); + return NULL; + } + + return result; + +} diff --git a/src/arch/x86/op_jump.c b/src/arch/x86/op_jump.c index b301b10..3739b24 100644 --- a/src/arch/x86/op_jump.c +++ b/src/arch/x86/op_jump.c @@ -54,6 +54,8 @@ asm_x86_instr *x86_read_instr_je_8(const uint8_t *data, off_t *pos, off_t len, u ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + ASM_INSTRUCTION(result)->type = AIT_JUMP; + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_REL8, offset)) { free(result); @@ -89,6 +91,8 @@ asm_x86_instr *x86_read_instr_jne_8(const uint8_t *data, off_t *pos, off_t len, ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + ASM_INSTRUCTION(result)->type = AIT_JUMP; + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_REL8, offset)) { free(result); @@ -124,6 +128,8 @@ asm_x86_instr *x86_read_instr_jmp_8(const uint8_t *data, off_t *pos, off_t len, ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + ASM_INSTRUCTION(result)->type = AIT_JUMP; + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_REL8, offset)) { free(result); @@ -133,3 +139,83 @@ asm_x86_instr *x86_read_instr_jmp_8(const uint8_t *data, off_t *pos, off_t len, return result; } + + +/****************************************************************************** +* * +* Paramètres : data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* offset = adresse virtuelle de l'instruction. * +* proc = architecture ciblée par le désassemblage. * +* * +* Description : Décode une instruction de type 'jmp' (grand saut relatif). * +* * +* Retour : Instruction mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_instr *x86_read_instr_jmp_rel1632(const uint8_t *data, off_t *pos, off_t len, uint64_t offset, const asm_x86_processor *proc) +{ + asm_x86_instr *result; /* Instruction à retourner */ + AsmOperandSize oprsize; /* Taille des opérandes */ + + result = (asm_x86_instr *)calloc(1, sizeof(asm_x86_instr)); + + oprsize = switch_x86_operand_size_if_needed(proc, data, pos); + + ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + + ASM_INSTRUCTION(result)->type = AIT_JUMP; + + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_REL1632, oprsize, offset)) + { + free(result); + return NULL; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* offset = adresse virtuelle de l'instruction. * +* proc = architecture ciblée par le désassemblage. * +* * +* Description : Décode une instruction de type 'jmp' (saut en mémoire). * +* * +* Retour : Instruction mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_instr *x86_read_instr_jmp_rm1632(const uint8_t *data, off_t *pos, off_t len, uint64_t offset, const asm_x86_processor *proc) +{ + asm_x86_instr *result; /* Instruction à retourner */ + AsmOperandSize oprsize; /* Taille des opérandes */ + + result = (asm_x86_instr *)calloc(1, sizeof(asm_x86_instr)); + + oprsize = switch_x86_operand_size_if_needed(proc, data, pos); + + ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + + ASM_INSTRUCTION(result)->type = AIT_JUMP; + + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_RM1632, oprsize)) + { + free(result); + return NULL; + } + + return result; + +} diff --git a/src/arch/x86/op_push.c b/src/arch/x86/op_push.c index ce76919..f51bd6f 100644 --- a/src/arch/x86/op_push.c +++ b/src/arch/x86/op_push.c @@ -58,6 +58,8 @@ asm_x86_instr *x86_read_instr_push_imm1632(const uint8_t *data, off_t *pos, off_ ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + ASM_INSTRUCTION(result)->type = AIT_PUSH; + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_IMM1632, oprsize)) { free(result); @@ -96,6 +98,8 @@ asm_x86_instr *x86_read_instr_push_r1632(const uint8_t *data, off_t *pos, off_t ASM_INSTRUCTION(result)->opcode = data[*pos]; + ASM_INSTRUCTION(result)->type = AIT_PUSH; + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_OP_R1632, oprsize, 0x50)) { free(result); @@ -134,6 +138,8 @@ asm_x86_instr *x86_read_instr_push_rm1632(const uint8_t *data, off_t *pos, off_t ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + ASM_INSTRUCTION(result)->type = AIT_PUSH; + if (!x86_read_one_operand(result, data, pos, len, X86_OTP_RM1632, oprsize)) { free(result); diff --git a/src/arch/x86/opcodes.h b/src/arch/x86/opcodes.h index cbadcf5..70d41b8 100644 --- a/src/arch/x86/opcodes.h +++ b/src/arch/x86/opcodes.h @@ -43,6 +43,9 @@ asm_x86_instr *x86_read_instr_add_imm8_to_rm1632(const uint8_t *, off_t *, off_t /* Décode une instruction de type 'add' (16 ou 32 bits). */ asm_x86_instr *x86_read_instr_add_imm1632_to_rm1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); +/* Décode une instruction de type 'add' (8 bits). */ +asm_x86_instr *x86_read_instr_add_rm8_r8(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); + /* Décode une instruction de type 'and' (16 ou 32 bits). */ asm_x86_instr *x86_read_instr_and_rm1632_with_imm8(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); @@ -82,6 +85,12 @@ asm_x86_instr *x86_read_instr_jne_8(const uint8_t *, off_t *, off_t, uint64_t, c /* Décode une instruction de type 'jump' (petit saut). */ asm_x86_instr *x86_read_instr_jmp_8(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); +/* Décode une instruction de type 'jmp' (grand saut relatif). */ +asm_x86_instr *x86_read_instr_jmp_rel1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); + +/* Décode une instruction de type 'jmp' (saut en mémoire). */ +asm_x86_instr *x86_read_instr_jmp_rm1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); + /* Décode une instruction de type 'lea' (16 ou 32 bits). */ asm_x86_instr *x86_read_instr_lea(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); diff --git a/src/arch/x86/operand.c b/src/arch/x86/operand.c index 375b0a5..e13c793 100644 --- a/src/arch/x86/operand.c +++ b/src/arch/x86/operand.c @@ -1300,7 +1300,8 @@ asm_x86_operand *x86_create_rel1632_operand_in_32b(uint64_t base, const uint8_t { asm_x86_operand *result; /* Emplacement à retourner */ off_t init_pos; /* Position avant lecture */ - int8_t offset; /* Décallage à appliquer */ + int32_t offset32; /* Décallage 32b à appliquer */ + int16_t offset16; /* Décallage 16b à appliquer */ uint32_t address; /* Adresse finale visée */ result = create_new_x86_operand(); @@ -1308,13 +1309,28 @@ asm_x86_operand *x86_create_rel1632_operand_in_32b(uint64_t base, const uint8_t init_pos = *pos; address = base; - if (!read_imm_value(is_reg32 ? AOS_32_BITS : AOS_16_BITS, data, pos, len, &offset)) + if (is_reg32) { - free(result); - return NULL; + if (!read_imm_value(AOS_32_BITS, data, pos, len, &offset32)) + { + free(result); + return NULL; + } + + address = base + (*pos - init_pos) + offset32; + } + else + { + if (!read_imm_value(AOS_16_BITS, data, pos, len, &offset16)) + { + free(result); + return NULL; + } - address = base + (*pos - init_pos) + offset; + address = base + (*pos - init_pos) + offset16; + + } if (!fill_imm_operand_with_value(ASM_OPERAND(result), AOS_32_BITS, &address)) { diff --git a/src/arch/x86/processor.c b/src/arch/x86/processor.c index 0b81a8c..5694d9e 100644 --- a/src/arch/x86/processor.c +++ b/src/arch/x86/processor.c @@ -61,7 +61,7 @@ typedef struct _x86_opcode do { \ target.prefix = _prefix; \ target.opcode = _opcode; \ - target.opt_prefix = true; \ + target.opt_prefix = (_prefix != 0x00); \ target.has_op_ext = false; \ target.name = _name; \ target.read = _read; \ @@ -72,7 +72,7 @@ typedef struct _x86_opcode target.prefix = _prefix; \ target.opcode = _opcode; \ target.op_ext = _ext << 3; \ - target.opt_prefix = true; \ + target.opt_prefix = (_prefix != 0x00); \ target.has_op_ext = true; \ target.name = _name; \ target.read = _read; \ @@ -205,6 +205,8 @@ AsmOperandSize switch_x86_operand_size_if_needed(const asm_x86_processor *proc, void x86_register_instructions(asm_x86_processor *proc) { + register_opcode(proc->opcodes[X86_OP_ADD_RM8_R8], 0x00, 0x00, "add", x86_read_instr_add_rm8_r8); + register_opcode(proc->opcodes[X86_OP_SUB_R1632_RM1632], 0x66, 0x29, "sub", x86_read_instr_sub_r1632_from_rm1632); register_opcode(proc->opcodes[X86_OP_XOR_RM8_R8], 0x00, 0x30, "xor", x86_read_instr_xor_rm8_with_r8); @@ -314,12 +316,14 @@ void x86_register_instructions(asm_x86_processor *proc) register_opcode(proc->opcodes[X86_OP_CALL_REL1632], 0x66, 0xe8, "call", x86_read_instr_call_rel1632); + register_opcode(proc->opcodes[X86_OP_JMP_REL1632], 0x66, 0xe9, "jmp", x86_read_instr_jmp_rel1632); register_opcode(proc->opcodes[X86_OP_JMP_8], 0x00, 0xeb, "jmp", x86_read_instr_jmp_8); register_opcode(proc->opcodes[X86_OP_HLT], 0x00, 0xf4, "hlt", x86_read_instr_hlt); register_opcode_with_ext(proc->opcodes[X86_OP_CALL_RM1632], 0x66, 0xff, 2, "call", x86_read_instr_call_rm1632); + register_opcode_with_ext(proc->opcodes[X86_OP_JMP_RM1632], 0x66, 0xff, 4, "jmp", x86_read_instr_jmp_rm1632); register_opcode_with_ext(proc->opcodes[X86_OP_PUSH_RM1632], 0x66, 0xff, 6, "push", x86_read_instr_push_rm1632); @@ -367,6 +371,12 @@ asm_instr *x86_fetch_instruction(const asm_x86_processor *proc, const uint8_t *d goto find_instr; } + if (proc->opcodes[i].prefix == 0x00 && data[*pos] == proc->opcodes[i].opcode) + { + tmp = *pos + 1; + goto find_instr; + } + continue; find_instr: @@ -381,7 +391,7 @@ asm_instr *x86_fetch_instruction(const asm_x86_processor *proc, const uint8_t *d else { *pos = old_pos; - printf("err while decoding at 0x%08llx :: [0x%02hhx] 0x%02hhx\n", offset, proc->opcodes[i].prefix, proc->opcodes[i].opcode); + printf("err while x86 decoding at 0x%08llx :: [0x%02hhx] 0x%02hhx\n", offset, proc->opcodes[i].prefix, proc->opcodes[i].opcode); } break; @@ -456,7 +466,7 @@ void x86_print_instruction(const asm_x86_processor *proc, const exe_format *form /* Impression globale finale */ - if (ASM_INSTRUCTION(instr)->opcode == DB_OPCODE) + if (ASM_INSTRUCTION(instr)->type == AIT_DB) snprintf(buffer, len, "db\t%s", opbuffer[0]); else diff --git a/src/format/elf/e_elf.c b/src/format/elf/e_elf.c index 3aa9394..03b2e82 100644 --- a/src/format/elf/e_elf.c +++ b/src/format/elf/e_elf.c @@ -137,6 +137,18 @@ 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)) + { + part = create_bin_part(); + + set_bin_part_name(part, ".plt"); + set_bin_part_values(part, offset, size, voffset); + + result = (bin_part **)realloc(result, ++(*count) * sizeof(bin_part *)); + result[*count - 1] = part; + + } + if (find_elf_section(format, ".init", &offset, &size, &voffset)) { part = create_bin_part(); diff --git a/src/format/elf/elf-int.h b/src/format/elf/elf-int.h index f366c71..6e7bca1 100644 --- a/src/format/elf/elf-int.h +++ b/src/format/elf/elf-int.h @@ -84,6 +84,39 @@ typedef union _Elf_Phdr #define ELF_PHDR(fmt, hdr, fld) (fmt->is_32b ? hdr.header32.fld : hdr.header64.fld) +/* Entrée de la table de relocalisation */ + +typedef union _Elf_Rel +{ + Elf32_Rel rel32; /* Version 32 bits */ + Elf64_Rel rel64; /* Version 64 bits */ + +} Elf_Rel; + +#define ELF_SIZEOF_REL(fmt) (fmt->is_32b ? sizeof(Elf32_Rel) : sizeof(Elf64_Rel)) + +#define ELF_REL(fmt, rl, fld) (fmt->is_32b ? rl.rel32.fld : rl.rel64.fld) + +#define ELF_REL_SYM(fmt, rl) (fmt->is_32b ? ELF32_R_SYM(rl.rel32.r_info) : ELF64_R_SYM(rl.rel64.r_info)) +#define ELF_REL_TYPE(fmt, rl) (fmt->is_32b ? ELF32_R_TYPE(rl.rel32.r_info) : ELF64_R_TYPE(rl.rel64.r_info)) + + +/* Information sur un symbole */ + +typedef union _Elf_Sym +{ + Elf32_Sym sym32; /* Version 32 bits */ + Elf64_Sym sym64; /* Version 64 bits */ + +} Elf_Sym; + +#define ELF_SIZEOF_SYM(fmt) (fmt->is_32b ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)) + +#define ELF_SYM(fmt, sb, fld) (fmt->is_32b ? sb.sym32.fld : sb.sym64.fld) + + + + #endif /* _FORMAT_ELF_ELF_INT_H */ diff --git a/src/format/elf/symbol.c b/src/format/elf/symbol.c index 729c154..8fa5690 100644 --- a/src/format/elf/symbol.c +++ b/src/format/elf/symbol.c @@ -26,9 +26,14 @@ #include #include +#include #include +#include "../../arch/processor.h" /* FIXME : remove me ! */ +#include "../../arch/instruction.h" /* FIXME : remove me ! */ +#include "../../arch/instruction-int.h" /* FIXME : remove me ! */ + #include "elf-int.h" #include "section.h" @@ -37,6 +42,24 @@ +/* -------------------------- DETAIL DES SYMBOLES EXTERNES -------------------------- */ + + +/* Charge en mémoire la liste des symboles dynamiques. */ +bool load_elf_relocation_table(elf_format *, const off_t *, const off_t *, const off_t *, const off_t *, const off_t *, const off_t *); + +/* Récupère les informations d'un symbole dynamique donné. */ +char *get_elf_dynamic_symbol_info(elf_format *, const off_t *, const off_t *, const off_t *, const off_t *, const off_t *); + +/* Décode les instructions liées à la relocalisation. */ +asm_instr **decode_elf_relocations(elf_format *, size_t *); + +/* Déduit les adresses effectives des relocalisations. */ +void translate_elf_relocations(elf_format *, asm_instr **, size_t); + + + + /* Charge en mémoire la liste humaine des symboles (32 bits). */ bool load_elf_symbol_table_32(elf_format *, const off_t *, const off_t *, const off_t *, const off_t *); @@ -69,6 +92,16 @@ bool load_elf_symbols(elf_format *format) off_t str_size; /* Taille de section */ + off_t plt_start; /* Début de section */ + off_t plt_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 &= find_elf_section(format, ".strtab", &str_start, &str_size, NULL); @@ -79,12 +112,46 @@ bool load_elf_symbols(elf_format *format) - result = load_elf_symbol_table_32(format, &sym_start, &sym_size, &str_start, &str_start); + 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); + + result &= find_elf_section(format, ".dynsym", &dyn_start, &dyn_size, NULL); + + result &= find_elf_section(format, ".dynstr", &str_start, &str_size, NULL); + + + + if (result) + { + + + + result = load_elf_relocation_table(format, &plt_start, &plt_size, &dyn_start, &dyn_size, &str_start, &str_size); + + if (result) + { + instructions = decode_elf_relocations(format, &count); + + translate_elf_relocations(format, instructions, count); + + /* TODO : free instructions */ + + } + + + } + return result; } @@ -96,11 +163,11 @@ bool load_elf_symbols(elf_format *format) /****************************************************************************** * * -* Paramètres : format = description de l'exécutable à compléter. * -* sym_start = début de la zone à traiter. * -* sym_size = taille de la zone à traiter. * -* 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. * +* Paramètres : format = description de l'exécutable à compléter. * +* sym_start = début de la zone à traiter. * +* sym_size = taille de la zone à traiter. * +* 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 : Charge en mémoire la liste humaine des symboles (32 bits). * * * @@ -149,11 +216,11 @@ bool load_elf_symbol_table_32(elf_format *format, const off_t *sym_start, const /****************************************************************************** * * -* Paramètres : format = description de l'exécutable à compléter. * -* sym_start = début de la zone à traiter. * -* sym_size = taille de la zone à traiter. * -* 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. * +* Paramètres : format = description de l'exécutable à compléter. * +* sym_start = début de la zone à traiter. * +* sym_size = taille de la zone à traiter. * +* 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 : Charge en mémoire la liste humaine des symboles (64 bits). * * * @@ -241,3 +308,219 @@ void get_elf_symbol_comments(const elf_format *format, char ***comments, uint64_ } } + + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* DETAIL DES SYMBOLES EXTERNES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à compléter. * +* plt_start = début de la zone à traiter. * +* plt_size = taille de la zone à traiter. * +* 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 : Charge en mémoire la liste des symboles dynamiques. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool load_elf_relocation_table(elf_format *format, const off_t *plt_start, const off_t *plt_size, const off_t *dyn_start, const off_t *dyn_size, const off_t *str_start, const off_t *str_size) +{ + off_t iter; /* Boucle de parcours */ + Elf_Rel reloc; /* Infos de relocalisation */ + off_t index; /* Indice de la portion visée */ + char *name; /* Nom du symbole trouvé */ + + for (iter = *plt_start; iter < (*plt_start + *plt_size); iter += ELF_SIZEOF_REL(format)) + { + memcpy(&reloc, &EXE_FORMAT(format)->content[iter], ELF_SIZEOF_REL(format)); + + switch (format->header.e_machine) + { + case EM_386: + switch (ELF32_R_TYPE(ELF_REL_TYPE(format, reloc))) + { + case R_386_JMP_SLOT: + + index = ELF_REL_SYM(format, reloc); + name = get_elf_dynamic_symbol_info(format, dyn_start, dyn_size, &index, str_start, str_size); + + if (name != NULL) + { + format->symbols = (elf_symbol *)realloc(format->symbols, ++format->sym_count * sizeof(elf_symbol)); + + format->symbols[format->sym_count - 1].name = name; + format->symbols[format->sym_count - 1].address = ELF_REL(format, reloc, r_offset); + + } + + break; + + default: + printf("Relocation not supported (%lld) !\n", ELF_REL_TYPE(format, reloc)); + break; + + } + break; + + default: + printf("Machine not recognized !\n"); + return false; + break; + + } + + + } + + return true; + +} + + +/****************************************************************************** +* * +* 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. * +* index = indice de l'entrée à venir lire. * +* 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 : Récupère les informations d'un symbole dynamique donné. * +* * +* Retour : Nom du symbole trouvé, ou NULL si erreur ou non adapté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *get_elf_dynamic_symbol_info(elf_format *format, const off_t *dyn_start, const off_t *dyn_size, const off_t *index, const off_t *str_start, const off_t *str_size) +{ + off_t offset; /* Emplacement à venir lire */ + Elf_Sym symbol; /* Symbole aux infos visées */ + + offset = *dyn_start + *index * ELF_SIZEOF_SYM(format); + if ((offset + ELF_SIZEOF_SYM(format)) > (*dyn_start + *dyn_size)) return NULL; + + memcpy(&symbol, &EXE_FORMAT(format)->content[offset], ELF_SIZEOF_SYM(format)); + + if (ELF_SYM(format, symbol, st_name) >= *str_size) return NULL; + + return (char *)&EXE_FORMAT(format)->content[*str_start + ELF_SYM(format, symbol, st_name)]; + +} + + +/****************************************************************************** +* * +* 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 : - * +* * +******************************************************************************/ + +asm_instr **decode_elf_relocations(elf_format *format, size_t *count) +{ + asm_instr **result; /* Liste à renvoyer */ + off_t rel_start; /* Début de section */ + off_t rel_size; /* Taille de section */ + uint64_t rel_vaddress; /* Adresse virtuelle associée */ + off_t pos; /* Tête de lecture */ + uint64_t offset; /* Adresse virtuelle courante */ + asm_instr *instr; /* Instruction décodée */ + + asm_processor *proc; /* TODO : remove me ! */ + proc = create_x86_processor(); + + 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; + + 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; + +} + + +/****************************************************************************** +* * +* 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, asm_instr **instructions, size_t count) +{ + size_t i; /* Boucle de parcours #1 */ + uint64_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 */ + + for (i = 0; (i + 2) < count; ) + { + if (instructions[i]->type == AIT_JUMP + && instructions[i + 1]->type == AIT_PUSH + && instructions[i + 2]->type == AIT_JUMP) + { + if (get_imm_operand_value(instructions[i]->operands[0], AOS_64_BITS, &address)) + for (j = 0; j < format->sym_count; j++) + if (format->symbols[j].address == address) + { + new_len = strlen(format->symbols[j].name) + 4 + 1; + new_name = calloc(new_len, sizeof(char)); + snprintf(new_name, new_len, "%s@plt", format->symbols[j].name); + + format->symbols = (elf_symbol *)realloc(format->symbols, ++format->sym_count * sizeof(elf_symbol)); + + format->symbols[format->sym_count - 1].name = new_name; + format->symbols[format->sym_count - 1].address = instructions[i]->vaddress; + + } + + i += 3; + + } + else i++; + + } + +} -- cgit v0.11.2-87-g4458