diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/analysis/block-int.h | 5 | ||||
| -rw-r--r-- | src/analysis/block.c | 21 | ||||
| -rw-r--r-- | src/analysis/block.h | 3 | ||||
| -rw-r--r-- | src/analysis/blocks/flow.c | 27 | ||||
| -rw-r--r-- | src/analysis/blocks/virtual.c | 27 | ||||
| -rw-r--r-- | src/analysis/decomp/il.c | 373 | ||||
| -rw-r--r-- | src/analysis/disass/macro.c | 97 | ||||
| -rw-r--r-- | src/arch/dalvik/decomp/if.c | 5 | ||||
| -rw-r--r-- | src/arch/dalvik/instruction.c | 12 | ||||
| -rw-r--r-- | src/decomp/instr/Makefile.am | 1 | ||||
| -rw-r--r-- | src/decomp/instr/keyword.c | 162 | ||||
| -rw-r--r-- | src/decomp/instr/keyword.h | 68 | ||||
| -rw-r--r-- | src/decomp/instr/switch.c | 11 | 
13 files changed, 691 insertions, 121 deletions
| diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h index 419a8b0..069b50c 100644 --- a/src/analysis/block-int.h +++ b/src/analysis/block-int.h @@ -38,6 +38,10 @@ typedef bool (* visit_all_blocks_fc) (GInstrBlock *, instr_block_visitor_cb, voi  /* Etablit la liste de tous les blocs présents. */  typedef void (* list_all_blocks_fc) (const GInstrBlock *, GInstrBlock ***, size_t *); +/* Etablit la liste de tous les blocs terminaux. */ +typedef void (* list_leafs_blocks_fc) (const GInstrBlock *, GInstrBlock ***, size_t *); + +  /* Fournit les différents accès aux registres. */  //typedef const reg_access * (* list_regs_accesses_fc) (const GInstrBlock *, size_t *); @@ -51,6 +55,7 @@ struct _GInstrBlock      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_leafs_blocks_fc list_leafs;        /* Liste des blocs terminaux   */      //list_regs_accesses_fc list_regs;        /* Liste des accès registres   */      GInstrBlock *links_block;               /* Lieu des blocs attachés     */ diff --git a/src/analysis/block.c b/src/analysis/block.c index 50d5644..d8d906a 100644 --- a/src/analysis/block.c +++ b/src/analysis/block.c @@ -202,6 +202,27 @@ void g_instr_block_list_all_blocks(const GInstrBlock *block, GInstrBlock ***list  /******************************************************************************  *                                                                             * +*  Paramètres  : block = bloc d'instructions à consulter.                     * +*                list  = ensemble de blocs à compléter. [OUT]                 * +*                count = nombre de blocs au total. [OUT]                      * +*                                                                             * +*  Description : Etablit la liste de tous les blocs terminaux.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_instr_block_list_leafs_blocks(const GInstrBlock *block, GInstrBlock ***list, size_t *count) +{ +    block->list_leafs(block, list, count); + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : block = bloc d'instructions à mettre à jour.                 *  *                links = bloc contenant les blocs liés au bloc.               *  *                                                                             * diff --git a/src/analysis/block.h b/src/analysis/block.h index 7786ce5..d4e5a2b 100644 --- a/src/analysis/block.h +++ b/src/analysis/block.h @@ -74,6 +74,9 @@ bool g_instr_block_visit(GInstrBlock *, instr_block_visitor_cb, void *);  /* Etablit la liste de tous les blocs présents. */  void g_instr_block_list_all_blocks(const GInstrBlock *, GInstrBlock ***, size_t *); +/* Etablit la liste de tous les blocs terminaux. */ +void g_instr_block_list_leafs_blocks(const GInstrBlock *, GInstrBlock ***, size_t *); +  /* Définit l'ensemble contenant les blocs liés. */  void g_instr_block_set_links_block(GInstrBlock *, GInstrBlock *); diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c index 4df729c..0b68a14 100644 --- a/src/analysis/blocks/flow.c +++ b/src/analysis/blocks/flow.c @@ -74,6 +74,9 @@ static bool g_flow_block_visit(GFlowBlock *, instr_block_visitor_cb, void *);  /* Etablit la liste de tous les blocs présents. */  static void g_flow_block_list_all_blocks(const GFlowBlock *, GInstrBlock ***, size_t *); +/* Etablit la liste de tous les blocs terminaux. */ +static void g_flow_block_list_leafs_blocks(const GFlowBlock *, GInstrBlock ***, size_t *); +  /* Prend note de l'usage d'un registre, au besoin. */  static void g_flow_block_memorize_access(GFlowBlock *, GArchRegister *, RegAccessType, vmpa_t); @@ -134,6 +137,7 @@ static void g_flow_block_init(GFlowBlock *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_leafs = (list_leafs_blocks_fc)g_flow_block_list_leafs_blocks;      //parent->list_regs = (list_regs_accesses_fc)g_flow_block_list_regs_accesses;      block->regs = g_raccess_list_new(); @@ -315,6 +319,29 @@ static void g_flow_block_list_all_blocks(const GFlowBlock *block, GInstrBlock **  /******************************************************************************  *                                                                             * +*  Paramètres  : block = bloc d'instructions à consulter.                     * +*                list  = ensemble de blocs à compléter. [OUT]                 * +*                count = nombre de blocs au total. [OUT]                      * +*                                                                             * +*  Description : Etablit la liste de tous les blocs terminaux.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_flow_block_list_leafs_blocks(const GFlowBlock *block, GInstrBlock ***list, size_t *count) +{ +    (*list) = (GInstrBlock **)realloc(*list, ++(*count) * sizeof(GInstrBlock *)); + +    (*list)[*count - 1] = G_INSTR_BLOCK(block); + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : block = bloc d'instructions à mettre à jour.                 *  *                reg   = registre visé par l'opération.                       *  *                type  = type d'accès à l'opérande.                           * diff --git a/src/analysis/blocks/virtual.c b/src/analysis/blocks/virtual.c index 42492e9..0cc6a0d 100644 --- a/src/analysis/blocks/virtual.c +++ b/src/analysis/blocks/virtual.c @@ -79,6 +79,9 @@ static bool g_virtual_block_visit(GVirtualBlock *, instr_block_visitor_cb, void  /* Etablit la liste de tous les blocs présents. */  static void g_virtual_block_list_all_blocks(const GVirtualBlock *, GInstrBlock ***, size_t *); +/* Etablit la liste de tous les blocs terminaux. */ +static void g_virtual_block_list_leafs_blocks(const GVirtualBlock *, GInstrBlock ***, size_t *); +  /* Fournit les différents accès aux registres. */  //static const reg_access *g_virtual_block_list_regs_accesses(const GVirtualBlock *, size_t *); @@ -133,6 +136,7 @@ static void g_virtual_block_init(GVirtualBlock *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_leafs = (list_leafs_blocks_fc)g_virtual_block_list_leafs_blocks;      //parent->list_regs = (list_regs_accesses_fc)g_virtual_block_list_regs_accesses;  } @@ -300,6 +304,29 @@ static void g_virtual_block_list_all_blocks(const GVirtualBlock *block, GInstrBl  } + +/****************************************************************************** +*                                                                             * +*  Paramètres  : block = bloc d'instructions à consulter.                     * +*                list  = ensemble de blocs à compléter. [OUT]                 * +*                count = nombre de blocs au total. [OUT]                      * +*                                                                             * +*  Description : Etablit la liste de tous les blocs terminaux.                * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_virtual_block_list_leafs_blocks(const GVirtualBlock *block, GInstrBlock ***list, size_t *count) +{ +    if (block->children_count > 0) +        g_instr_block_list_leafs_blocks(block->children[block->children_count - 1], list, count); + +} + +  #if 0  /******************************************************************************  *                                                                             * diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c index f241e46..9e235a6 100644 --- a/src/analysis/decomp/il.c +++ b/src/analysis/decomp/il.c @@ -24,11 +24,15 @@  #include "il.h" +#include <malloc.h> + +  #include "../blocks/flow.h"  #include "../blocks/virtual.h"  #include "../../decomp/expr/block.h"  #include "../../decomp/expr/immediate.h"  #include "../../decomp/instr/ite.h" +#include "../../decomp/instr/keyword.h"  #include "../../decomp/instr/switch.h" @@ -67,6 +71,20 @@ static GDecInstruction *decompiled_basic_block(GInstrBlock *, GDecContext *); +/* --------------------------- DECOMPILATIONS SPECIFIQUES --------------------------- */ + + +/* Procède à la décompilation des éléments d'un 'if then else'. */ +static void build_ite_branches(GITEInstruction *, GFlowBlock *, GDecContext *); + +/* Termine le traitement d'un cas de 'switch'. */ +static void close_case_decomp_instructions(GDecInstruction *, GInstrBlock *, GArchInstruction **, size_t, size_t); + +/* Procède à la décompilation des éléments d'un 'switch'. */ +static void build_switch_branches(GSwitchInstruction *, GFlowBlock *, GDecContext *); + + +  /* ---------------------------------------------------------------------------------- */  /*                       GESTION DES CONTEXTES DE DECOMPILATION                       */  /* ---------------------------------------------------------------------------------- */ @@ -328,27 +346,12 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon  {      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 #1       */      GDecInstruction *decomp;                /* Dernier résultat de décomp. */ -    GInstrBlock *sub_parent;                /* Groupe des sous-branches    */ -    GHashTable *sub_shared;                 /* Allocations communes        */ -    GDecContext *sub_ctx;                   /* Sous-contexte pour branche  */ -    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;                /* Sous-bloc basique direct    */ -    GArchInstruction **dests;               /* Instr. visée par une autre  */ -    link_extra_info *info;                  /* Compléments pour les liens  */ -    size_t dcount;                          /* Nombre de liens de dest.    */ -    size_t i;                               /* Boucle de parcours #2       */ -    GDecInstruction *case_dinstr;           /* Décompilation 'case'        */ -    GDecExpression *case_value;             /* Valeur d'aiguillage         */      instrs = g_flow_block_get_all_instructions_list(block); -    g_flow_block_get_boundary(block, &first, &last); +    g_flow_block_get_boundary(block, &first, NULL);      g_flow_block_get_boundary_addresses(block, NULL, &max);      max++; @@ -366,92 +369,11 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon      /* if ... then ... else ... */      if (G_IS_ITE_INSTRUCTION(decomp)) -    { -        sub_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); -        sub_shared = g_hash_table_new_full((GHashFunc)g_arch_register_hash, -                                           (GEqualFunc)g_arch_register_equal, -                                           g_object_unref, g_object_unref); - -        true_dinstr = NULL; - -        next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_TRUE); -        if (next != NULL) -        { -            g_arch_instruction_get_location(next, NULL, NULL, &next_addr); -            next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false); - -            if (next_block != NULL) -            { -                sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared); -                true_dinstr = decompiled_basic_block(next_block, sub_ctx); -                g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx); -                g_object_unref(G_OBJECT(sub_ctx)); -            } - -        } - -        false_dinstr = NULL; - -        next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_FALSE); -        if (next != NULL) -        { -            g_arch_instruction_get_location(next, NULL, NULL, &next_addr); -            next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false); - -            if (next_block != NULL) -            { -                sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared); -                false_dinstr = decompiled_basic_block(next_block, sub_ctx); -                g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx); -                g_object_unref(G_OBJECT(sub_ctx)); -            } - -        } - -        g_ite_instruction_set_branches(G_ITE_INSTRUCTION(decomp), true_dinstr, false_dinstr); - -        g_hash_table_unref(sub_shared); - -    } +        build_ite_branches(G_ITE_INSTRUCTION(decomp), block, ctx);      /* switch ... case ... */      else if (G_IS_SWITCH_INSTRUCTION(decomp)) -    { -        sub_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); -        sub_shared = g_hash_table_new_full((GHashFunc)g_arch_register_hash, -                                           (GEqualFunc)g_arch_register_equal, -                                           g_object_unref, g_object_unref); - -        dcount = g_arch_instruction_get_destinations(last, &dests, NULL, &info); - -        for (i = 0; i < dcount; i++) -        { -            g_arch_instruction_get_location(dests[i], NULL, NULL, &next_addr); -            next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false); - -            if (next_block != NULL) -            { -                sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared); -                case_dinstr = decompiled_basic_block(next_block, sub_ctx); -                g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx); -                g_object_unref(G_OBJECT(sub_ctx)); - -                if (info[i].imm != NULL) -                { -                    case_value = G_DEC_EXPRESSION(g_imm_expression_new(info[i].imm)); -                    g_switch_instruction_add_case(G_SWITCH_INSTRUCTION(decomp), -                                                  case_value, case_dinstr, next_addr); -                } -                else g_switch_instruction_set_default_case(G_SWITCH_INSTRUCTION(decomp), -                                                           case_dinstr); - -            } - -        } - -        g_hash_table_unref(sub_shared); - -    } +        build_switch_branches(G_SWITCH_INSTRUCTION(decomp), block, ctx);      /* Renvoi des instructions mises en place */ @@ -578,3 +500,256 @@ GDecInstruction *decompiled_routine_instructions(GBinRoutine *routine, GExeForma      return result;  } + + + +/* ---------------------------------------------------------------------------------- */ +/*                             DECOMPILATIONS SPECIFIQUES                             */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : decomp = instruction 'if ... then ... else' à compléter.     * +*                block  = ensemble des instructions d'assemblage traitées.    * +*                ctx    = contexte de soutien à associer à l'opération.       * +*                                                                             * +*  Description : Procède à la décompilation des éléments d'un 'if then else'. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void build_ite_branches(GITEInstruction *decomp, GFlowBlock *block, GDecContext *ctx) +{ +    GArchInstruction *last;                 /* Dernière instruction du lot */ +    GInstrBlock *sub_parent;                /* Groupe des sous-branches    */ +    GHashTable *sub_shared;                 /* Allocations communes        */ +    GDecContext *sub_ctx;                   /* Sous-contexte pour branche  */ +    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;                /* Sous-bloc basique direct    */ + +    g_flow_block_get_boundary(block, NULL, &last); + +    sub_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); +    sub_shared = g_hash_table_new_full((GHashFunc)g_arch_register_hash, +                                       (GEqualFunc)g_arch_register_equal, +                                       g_object_unref, g_object_unref); + +    true_dinstr = NULL; +    false_dinstr = NULL; + +    /* Branche 'true' */ +    next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_TRUE); +    if (next != NULL) +    { +        g_arch_instruction_get_location(next, NULL, NULL, &next_addr); +        next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false); + +        if (next_block != NULL) +        { +            sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared); +            true_dinstr = decompiled_basic_block(next_block, sub_ctx); +            g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx); +            g_object_unref(G_OBJECT(sub_ctx)); +        } + +    } + +    /* Branche 'false' */ +    next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_FALSE); +    if (next != NULL) +    { +        g_arch_instruction_get_location(next, NULL, NULL, &next_addr); +        next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false); + +        if (next_block != NULL) +        { +            sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared); +            false_dinstr = decompiled_basic_block(next_block, sub_ctx); +            g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx); +            g_object_unref(G_OBJECT(sub_ctx)); +        } + +    } + +    g_ite_instruction_set_branches(decomp, true_dinstr, false_dinstr); + +    g_hash_table_unref(sub_shared); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : case_dinstr = instructions d'un cas de 'switch' décompilées. * +*                case_block  = bloc d'instructions assembleur correspondantes.* +*                cases       = listes des instructions des différents cas.    * +*                current     = indice du cas courant.                         * +*                ccount      = nombre de cas présents dans le 'switch'.       * +*                                                                             * +*  Description : Termine le traitement d'un cas de 'switch'.                  * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void close_case_decomp_instructions(GDecInstruction *case_dinstr, GInstrBlock *case_block, GArchInstruction **cases, size_t current, size_t ccount) +{ +    vmpa_t *cases_addr;                     /* Adresses des cas du 'switch'*/ +    size_t i;                               /* Boucle de parcours #1       */ +    GInstrBlock **leafs;                    /* Blocs terminaux du cas      */ +    size_t lcount;                          /* Nombre de blocs terminaux   */ +    vmpa_t common_addr;                     /* Adresse commune de suite    */ +    bool is_common;                         /* Suite commune ?             */ +    GArchInstruction *last;                 /* Dernière instruction de bloc*/ +    GArchInstruction **dests;               /* Instr. visée par une autre  */ +    size_t dcount;                          /* Nombre de liens de dest.    */ +    size_t j;                               /* Boucle de parcours #2       */ +    vmpa_t addr;                            /* Adresse d'une instruction   */ +    bool jump_to_case;                      /* Suite dans le cas suivant ? */ + +    /* Etablit la liste des adresses des cas */ + +    cases_addr = (vmpa_t *)calloc(ccount, sizeof(vmpa_t)); + +    for (i = 0; i < ccount; i++) +        g_arch_instruction_get_location(cases[i], NULL, NULL, &cases_addr[i]); + +    /* Récupère la (les) fin(s) du cas présent */ + +    leafs = NULL; +    lcount = 0; + +    g_instr_block_list_leafs_blocks(case_block, &leafs, &lcount); + +    /* Procède à une première analyse de la suite */ + +    common_addr = VMPA_MAX; +    is_common = true; + +    for (i = 0; i < lcount && is_common; i++) +    { +        g_flow_block_get_boundary(G_FLOW_BLOCK(leafs[i]), NULL, &last); +        dcount = g_arch_instruction_get_destinations(last, &dests, NULL, NULL); + +        for (j = 0; j < dcount && is_common; j++) +        { +            g_arch_instruction_get_location(dests[j], NULL, NULL, &addr); + +            if (common_addr == VMPA_MAX) +                common_addr = addr; +            else +                is_common = (common_addr == addr); + +        } + +    } + +    /* La sortie du cas est unique ! */ +    if (is_common) +    { +        if (common_addr == VMPA_MAX) +            goto ecdi_exit; + +        jump_to_case = false; + +        for (i = 0; i < ccount && !jump_to_case; i++) +            if (i != current) +                jump_to_case = (cases_addr[i] == common_addr); + +        if (!jump_to_case) +            g_expr_block_add_item(G_EXPR_BLOCK(case_dinstr), g_keyword_instruction_new(DKW_BREAK)); + +    } + +    /* ... ou il faut suivre les différentes branches... */ +    else +    { + +        /* TODO */ + +    } + + ecdi_exit: + +    free(cases_addr); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : decomp = instruction 'switch' à compléter.                   * +*                block  = ensemble des instructions d'assemblage traitées.    * +*                ctx    = contexte de soutien à associer à l'opération.       * +*                                                                             * +*  Description : Procède à la décompilation des éléments d'un 'switch'.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void build_switch_branches(GSwitchInstruction *decomp, GFlowBlock *block, GDecContext *ctx) +{ +    GArchInstruction *last;                 /* Dernière instruction du lot */ +    GInstrBlock *sub_parent;                /* Groupe des sous-branches    */ +    GHashTable *sub_shared;                 /* Allocations communes        */ +    GDecContext *sub_ctx;                   /* Sous-contexte pour branche  */ +    vmpa_t next_addr;                       /* Adresse de cette instruct°  */ +    GInstrBlock *next_block;                /* Sous-bloc basique direct    */ +    GArchInstruction **dests;               /* Instr. visée par une autre  */ +    link_extra_info *info;                  /* Compléments pour les liens  */ +    size_t dcount;                          /* Nombre de liens de dest.    */ +    size_t i;                               /* Boucle de parcours #2       */ +    GDecInstruction *case_dinstr;           /* Décompilation 'case'        */ +    GDecExpression *case_value;             /* Valeur d'aiguillage         */ + +    g_flow_block_get_boundary(block, NULL, &last); + +    sub_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); +    sub_shared = g_hash_table_new_full((GHashFunc)g_arch_register_hash, +                                       (GEqualFunc)g_arch_register_equal, +                                       g_object_unref, g_object_unref); + +    dcount = g_arch_instruction_get_destinations(last, &dests, NULL, &info); + +    for (i = 0; i < dcount; i++) +    { +        g_arch_instruction_get_location(dests[i], NULL, NULL, &next_addr); +        next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false); + +        if (next_block != NULL) +        { +            sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared); +            case_dinstr = decompiled_basic_block(next_block, sub_ctx); +            g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx); +            g_object_unref(G_OBJECT(sub_ctx)); + +            close_case_decomp_instructions(case_dinstr, next_block, dests, i, dcount); + +            if (info[i].imm != NULL) +            { +                case_value = G_DEC_EXPRESSION(g_imm_expression_new(info[i].imm)); +                g_switch_instruction_add_case(G_SWITCH_INSTRUCTION(decomp), +                                              case_value, case_dinstr, next_addr); +            } +            else g_switch_instruction_set_default_case(G_SWITCH_INSTRUCTION(decomp), +                                                       case_dinstr); + +        } + +    } + +    g_hash_table_unref(sub_shared); + +} diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c index 14dad95..993f70f 100644 --- a/src/analysis/disass/macro.c +++ b/src/analysis/disass/macro.c @@ -52,7 +52,7 @@ typedef struct _branch_info  /* Indique si une adresse est retenue comme point de passage. */ -static bool is_addr_in_branch(const branch_info *, const vmpa_t *, bool); +static bool is_addr_in_branch(const branch_info *, const vmpa_t *, bool, size_t *);  /* Identifie les différents points de passage d'une branche. */  static void find_next_jumps(GArchInstruction *, vmpa_t, vmpa_t, branch_info *); @@ -73,6 +73,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *, vmpa_t, vmpa_t,  *  Paramètres  : info = informations à consulter.                             *  *                addr = adresse à rechercher.                                 *  *                fast = autorise une recherche rapide.                        * +*                pos  = enregistrement de la position de la trouvaille. [OUT] *  *                                                                             *  *  Description : Indique si une adresse est retenue comme point de passage.   *  *                                                                             * @@ -82,7 +83,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *, vmpa_t, vmpa_t,  *                                                                             *  ******************************************************************************/ -static bool is_addr_in_branch(const branch_info *info, const vmpa_t *addr, bool fast) +static bool is_addr_in_branch(const branch_info *info, const vmpa_t *addr, bool fast, size_t *pos)  {      bool result;                            /* Bilan à retourner           */      size_t i;                               /* Boucle de parcours          */ @@ -92,12 +93,20 @@ static bool is_addr_in_branch(const branch_info *info, const vmpa_t *addr, bool      if (!fast)          for (i = 0; i < info->count && !result; i++) +        {              result = (info->jumps[i] == *addr); +            if (result && pos != NULL) +                *pos = i; +        }      else      {          ptr = bsearch(addr, info->jumps, info->count, sizeof(vmpa_t), (__compar_fn_t)compare_vmpa);          result = (ptr != NULL); + +        if (result && pos != NULL) +            *pos = (ptr - ((void *)info->jumps)) / sizeof(vmpa_t); +      }      return result; @@ -130,7 +139,7 @@ static void find_next_jumps(GArchInstruction *instrs, vmpa_t start, vmpa_t end,      vmpa_t addr;                            /* Adresse de la destination   */      /* On évite de boucler... */ -    if (is_addr_in_branch(info, &start, false)) +    if (is_addr_in_branch(info, &start, false, NULL))          return;      info->jumps = (vmpa_t *)realloc(info->jumps, ++(info->count) * sizeof(vmpa_t)); @@ -174,7 +183,7 @@ static void find_next_jumps(GArchInstruction *instrs, vmpa_t start, vmpa_t end,      }      /* Si on termine... */ -    if (iter != NULL && !is_addr_in_branch(info, &end, false)) +    if (iter != NULL && !is_addr_in_branch(info, &end, false, NULL))      {          info->jumps = (vmpa_t *)realloc(info->jumps, ++(info->count) * sizeof(vmpa_t));          info->jumps[info->count - 1] = end; @@ -208,7 +217,7 @@ static vmpa_t compute_first_common_addr(branch_info *a, branch_info *b)      //qsort(b->jumps, b->count, sizeof(vmpa_t), (__compar_fn_t)compare_vmpa);      for (i = 0; i < a->count && result == VMPA_MAX; i++) -        if (is_addr_in_branch(b, &a->jumps[i], false)) +        if (is_addr_in_branch(b, &a->jumps[i], false, NULL))              result = a->jumps[i];      return result; @@ -247,7 +256,7 @@ static vmpa_t compute_first_common_addr_in_group(const branch_info *list, size_t          keep = true;          for (j = 1; j < count && keep; j++) -            keep = is_addr_in_branch(&list[j], &list[0].jumps[i], false); +            keep = is_addr_in_branch(&list[j], &list[0].jumps[i], false, NULL);          if (keep)              result = list[0].jumps[i]; @@ -259,6 +268,51 @@ static vmpa_t compute_first_common_addr_in_group(const branch_info *list, size_t  } + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : list  = liste d'ensembles de jalons à parcourir.             * +*                count = taille de cette liste.                               * +*                                                                             * +*  Description : Retrouve le point de ralliement entre un groupe de branches. * +*                                                                             * +*  Retour      : Adresse commune aux branches.                                * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static vmpa_t avoid_cases_common_part(const branch_info *list, size_t cur, size_t count, vmpa_t max) +{ +    vmpa_t result;                          /* Adresse trouvée à retourner */ +    size_t found_pos;                       /* Plus petit tronc commun     */ +    size_t i;                               /* Boucle de parcours          */ +    size_t pos;                             /* Emplacement du cas commun   */ + +    result = max; + +    found_pos = list[cur].count; + +    for (i = 0; i < count; i++) +    { +        if (i == cur) continue; + +        if (is_addr_in_branch(&list[cur], &list[i].jumps[0], false, &pos)) +        { +            if (pos < found_pos) +                result = list[i].jumps[0]; +        } + +    } + +    return result; + +} + + +  /******************************************************************************  *                                                                             *  *  Paramètres  : instrs = ensemble des instructions d'assemblage.             * @@ -447,13 +501,38 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta              parent = block;              group = g_virtual_block_new(); +            do +            { +                size_t _i, _j; + +                for (_i = 0; _i < cases_count; _i++) +                { +                    printf("  [case %d] : ", _i); + +                    for (_j = 0; _j < cases_branches[_i].count; _j++) +                        printf("0x%08lx ", cases_branches[_i].jumps[_j]); + +                    printf("\n"); + +                } + +            } while (0); + +              for (j = 0; j < cases_count; j++)              { -                printf(" ## %zu...", j); +                printf(" ## %zu start=0x%08lx (0x%08lx)...\n", j, cases_branches[j].jumps[0], +                       next_addr); + +                //block = build_instruction_block(instrs, cases_branches[j].jumps[0], end, next_addr); + +                //next_addr = avoid_cases_common_part(cases_branches, j, cases_count, next_addr); -                block = build_instruction_block(instrs, cases_branches[j].jumps[0], end, next_addr); +                block = build_instruction_block(instrs, cases_branches[j].jumps[0], end, +                                                avoid_cases_common_part(cases_branches, j, cases_count, next_addr)); -                printf(" %p\n", block); +                printf(" %p (0x%08lx)\n", block, +                       avoid_cases_common_part(cases_branches, j, cases_count, next_addr));                  if (block != NULL) diff --git a/src/arch/dalvik/decomp/if.c b/src/arch/dalvik/decomp/if.c index 93e21d9..f7591b9 100644 --- a/src/arch/dalvik/decomp/if.c +++ b/src/arch/dalvik/decomp/if.c @@ -26,6 +26,7 @@  #include "../instruction.h"  #include "../../../decomp/expr/cond.h" +#include "../../../decomp/expr/immediate.h"  #include "../../../decomp/instr/ite.h" @@ -153,8 +154,8 @@ GDecInstruction *dalvik_decomp_instr_if_zero(const GArchInstruction *instr, GDec      operand = g_arch_instruction_get_operand(instr, 0);      op1 = g_dec_context_convert_register(ctx, operand, false, addr); -    operand = g_imm_operand_new_from_value(MDS_8_BITS_UNSIGNED, (unsigned int)0); -    op2 = g_imm_expression_new(operand); +    operand = g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, (unsigned int)0); +    op2 = g_imm_expression_new(G_IMM_OPERAND(operand));      operand = g_arch_instruction_get_operand(instr, 2);      jmp = 0x1234ull;/*g_dec_context_convert_register(ctx, operand, addr);*/ diff --git a/src/arch/dalvik/instruction.c b/src/arch/dalvik/instruction.c index 81b8993..1ab6e3c 100644 --- a/src/arch/dalvik/instruction.c +++ b/src/arch/dalvik/instruction.c @@ -117,12 +117,12 @@ static dalvik_instruction _instructions[DOP_COUNT] = {      [DOP_IF_GE]                 = { 0x35, "if-ge",              dalvik_decomp_instr_if },      [DOP_IF_GT]                 = { 0x36, "if-gt",              dalvik_decomp_instr_if },      [DOP_IF_LE]                 = { 0x37, "if-le",              dalvik_decomp_instr_if }, -    [DOP_IF_EQZ]                = { 0x38, "if-eqz"/*,             dalvik_decomp_instr_if_zero*/ }, -    [DOP_IF_NEZ]                = { 0x39, "if-nez"/*,             dalvik_decomp_instr_if_zero*/ }, -    [DOP_IF_LTZ]                = { 0x3a, "if-ltz"/*,             dalvik_decomp_instr_if_zero*/ }, -    [DOP_IF_GEZ]                = { 0x3b, "if-gez"/*,             dalvik_decomp_instr_if_zero*/ }, -    [DOP_IF_GTZ]                = { 0x3c, "if-gtz"/*,             dalvik_decomp_instr_if_zero*/ }, -    [DOP_IF_LEZ]                = { 0x3d, "if-lez"/*,             dalvik_decomp_instr_if_zero*/ }, +    [DOP_IF_EQZ]                = { 0x38, "if-eqz",             dalvik_decomp_instr_if_zero }, +    [DOP_IF_NEZ]                = { 0x39, "if-nez",             dalvik_decomp_instr_if_zero }, +    [DOP_IF_LTZ]                = { 0x3a, "if-ltz",             dalvik_decomp_instr_if_zero }, +    [DOP_IF_GEZ]                = { 0x3b, "if-gez",             dalvik_decomp_instr_if_zero }, +    [DOP_IF_GTZ]                = { 0x3c, "if-gtz",             dalvik_decomp_instr_if_zero }, +    [DOP_IF_LEZ]                = { 0x3d, "if-lez",             dalvik_decomp_instr_if_zero },      [DOP_UNUSED_3E]             = { 0x3e, NULL /* unused */ },      [DOP_UNUSED_3F]             = { 0x3f, NULL /* unused */ },      [DOP_UNUSED_40]             = { 0x40, NULL /* unused */ }, diff --git a/src/decomp/instr/Makefile.am b/src/decomp/instr/Makefile.am index 6120cac..d299cd2 100644 --- a/src/decomp/instr/Makefile.am +++ b/src/decomp/instr/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libdecompinstr.la  libdecompinstr_la_SOURCES =				\  	ite.h ite.c							\ +	keyword.h keyword.c					\  	switch.h switch.c  libdecompinstr_la_LDFLAGS =  diff --git a/src/decomp/instr/keyword.c b/src/decomp/instr/keyword.c new file mode 100644 index 0000000..eca1530 --- /dev/null +++ b/src/decomp/instr/keyword.c @@ -0,0 +1,162 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * keyword.c - insertions de mots clefs de haut niveau + * + * Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. + */ + + +#include "keyword.h" + + +#include "../instruction-int.h" + + + +/* Définition d'un mot clef de haut niveau (instance) */ +struct _GKeywordInstruction +{ +    GDecInstruction parent;                 /* A laisser en premier        */ + +    DecompiledKeyWord keyword;              /* Mot clef représenté         */ + +}; + + +/* Indique le type défini pour un mot clef de haut niveau. */ +struct _GKeywordInstructionClass +{ +    GDecInstructionClass parent;            /* A laisser en premier        */ + +}; + + + +/* Initialise la classe des mots clefs de haut niveau. */ +static void g_keyword_instruction_class_init(GKeywordInstructionClass *); + +/* Initialise une instance de mot clef de haut niveau. */ +static void g_keyword_instruction_init(GKeywordInstruction *); + +/* Imprime pour l'écran un version humaine d'une instruction. */ +static GBufferLine *g_keyword_instruction_print(const GKeywordInstruction *, GCodeBuffer *, GBufferLine *, GLangOutput *); + + + +/* Indique le type défini pour un mot clef de haut niveau. */ +G_DEFINE_TYPE(GKeywordInstruction, g_keyword_instruction, G_TYPE_DEC_INSTRUCTION); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : klass = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des mots clefs de haut niveau.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_keyword_instruction_class_init(GKeywordInstructionClass *klass) +{ + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : instr = instance à initialiser.                              * +*                                                                             * +*  Description : Initialise une instance de mot clef de haut niveau.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_keyword_instruction_init(GKeywordInstruction *instr) +{ +    GDecInstruction *base;                  /* Autre version de l'objet    */ + +    base = G_DEC_INSTRUCTION(instr); + +    base->print = (dec_instr_print_fc)g_keyword_instruction_print; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : keyword = mot clef à représenter.                            * +*                                                                             * +*  Description : Crée un mot clef de haut niveau.                             * +*                                                                             * +*  Retour      : Instruction mise en place.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GDecInstruction *g_keyword_instruction_new(DecompiledKeyWord keyword) +{ +    GKeywordInstruction *result;              /* Expression à retourner      */ + +    result = g_object_new(G_TYPE_KEYWORD_INSTRUCTION, NULL); + +    result->keyword = keyword; + +    return G_DEC_INSTRUCTION(result); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : instr  = instruction à transcrire en version humaine.        * +*                buffer = tampon où doit se réaliser l'insertion.             * +*                line   = ligne d'impression prête à emploi ou NULL.          * +*                output = langage de programmation de sortie.                 * +*                                                                             * +*  Description : Imprime pour l'écran un version humaine d'une instruction.   * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static GBufferLine *g_keyword_instruction_print(const GKeywordInstruction *instr, GCodeBuffer *buffer, GBufferLine *line, GLangOutput *output) +{ +    switch (instr->keyword) +    { +        case DKW_BREAK: +            g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "break", 5, RTT_KEY_WORD); +            break; + +        case DKW_CONTINUE: +            g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "continue", 8, RTT_KEY_WORD); +            break; + +    } + +    return line; + +} diff --git a/src/decomp/instr/keyword.h b/src/decomp/instr/keyword.h new file mode 100644 index 0000000..69d6901 --- /dev/null +++ b/src/decomp/instr/keyword.h @@ -0,0 +1,68 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * keyword.h - prototypes pour les insertions de mots clefs de haut niveau + * + * Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _DECOMP_INSTR_KEYWORD_H +#define _DECOMP_INSTR_KEYWORD_H + + +#include <glib-object.h> + + +#include "../instruction.h" + + + +#define G_TYPE_KEYWORD_INSTRUCTION               g_keyword_instruction_get_type() +#define G_KEYWORD_INSTRUCTION(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_keyword_instruction_get_type(), GKeywordInstruction)) +#define G_IS_KEYWORD_INSTRUCTION(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_keyword_instruction_get_type())) +#define G_KEYWORD_INSTRUCTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KEYWORD_INSTRUCTION, GKeywordInstructionClass)) +#define G_IS_KEYWORD_INSTRUCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KEYWORD_INSTRUCTION)) +#define G_KEYWORD_INSTRUCTION_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KEYWORD_INSTRUCTION, GKeywordInstructionClass)) + + + +/* Type de mots clefs pris en charge */ +typedef enum _DecompiledKeyWord +{ +    DKW_BREAK,                              /* 'break'                     */ +    DKW_CONTINUE,                           /* 'continue'                  */ + +} DecompiledKeyWord; + + +/* Définition d'un mot clef de haut niveau (instance) */ +typedef struct _GKeywordInstruction GKeywordInstruction; + +/* Définition d'un mot clef de haut niveau (classe) */ +typedef struct _GKeywordInstructionClass GKeywordInstructionClass; + + +/* Indique le type défini pour un mot clef de haut niveau. */ +GType g_keyword_instruction_get_type(void); + +/* Crée un mot clef de haut niveau. */ +GDecInstruction *g_keyword_instruction_new(DecompiledKeyWord); + + + +#endif  /* _DECOMP_INSTR_KEYWORD_H */ diff --git a/src/decomp/instr/switch.c b/src/decomp/instr/switch.c index 3c204a0..4b1662b 100644 --- a/src/decomp/instr/switch.c +++ b/src/decomp/instr/switch.c @@ -31,15 +31,16 @@  #include "../instruction-int.h" +  /* Détails d'un cas */  typedef struct _case_info  { -    vmpa_t addr;                            /* Adresse des blocs associés */ +    vmpa_t addr;                            /* Adresse des blocs associés  */ -    GDecExpression **values;                /* Valeur d'embranchement     */ -    size_t values_count;                    /* Quantité de cas rassemblés */ +    GDecExpression **values;                /* Valeur d'embranchement      */ +    size_t values_count;                    /* Quantité de cas rassemblés  */ -    GDecInstruction *instrs;                /* Instructions du cas        */ +    GDecInstruction *instrs;                /* Instructions du cas         */  } case_info; @@ -138,7 +139,7 @@ static void g_switch_instruction_init(GSwitchInstruction *instr)  *                                                                             *  *  Description : Exprime un aiguillage multiple du flux selon une valeur.     *  *                                                                             * -*  Retour      : Expression mise en place.                                    * +*  Retour      : Instruction mise en place.                                   *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             * | 
