From bacf50f92fb497b201925b010cae78bf44584072 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 8 Feb 2020 01:21:49 +0100
Subject: Counted Elf symbols using the DT_GNU_HASH dynamic item.

---
 plugins/elf/elf_def.h |   2 +
 plugins/elf/symbols.c | 120 ++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 108 insertions(+), 14 deletions(-)

diff --git a/plugins/elf/elf_def.h b/plugins/elf/elf_def.h
index 355fa2f..915eb15 100644
--- a/plugins/elf/elf_def.h
+++ b/plugins/elf/elf_def.h
@@ -518,6 +518,8 @@ typedef union _elf_dyn
 #define DT_PREINIT_ARRAYSZ 33           /* Taille de DT_PREINIT_ARRAY      */
 #define DT_NUM          34              /* Nombre utilisé                  */
 
+#define DT_GNU_HASH     0x6ffffef5      /* Table d'empreintes version GNU  */
+
 
 
 /* ---------------------------- SYMBOLES DE BINAIRES ELF ---------------------------- */
diff --git a/plugins/elf/symbols.c b/plugins/elf/symbols.c
index d90f4a5..26876bd 100644
--- a/plugins/elf/symbols.c
+++ b/plugins/elf/symbols.c
@@ -781,6 +781,13 @@ static bool count_elf_global_symbols(GElfFormat *format, GExeFormat *exec, uint3
     elf_dyn hash;                           /* Table de type DT_HASH       */
     bool found;                             /* Détection validée           */
     vmpa2t addr;                            /* Position de départ brute    */
+    uint32_t n_buckets;                     /* Quantité de bacs en place   */
+    uint32_t sym_offset;                    /* Indice du premier symbole   */
+    uint32_t bloom_size;                    /* Taille du filtre Bloom      */
+    uint32_t last_symbol;                   /* Indice de dernier symbole   */
+    uint32_t i;                             /* Boucle de parcours          */
+    uint32_t start;                         /* Indice de départ d'un bac   */
+    uint32_t value;                         /* Valeur d'un maillon         */
 
     result = false;
 
@@ -790,22 +797,107 @@ static bool count_elf_global_symbols(GElfFormat *format, GExeFormat *exec, uint3
      *    - http://www.gabriel.urdhr.fr/2015/09/28/elf-file-format/#symbol-tables
      *    - http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash
      *
+     * Le fonctionnement global des chaînes est décrit ici :
+     *
+     *    - https://flapenguin.me/2017/04/24/elf-lookup-dt-hash/
+     *
+     * Celui des chaînes GNU fait l'objet de l'article suivant :
+     *
+     *    - https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/
+     *
      */
 
+    /* Méthode DT_HASH */
+
     found = find_elf_dynamic_item_by_type(format, DT_HASH, &hash);
-    if (!found) goto cegs_exit;
 
-    exec = G_EXE_FORMAT(format);
+    if (found)
+    {
+        result = g_exe_format_translate_address_into_vmpa(exec, ELF_DYN(format, hash, d_un.d_ptr), &addr);
+        if (!result) goto exit;
+
+        advance_vmpa(&addr, sizeof(uint32_t));
+
+        result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, count);
+        if (!result) goto exit;
+
+        goto exit;
+
+    }
 
-    result = g_exe_format_translate_address_into_vmpa(exec, ELF_DYN(format, hash, d_un.d_ptr), &addr);
-    if (!result) goto cegs_exit;
+    /* Méthode DT_GNU_HASH */
 
-    advance_vmpa(&addr, 4);
+    found = find_elf_dynamic_item_by_type(format, DT_GNU_HASH, &hash);
 
-    result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, count);
-    if (!result) goto cegs_exit;
+    if (found)
+    {
+        result = g_exe_format_translate_address_into_vmpa(exec, ELF_DYN(format, hash, d_un.d_ptr), &addr);
+        if (!result) goto exit;
+
+        result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, &n_buckets);
+        if (!result) goto exit;
+
+        result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, &sym_offset);
+        if (!result) goto exit;
+
+        result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, &bloom_size);
+        if (!result) goto exit;
+
+        /* Saut de bloom_shift */
+        advance_vmpa(&addr, sizeof(uint32_t));
+
+        /* Saut de bloom[bloom_size] */
+        if (format->is_32b)
+            advance_vmpa(&addr, bloom_size * sizeof(uint32_t));
+        else
+            advance_vmpa(&addr, bloom_size * sizeof(uint64_t));
+
+        /* Localisation de la chaîne comportant le plus grand index */
+
+        last_symbol = 0;
+
+        for (i = 0; i < n_buckets; i++)
+        {
+            result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, &start);
+            if (!result) goto exit;
+
+            if (last_symbol < start)
+                last_symbol = start;
+
+        }
+
+        if (last_symbol < sym_offset)
+        {
+            *count = sym_offset;
+            result = true;
+        }
+
+        else
+        {
+            /* Parcours de la chaîne au plus haut potentiel */
+
+            advance_vmpa(&addr, (last_symbol - sym_offset) * sizeof(uint32_t));
+
+            while (true)
+            {
+                result = g_binary_content_read_u32(G_BIN_FORMAT(format)->content, &addr, format->endian, &value);
+                if (!result) goto exit;
+
+                last_symbol++;
+
+                if (value & 0x1)
+                    break;
+
+            }
+
+            *count = last_symbol;
+            result = true;
+
+        }
+
+    }
 
- cegs_exit:
+ exit:
 
     return result;
 
@@ -851,23 +943,23 @@ static bool load_elf_global_symbols(GElfFormat *format, wgroup_id_t gid, GtkStat
     /* Récupération du début des chaînes de description */
 
     result = find_elf_dynamic_item_by_type(format, DT_STRTAB, &strtab);
-    if (!result) goto lees_exit;
+    if (!result) goto exit;
 
     result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, strtab, d_un.d_ptr), &str_start);
-    if (!result) goto lees_exit;
+    if (!result) goto exit;
 
     /* Récupération du début des définitions de symboles */
 
     result = find_elf_dynamic_item_by_type(format, DT_SYMTAB, &symtab);
-    if (!result) goto lees_exit;
+    if (!result) goto exit;
 
     result = g_exe_format_translate_address_into_offset(exec, ELF_DYN(format, symtab, d_un.d_ptr), &sym_start);
-    if (!result) goto lees_exit;
+    if (!result) goto exit;
 
     /* Détermination du nombre d'éléments */
 
     result = count_elf_global_symbols(format, exec, &count);
-    if (!result) goto lees_exit;
+    if (!result) goto exit;
 
     /* Chargement des symboles */
 
@@ -882,7 +974,7 @@ static bool load_elf_global_symbols(GElfFormat *format, wgroup_id_t gid, GtkStat
 
     gtk_status_stack_remove_activity(status, msg);
 
- lees_exit:
+ exit:
 
     return result;
 
-- 
cgit v0.11.2-87-g4458