diff options
Diffstat (limited to 'src/analysis')
-rw-r--r-- | src/analysis/block-int.h | 4 | ||||
-rw-r--r-- | src/analysis/block.c | 20 | ||||
-rw-r--r-- | src/analysis/block.h | 3 | ||||
-rw-r--r-- | src/analysis/blocks/flow.c | 62 | ||||
-rw-r--r-- | src/analysis/blocks/flow.h | 3 | ||||
-rw-r--r-- | src/analysis/blocks/virtual.c | 56 | ||||
-rw-r--r-- | src/analysis/blocks/virtual.h | 3 | ||||
-rw-r--r-- | src/analysis/decomp/decompiler.c | 11 | ||||
-rw-r--r-- | src/analysis/decomp/il.c | 326 | ||||
-rw-r--r-- | src/analysis/decomp/il.h | 14 | ||||
-rw-r--r-- | src/analysis/variable.c | 7 |
11 files changed, 500 insertions, 9 deletions
diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h index ba84fcb..355c1ee 100644 --- a/src/analysis/block-int.h +++ b/src/analysis/block-int.h @@ -29,6 +29,9 @@ +/* Recherche le bloc contenant une adresse donnée. */ +typedef GInstrBlock * (* find_by_addr_fc) (const GInstrBlock *, vmpa_t); + /* Parcours tous les blocs d'instructions dans un ordre donné. */ typedef bool (* visit_all_blocks_fc) (GInstrBlock *, instr_block_visitor_cb, void *); @@ -45,6 +48,7 @@ struct _GInstrBlock { GObject parent; /* A laisser en premier */ + find_by_addr_fc find_by_addr; /* Recherche par adresse */ visit_all_blocks_fc visit_blocks; /* Visite des différents blocs */ list_all_blocks_fc list_blocks; /* Liste de tous les blocs */ list_regs_accesses_fc list_regs; /* Liste des accès registres */ diff --git a/src/analysis/block.c b/src/analysis/block.c index 3b3eaf3..62b56ab 100644 --- a/src/analysis/block.c +++ b/src/analysis/block.c @@ -157,6 +157,26 @@ static void g_instr_block_finalize(GInstrBlock *block) /****************************************************************************** * * +* Paramètres : block = bloc de départ des recherches. * +* addr = ensemble de blocs à parcourir. * +* * +* Description : Recherche le bloc contenant une adresse donnée. * +* * +* Retour : bloc basique trouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GInstrBlock *g_instr_block_find_by_addr(const GInstrBlock *block, vmpa_t addr) +{ + return block->find_by_addr(block, addr); + +} + + +/****************************************************************************** +* * * Paramètres : block = bloc d'instructions démarrant la visite. * * callback = ensemble de blocs à parcourir. * * data = donnée utilisateur à associer au parcours. * diff --git a/src/analysis/block.h b/src/analysis/block.h index a85e4aa..1574dc1 100644 --- a/src/analysis/block.h +++ b/src/analysis/block.h @@ -95,6 +95,9 @@ typedef bool (* instr_block_visitor_cb) (GInstrBlock *, BlockVisitOrder, void *) /* Indique le type défini pour un bloc d'instructions. */ GType g_instr_block_get_type(void); +/* Recherche le bloc contenant une adresse donnée. */ +GInstrBlock *g_instr_block_find_by_addr(const GInstrBlock *, vmpa_t); + /* Parcours tous les blocs d'instructions dans un ordre donné. */ bool g_instr_block_visit(GInstrBlock *, instr_block_visitor_cb, void *); diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c index 85d98ee..6fb5849 100644 --- a/src/analysis/blocks/flow.c +++ b/src/analysis/blocks/flow.c @@ -65,6 +65,9 @@ static void g_flow_block_dispose(GFlowBlock *); /* Procède à la libération totale de la mémoire. */ static void g_flow_block_finalize(GFlowBlock *); +/* Recherche le bloc contenant une adresse donnée. */ +static GInstrBlock *g_flow_block_find_by_addr(const GFlowBlock *, vmpa_t); + /* Parcours le bloc d'instructions dans un ordre donné. */ static bool g_flow_block_visit(GFlowBlock *, instr_block_visitor_cb, void *); @@ -128,6 +131,7 @@ static void g_flow_block_init(GFlowBlock *block) parent = G_INSTR_BLOCK(block); + parent->find_by_addr = (find_by_addr_fc)g_flow_block_find_by_addr; parent->visit_blocks = (visit_all_blocks_fc)g_flow_block_visit; parent->list_blocks = (list_all_blocks_fc)g_flow_block_list_all_blocks; parent->list_regs = (list_regs_accesses_fc)g_flow_block_list_regs_accesses; @@ -236,6 +240,38 @@ GInstrBlock *g_flow_block_new(GArchInstruction *instrs, GArchInstruction *first, /****************************************************************************** * * +* Paramètres : block = bloc de départ des recherches. * +* addr = ensemble de blocs à parcourir. * +* * +* Description : Recherche le bloc contenant une adresse donnée. * +* * +* Retour : bloc basique trouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GInstrBlock *g_flow_block_find_by_addr(const GFlowBlock *block, vmpa_t addr) +{ + GInstrBlock *result; /* Resultat à retourner */ + vmpa_t start; /* Adresse de début du bloc */ + vmpa_t end; /* Adresse de fin du bloc */ + + g_flow_block_get_boundary_addresses(block, &start, &end); + + if (start <= addr && addr <= end) + result = G_INSTR_BLOCK(block); + + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : block = bloc d'instructions concerné par la visite. * * callback = ensemble de blocs à parcourir. * * data = donnée utilisateur à associer au parcours. * @@ -419,6 +455,25 @@ static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *block /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * +* * +* Description : Fournit la liste d'appartenance des instructions du bloc. * +* * +* Retour : Liste de l'ensemble des instructions. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchInstruction *g_flow_block_get_all_instructions_list(const GFlowBlock *block) +{ + return block->instrs; + +} + + +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions à consulter. * * first = instruction de départ du bloc. [OUT] * * last = dernière instruction du bloc. [OUT] * * * @@ -432,8 +487,11 @@ static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *block void g_flow_block_get_boundary(const GFlowBlock *block, GArchInstruction **first, GArchInstruction **last) { - *first = block->first; - *last = block->last; + if (first != NULL) + *first = block->first; + + if (last != NULL) + *last = block->last; } diff --git a/src/analysis/blocks/flow.h b/src/analysis/blocks/flow.h index 8bd7257..28fb5a9 100644 --- a/src/analysis/blocks/flow.h +++ b/src/analysis/blocks/flow.h @@ -55,6 +55,9 @@ GType g_flow_block_get_type(void); /* Crée un bloc d'exécution d'instructions. */ GInstrBlock *g_flow_block_new(GArchInstruction *, GArchInstruction *, GArchInstruction *); +/* Fournit la liste d'appartenance des instructions du bloc. */ +GArchInstruction *g_flow_block_get_all_instructions_list(const GFlowBlock *); + /* Fournit les instructions limites d'un bloc d'exécution. */ void g_flow_block_get_boundary(const GFlowBlock *, GArchInstruction **, GArchInstruction **); diff --git a/src/analysis/blocks/virtual.c b/src/analysis/blocks/virtual.c index 90bccca..71a6d06 100644 --- a/src/analysis/blocks/virtual.c +++ b/src/analysis/blocks/virtual.c @@ -69,6 +69,9 @@ static void g_virtual_block_dispose(GVirtualBlock *); /* Procède à la libération totale de la mémoire. */ static void g_virtual_block_finalize(GVirtualBlock *); +/* Recherche le bloc contenant une adresse donnée. */ +static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *, vmpa_t); + /* Parcours le bloc d'instructions dans un ordre donné. */ static bool g_virtual_block_visit(GVirtualBlock *, instr_block_visitor_cb, void *); @@ -126,6 +129,7 @@ static void g_virtual_block_init(GVirtualBlock *block) parent = G_INSTR_BLOCK(block); + parent->find_by_addr = (find_by_addr_fc)g_virtual_block_find_by_addr; parent->visit_blocks = (visit_all_blocks_fc)g_virtual_block_visit; parent->list_blocks = (list_all_blocks_fc)g_virtual_block_list_all_blocks; parent->list_regs = (list_regs_accesses_fc)g_virtual_block_list_regs_accesses; @@ -207,6 +211,34 @@ GInstrBlock *g_virtual_block_new(void) /****************************************************************************** * * +* Paramètres : block = bloc de départ des recherches. * +* addr = ensemble de blocs à parcourir. * +* * +* Description : Recherche le bloc contenant une adresse donnée. * +* * +* Retour : bloc basique trouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *block, vmpa_t addr) +{ + GInstrBlock *result; /* Resultat à retourner */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < block->children_count && result == NULL; i++) + result = g_instr_block_find_by_addr(block->children[i], addr); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : block = bloc d'instructions concerné par la visite. * * callback = ensemble de blocs à parcourir. * * data = donnée utilisateur à associer au parcours. * @@ -324,3 +356,27 @@ size_t g_virtual_block_count_children(GVirtualBlock *block) return block->children_count; } + + +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions à consulter. * +* index = indice du sous-bloc recherché. * +* * +* Description : Renvoie un des blocs contenus dans le groupe courant. * +* * +* Retour : Un des blocs du groupe. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GInstrBlock *g_virtual_block_get_child(GVirtualBlock *block, size_t index) +{ + if (index >= block->children_count) + return NULL; + + else + return block->children[index]; + +} diff --git a/src/analysis/blocks/virtual.h b/src/analysis/blocks/virtual.h index 5e8ddcd..b254a27 100644 --- a/src/analysis/blocks/virtual.h +++ b/src/analysis/blocks/virtual.h @@ -61,6 +61,9 @@ void g_virtual_block_add_child(GVirtualBlock *, GInstrBlock *); /* Compte le nombre de blocs contenus dans le groupe courant. */ size_t g_virtual_block_count_children(GVirtualBlock *); +/* Renvoie un des blocs contenus dans le groupe courant. */ +GInstrBlock *g_virtual_block_get_child(GVirtualBlock *, size_t); + #endif /* _ANALYSIS_BLOCKS_VIRTUAL_H */ diff --git a/src/analysis/decomp/decompiler.c b/src/analysis/decomp/decompiler.c index c824697..47c379d 100644 --- a/src/analysis/decomp/decompiler.c +++ b/src/analysis/decomp/decompiler.c @@ -167,11 +167,16 @@ static void prepare_all_routines_for_decomp(const GLoadedBinary *binary, const c max = g_binary_routine_get_address(routines[i]) + g_binary_routine_get_size(routines[i]); - //printf("##### DECOMPILE '%s' #####\n", g_binary_routine_to_string(routines[i])); + printf("##### DECOMPILE '%s' #####\n", g_binary_routine_to_string(routines[i])); + + dinstrs = decompiled_routine_instructions(routines[i], format, proc); + + /* dinstrs = build_decompiled_block(instrs, g_binary_routine_get_address(routines[i]), max, VMPA_MAX, context); + */ //instr = g_binary_format_decompile_routine(G_BIN_FORMAT(format), routines[i], context); @@ -216,8 +221,6 @@ GCodeBuffer *decompile_all_from_file(const GLoadedBinary *binary, const char *fi build_decomp_prologue(result, filename); - - /* prepare_all_routines_for_decomp(binary, filename); @@ -225,7 +228,7 @@ GCodeBuffer *decompile_all_from_file(const GLoadedBinary *binary, const char *fi format = g_loaded_binary_get_format(binary); g_binary_format_decompile(G_BIN_FORMAT(format), result, filename); - */ + return result; diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c index 693b8cb..c2bc0be 100644 --- a/src/analysis/decomp/il.c +++ b/src/analysis/decomp/il.c @@ -24,6 +24,330 @@ #include "il.h" +#include "../blocks/flow.h" +#include "../blocks/virtual.h" +#include "../../decomp/expr/block.h" +#include "../../decomp/instr/ite.h" + + + +/* --------------------- GESTION DES CONTEXTES DE DECOMPILATION --------------------- */ + + + + + + + +/* -------------------------- ENCADREMENT DES INSTRUCTIONS -------------------------- */ + + +/* Retrouve et rassemble les instructions décompilées. */ +static GDecInstruction *merge_decompiled_instructions(GDecInstruction *, GDecInstruction *); + +/* Procède à la décompilation d'un bloc déterminé. */ +static GDecInstruction *decompiled_instructions_block(GFlowBlock *, GVirtualBlock *, GDecContext *); + +/* Procède à la décompilation d'un ensemble de blocs déterminé. */ +static GDecInstruction *decompiled_instructions_blocks(GVirtualBlock *, GDecContext *); + +/* Procède à la décompilation d'un bloc basique quelconque. */ +static GDecInstruction *decompiled_basic_block(GInstrBlock *, GDecContext *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GESTION DES CONTEXTES DE DECOMPILATION */ +/* ---------------------------------------------------------------------------------- */ + + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* ENCADREMENT DES INSTRUCTIONS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : group = groupe d'instructions à compléter ou constituer. * +* list = liste d'instructions à intégrer. * +* * +* Description : Retrouve et rassemble les instructions décompilées. * +* * +* Retour : Groupe fourni ou nouveau groupe créé pour l'occasion. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDecInstruction *merge_decompiled_instructions(GDecInstruction *group, GDecInstruction *list) +{ + GExprBlock *block; /* Autre vision du groupe */ + GDecInstruction *iter; /* Boucle de parcours */ + + if (group == NULL) block = NULL; + else block = G_EXPR_BLOCK(group); + + for (iter = list; + iter != NULL; + iter = g_dec_instruction_get_next_iter(list, iter)) + { + if (block == NULL) + block = G_EXPR_BLOCK(g_expr_block_new(iter)); + else + g_expr_block_add_item(block, iter); + + } + + return G_DEC_INSTRUCTION(block); + +} + + +/****************************************************************************** +* * +* Paramètres : block = ensemble des instructions d'assemblage à traiter. * +* parent = groupe de blocs d'appartenance. * +* ctx = contexte de soutien à associer à l'opération. * +* * +* Description : Procède à la décompilation d'un bloc déterminé. * +* * +* Retour : Instructions créées et enregistrées, ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtualBlock *parent, GDecContext *ctx) +{ + GDecInstruction *res; + + GArchInstruction *instrs; /* Liste d'instructions natives*/ + GArchInstruction *first; /* Première instruction du lot */ + GArchInstruction *last; /* Dernière instruction du lot */ + vmpa_t max; /* Adresse de fin du bloc */ + GArchInstruction *iter; /* Boucle de parcours */ + GDecInstruction *decomp; /* Dernier résultat de décomp. */ + GDecInstruction *true_dinstr; /* Décompilation 'cond vraie' */ + GDecInstruction *false_dinstr; /* Décompilation 'cond fausse' */ + GArchInstruction *next; /* Instruction de branchement */ + vmpa_t next_addr; /* Adresse de cette instruct° */ + GInstrBlock *next_block; /* Bloc basique correspondant */ + + instrs = g_flow_block_get_all_instructions_list(block); + g_flow_block_get_boundary(block, &first, &last); + + g_flow_block_get_boundary_addresses(block, NULL, &max); + max++; + + /* Décompilation du corps du bloc */ + + for (iter = first; + iter != NULL; + iter = g_arch_instruction_get_next_iter(instrs, iter, max)) + { + decomp = g_arch_instruction_decompile(iter, ctx); + } + + /* Post-traitement selon les types de lien */ + + + res = g_dec_context_get_decomp_instrs(ctx); + + + /* if ... then ... else ... */ + if (G_IS_ITE_INSTRUCTION(decomp)) + { + next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_TRUE); + + printf("@ 0x%08llx : true : %p\n", max, next); + + true_dinstr = NULL; + + if (next != NULL) + { + g_arch_instruction_get_location(next, NULL, NULL, &next_addr); + next_block = g_instr_block_find_by_addr(G_INSTR_BLOCK(parent), next_addr); + + if (next_block != NULL) + { + next_block = g_instr_block_find_by_addr(next_block, next_addr); + true_dinstr = decompiled_basic_block(next_block, ctx); + } + + } + + next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_FALSE); + + printf("@ 0x%08llx : false : %p\n", max, next); + + false_dinstr = NULL; + + if (next != NULL) + { + g_arch_instruction_get_location(next, NULL, NULL, &next_addr); + next_block = g_instr_block_find_by_addr(G_INSTR_BLOCK(parent), next_addr); + + if (next_block != NULL) + { + next_block = g_instr_block_find_by_addr(next_block, next_addr); + false_dinstr = decompiled_basic_block(next_block, ctx); + } + + } + + printf(" -> ite : %p + %p\n", true_dinstr, false_dinstr); + + printf(" -> ite : %s + %s\n", + g_type_name(G_TYPE_FROM_INSTANCE(true_dinstr)), + g_type_name(G_TYPE_FROM_INSTANCE(false_dinstr))); + + + g_ite_instruction_set_branches(G_ITE_INSTRUCTION(decomp), true_dinstr, false_dinstr); + + } + + /* Renvoi des instructions mises en place */ + + return res; + + //return g_dec_context_get_decomp_instrs(ctx); + +} + + +/****************************************************************************** +* * +* Paramètres : block = ensemble des instructions d'assemblage à traiter. * +* ctx = contexte de soutien à associer à l'opération. * +* * +* Description : Procède à la décompilation d'un ensemble de blocs déterminé. * +* * +* Retour : Instructions créées et enregistrées, ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDecInstruction *decompiled_instructions_blocks(GVirtualBlock *block, GDecContext *ctx) +{ + GDecInstruction *result; /* Instructions à renvoyer */ + size_t count; /* Nombre de sous-blocs */ + size_t i; /* Boucle de parcours */ + GInstrBlock *sub_block; /* Sous-bloc à traiter */ + GDecInstruction *dinstrs; /* Instructions décompilées */ + + result = NULL; + + count = g_virtual_block_count_children(block); + + for (i = 0; i < count; i++) + { + sub_block = g_virtual_block_get_child(block, i); + + /** + * Les groupes de blocs sont forcément rattachés à une instruction, + * donc ils sont décompilés depuis ces instructions, pas ici. + */ + if (!G_IS_FLOW_BLOCK(sub_block)) continue; + + /* FIXME */ + g_dec_context_set_decomp_instrs(ctx, NULL); + + dinstrs = decompiled_instructions_block(G_FLOW_BLOCK(sub_block), block, ctx); + result = merge_decompiled_instructions(result, dinstrs); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : block = ensemble des instructions d'assemblage à traiter. * +* ctx = contexte de soutien à associer à l'opération. * +* * +* Description : Procède à la décompilation d'un bloc basique quelconque. * +* * +* Retour : Instructions créées et enregistrées, ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDecInstruction *decompiled_basic_block(GInstrBlock *block, GDecContext *ctx) +{ + GDecInstruction *result; /* Instructions à retourner */ + + /* FIXME */ + g_dec_context_set_decomp_instrs(ctx, NULL); + + if (G_IS_VIRTUAL_BLOCK(block)) + result = decompiled_instructions_blocks(G_VIRTUAL_BLOCK(block), ctx); + + else + { + result = decompiled_instructions_block(G_FLOW_BLOCK(block), NULL, ctx); + + if (!G_IS_EXPR_BLOCK(result)) + result = merge_decompiled_instructions(NULL, result); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : routine = routine dont le corps est à traiter. * +* format = format du binaire contenant les instructions. * +* proc = architecture du code machine. * +* * +* Description : Procède à la décompilation d'une routinée déterminée. * +* * +* Retour : Instructions créées ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDecInstruction *decompiled_routine_instructions(GBinRoutine *routine, GExeFormat *format, GArchProcessor *proc) +{ + GDecInstruction *result; /* Instructions à retourner */ + GDecContext *context; /* Contexte pour la décompil. */ + GInstrBlock *blocks; /* Blocs basiques de routine */ + + context = g_arch_processor_get_decomp_context(proc); + + g_object_set_data(G_OBJECT(context), "format", format); + g_object_set_data(G_OBJECT(context), "routine", routine); + + blocks = g_binary_routine_get_basic_blocks(routine); + + result = decompiled_basic_block(blocks, context); + + g_object_unref(context); + + return result; + +} + + + + + +#if 0 + + #include <malloc.h> #include <stdlib.h> #include <string.h> @@ -380,3 +704,5 @@ GDecInstruction *build_decompiled_block(GArchInstruction *instrs, vmpa_t start, return result; } + +#endif diff --git a/src/analysis/decomp/il.h b/src/analysis/decomp/il.h index 4f38b4f..670505c 100644 --- a/src/analysis/decomp/il.h +++ b/src/analysis/decomp/il.h @@ -25,6 +25,18 @@ #define _ANALYSIS_DECOMP_IL_H +#include "../routine.h" +#include "../../arch/processor.h" + + + +/* Procède à la décompilation d'une routinée déterminée. */ +GDecInstruction *decompiled_routine_instructions(GBinRoutine *, GExeFormat *, GArchProcessor *); + + + + +#if 0 #include "../../arch/instruction.h" #include "../../decomp/instruction.h" @@ -32,7 +44,7 @@ /* Procède à la décompilation basique d'un bloc déterminé. */ GDecInstruction *build_decompiled_block(GArchInstruction *, vmpa_t, vmpa_t, vmpa_t, GDecContext *); - +#endif #endif /* _ANALYSIS_DECOMP_IL_H */ diff --git a/src/analysis/variable.c b/src/analysis/variable.c index 6a7c145..edc176a 100644 --- a/src/analysis/variable.c +++ b/src/analysis/variable.c @@ -253,11 +253,14 @@ char *g_binary_variable_to_string(const GBinVariable *var, bool simple) { char *result; /* Valeur à retourner */ - result = _g_data_type_to_string(var->type, simple); + /* FIXME : décompilation sans type ! */ + //result = _g_data_type_to_string(var->type, simple); + + result = strdup(""); if (var->name != NULL) { - if (!g_data_type_is_pointer(var->type, true)) + if (!g_data_type_is_pointer(var->type, true) /* FIXME */ && strlen(result) > 0 /* FIXME */) result = stradd(result, " "); result = stradd(result, var->name); |