From eca08119377ce38232581d444f48e28e0d02692b Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 10 Jul 2018 20:08:17 +0200
Subject: Linked all used Dalvik strings with their origin.

---
 plugins/dalvik/link.c                |  65 +++++++++++++++
 plugins/dalvik/link.h                |   4 +
 plugins/dalvik/v35/opdefs/const_1a.d |   6 ++
 plugins/dalvik/v35/opdefs/const_1b.d |   6 ++
 plugins/dex/dex-int.c                |   6 +-
 plugins/dex/dex-int.h                |   3 +-
 plugins/dex/format.c                 |   3 +
 plugins/dex/pool.c                   | 148 ++++++++++++++++++++++++++++-------
 plugins/dex/pool.h                   |   7 +-
 plugins/readdex/ids.c                |  14 +---
 10 files changed, 216 insertions(+), 46 deletions(-)

diff --git a/plugins/dalvik/link.c b/plugins/dalvik/link.c
index aaed263..c37abb8 100644
--- a/plugins/dalvik/link.c
+++ b/plugins/dalvik/link.c
@@ -34,8 +34,10 @@
 #include <analysis/db/items/comment.h>
 #include <arch/target.h>
 #include <common/extstr.h>
+#include <plugins/dex/pool.h>
 
 
+#include "operands/pool.h"
 #include "pseudo/switch.h"
 
 
@@ -63,6 +65,69 @@ typedef struct _case_comment
 #define COMMENT_LINE_SEP "\n"
 
 
+
+/******************************************************************************
+*                                                                             *
+*  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 : Etablit une référence entre utilisation et origine de chaîne.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void handle_links_for_dalvik_string(GArchInstruction *instr, GArchProcessor *proc, GProcContext *context, GExeFormat *format)
+{
+    GArchOperand *op;                       /* Opérande numérique en place */
+    uint32_t index;                         /* Indice dans la table Dex    */
+    GBinSymbol *string;                     /* Emplacement de la chaîne    */
+    const mrange_t *range;                  /* Zone d'occupation           */
+    GArchInstruction *target;               /* Ligne visée par la référence*/
+
+    g_arch_instruction_lock_operands(instr);
+
+    assert(_g_arch_instruction_count_operands(instr) == 2);
+
+    op = _g_arch_instruction_get_operand(instr, 1);
+
+    g_arch_instruction_unlock_operands(instr);
+
+    assert(G_IS_DALVIK_POOL_OPERAND(op));
+
+    assert(g_dalvik_pool_operand_get_pool_type(G_DALVIK_POOL_OPERAND(op)) == DPT_STRING);
+
+    index = g_dalvik_pool_operand_get_index(G_DALVIK_POOL_OPERAND(op));
+
+    string = get_string_symbol_from_dex_pool(G_DEX_FORMAT(format), index);
+
+    if (string != NULL)
+    {
+        range = g_binary_symbol_get_range(string);
+
+        target = g_arch_processor_find_instr_by_address(proc, get_mrange_addr(range));
+
+        if (target != NULL)
+        {
+            g_arch_instruction_link_with(instr, target, ILT_REF);
+
+            g_object_unref(G_OBJECT(target));
+
+        }
+
+        g_object_unref(G_OBJECT(string));
+
+    }
+
+    g_object_unref(G_OBJECT(op));
+
+}
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : instr   = instruction ARMv7 à traiter.                       *
diff --git a/plugins/dalvik/link.h b/plugins/dalvik/link.h
index 38dfd46..3b4a91f 100644
--- a/plugins/dalvik/link.h
+++ b/plugins/dalvik/link.h
@@ -29,6 +29,10 @@
 
 
 
