From 4c5f0e1341b094fed40f9e6944134545f971b1eb Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 15 Oct 2016 14:12:15 +0200
Subject: Built proper comments for all the Dalvik switch cases.

---
 ChangeLog                       |  13 +++
 src/analysis/db/item.c          |  14 +--
 src/analysis/db/item.h          |   2 +-
 src/arch/dalvik/link.c          | 185 ++++++++++++++++++++++++++++++++++++----
 src/arch/dalvik/pseudo/switch.c |  24 +++---
 src/arch/dalvik/pseudo/switch.h |   2 +-
 6 files changed, 202 insertions(+), 38 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 94120dd..4f75240 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+16-10-15  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/db/item.c:
+	* src/analysis/db/item.h:
+	Ensure all items have their label when it is requested.
+
+	* src/arch/dalvik/link.c:
+	Build proper comments for all the Dalvik switch cases.
+
+	* src/arch/dalvik/pseudo/switch.c:
+	* src/arch/dalvik/pseudo/switch.h:
+	Follow the specifications for the sign of the switch keys and targets.
+
 16-10-14  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/disass/disassembler.c:
diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c
index 62e8ce9..243e97b 100644
--- a/src/analysis/db/item.c
+++ b/src/analysis/db/item.c
@@ -241,7 +241,7 @@ gint g_db_item_cmp(GDbItem *a, GDbItem *b, bool with)
         result = cmp_timestamp(&a->created, &b->created);
 
     if (result == 0)
-        result = strcmp(a->label, b->label);
+        result = strcmp(g_db_item_get_label(a), g_db_item_get_label(b));
 
     return result;
 
@@ -343,8 +343,6 @@ bool g_db_item_recv(GDbItem *item, int fd, int flags)
 
     result = G_DB_ITEM_GET_CLASS(item)->recv(item, fd, flags);
 
-    G_DB_ITEM_GET_CLASS(item)->build_label(item);
-
     return result;
 
 }
@@ -470,8 +468,14 @@ bool g_db_item_cancel(GDbItem *item, GLoadedBinary *binary)
 *                                                                             *
 ******************************************************************************/
 
-const char *g_db_item_get_label(const GDbItem *item)
+const char *g_db_item_get_label(GDbItem *item)
 {
+    if (item->label == NULL)
+    {
+        G_DB_ITEM_GET_CLASS(item)->build_label(item);
+        assert(item->label != NULL);
+    }
+
     return item->label;
 
 }
@@ -721,8 +725,6 @@ bool g_db_item_load(GDbItem *item, const bound_value *values, size_t count)
 
     result = G_DB_ITEM_GET_CLASS(item)->load(item, values, count);
 
-    G_DB_ITEM_GET_CLASS(item)->build_label(item);
-
     return result;
 
 }
diff --git a/src/analysis/db/item.h b/src/analysis/db/item.h
index f8bb707..afeaed3 100644
--- a/src/analysis/db/item.h
+++ b/src/analysis/db/item.h
@@ -85,7 +85,7 @@ bool g_db_item_apply(GDbItem *, GLoadedBinary *);
 bool g_db_item_cancel(GDbItem *, GLoadedBinary *);
 
 /* Décrit l'élément de collection en place. */
-const char *g_db_item_get_label(const GDbItem *);
+const char *g_db_item_get_label(GDbItem *);
 
 /* Fournit l'horodatage associé à l'élément de collection. */
 timestamp_t g_db_item_get_timestamp(const GDbItem *);
diff --git a/src/arch/dalvik/link.c b/src/arch/dalvik/link.c
index b698f03..538a57f 100644
--- a/src/arch/dalvik/link.c
+++ b/src/arch/dalvik/link.c
@@ -26,6 +26,7 @@
 
 #include <assert.h>
 #include <malloc.h>
+#include <stdbool.h>
 #include <stdio.h>
 
 
@@ -34,6 +35,27 @@
 
 #include "pseudo/switch.h"
 #include "../target.h"
+#include "../../common/extstr.h"
+
+
+
+/* Mémorisation des cas rencontrés */
+typedef struct _case_comment
+{
+    bool valid;                             /* Entrée utilisable ?         */
+
+    vmpa2t handler;                         /* Position du code associé    */
+
+    bool is_default;                        /* Gestion par défaut ?        */
+    union
+    {
+        int32_t key;                        /* Clef unique                 */
+        int32_t *keys;                      /* Ensemble de clefs dynamique */
+    };
+
+    size_t count;                           /* Nombre de clefs conservées  */
+
+} case_comment;
 
 
 
