diff options
| author | Cyrille Bagard <nocbos@gmail.com> | 2024-11-23 15:59:19 (GMT) | 
|---|---|---|
| committer | Cyrille Bagard <nocbos@gmail.com> | 2024-11-23 15:59:19 (GMT) | 
| commit | 411f03130cf45194689bc344f19a3b77c33a31ae (patch) | |
| tree | f047b62015eb37e30629398f9adcb977a5a6c6f6 /plugins/pychrysalide/format/executable.c | |
| parent | 80d779749adf228078b61f268bf952ba91a277f0 (diff) | |
Restore more features for formats.
Diffstat (limited to 'plugins/pychrysalide/format/executable.c')
| -rw-r--r-- | plugins/pychrysalide/format/executable.c | 392 | 
1 files changed, 351 insertions, 41 deletions
diff --git a/plugins/pychrysalide/format/executable.c b/plugins/pychrysalide/format/executable.c index d886e9a..7d05578 100644 --- a/plugins/pychrysalide/format/executable.c +++ b/plugins/pychrysalide/format/executable.c @@ -36,9 +36,10 @@  #include "program.h"  #include "../access.h"  #include "../helpers.h" +#include "../analysis/content.h"  //#include "../arch/processor.h" -//#include "../arch/vmpa.h" -//#include "../glibext/binportion.h" +#include "../arch/vmpa.h" +#include "../glibext/portion.h" @@ -56,23 +57,35 @@ static int py_executable_format_init(PyObject *, PyObject *, PyObject *);  /* Indique le type d'architecture visée par le format. */  static char *py_executable_format_get_target_machine_wrapper(const GExecutableFormat *); +/* Fournit l'adresse principale associée à un format. */ +static bool py_executable_format_get_main_address_wrapper(GExecutableFormat *, vmpa2t *); + +/* Etend la définition des portions au sein d'un binaire. */ +static bool py_executable_format_refine_portions_wrapper(GExecutableFormat *); +  /* ------------------------ DECLARATION DE FORMAT EXECUTABLE ------------------------ */ -/* Enregistre une portion artificielle pour le format. */ -//static PyObject *py_executable_format_register_user_portion(PyObject *, PyObject *); +/* Procède à l'enregistrement d'une portion dans un format. */ +static PyObject *py_executable_format_include_portion(PyObject *, PyObject *);  /* Fournit l'emplacement correspondant à une position physique. */ -//static PyObject *py_executable_format_translate_offset_into_vmpa(PyObject *, PyObject *); +static PyObject *py_executable_format_translate_offset_into_vmpa(PyObject *, PyObject *);  /* Fournit l'emplacement correspondant à une adresse virtuelle. */ -//static PyObject *py_executable_format_translate_address_into_vmpa(PyObject *, PyObject *); +static PyObject *py_executable_format_translate_address_into_vmpa(PyObject *, PyObject *);  /* Indique le type d'architecture visée par le format. */  static PyObject *py_executable_format_get_target_machine(PyObject *, void *); +/* Fournit l'adresse principale associée à un format. */ +static PyObject *py_executable_format_get_main_address(PyObject *, void *); + +/* Indique le type d'architecture visée par le format. */ +static PyObject *py_executable_format_get_portions(PyObject *, void *); +  /* ---------------------------------------------------------------------------------- */ @@ -97,6 +110,9 @@ static void py_executable_format_init_gclass(GExecutableFormatClass *class, gpoi  {      class->get_machine = py_executable_format_get_target_machine_wrapper; +    class->get_main_addr = py_executable_format_get_main_address_wrapper; +    class->refine_portions = py_executable_format_refine_portions_wrapper; +  } @@ -116,24 +132,42 @@ static void py_executable_format_init_gclass(GExecutableFormatClass *class, gpoi  static int py_executable_format_init(PyObject *self, PyObject *args, PyObject *kwds)  { +    GBinContent *content;                   /* Contenu à intégrer au format*/      int ret;                                /* Bilan de lecture des args.  */ +    GExecutableFormat *format;              /* Format à manipuler          */  #define EXECUTABLE_FORMAT_DOC                                           \      "The ExecutableFormat class provides support for formats containing"\      " code to run.\n"                                                   \      "\n"                                                                \ -    "The following method has to be defined for new classes:\n"         \ +    "The following methods have to be defined for new classes:\n"       \      "* pychrysalide.format.ExecutableFormat._get_target_machine();\n"   \ +    "* pychrysalide.format.ExecutableFormat._get_main_address().\n"     \      "\n"                                                                \ +    "The following method may be defined for new classes:\n"            \ +    "* pychrysalide.format.ExecutableFormat._refine_portions().\n"      \      "\n"                                                                \      "Calls to the *__init__* constructor of this abstract object expect"\ -    " no particular argument." +    " only one argument: a binary content, provided as a"               \ +    " pychrysalide.analysis.BinContent instance." + +    /* Récupération des paramètres */ + +    ret = PyArg_ParseTuple(args, "O&", convert_to_binary_content, &content); +    if (!ret) return -1;      /* Initialisation d'un objet GLib */      ret = forward_pygobjet_init(self);      if (ret == -1) return -1; +    /* Eléments de base */ + +    format = G_EXECUTABLE_FORMAT(pygobject_get(self)); + +    if (!g_executable_format_create(format, content)) +        return -1; +      return 0;  } @@ -203,41 +237,221 @@ static char *py_executable_format_get_target_machine_wrapper(const GExecutableFo  } +/****************************************************************************** +*                                                                             * +*  Paramètres  : format = description de l'exécutable à consulter.            * +*                addr   = adresse principale trouvée si possible. [OUT]       * +*                                                                             * +*  Description : Fournit l'adresse principale associée à un format.           * +*                                                                             * +*  Retour      : Validité de l'adresse transmise.                             * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool py_executable_format_get_main_address_wrapper(GExecutableFormat *format, vmpa2t *addr) +{ +    bool result;                            /* Bilan à retourner           */ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *pyret;                        /* Valeur retournée            */ +    vmpa2t *tmp;                            /* Zone de stockage Python     */ +    int ret;                                /* Bilan d'une conversion      */ + +#define EXECUTABLE_FORMAT_GET_MAIN_ADDRESS_WRAPPER PYTHON_WRAPPER_DEF   \ +(                                                                       \ +    _get_main_address, "$self",                                         \ +    METH_NOARGS,                                                        \ +    "Abstract method used to provide the main address of code for"      \ +    " the executable format.\n"                                         \ +    "\n"                                                                \ +    "The return value has to be a pychrysalide.arch.vmpa instance or"   \ +    " *None* in case of failure."                                       \ +    ) + +    result = false; + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(format)); + +    if (has_python_method(pyobj, "_get_main_address")) +    { +        pyret = run_python_method(pyobj, "_get_main_address", NULL); + +        if (pyret != NULL) +        { +            if (pyret == Py_None) +            { +                init_vmpa(addr, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); +                result = true; +            } + +            else +            { +                ret = convert_any_to_vmpa(pyret, &tmp); + +                result = (ret == 1 || ret == Py_CLEANUP_SUPPORTED); + +                if (result) +                { +                    copy_vmpa(addr, tmp); + +                    if (ret == Py_CLEANUP_SUPPORTED) +                        clean_vmpa_arg(tmp); + +                } + +                else +                { +                    /** +                     * L'erreur Python peut être effacée. +                     * +                     * Elle sera remontée : +                     *  - au code C via le retour (false) : +                     *  - à Python lors de l'accès à la propriétée. +                     */ +                    PyErr_Clear(); + +                } + +            } + +            Py_DECREF(pyret); + +        } + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : format = informations chargées à consulter.                  * +*                                                                             * +*  Description : Etend la définition des portions au sein d'un binaire.       * +*                                                                             * +*  Retour      : Bilan des définitions de portions.                           * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool py_executable_format_refine_portions_wrapper(GExecutableFormat *format) +{ +    bool result;                            /* Bilan à retourner           */ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *pyret;                        /* Valeur retournée            */ + +#define EXECUTABLE_FORMAT_REFINE_PORTIONS_WRAPPER PYTHON_WRAPPER_DEF    \ +(                                                                       \ +    _refine_portions, "$self",                                          \ +    METH_NOARGS,                                                        \ +    "Abstract method used to extend the definition of the format"       \ +    " with binary portions.\n"                                          \ +    "\n"                                                                \ +    "Extra portions should be included with calls to"                   \ +    " pychrysalide.format.ExecutableFormat.include_portion().\n"        \ +    "\n"                                                                \ +    "The return value has to be a boolean value: *True* in case of"     \ +    " success, *False* in case of failure."                             \ +) + +    result = true; + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(format)); + +    if (has_python_method(pyobj, "_refine_portions")) +    { +        pyret = run_python_method(pyobj, "_refine_portions", NULL); + +        if (pyret != NULL) +        { +            result = (pyret == Py_True); +            Py_DECREF(pyret); +        } + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +    return result; + +} + +  /* ---------------------------------------------------------------------------------- */  /*                          DECLARATION DE FORMAT EXECUTABLE                          */  /* ---------------------------------------------------------------------------------- */ -#if 0  /******************************************************************************  *                                                                             *  *  Paramètres  : self = description de l'exécutable à consulter.              *  *                args = arguments accompagnant l'appel.                       *  *                                                                             * -*  Description : Enregistre une portion artificielle pour le format.          * +*  Description : Procède à l'enregistrement d'une portion dans un format.     *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération : True si inclusion, False sinon.       *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -static PyObject *py_executable_format_register_user_portion(PyObject *self, PyObject *args) +static PyObject *py_executable_format_include_portion(PyObject *self, PyObject *args)  { -    GBinPortion *portion;                   /* Portion binaire à conserver */ +    PyObject *result;                       /* Bilan à retourner           */ +    GBinaryPortion *portion;                /* Portion binaire à conserver */ +    vmpa2t *origin;                         /* Source de l'inclusion       */      int ret;                                /* Bilan de lecture des args.  */      GExecutableFormat *format;              /* Version GLib du format      */ +    bool status;                            /* Bilan de l'inclusion        */ + +#define EXECUTABLE_FORMAT_INCLUDE_PORTION_METHOD PYTHON_METHOD_DEF          \ +(                                                                           \ +    include_portion, "$self, portion, /, origin=None",                      \ +    METH_VARARGS, py_executable_format,                                     \ +    "Register a new portion inside the content of an executable format.\n"  \ +    "\n"                                                                    \ +    "The *portion* argument is a pychrysalide.glibext.BinaryPortion"        \ +    " instance. The optional *origin* arguement specifies the source of the"\ +    " operation, as a pychrysalide.arch.vmpa definition, which may be used" \ +    " for tracking errors.\n"                                               \ +    "\n"                                                                    \ +    "The return value is a boolean value: *True* in case of success,"       \ +    " *False* in case of failure."                                          \ +) + +    origin = NULL; -    ret = PyArg_ParseTuple(args, "O&", convert_to_binary_portion, &portion); +    ret = PyArg_ParseTuple(args, "O&|O&", convert_to_binary_portion, &portion, convert_any_to_vmpa, &origin);      if (!ret) return NULL;      format = G_EXECUTABLE_FORMAT(pygobject_get(self)); -    g_object_ref(G_OBJECT(portion)); -    g_exe_format_register_user_portion(format, portion); +    status = g_executable_format_include_portion(format, portion, origin); + +    result = status ? Py_True : Py_False; +    Py_INCREF(result); -    Py_RETURN_NONE; +    if (origin != NULL) +        clean_vmpa_arg(origin); + +    return result;  } @@ -264,13 +478,24 @@ static PyObject *py_executable_format_translate_offset_into_vmpa(PyObject *self,      vmpa2t pos;                             /* Position complète déterminée*/      bool status;                            /* Bilan de l'opération        */ -    format = G_EXECUTABLE_FORMAT(pygobject_get(self)); -    assert(format != NULL); +#define EXECUTABLE_FORMAT_TRANSLATE_OFFSET_INTO_VMPA_METHOD PYTHON_METHOD_DEF   \ +(                                                                               \ +    translate_offset_into_vmpa, "$self, addr",                                  \ +    METH_VARARGS, py_executable_format,                                         \ +    "Translate a physical offset to a full location.\n"                         \ +    "\n"                                                                        \ +    "The *off* argument is a physical offset provided as an integer value.\n"   \ +    "\n"                                                                        \ +    "The returned position is a pychrysalide.arch.vmpa instance or *None* in"   \ +    " case of failure."                                                         \ +)      ret = PyArg_ParseTuple(args, "K", &off);      if (!ret) return NULL; -    status = g_exe_format_translate_offset_into_vmpa(format, off, &pos); +    format = G_EXECUTABLE_FORMAT(pygobject_get(self)); + +    status = g_executable_format_translate_offset_into_vmpa(format, off, &pos);      if (status)          result = build_from_internal_vmpa(&pos); @@ -308,13 +533,24 @@ static PyObject *py_executable_format_translate_address_into_vmpa(PyObject *self      vmpa2t pos;                             /* Position complète déterminée*/      bool status;                            /* Bilan de l'opération        */ -    format = G_EXECUTABLE_FORMAT(pygobject_get(self)); -    assert(format != NULL); +#define EXECUTABLE_FORMAT_TRANSLATE_ADDRESS_INTO_VMPA_METHOD PYTHON_METHOD_DEF  \ +(                                                                               \ +    translate_address_into_vmpa, "$self, addr",                                 \ +    METH_VARARGS, py_executable_format,                                         \ +    "Translate a virtual address to a full location.\n"                         \ +    "\n"                                                                        \ +    "The *addr* argument is a virtual address provided as an integer value.\n"  \ +    "\n"                                                                        \ +    "The returned position is a pychrysalide.arch.vmpa instance or *None* in"   \ +    " case of failure."                                                         \ +)      ret = PyArg_ParseTuple(args, "K", &addr);      if (!ret) return NULL; -    status = g_exe_format_translate_address_into_vmpa(format, addr, &pos); +    format = G_EXECUTABLE_FORMAT(pygobject_get(self)); + +    status = g_executable_format_translate_address_into_vmpa(format, addr, &pos);      if (status)          result = build_from_internal_vmpa(&pos); @@ -328,7 +564,6 @@ static PyObject *py_executable_format_translate_address_into_vmpa(PyObject *self      return result;  } -#endif  /****************************************************************************** @@ -382,6 +617,91 @@ static PyObject *py_executable_format_get_target_machine(PyObject *self, void *c  /******************************************************************************  *                                                                             * +*  Paramètres  : self    = objet Python concerné par l'appel.                 * +*                closure = non utilisé ici.                                   * +*                                                                             * +*  Description : Fournit l'adresse principale associée à un format.           * +*                                                                             * +*  Retour      : Validité de l'adresse transmise.                             * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_executable_format_get_main_address(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Trouvailles à retourner     */ +    GExecutableFormat *format;              /* Format exécutable manipulé  */ +    vmpa2t addr;                            /* Point d'entrée principal    */ +    bool status;                            /* Validité de l'adresse       */ + +#define EXECUTABLE_FORMAT_MAIN_ADDRESS_ATTRIB PYTHON_GET_DEF_FULL   \ +(                                                                   \ +    main_address, py_executable_format,                             \ +    "Main address of code for the executable format.\n"             \ +    "\n"                                                            \ +    "This property provide a pychrysalide.arch.vmpa instance or"    \ +    " *None* in case of failure."                                   \ +) + +    format = G_EXECUTABLE_FORMAT(pygobject_get(self)); + +    status = g_executable_format_get_main_address(format, &addr); + +    if (status) +        result = build_from_internal_vmpa(&addr); + +    else +    { +        PyErr_SetString(PyExc_AttributeError, _("unable to define a value for the main address")); +        result = NULL; +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self    = objet Python concerné par l'appel.                 * +*                closure = non utilisé ici.                                   * +*                                                                             * +*  Description : Indique le type d'architecture visée par le format.          * +*                                                                             * +*  Retour      : Identifiant de l'architecture ciblée par le format.          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_executable_format_get_portions(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Trouvailles à retourner     */ +    GExecutableFormat *format;              /* Format exécutable manipulé  */ +    GBinaryPortion *portions;               /* Portion principale du format*/ + +#define EXECUTABLE_FORMAT_PORTIONS_ATTRIB PYTHON_GET_DEF_FULL   \ +(                                                               \ +    portions, py_executable_format,                             \ +    "Root portion of the executable format, provided as a"      \ +    " pychrysalide.glibext.BinaryPortion instance."             \ +) + +    format = G_EXECUTABLE_FORMAT(pygobject_get(self)); + +    portions = g_executable_format_get_portions(format); + +    result = pygobject_new(G_OBJECT(portions)); +    unref_object(portions); + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : -                                                            *  *                                                                             *  *  Description : Fournit un accès à une définition de type à diffuser.        * @@ -396,28 +716,18 @@ PyTypeObject *get_python_executable_format_type(void)  {      static PyMethodDef py_executable_format_methods[] = {          EXECUTABLE_FORMAT_GET_TARGET_MACHINE_WRAPPER, -#if 0 -        { -            "register_user_portion", py_executable_format_register_user_portion, -            METH_VARARGS, -            "register_user_portion($self, portion, /)\n--\n\nRemember a given user-defined binary portion as part of the executable format content." -        }, -        { -            "translate_offset_into_vmpa", py_executable_format_translate_offset_into_vmpa, -            METH_VARARGS, -            "translate_offset_into_vmpa($self, off, /)\n--\n\nTranslate a physical offset to a full location." -        }, -        { -            "translate_address_into_vmpa", py_executable_format_translate_address_into_vmpa, -            METH_VARARGS, -            "translate_address_into_vmpa($self, addr, /)\n--\n\nTranslate a physical offset to a full location." -        }, -#endif +        EXECUTABLE_FORMAT_GET_MAIN_ADDRESS_WRAPPER, +        EXECUTABLE_FORMAT_REFINE_PORTIONS_WRAPPER, +        EXECUTABLE_FORMAT_INCLUDE_PORTION_METHOD, +        EXECUTABLE_FORMAT_TRANSLATE_OFFSET_INTO_VMPA_METHOD, +        EXECUTABLE_FORMAT_TRANSLATE_ADDRESS_INTO_VMPA_METHOD,          { NULL }      };      static PyGetSetDef py_executable_format_getseters[] = {          EXECUTABLE_FORMAT_TARGET_MACHINE_ATTRIB, +        EXECUTABLE_FORMAT_MAIN_ADDRESS_ATTRIB, +        EXECUTABLE_FORMAT_PORTIONS_ATTRIB,          { NULL }      };  | 