+/* Etablit une référence entre utilisation et origine de chaîne. */
+void handle_links_for_dalvik_string(GArchInstruction *, GArchProcessor *, GProcContext *, GExeFormat *);
+
+
 static inline void handle_dalvik_if_branch_as_link(GArchInstruction *ins, GArchProcessor *proc, GProcContext *ctx, GExeFormat *fmt)
 {
     handle_branch_as_link(ins, proc, ctx, fmt, 2);
diff --git a/plugins/dalvik/v35/opdefs/const_1a.d b/plugins/dalvik/v35/opdefs/const_1a.d
index 54101cd..ff01dbc 100644
--- a/plugins/dalvik/v35/opdefs/const_1a.d
+++ b/plugins/dalvik/v35/opdefs/const_1a.d
@@ -35,4 +35,10 @@
 
     @format 21c | pool_string
 
+    @hooks {
+
+        link = handle_links_for_dalvik_string
+
+    }
+
 }
diff --git a/plugins/dalvik/v35/opdefs/const_1b.d b/plugins/dalvik/v35/opdefs/const_1b.d
index 0aef637..9153206 100644
--- a/plugins/dalvik/v35/opdefs/const_1b.d
+++ b/plugins/dalvik/v35/opdefs/const_1b.d
@@ -35,4 +35,10 @@
 
     @format 31c | pool_string
 
+    @hooks {
+
+        link = handle_links_for_dalvik_string
+
+    }
+
 }
