From 7fd6e0b76f33de5934fad17efb75366904a3875b Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 29 Nov 2017 17:24:20 +0100
Subject: Provided the list of needed shared objects for an Elf binary.

---
 ChangeLog                          | 29 ++++++++++++
 plugins/elf/dynamic.c              | 95 ++++++++++++++++++++++++++++++++++++++
 plugins/elf/dynamic.h              |  3 ++
 plugins/elf/program.c              | 37 ++++++++++++++-
 plugins/elf/program.h              |  3 ++
 plugins/elf/python/Makefile.am     |  1 +
 plugins/elf/python/dynamic.c       | 79 +++++++++++++++++++++++++++++++
 plugins/elf/python/dynamic.h       | 38 +++++++++++++++
 plugins/elf/python/format.c        |  5 ++
 src/analysis/content-int.h         |  4 ++
 src/analysis/content.c             | 24 ++++++++++
 src/analysis/content.h             |  3 ++
 src/analysis/contents/file.c       | 24 ++++++++++
 src/analysis/contents/restricted.c | 52 +++++++++++++++++++++
 14 files changed, 396 insertions(+), 1 deletion(-)
 create mode 100644 plugins/elf/python/dynamic.c
 create mode 100644 plugins/elf/python/dynamic.h

diff --git a/ChangeLog b/ChangeLog
index ba00eee..30c1bcd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+17-11-29  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/elf/dynamic.c:
+	* plugins/elf/dynamic.h:
+	Provide the list of needed shared objects for an Elf binary.
+
+	* plugins/elf/program.c:
+	* plugins/elf/program.h:
+	Find program headers by type.
+
+	* plugins/elf/python/Makefile.am:
+	Add the 'dynamic.[ch]' files to libelfpython_la_SOURCES.
+
+	* plugins/elf/python/dynamic.c:
+	* plugins/elf/python/dynamic.h:
+	New entries: provide the list of needed shared objects for an Elf binary.
+
+	* plugins/elf/python/format.c:
+	Update code.
+
+	* src/analysis/content-int.h:
+	* src/analysis/content.c:
+	* src/analysis/content.h:
+	Provide the last position in a binary content.
+
+	* src/analysis/contents/file.c:
+	* src/analysis/contents/restricted.c:
+	Update code.
+
 17-11-27  Cyrille Bagard <nocbos@gmail.com>
 
 	* plugins/pychrysa/arch/vmpa.c:
