/* Chrysalide - Outil d'analyse de fichiers binaires
* fetch.c - ajouts de sauts à traiter durant la phase de désassemblage
*
* Copyright (C) 2015-2017 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide 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.
*
* Chrysalide 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 "fetch.h"
#include
#include
#include
#include "operands/offset.h"
#include "../register.h"
#include "../../raw.h"
#include "../../../format/format.h"
/******************************************************************************
* *
* Paramètres : instr = instruction ARMv7 à traiter. *
* proc = représentation de l'architecture utilisée. *
* context = contexte associé à la phase de désassemblage. *
* format = acès aux données du binaire d'origine. *
* iset = type de jeu d'instructions courant à faire suivre. *
* *
* Description : Complète un désassemblage accompli pour une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void help_fetching_with_instruction_b_with_orig(GArchInstruction *instr, GArchProcessor *proc, GArmV7Context *context, GExeFormat *format, ArmV7InstrSet iset)
{
const mrange_t *range; /* Emplacementt d'instruction */
virt_t pc; /* Position dans l'exécution */
GArchOperand *op; /* Opérande numérique en place */
int32_t offset; /* Décallage encodé en dur */
virt_t target; /* Adresse virtuelle visée */
range = g_arch_instruction_get_range(instr);
pc = get_virt_addr(get_mrange_addr(range));
switch (iset)
{
case AV7IS_ARM:
pc += 8;
break;
case AV7IS_THUMB:
pc += 4;
break;
default:
assert(0);
break;
}
//pc += get_mrange_length(range);
op = g_arch_instruction_get_operand(instr, 0);
if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_SIGNED, &offset))
g_imm_operand_set_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, pc + offset);
else assert(0);
target = pc + offset;
//g_armv7_context_define_encoding(context, target, iset);
g_proc_context_push_drop_point(G_PROC_CONTEXT(context), DPL_OTHER, target, iset);
}
/******************************************************************************
* *
* Paramètres : instr = instruction ARMv7 à traiter. *
* proc = représentation de l'architecture utilisée. *
* context = contexte associé à la phase de désassemblage. *
* format = acès aux données du binaire d'origine. *
* iset = type de jeu d'instructions courant à faire suivre. *
* *
* Description : Complète un désassemblage accompli pour une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void help_fetching_with_instruction_bl_with_orig(GArchInstruction *instr, GArchProcessor *proc, GArmV7Context *context, GExeFormat *format, ArmV7InstrSet iset)
{
const mrange_t *range; /* Emplacementt d'instruction */
virt_t pc; /* Position dans l'exécution */
GArchOperand *op; /* Opérande numérique en place */
int32_t offset; /* Décallage encodé en dur */
virt_t target; /* Adresse virtuelle visée */
range = g_arch_instruction_get_range(instr);
pc = get_virt_addr(get_mrange_addr(range));
/**
* Qu'on se trouve en mode Thumb ou ARM, l'instruction
* ne peut qu'être encodée sur 4 octets.
*/
assert(get_mrange_length(range) == 4);
switch (iset)
{
case AV7IS_ARM:
pc += 8;
break;
case AV7IS_THUMB:
pc += 4;
break;
default:
assert(0);
break;
}
op = g_arch_instruction_get_operand(instr, 0);
if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_SIGNED, &offset))
g_imm_operand_set_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, pc + offset);
else assert(0);
target = pc + offset;
//g_armv7_context_define_encoding(context, target, iset);
g_proc_context_push_drop_point(G_PROC_CONTEXT(context), DPL_OTHER, target, iset);
}
/******************************************************************************
* *
* Paramètres : instr = instruction ARMv7 à traiter. *
* proc = représentation de l'architecture utilisée. *
* context = contexte associé à la phase de désassemblage. *
* format = acès aux données du binaire d'origine. *
* iset = type de jeu d'instructions courant à inverser. *
* *
* Description : Complète un désassemblage accompli pour une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void help_fetching_with_instruction_blx_with_dest(GArchInstruction *instr, GArchProcessor *proc, GArmV7Context *context, GExeFormat *format, ArmV7InstrSet iset)
{
const mrange_t *range; /* Emplacementt d'instruction */
virt_t pc; /* Position dans l'exécution */
GArchOperand *op; /* Opérande numérique en place */
int32_t offset; /* Décallage encodé en dur */
virt_t target; /* Adresse virtuelle visée */
range = g_arch_instruction_get_range(instr);
pc = get_virt_addr(get_mrange_addr(range));
/**
* Qu'on se trouve en mode Thumb ou ARM, l'instruction
* ne peut qu'être encodée sur 4 octets.
*/
assert(get_mrange_length(range) == 4);
pc += 4;
pc -= pc % 4;
op = g_arch_instruction_get_operand(instr, 0);
if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_SIGNED, &offset))
g_imm_operand_set_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, pc + offset);
else assert(0);
target = pc + offset;
//g_armv7_context_define_encoding(context, target, iset);
g_proc_context_push_drop_point(G_PROC_CONTEXT(context), DPL_OTHER, target, iset);
}
/******************************************************************************
* *
* Paramètres : instr = instruction ARMv7 à traiter. *
* proc = représentation de l'architecture utilisée. *
* context = contexte associé à la phase de désassemblage. *
* format = acès aux données du binaire d'origine. *
* iset = type de jeu d'instructions courant à faire suivre. *
* *
* Description : Complète un désassemblage accompli pour une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void help_fetching_with_instruction_bx_with_orig(GArchInstruction *instr, GArchProcessor *proc, GArmV7Context *context, GExeFormat *format, ArmV7InstrSet iset)
{
GArchOperand *op; /* Opérande numérique en place */
GArmRegister *reg; /* Registre matériel manipulé */
const mrange_t *range; /* Emplacementt d'instruction */
virt_t pc; /* Position dans l'exécution */
op = g_arch_instruction_get_operand(instr, 0);
assert(G_IS_REGISTER_OPERAND(op));
reg = G_ARM_REGISTER(g_register_operand_get_register(G_REGISTER_OPERAND(op)));
/**
* On ne sait agir qu'avec le seul contenu facilement prédictible : pc !
*/
if (g_arm_register_get_index(reg) != 15 /* pc */)
return;
/**
* On bascule alors le mode de décodage à cette adresse...
*/
range = g_arch_instruction_get_range(instr);
pc = get_virt_addr(get_mrange_addr(range));
switch (iset)
{
case AV7IS_ARM:
pc += 8;
//g_armv7_context_define_encoding(context,
g_proc_context_push_drop_point(G_PROC_CONTEXT(context), DPL_OTHER, pc, AV7IS_THUMB);
break;
case AV7IS_THUMB:
pc += 4;
//g_armv7_context_define_encoding(context,
g_proc_context_push_drop_point(G_PROC_CONTEXT(context), DPL_OTHER, pc, AV7IS_ARM);
break;
default:
assert(0);
break;
}
}
/******************************************************************************
* *
* Paramètres : instr = instruction ARMv7 à traiter. *
* proc = représentation de l'architecture utilisée. *
* context = contexte associé à la phase de désassemblage. *
* format = acès aux données du binaire d'origine. *
* *
* Description : Complète un désassemblage accompli pour une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void help_fetching_with_instruction_cb_n_z(GArchInstruction *instr, GArchProcessor *proc, GArmV7Context *context, GExeFormat *format)
{
const mrange_t *range; /* Emplacementt d'instruction */
virt_t pc; /* Position dans l'exécution */
GArchOperand *op; /* Opérande numérique en place */
uint32_t offset; /* Décallage encodé en dur */
virt_t target; /* Adresse virtuelle visée */
range = g_arch_instruction_get_range(instr);
pc = get_virt_addr(get_mrange_addr(range));
/**
* En mode Thumb, pc a pour valeur l'adresse courante plus 4.
*/
pc += 4;
op = g_arch_instruction_get_operand(instr, 1);
if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, &offset))
g_imm_operand_set_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, pc + offset);
else assert(0);
target = pc + offset;
//g_armv7_context_define_encoding(context, target, AV7IS_THUMB);
g_proc_context_push_drop_point(G_PROC_CONTEXT(context), DPL_OTHER, target, AV7IS_THUMB);
}
/******************************************************************************
* *
* Paramètres : instr = instruction ARMv7 à traiter. *
* proc = représentation de l'architecture utilisée. *
* context = contexte associé à la phase de désassemblage. *
* format = acès aux données du binaire d'origine. *
* iset = type de jeu d'instructions courant. *
* *
* Description : Complète un désassemblage accompli pour une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void help_fetching_with_instruction_ldr_literal_with_orig(GArchInstruction *instr, GArchProcessor *proc, GArmV7Context *context, GExeFormat *format, ArmV7InstrSet iset)
{
const mrange_t *range; /* Emplacementt d'instruction */
phys_t phys_pc; /* Position dans l'exécution */
GArchOperand *op; /* Opérande de surcouche */
uint32_t offset; /* Décallage encodé en dur */
bool ret; /* Bilan d'une récupération */
off_t val_offset; /* Position de valeur à lire */
vmpa2t sym_addr; /* Adresse de nouveau symbole */
GBinContent *content; /* Contenu binaire à relire */
uint32_t target; /* Adresse virtuelle visée */
vmpa2t pos; /* Tête de lecture de valeur */
mrange_t sym_range; /* Espace du nouveau symbole */
VMPA_BUFFER(loc); /* Adresse au format texte */
size_t name_len; /* Taille de nomination finale */
char *name; /* Désignation humaine */
GArchInstruction *sym_instr; /* Instruction de symbole */
GBinSymbol *symbol; /* Nouveau symbole construit */
GDbComment *comment; /* Définition de commentaire */
bool added; /* Bilan de l'insertion */
GArchOperand *new; /* Instruction de ciblage */
/* Récupération de l'adresse visée par le chargement */
range = g_arch_instruction_get_range(instr);
phys_pc = get_phy_addr(get_mrange_addr(range));
phys_pc &= ~3;
//phys_pc = (phys_pc + 3) & ~3;
switch (iset)
{
case AV7IS_ARM:
phys_pc += 8;
break;
case AV7IS_THUMB:
phys_pc += 4;
break;
default:
assert(0);
break;
}
g_arch_instruction_lock_operands(instr);
op = _g_arch_instruction_get_operand(instr, 1);
assert(G_IS_IMM_OPERAND(op));
ret = g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, &offset);
if (!ret)
{
assert(0);
g_arch_instruction_unlock_operands(instr);
return;
}
/* Transformations et conservation d'une position de symbole */
val_offset = phys_pc + offset;
if (!g_exe_format_translate_offset_into_vmpa(format, val_offset, &sym_addr))
{
assert(0);
g_arch_instruction_unlock_operands(instr);
return;
}
//init_vmpa(&sym_addr, val_offset, VMPA_NO_VIRTUAL);
init_mrange(&sym_range, &sym_addr, 4);
/* Lecture de la valeur vers laquelle renvoyer */
content = g_binary_format_get_content(G_BIN_FORMAT(format));
copy_vmpa(&pos, &sym_addr);
ret = g_binary_content_read_u32(content, &pos, SRE_LITTLE /* FIXME */, &target);
g_object_unref(G_OBJECT(content));
if (!ret)
{
g_arch_instruction_unlock_operands(instr);
return;
}
/* Réalise l'intégration du symbole associé */
sym_instr = g_raw_instruction_new_from_value(&sym_addr, MDS_32_BITS_UNSIGNED, target);
name_len = strlen(_("Value used @ %s")) + VMPA_MAX_LEN + 1;
name = (char *)calloc(name_len, sizeof(char));
vmpa2_virt_to_string(get_mrange_addr(range), MDS_32_BITS, loc, NULL);
snprintf(name, name_len, _("Value used @ %s"), loc);
added = ADD_RAW_AS_SYM(G_BIN_FORMAT(format), symbol, sym_instr, comment, name);
free(name);
if (added)
g_proc_context_push_new_symbol_at(G_PROC_CONTEXT(context), &sym_addr);
//g_proc_context_push_new_symbol_at(context, &sym_addr);
//g_imm_operand_set_value(G_IMM_OPERAND(sub_op), MDS_32_BITS_UNSIGNED, target);
/// FIXME ?!
//if (target < 0x8000) return;
//if (target > 0x6966c) return;
new = g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, target);
_g_arch_instruction_replace_operand(instr, new, op);
g_arch_instruction_unlock_operands(instr);
//exit(0);
//target = pc + offset;
if (target & 0x1)
iset = AV7IS_THUMB;
//else
// iset = AV7IS_ARM;
//g_armv7_context_define_encoding(context, target, AV7IS_THUMB);
g_proc_context_push_drop_point(G_PROC_CONTEXT(context), DPL_OTHER, target, iset);
//exit(0);
}