diff --git a/plugins/dex/dex-int.c b/plugins/dex/dex-int.c
index e3121b6..287ec7a 100644
--- a/plugins/dex/dex-int.c
+++ b/plugins/dex/dex-int.c
@@ -145,6 +145,7 @@ bool read_dex_string_id_item(const GDexFormat *format, vmpa2t *pos, string_id_it
 *                                                                             *
 *  Paramètres  : format   = informations chargées à consulter.                *
 *                pos      = position de début de lecture. [OUT]               *
+*                inter    = position intermédiaire à conserver. [OUT]         *
 *                str_data = structure lue à retourner. [OUT]                  *
 *                                                                             *
 *  Description : Procède à la lecture de proriétés de chaîne DEX.             *
@@ -155,7 +156,7 @@ bool read_dex_string_id_item(const GDexFormat *format, vmpa2t *pos, string_id_it
 *                                                                             *
 ******************************************************************************/
 
-bool read_dex_string_data_item(const GDexFormat *format, vmpa2t *pos, string_data_item *str_data)
+bool read_dex_string_data_item(const GDexFormat *format, vmpa2t *pos, vmpa2t *inter, string_data_item *str_data)
 {
     bool result;                            /* Bilan à retourner           */
     GBinContent *content;                   /* Contenu binaire à lire      */
@@ -166,6 +167,9 @@ bool read_dex_string_data_item(const GDexFormat *format, vmpa2t *pos, string_dat
 
     if (result)
     {
+        if (inter != NULL)
+            copy_vmpa(inter, pos);
+
         str_data->data = g_binary_content_get_raw_access(content, pos, str_data->utf16_size);
         result = (str_data->data != NULL);
     }
diff --git a/plugins/dex/dex-int.h b/plugins/dex/dex-int.h
index 4016b1c..5180b58 100644
--- a/plugins/dex/dex-int.h
+++ b/plugins/dex/dex-int.h
@@ -41,6 +41,7 @@ struct _GDexFormat
 
     dex_header header;                      /* En-tête du programme        */
 
+    GBinSymbol **strings;                   /* Symboles pour les chaînes   */
     GDataType **types;                      /* Types partagés pour Dalvik  */
     GBinVariable **fields;                  /* Champs de données partagés  */
     GDexClass **classes;                    /* Classes retrouvées          */
@@ -80,7 +81,7 @@ bool read_dex_header(const GDexFormat *, vmpa2t *, dex_header *);
 bool read_dex_string_id_item(const GDexFormat *, vmpa2t *, string_id_item *);
 
 /* Procède à la lecture de proriétés de chaîne DEX. */
-bool read_dex_string_data_item(const GDexFormat *, vmpa2t *, string_data_item *);
+bool read_dex_string_data_item(const GDexFormat *, vmpa2t *, vmpa2t *, string_data_item *);
 
 /* Procède à la lecture d'un identifiant de type DEX. */
 bool read_dex_type_id_item(const GDexFormat *, vmpa2t *, type_id_item *);
diff --git a/plugins/dex/format.c b/plugins/dex/format.c
index f185cc3..b69cc76 100644
--- a/plugins/dex/format.c
+++ b/plugins/dex/format.c
@@ -396,6 +396,9 @@ static bool g_dex_format_analyze(GDexFormat *format, wgroup_id_t gid, GtkStatusS
     /* TODO : vérifier que les *_id ne se chevauchent pas */
 
 
+    if (!load_all_dex_string_symbols(format, gid, status))
+        goto gdfa_error;
+
     if (!load_all_dex_types(format, gid, status))
         goto gdfa_error;
 
diff --git a/plugins/dex/pool.c b/plugins/dex/pool.c
index 8c740bc..8a421b2 100644
--- a/plugins/dex/pool.c
+++ b/plugins/dex/pool.c
@@ -41,9 +41,11 @@
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : format = description de l'exécutable à analyser.             *
+*  Paramètres  : format = description de l'exécutable à compléter.            *
+*                gid    = groupe de travail impliqué.                         *
+                 status = barre de statut à tenir informée.                   *
 *                                                                             *
-*  Description : Charge en mémoire toutes les chaînes trouvées.               *
+*  Description : Charge en mémoire l'ensemble des chaînes du format DEX.      *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -51,38 +53,58 @@
 *                                                                             *
 ******************************************************************************/
 
-bool find_all_dex_strings(GDexFormat *format)
+bool load_all_dex_string_symbols(GDexFormat *format, wgroup_id_t gid, GtkStatusStack *status)
 {
-    GBinFormat *base;                       /* Autre version du format     */
+    bool result;                            /* Bilan à retourner           */
     uint32_t count;                         /* Nombre d'éléments présents  */
-    uint32_t i;                             /* Boucle de parcours          */
-    mrange_t range;                         /* Couverture associée         */
-    const char *text;                       /* Texte issu du binaire       */
-    GBinSymbol *symbol;                     /* Nouveau symbole construit   */
-    char *label;                            /* Désignation de la chaîne    */
+    guint runs_count;                       /* Qté d'exécutions parallèles */
+    uint32_t run_size;                      /* Volume réparti par exécution*/
+    GWorkQueue *queue;                      /* Gestionnaire de différés    */
+    activity_id_t msg;                      /* Message de progression      */
+    guint i;                                /* Boucle de parcours          */
+    uint32_t begin;                         /* Début de bloc de traitement */
+    uint32_t end;                           /* Fin d'un bloc de traitement */
+    GDexLoading *loading;                   /* Tâche de chargement à lancer*/
 
-    base = G_BIN_FORMAT(format);
+    result = true;
+
+    /* Préparation du réceptacle */
 
     count = count_strings_in_dex_pool(format);
 
-    for (i = 0; i < count; i++)
-    {
-        text = get_string_from_dex_pool(format, i, &range);
-        if (text == NULL) continue;
+    format->strings = (GBinSymbol **)calloc(count, sizeof(GBinSymbol *));
 
-        symbol = g_binary_symbol_new(&range, STP_STRING);
+    /* Lancement des chargements */
 
-        label = create_string_label(base, get_mrange_addr(&range), get_mrange_length(&range));
+    runs_count = get_max_online_threads();
 
-        g_binary_symbol_set_alt_label(symbol, label);
+    run_size = count / runs_count;
 
-        free(label);
+    queue = get_work_queue();
+
+    msg = gtk_status_stack_add_activity(status, _("Loading all strings from the Dex pool..."), count);
+
+    for (i = 0; i < runs_count; i++)
+    {
+        begin = i * run_size;
+
+        if ((i + 1) == runs_count)
+            end = count;
+        else
+            end = begin + run_size;
+
+        loading = g_dex_loading_new(format, begin, end, msg,
+                                    (dex_loading_cb)get_string_symbol_from_dex_pool, &result);
 
-        g_binary_format_add_symbol(base, symbol);
+        g_work_queue_schedule_work(queue, G_DELAYED_WORK(loading), gid);
 
     }
 
-    return true;
+    g_work_queue_wait_for_completion(queue, gid);
+
+    gtk_status_stack_remove_activity(status, msg);
+
+    return result;
 
 }
 
@@ -113,12 +135,12 @@ uint32_t count_strings_in_dex_pool(const GDexFormat *format)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = représentation interne du format DEX à consulter.   *
-*                index  = index du type recherchée.                           *
+*                index  = index de la chaîne recherchée.                      *
 *                range  = éventuelle couverture à renseigner ou NULL. [OUT]   *
 *                                                                             *
 *  Description : Extrait une chaîne de caractères d'une table DEX.            *
 *                                                                             *
-*  Retour      : Chaîne de caractères trouvées ou NULL en cas d'erreur.       *
+*  Retour      : Chaîne de caractères trouvée ou NULL en cas d'erreur.        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -130,8 +152,8 @@ const char *get_string_from_dex_pool(const GDexFormat *format, uint32_t index, m
     off_t pos;                              /* Tête de lecture             */
     vmpa2t addr;                            /* Tête de lecture générique   */
     string_id_item str_id;                  /* Identifiant de chaîne       */
+    vmpa2t inter;                           /* Position intermédiaire      */
     string_data_item str_data;              /* Description de chaîne       */
-    vmpa2t start;                           /* Début de la chaîne          */
     phys_t diff;                            /* Avancée de tête de lecture  */
 
     count = count_strings_in_dex_pool(format);
@@ -148,15 +170,14 @@ const char *get_string_from_dex_pool(const GDexFormat *format, uint32_t index, m
     pos = str_id.string_data_off;
     init_vmpa(&addr, pos, VMPA_NO_VIRTUAL);
 
-    if (!read_dex_string_data_item(format, &addr, &str_data))
+    if (!read_dex_string_data_item(format, &addr, &inter, &str_data))
         return NULL;
 
     if (range != NULL)
     {
-        init_vmpa(&start, pos, VMPA_NO_VIRTUAL);
-        diff = compute_vmpa_diff(&start, &addr);
+        diff = compute_vmpa_diff(&inter, &addr);
 
-        init_mrange(range, &start, diff);
+        init_mrange(range, &inter, diff);
 
     }
 
@@ -167,6 +188,75 @@ const char *get_string_from_dex_pool(const GDexFormat *format, uint32_t index, m
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : format = représentation interne du format DEX à consulter.   *
+*                index  = index de la chaîne recherchée.                      *
+*                                                                             *
+*  Description : Extrait un symbole de chaîne d'une table DEX.                *
+*                                                                             *
+*  Retour      : Composant GLib créé.                                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBinSymbol *get_string_symbol_from_dex_pool(GDexFormat *format, uint32_t index)
+{
+    GBinSymbol *result;                     /* Instance à retourner        */
+    uint32_t count;                         /* Nombre d'éléments présents  */
+    mrange_t range;                         /* Emplacement de la chaîne    */
+    const char *string;                     /* Chaîne de caractères liée   */
+    GBinSymbol *new;                        /* Nouveau symbol créé         */
+    GBinFormat *base;                       /* Autre version du format     */
+    char *label;                            /* Désignation de la chaîne    */
+    bool inserted;                          /* Bilan d'une insertion       */
+
+    result = NULL;
+
+    count = count_strings_in_dex_pool(format);
+
+    if (index >= count)
+        goto gssfdp_error;
+
+    if (format->strings[index] == NULL)
+    {
+        string = get_string_from_dex_pool(format, index, &range);
+        if (string == NULL) goto gssfdp_error;
+
+        new = g_binary_symbol_new(&range, STP_RO_STRING);
+
+        base = G_BIN_FORMAT(format);
+
+        label = create_string_label(base, get_mrange_addr(&range), get_mrange_length(&range));
+
+        g_binary_symbol_set_alt_label(new, label);
+
+        free(label);
+
+        g_object_ref(G_OBJECT(new));
+        inserted = g_binary_format_add_symbol(base, new);
+
+        if (inserted)
+            format->strings[index] = new;
+
+        else
+            g_object_unref(G_OBJECT(new));
+
+    }
+
+    result = format->strings[index];
+
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
+
+ gssfdp_error:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : format = description de l'exécutable à compléter.            *
 *                gid    = groupe de travail impliqué.                         *
                  status = barre de statut à tenir informée.                   *
@@ -261,7 +351,7 @@ uint32_t count_types_in_dex_pool(const GDexFormat *format)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = représentation interne du format DEX à consulter.   *
-*                index  = index du type recherchée.                           *
+*                index  = index du type recherché.                            *
 *                                                                             *
 *  Description : Extrait une représentation de type d'une table DEX.          *
 *                                                                             *
@@ -305,7 +395,7 @@ GDataType *get_type_from_dex_pool(GDexFormat *format, uint32_t index)
         pos = str_id.string_data_off;
         init_vmpa(&addr, pos, VMPA_NO_VIRTUAL);
 
-        if (!read_dex_string_data_item(format, &addr, &str_data))
+        if (!read_dex_string_data_item(format, &addr, NULL, &str_data))
             goto gtfdp_error;
 
         format->types[index] = g_binary_format_decode_type(G_BIN_FORMAT(format), (char *)str_data.data);
diff --git a/plugins/dex/pool.h b/plugins/dex/pool.h
index ed5b447..ac7db60 100644
--- a/plugins/dex/pool.h
+++ b/plugins/dex/pool.h
@@ -35,8 +35,8 @@
 
 
 
-/* Charge en mémoire toutes les chaînes trouvées. */
-bool find_all_dex_strings(GDexFormat *);
+/* Charge en mémoire l'ensemble des chaînes du format DEX. */
+bool load_all_dex_string_symbols(GDexFormat *, wgroup_id_t, GtkStatusStack *);
 
 /* Compte le nombre de chaînes de caractères dans une table DEX. */
 uint32_t count_strings_in_dex_pool(const GDexFormat *);
@@ -44,6 +44,9 @@ uint32_t count_strings_in_dex_pool(const GDexFormat *);
 /* Extrait une chaîne de caractères d'une table DEX. */
 const char *get_string_from_dex_pool(const GDexFormat *, uint32_t, mrange_t *);
 
+/* Extrait un symbole de chaîne d'une table DEX. */
+GBinSymbol *get_string_symbol_from_dex_pool(GDexFormat *, uint32_t);
+
 /* Charge en mémoire l'ensemble des types du format DEX. */
 bool load_all_dex_types(GDexFormat *, wgroup_id_t, GtkStatusStack *);
 
diff --git a/plugins/readdex/ids.c b/plugins/readdex/ids.c
index 82d17f4..702e071 100644
--- a/plugins/readdex/ids.c
+++ b/plugins/readdex/ids.c
@@ -253,9 +253,6 @@ bool annotate_dex_string_ids(const GDexFormat *format, GPreloadInfo *info, GtkSt
     vmpa2t item_pos;                        /* Position d'un élément       */
     uleb128_t length;                       /* Taille de la chaîne en cours*/
     GArchInstruction *instr;                /* Instruction décodée         */
-    bool inserted;                          /* Bilan d'une insertion       */
-    const mrange_t *range;                  /* Espace occupé par une chaîne*/
-    GBinSymbol *symbol;                     /* Symbole à intégrer          */
 
     content = g_binary_format_get_content(G_BIN_FORMAT(format));
 
@@ -333,16 +330,7 @@ bool annotate_dex_string_ids(const GDexFormat *format, GPreloadInfo *info, GtkSt
             {
                 g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true);
 
-                inserted = g_preload_info_add_instruction(info, instr);
-
-                if (inserted)
-                {
-                    range = g_arch_instruction_get_range(instr);
-
-                    symbol = g_binary_symbol_new(range, STP_RO_STRING);
-                    g_binary_format_add_symbol(bformat, symbol);
-
-                }
+                g_preload_info_add_instruction(info, instr);
 
             }
 
-- 
cgit v0.11.2-87-g4458