diff --git a/plugins/elf/dynamic.c b/plugins/elf/dynamic.c
index 782167c..ed681d1 100644
--- a/plugins/elf/dynamic.c
+++ b/plugins/elf/dynamic.c
@@ -107,3 +107,98 @@ bool find_elf_dynamic_item_from_pheader(const GElfFormat *format, const elf_phdr
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = description de l'exécutable à consulter.            *
+*                count  = nombre d'éléments dans la liste constituée.         *
+*                                                                             *
+*  Description : Fournit la liste des objets partagés requis.                 *
+*                                                                             *
+*  Retour      : Liste de noms d'objets ou NULL en cas d'échec.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const char **list_elf_needed_objects(const GElfFormat *format, size_t *count)
+{
+    const char **result;                    /* Liste à retourner           */
+    elf_phdr dynamic;                       /* Programme à analyser        */
+    virt_t strtab_virt;                     /* Adresse mémoire des chaînes */
+    uint64_t max;                           /* Nombre d'entités présentes  */
+    uint64_t i;                             /* Boucle de parcours          */
+    phys_t pos;                             /* Position de lecture         */
+    elf_dyn item;                           /* Informations extraites      */
+    vmpa2t strtab_pos;                      /* Emplacement des chaînes     */
+    GBinContent *content;                   /* Contenu global analysé      */
+    vmpa2t end;                             /* Limite finale de contenu    */
+    vmpa2t str_pos;                         /* Emplacement d'une chaîne    */
+    phys_t diff;                            /* Données encore disponibles  */
+    const bin_t *string;                    /* Nouvelle chaîne trouvée     */
+
+    result = NULL;
+    *count = 0;
+
+    if (!find_elf_program_by_type(format, PT_DYNAMIC, &dynamic))
+        goto leno_exit;
+
+    max = ELF_PHDR(format, dynamic, p_filesz) / ELF_SIZEOF_DYN(format);
+
+    /* Première passe : recherche des chaînes */
+
+    strtab_virt = VMPA_NO_VIRTUAL;
+
+    for (i = 0; i < max; i++)
+    {
+        pos = ELF_PHDR(format, dynamic, p_offset) + i * ELF_SIZEOF_DYN(format);
+
+        if (!read_elf_dynamic_entry(format, pos, &item))
+            break;
+
+        if (ELF_DYN(format, item, d_tag) == DT_STRTAB)
+            strtab_virt = ELF_DYN(format, item, d_un.d_val);
+
+    }
+
+    if (strtab_virt == VMPA_NO_VIRTUAL)
+        goto leno_exit;
+
+    if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), strtab_virt, &strtab_pos))
+        goto leno_exit;
+
+    /* Seconde passe : recherche des objets requis */
+
+    content = G_BIN_FORMAT(format)->content;
+
+    g_binary_content_compute_end_pos(content, &end);
+
+    for (i = 0; i < max; i++)
+    {
+        pos = ELF_PHDR(format, dynamic, p_offset) + i * ELF_SIZEOF_DYN(format);
+
+        if (!read_elf_dynamic_entry(format, pos, &item))
+            break;
+
+        if (ELF_DYN(format, item, d_tag) == DT_NEEDED)
+        {
+            copy_vmpa(&str_pos, &strtab_pos);
+            advance_vmpa(&str_pos, ELF_DYN(format, item, d_un.d_val));
+
+            diff = compute_vmpa_diff(&str_pos, &end);
+
+            string = g_binary_content_get_raw_access(content, &str_pos, diff);
+
+            result = (const char **)realloc(result, ++(*count) * sizeof(const char *));
+            result[*count - 1] = (const char *)string;
+
+        }
+
+    }
+
+ leno_exit:
+
+    return result;
+
+}
diff --git a/plugins/elf/dynamic.h b/plugins/elf/dynamic.h
index ee5d3d8..c166712 100644
--- a/plugins/elf/dynamic.h
+++ b/plugins/elf/dynamic.h
@@ -36,6 +36,9 @@ bool find_elf_dynamic_program_header(const GElfFormat *, elf_phdr *);
 /* Retrouve un élément donné dans la section dynamique. */
 bool find_elf_dynamic_item_from_pheader(const GElfFormat *, const elf_phdr *, int64_t, elf_dyn *);
 
+/* Fournit la liste des objets partagés requis. */
+const char **list_elf_needed_objects(const GElfFormat *, size_t *);
+
 
 
 #endif  /* _PLUGINS_ELF_DYNAMIC_H */
diff --git a/plugins/elf/program.c b/plugins/elf/program.c
index 3016feb..7e6f2e4 100644
--- a/plugins/elf/program.c
+++ b/plugins/elf/program.c
@@ -108,7 +108,7 @@ const char *get_elf_program_type_desc(const GElfFormat *format, uint32_t p_type)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format  = description de l'exécutable à consulter.           *
-*                index   = indice de la section recherchée.                   *
+*                index   = indice de la partie recherchée.                    *
 *                program = ensemble d'informations à faire remonter. [OUT]    *
 *                                                                             *
 *  Description : Recherche un programme donné au sein de binaire par indice.  *