@@ -60,14 +82,20 @@ void handle_dalvik_packed_switch_links(GArchInstruction *instr, GArchProcessor *
     GArchInstruction *switch_ins;           /* Instruction de branchements */
     const mrange_t *range;                  /* Zone d'occupation           */
     const vmpa2t *start_addr;               /* Adresse de référentiel      */
+    const int32_t *keys;                    /* Conditions de sauts         */
+    const int32_t *targets;                 /* Positions relatives liées   */
+    uint16_t count;                         /* Taille de ces tableaux      */
+    case_comment *comments;                 /* Mémorisation progressive    */
     vmpa2t def_addr;                        /* Traitement par défaut       */
     GArchInstruction *target;               /* Ligne visée par la référence*/
-    GDbComment *comment;                    /* Indication sur la condition */
-    const uint32_t *keys;                   /* Conditions de sauts         */
-    const uint32_t *targets;                /* Positions relatives liées   */
-    uint16_t count;                         /* Taille de ces tableaux      */
-    uint16_t i;                             /* Boucle de parcours          */
-    char *int_val;/* Valeur en chaîne de carac.  */
+    case_comment *comment;                  /* Commentaire à éditer        */
+    uint16_t i;                             /* Boucle de parcours #1       */
+    size_t j;                               /* Boucle de parcours #2       */
+    int32_t tmp;                            /* Sauvegarde temporaire       */
+    char *msg;                              /* Indication à imprimer       */
+    size_t k;                               /* Boucle de parcours #3       */
+    char *int_val;                          /* Valeur en chaîne de carac.  */
+    GDbComment *item;                       /* Indication sur la condition */
 
     assert(g_arch_instruction_count_operands(instr) == 2);
 
@@ -99,6 +127,12 @@ void handle_dalvik_packed_switch_links(GArchInstruction *instr, GArchProcessor *
 
             start_addr = get_mrange_addr(range);
 
+            /* Préparation de l'édition des commentaires */
+
+            count = g_dalvik_switch_get_data(G_DALVIK_SWITCH_INSTR(switch_ins), &keys, &targets);
+
+            comments = (case_comment *)calloc(1 + count, sizeof(case_comment));
+
             /* Cas par défaut */
 
             compute_mrange_end_addr(range, &def_addr);
@@ -107,10 +141,13 @@ void handle_dalvik_packed_switch_links(GArchInstruction *instr, GArchProcessor *
 
             if (target != NULL)
             {
-                comment = g_db_comment_new_area(&def_addr, BLF_NONE, _("Defaut case"), true);
+                comment = &comments[0];
+
+                comment->valid = true;
 
-                // FIXME g_db_item_set_volatile(G_DB_ITEM(comment), true);
-                g_proc_context_add_db_item(context, G_DB_ITEM(comment));
+                copy_vmpa(&comment->handler, &def_addr);
+
+                comment->is_default = true;
 
                 g_arch_instruction_link_with(instr, target, ILT_CASE_JUMP);
 
@@ -118,10 +155,6 @@ void handle_dalvik_packed_switch_links(GArchInstruction *instr, GArchProcessor *
 
             /* Autres cas */
 
-            assert(G_IS_DALVIK_SWITCH_INSTR(switch_ins));
-
-            count = g_dalvik_switch_get_data(G_DALVIK_SWITCH_INSTR(switch_ins), &keys, &targets);
-
             for (i = 0; i < count; i++)
             {
                 copy_vmpa(&addr, start_addr);
@@ -134,12 +167,59 @@ void handle_dalvik_packed_switch_links(GArchInstruction *instr, GArchProcessor *
 
                 if (target != NULL)
                 {
-                    asprintf(&int_val, _("Case %d"), keys[i]);
-                    comment = g_db_comment_new_area(&addr, BLF_NONE, int_val, true);
-                    free(int_val);
+                    for (j = 0; j < (1 + count); j++)
+                    {
+                        if (!comments[j].valid)
+                            break;
+
+                        if (cmp_vmpa(&addr, &comments[j].handler) == 0)
+                            break;
+
+                    }
+
+                    assert(j < (1 + count));
+
+                    comment = &comments[j];
+
+                    if (!comment->valid)
+                    {
+                        comment->valid = true;
+
+                        copy_vmpa(&comment->handler, &addr);
+
+                        comment->key = keys[i];
+                        comment->count = 1;
+
+                    }
+                    else
+                    {
+                        if (comment->count == 0)
+                            comment->key = keys[i];
+
+                        if (comment->count == 1)
+                        {
+                            tmp = comment->key;
+
+                            comment->keys = (int32_t *)calloc(2, sizeof(int32_t));
+
+                            comment->keys[0] = tmp;
+                            comment->keys[1] = keys[i];
+
+                            comment->count = 2;
 
-                    // FIXME g_db_item_set_volatile(G_DB_ITEM(comment), true);
-                    g_proc_context_add_db_item(context, G_DB_ITEM(comment));
+                        }
+
+                        else
+                        {
+                            comment->count++;
+
+                            comment->keys = (int32_t *)realloc(comment->keys, comment->count * sizeof(int32_t));
+
+                            comment->keys[comment->count - 1] = keys[i];
+
+                        }
+
+                    }
 
                     g_arch_instruction_link_with(instr, target, ILT_CASE_JUMP);
 
@@ -147,6 +227,75 @@ void handle_dalvik_packed_switch_links(GArchInstruction *instr, GArchProcessor *
 
             }
 
+            /* Edition des commentaires et nettoyage */
+
+            for (j = 0; j < (1 + count); j++)
+            {
+                comment = &comments[j];
+
+                if (!comment->valid)
+                    break;
+
+                switch (comment->count)
+                {
+                    case 0:
+                        msg = NULL;
+                        break;
+
+                    case 1:
+                        asprintf(&msg, _("Case %d"), comment->key);
+                        break;
+
+                    default:
+
+                        msg = NULL;
+
+                        /**
+                         * Les spécifications indiquent que les clefs sont triées.
+                         * Donc nul besoin de s'occuper de leur ordre ici.
+                         */
+
+                        for (k = 0; k < comment->count; k++)
+                        {
+                            if (k > 0)
+                                msg = stradd(msg, COMMENT_LINE_SEP);
+
+                            asprintf(&int_val, _("Case %d:"), comment->keys[k]);
+                            msg = stradd(msg, int_val);
+                            free(int_val);
+
+                        }
+
+                        break;
+
+                }
+
+                if (comment->is_default)
+                {
+                    if (msg == NULL)
+                        msg = strdup(_("Defaut case:"));
+                    else
+                    {
+                        msg = stradd(msg, COMMENT_LINE_SEP);
+                        msg = stradd(msg, _("Defaut case"));
+                    }
+
+                }
+
+                item = g_db_comment_new_area(&comment->handler, BLF_NONE, msg, true);
+
+                g_db_item_set_volatile(G_DB_ITEM(item), true);
+                g_proc_context_add_db_item(context, G_DB_ITEM(item));
+
+                free(msg);
+
+                if (comment->count > 1)
+                    free(comment->keys);
+
+            }
+
+            free(comments);
+
         }
 
     }
diff --git a/src/arch/dalvik/pseudo/switch.c b/src/arch/dalvik/pseudo/switch.c
index fd7e442..70afb3e 100644
--- a/src/arch/dalvik/pseudo/switch.c
+++ b/src/arch/dalvik/pseudo/switch.c
@@ -39,8 +39,8 @@ struct _GDalvikSwitchInstr
 
     uint16_t switch_size;                   /* Taille du switch considéré  */
 
-    uint32_t *keys;                         /* Table de clefs              */
-    uint32_t *targets;                      /* Table des sauts relatifs    */
+    int32_t *keys;                          /* Table de clefs              */
+    int32_t *targets;                       /* Table des sauts relatifs    */
 
 };
 
@@ -194,9 +194,9 @@ GArchInstruction *g_dalvik_switch_instr_new(uint16_t ident, GDalvikContext *ctx,
         goto gdsin_bad;
 
     if (ident != DPO_PACKED_SWITCH)
-        consumed = (1 + result->switch_size) * sizeof(uint32_t);
+        consumed = (1 + result->switch_size) * sizeof(int32_t);
     else
-        consumed = (2 * result->switch_size) * sizeof(uint32_t);
+        consumed = (2 * result->switch_size) * sizeof(int32_t);
 
     if (!g_dalvik_context_register_switch_data(ctx, pos, consumed))
         goto gdsin_bad;
@@ -229,24 +229,24 @@ GArchInstruction *g_dalvik_switch_instr_new(uint16_t ident, GDalvikContext *ctx,
 static bool g_dalvik_switch_decode_data(GDalvikSwitchInstr *instr, const GBinContent *content, const vmpa2t *pos)
 {
     vmpa2t iter;                            /* Position modifiable         */
-    uint32_t first_key;                     /* Première clef               */
+    int32_t first_key;                      /* Première clef               */
     uint16_t i;                             /* Boucle de parcours          */
 
-    instr->keys = (uint32_t *)calloc(instr->switch_size, sizeof(uint32_t));
-    instr->targets = (uint32_t *)calloc(instr->switch_size, sizeof(uint32_t));
+    instr->keys = (int32_t *)calloc(instr->switch_size, sizeof(int32_t));
+    instr->targets = (int32_t *)calloc(instr->switch_size, sizeof(int32_t));
 
     copy_vmpa(&iter, pos);
 
     if (G_DALVIK_INSTRUCTION(instr)->ptype == DPO_PACKED_SWITCH)
     {
-        if (!g_binary_content_read_u32(content, &iter, SRE_LITTLE, &first_key))
+        if (!g_binary_content_read_s32(content, &iter, SRE_LITTLE, &first_key))
             goto gdsdd_bad;
 
         for (i = 0; i < instr->switch_size; i++)
         {
             instr->keys[i] = first_key + i;
 
-            if (!g_binary_content_read_u32(content, &iter, SRE_LITTLE, &instr->targets[i]))
+            if (!g_binary_content_read_s32(content, &iter, SRE_LITTLE, &instr->targets[i]))
                 goto gdsdd_bad;
 
         }
@@ -256,11 +256,11 @@ static bool g_dalvik_switch_decode_data(GDalvikSwitchInstr *instr, const GBinCon
     else
     {
         for (i = 0; i < instr->switch_size; i++)
-            if (!g_binary_content_read_u32(content, &iter, SRE_LITTLE, &instr->keys[i]))
+            if (!g_binary_content_read_s32(content, &iter, SRE_LITTLE, &instr->keys[i]))
                 goto gdsdd_bad;
 
         for (i = 0; i < instr->switch_size; i++)
-            if (!g_binary_content_read_u32(content, &iter, SRE_LITTLE, &instr->targets[i]))
+            if (!g_binary_content_read_s32(content, &iter, SRE_LITTLE, &instr->targets[i]))
                 goto gdsdd_bad;
 
     }
@@ -288,7 +288,7 @@ static bool g_dalvik_switch_decode_data(GDalvikSwitchInstr *instr, const GBinCon
 *                                                                             *
 ******************************************************************************/
 
-uint16_t g_dalvik_switch_get_data(GDalvikSwitchInstr *instr, const uint32_t **keys, const uint32_t **targets)
+uint16_t g_dalvik_switch_get_data(GDalvikSwitchInstr *instr, const int32_t **keys, const int32_t **targets)
 {
     if (keys != NULL)
         *keys = instr->keys;
diff --git a/src/arch/dalvik/pseudo/switch.h b/src/arch/dalvik/pseudo/switch.h
index ae52758..b0fb1b2 100644
--- a/src/arch/dalvik/pseudo/switch.h
+++ b/src/arch/dalvik/pseudo/switch.h
@@ -56,7 +56,7 @@ GType g_dalvik_switch_instr_get_type(void);
 GArchInstruction *g_dalvik_switch_instr_new(uint16_t, GDalvikContext *, const GBinContent *, vmpa2t *);
 
 /* Fournit les données associées à un branchement Dalvik. */
-uint16_t g_dalvik_switch_get_data(GDalvikSwitchInstr *, const uint32_t **, const uint32_t **);
+uint16_t g_dalvik_switch_get_data(GDalvikSwitchInstr *, const int32_t **, const int32_t **);
 
 
 
-- 
cgit v0.11.2-87-g4458