@@ -135,6 +135,41 @@ bool find_elf_program_by_index(const GElfFormat *format, uint16_t index, elf_phd
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : format  = description de l'exécutable à consulter.           *
+*                type    = type de la partie recherchée.                      *
+*                program = ensemble d'informations à faire remonter. [OUT]    *
+*                                                                             *
+*  Description : Recherche un programme donné au sein de binaire par type.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool find_elf_program_by_type(const GElfFormat *format, uint32_t type, elf_phdr *program)
+{
+    bool result;                            /* Bilan à retourner           */
+    uint16_t i;                             /* Boucle de parcours          */
+
+    result = false;
+
+    for (i = 0; i < ELF_HDR(format, format->header, e_phnum) && !result; i++)
+    {
+        find_elf_program_by_index(format, i, program);
+
+        if (ELF_PHDR(format, *program, p_type) == type)
+            result = true;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : format = description de l'exécutable à consulter.            *
 *                off    = position physique à retrouver.                      *
 *                pos    = position correspondante. [OUT]                      *
diff --git a/plugins/elf/program.h b/plugins/elf/program.h
index 91de4ec..fcb7b1a 100644
--- a/plugins/elf/program.h
+++ b/plugins/elf/program.h
@@ -36,6 +36,9 @@ const char *get_elf_program_type_desc(const GElfFormat *, uint32_t);
 /* Recherche un programme donné au sein de binaire par indice. */
 bool find_elf_program_by_index(const GElfFormat *, uint16_t, elf_phdr *);
 
+/* Recherche un programme donné au sein de binaire par type. */
+bool find_elf_program_by_type(const GElfFormat *, uint32_t, elf_phdr *);
+
 /* Fournit l'emplacement correspondant à une position physique. */
 bool translate_offset_into_vmpa_using_elf_programs(const GElfFormat *, phys_t, vmpa2t *);
 
diff --git a/plugins/elf/python/Makefile.am b/plugins/elf/python/Makefile.am
index 91e86f0..bcb739e 100644
--- a/plugins/elf/python/Makefile.am
+++ b/plugins/elf/python/Makefile.am
@@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libelfpython.la
 
 libelfpython_la_SOURCES =				\
 	constants.h constants.c				\
+	dynamic.h dynamic.c					\
 	format.h format.c					\
 	module.h module.c
 
diff --git a/plugins/elf/python/dynamic.c b/plugins/elf/python/dynamic.c
new file mode 100644
index 0000000..b87cba0
--- /dev/null
+++ b/plugins/elf/python/dynamic.c
@@ -0,0 +1,79 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * utils.c - prototypes pour l'équivalent Python du fichier "plugins/elf/utils.c"
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "dynamic.h"
+
+
+#include <malloc.h>
+#include <pygobject.h>
+
+
+#include "../dynamic.h"
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = classe représentant un format ELF.                 *
+*                closure = adresse non utilisée ici.                          *
+*                                                                             *
+*  Description : Fournit la liste des objets partagés requis.                 *
+*                                                                             *
+*  Retour      : Liste de noms d'objets ou None en cas d'échec.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyObject *py_elf_format_get_needed(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Liste éventuelle à renvoyer */
+    GElfFormat *format;                     /* Version native              */
+    size_t count;                           /* Taille de la liste obtenue  */
+    const char **needed;                    /* Objets nécessaires          */
+    size_t i;                               /* Boucle de parcours          */
+
+    format = G_ELF_FORMAT(pygobject_get(self));
+
+    needed = list_elf_needed_objects(format, &count);
+
+    if (count > 0)
+    {
+        result = PyTuple_New(count);
+
+        for (i = 0; i < count; i++)
+            PyTuple_SetItem(result, i, PyUnicode_FromString(needed[i]));
+
+        free(needed);
+
+    }
+    else
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    return result;
+
+}
diff --git a/plugins/elf/python/dynamic.h b/plugins/elf/python/dynamic.h
new file mode 100644
index 0000000..4656c6d
--- /dev/null
+++ b/plugins/elf/python/dynamic.h
@@ -0,0 +1,38 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * utils.h - prototypes pour l'équivalent Python du fichier "plugins/elf/utils.h"
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _PLUGINS_ELF_PYTHON_UTILS_H
+#define _PLUGINS_ELF_PYTHON_UTILS_H
+
+
+#include <Python.h>
+
+
+
+/* Fournit la liste des objets partagés requis. */
+PyObject *py_elf_format_get_needed(PyObject *, void *);
+
+
+
+#endif  /* _PLUGINS_ELF_PYTHON_UTILS_H */
diff --git a/plugins/elf/python/format.c b/plugins/elf/python/format.c
index 1ff22bd..eb1bedb 100644
--- a/plugins/elf/python/format.c
+++ b/plugins/elf/python/format.c
@@ -37,6 +37,7 @@
 
 
 #include "constants.h"
+#include "dynamic.h"
 #include "../format.h"
 
 
@@ -144,6 +145,10 @@ PyTypeObject *get_python_elf_format_type(void)
     };
 
     static PyGetSetDef py_elf_format_getseters[] = {
+        {
+            "needed", py_elf_format_get_needed, NULL,
+            "Provide the list of requiered shared objects.", NULL
+        },
         { NULL }
     };
 
diff --git a/src/analysis/content-int.h b/src/analysis/content-int.h
index 4635047..7da78db 100644
--- a/src/analysis/content-int.h
+++ b/src/analysis/content-int.h
@@ -41,6 +41,9 @@ typedef void (* compute_checksum_fc) (GBinContent *, GChecksum *);
 /* Détermine le nombre d'octets lisibles. */
 typedef phys_t (* compute_size_fc) (const GBinContent *);
 
+/* Détermine la position finale d'un contenu. */
+typedef void (* compute_end_pos_fc) (const GBinContent *, vmpa2t *);
+
 /* Avance la tête de lecture d'une certaine quantité de données. */
 typedef bool (* seek_fc) (const GBinContent *, vmpa2t *, phys_t);
 
@@ -84,6 +87,7 @@ struct _GBinContentIface
     compute_checksum_fc compute_checksum;   /* Calcul de l'empreinte       */
 
     compute_size_fc compute_size;           /* Calcul de la taille totale  */
+    compute_end_pos_fc compute_end_pos;     /* Calcul de position finale   */
 
     seek_fc seek;                           /* Avancée de tête de lecture  */
 
diff --git a/src/analysis/content.c b/src/analysis/content.c
index 0a57972..562ec2a 100644
--- a/src/analysis/content.c
+++ b/src/analysis/content.c
@@ -215,6 +215,30 @@ phys_t g_binary_content_compute_size(const GBinContent *content)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : content = contenu binaire à venir lire.                      *
+*                pos     = position finale (exclusive). [OUT]                 *
+*                                                                             *
+*  Description : Détermine la position finale d'un contenu.                   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_binary_content_compute_end_pos(const GBinContent *content, vmpa2t *pos)
+{
+    GBinContentIface *iface;                /* Interface utilisée          */
+
+    iface = G_BIN_CONTENT_GET_IFACE(content);
+
+    return iface->compute_end_pos(content, pos);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = contenu binaire à venir lire.                      *
 *                addr    = position de la tête de lecture.                    *
 *                length  = quantité d'octets à provisionner.                  *
 *                                                                             *
diff --git a/src/analysis/content.h b/src/analysis/content.h
index 4bb1dc1..a4fff20 100644
--- a/src/analysis/content.h
+++ b/src/analysis/content.h
@@ -69,6 +69,9 @@ const gchar *g_binary_content_get_checksum(GBinContent *);
 /* Détermine le nombre d'octets lisibles. */
 phys_t g_binary_content_compute_size(const GBinContent *);
 
+/* Détermine la position finale d'un contenu. */
+void g_binary_content_compute_end_pos(const GBinContent *, vmpa2t *);
+
 /* Avance la tête de lecture d'une certaine quantité de données. */
 bool g_binary_content_seek(const GBinContent *, vmpa2t *, phys_t);
 
diff --git a/src/analysis/contents/file.c b/src/analysis/contents/file.c
index 8b371ab..2461017 100644
--- a/src/analysis/contents/file.c
+++ b/src/analysis/contents/file.c
@@ -85,6 +85,9 @@ static void g_file_content_compute_checksum(GFileContent *, GChecksum *);
 /* Détermine le nombre d'octets lisibles. */
 static phys_t g_file_content_compute_size(const GFileContent *);
 
+/* Détermine la position finale d'un contenu. */
+static void g_file_content_compute_end_pos(const GFileContent *, vmpa2t *);
+
 /* Avance la tête de lecture d'une certaine quantité de données. */
 static bool g_file_content_seek(const GFileContent *, vmpa2t *, phys_t);
 
@@ -185,6 +188,7 @@ static void g_file_content_interface_init(GBinContentInterface *iface)
     iface->compute_checksum = (compute_checksum_fc)g_file_content_compute_checksum;
 
     iface->compute_size = (compute_size_fc)g_file_content_compute_size;
+    iface->compute_end_pos = (compute_end_pos_fc)g_file_content_compute_end_pos;
 
     iface->seek = (seek_fc)g_file_content_seek;
 
@@ -493,6 +497,26 @@ static phys_t g_file_content_compute_size(const GFileContent *content)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : content = contenu binaire à venir lire.                      *
+*                pos     = position finale (exclusive). [OUT]                 *
+*                                                                             *
+*  Description : Détermine la position finale d'un contenu.                   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_file_content_compute_end_pos(const GFileContent *content, vmpa2t *pos)
+{
+    compute_mrange_end_addr(&content->range, pos);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = contenu binaire à venir lire.                      *
 *                addr    = position de la tête de lecture.                    *
 *                length  = quantité d'octets à provisionner.                  *
 *                                                                             *
diff --git a/src/analysis/contents/restricted.c b/src/analysis/contents/restricted.c
index 132d60b..28949ba 100644
--- a/src/analysis/contents/restricted.c
+++ b/src/analysis/contents/restricted.c
@@ -69,6 +69,12 @@ static void g_restricted_content_finalize(GRestrictedContent *);
 /* Calcule une empreinte unique (SHA256) pour les données. */
 static void g_restricted_content_compute_checksum(GRestrictedContent *, GChecksum *);
 
+/* Détermine le nombre d'octets lisibles. */
+static phys_t g_restricted_content_compute_size(const GRestrictedContent *);
+
+/* Détermine la position finale d'un contenu. */
+static void g_restricted_content_compute_end_pos(const GRestrictedContent *, vmpa2t *);
+
 /* Avance la tête de lecture d'une certaine quantité de données. */
 static bool g_restricted_content_seek(const GRestrictedContent *, vmpa2t *, phys_t);
 
@@ -164,6 +170,9 @@ static void g_restricted_content_interface_init(GBinContentInterface *iface)
 {
     iface->compute_checksum = (compute_checksum_fc)g_restricted_content_compute_checksum;
 
+    iface->compute_size = (compute_size_fc)g_restricted_content_compute_size;
+    iface->compute_end_pos = (compute_end_pos_fc)g_restricted_content_compute_end_pos;
+
     iface->seek = (seek_fc)g_restricted_content_seek;
 
     iface->get_raw_access = (get_raw_access_fc)g_restricted_content_get_raw_access;
@@ -319,6 +328,49 @@ static void g_restricted_content_compute_checksum(GRestrictedContent *content, G
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : content = contenu binaire à venir lire.                      *
+*                                                                             *
+*  Description : Détermine le nombre d'octets lisibles.                       *
+*                                                                             *
+*  Retour      : Quantité représentée.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static phys_t g_restricted_content_compute_size(const GRestrictedContent *content)
+{
+    phys_t result;                          /* Quantité trouvée à retourner*/
+
+    result = get_mrange_length(&content->range);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = contenu binaire à venir lire.                      *
+*                pos     = position finale (exclusive). [OUT]                 *
+*                                                                             *
+*  Description : Détermine la position finale d'un contenu.                   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_restricted_content_compute_end_pos(const GRestrictedContent *content, vmpa2t *pos)
+{
+    compute_mrange_end_addr(&content->range, pos);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = contenu binaire à venir lire.                      *
 *                addr    = position de la tête de lecture.                    *
 *                length  = quantité d'octets à provisionner.                  *
 *                                                                             *
-- 
cgit v0.11.2-87-g4458