diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2018-01-16 19:02:56 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2018-01-16 19:02:56 (GMT) |
commit | 9da8f8b37e3edebc917b4e223dd2447cd7cbc818 (patch) | |
tree | 3f330b13e7ca2a0a163882be3043ca9571f25211 /plugins/pychrysalide/arch | |
parent | eb9b7fd76451db5c9f07a800c0394480e4b88c9c (diff) |
Changed the Python bindings source directory and updated code.
Diffstat (limited to 'plugins/pychrysalide/arch')
-rw-r--r-- | plugins/pychrysalide/arch/Makefile.am | 25 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/immediate.c | 700 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/immediate.h | 42 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/instriter.c | 276 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/instriter.h | 42 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/instruction.c | 462 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/instruction.h | 42 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/module.c | 165 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/module.h | 39 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/operand.c | 109 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/operand.h | 42 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/processor.c | 459 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/processor.h | 42 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/raw.c | 263 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/raw.h | 42 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/vmpa.c | 1303 | ||||
-rw-r--r-- | plugins/pychrysalide/arch/vmpa.h | 71 |
17 files changed, 4124 insertions, 0 deletions
diff --git a/plugins/pychrysalide/arch/Makefile.am b/plugins/pychrysalide/arch/Makefile.am new file mode 100644 index 0000000..694c9e0 --- /dev/null +++ b/plugins/pychrysalide/arch/Makefile.am @@ -0,0 +1,25 @@ + +noinst_LTLIBRARIES = libpychrysaarch.la + +libpychrysaarch_la_SOURCES = \ + immediate.h immediate.c \ + instriter.h instriter.c \ + instruction.h instruction.c \ + module.h module.c \ + operand.h operand.c \ + processor.h processor.c \ + raw.h raw.c \ + vmpa.h vmpa.c + +libpychrysaarch_la_LIBADD = + + +libpychrysaarch_la_LDFLAGS = + + +AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I../../../src + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) + +SUBDIRS = diff --git a/plugins/pychrysalide/arch/immediate.c b/plugins/pychrysalide/arch/immediate.c new file mode 100644 index 0000000..f1ec125 --- /dev/null +++ b/plugins/pychrysalide/arch/immediate.c @@ -0,0 +1,700 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * immediate.c - équivalent Python du fichier "arch/immediate.h" + * + * Copyright (C) 2012-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 "immediate.h" + + +#include <pygobject.h> + + +#include <i18n.h> + + +#include <arch/immediate.h> + + +#include "operand.h" +#include "../helpers.h" + + + +/* Fournit la valeur portée par une opérande numérique. */ +static PyObject *py_imm_operand_get_value(PyObject *, void *); + +/* Indique si l'affichage est complété avec des zéros. */ +static PyObject *py_imm_operand_get_padding_by_default(PyObject *self, void *); + +/* Précise si des zéro doivent compléter l'affichage ou non. */ +static int py_imm_operand_set_padding_by_default(PyObject *, PyObject *, void *); + +/* Indique si l'affichage est complété avec des zéros. */ +static PyObject *py_imm_operand_get_padding(PyObject *self, void *); + +/* Précise si des zéro doivent compléter l'affichage ou non. */ +static int py_imm_operand_set_padding(PyObject *, PyObject *, void *); + +/* Indique le format textuel par défaut de la valeur. */ +static PyObject *py_imm_operand_get_default_display(PyObject *, void *); + +/* Définit le format textuel par défaut de la valeur. */ +static int py_imm_operand_set_default_display(PyObject *, PyObject *, void *); + +/* Indique la grande ligne du format textuel de la valeur. */ +static PyObject *py_imm_operand_get_display(PyObject *, void *); + +/* Définit la grande ligne du format textuel de la valeur. */ +static int py_imm_operand_set_display(PyObject *, PyObject *, void *); + +/* Construit la chaîne de caractères correspondant à l'opérande. */ +static PyObject *py_imm_operand_to_string(PyObject *, PyObject *); + +/* Crée un nouvel objet Python de type 'ImmOperand'. */ +static PyObject *py_imm_operand_new(PyTypeObject *, PyObject *, PyObject *); + +/* Définit les constantes pour les opérandes d'immédiats. */ +static bool py_imm_operand_define_constants(PyTypeObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Renseigne la taille de la valeur indiquée à la construction. * +* * +* Retour : Taille de la valeur représentée en mémoire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_imm_operand_get_size(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GImmOperand *operand; /* Version GLib de l'opérande */ + MemoryDataSize size; /* Type de donnée représentée */ + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + size = g_imm_operand_get_size(operand); + + result = Py_BuildValue("I", size); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la valeur portée par une opérande numérique. * +* * +* Retour : Valeur contenue dans l'opérande, ou None en cas de soucis. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_imm_operand_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GImmOperand *operand; /* Version GLib de l'opérande */ + MemoryDataSize size; /* Type de donnée représentée */ + uint8_t uval8; /* Valeur sur 8 bits */ + uint16_t uval16; /* Valeur sur 16 bits */ + uint32_t uval32; /* Valeur sur 32 bits */ + uint64_t uval64; /* Valeur sur 64 bits */ + int8_t sval8; /* Valeur sur 8 bits */ + int16_t sval16; /* Valeur sur 16 bits */ + int32_t sval32; /* Valeur sur 32 bits */ + int64_t sval64; /* Valeur sur 64 bits */ + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + size = g_imm_operand_get_size(operand); + + switch (size) + { + /* Pour GCC... */ + case MDS_UNDEFINED: + result = Py_None; + Py_INCREF(result); + break; + case MDS_4_BITS_UNSIGNED: + case MDS_8_BITS_UNSIGNED: + g_imm_operand_get_value(operand, size, &uval8); + result = PyLong_FromUnsignedLong(uval8); + break; + case MDS_16_BITS_UNSIGNED: + g_imm_operand_get_value(operand, size, &uval16); + result = PyLong_FromUnsignedLong(uval16); + break; + case MDS_32_BITS_UNSIGNED: + g_imm_operand_get_value(operand, size, &uval32); + result = PyLong_FromUnsignedLong(uval32); + break; + case MDS_64_BITS_UNSIGNED: + g_imm_operand_get_value(operand, size, &uval64); + result = PyLong_FromUnsignedLongLong(uval64); + break; + case MDS_4_BITS_SIGNED: + case MDS_8_BITS_SIGNED: + g_imm_operand_get_value(operand, size, &sval8); + result = PyLong_FromLong(sval8); + break; + case MDS_16_BITS_SIGNED: + g_imm_operand_get_value(operand, size, &sval16); + result = PyLong_FromLong(sval16); + break; + case MDS_32_BITS_SIGNED: + g_imm_operand_get_value(operand, size, &sval32); + result = PyLong_FromLong(sval32); + break; + case MDS_64_BITS_SIGNED: + g_imm_operand_get_value(operand, size, &sval64); + result = PyLong_FromLongLong(sval64); + break; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique si l'affichage est complété avec des zéros. * +* * +* Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_imm_operand_get_padding_by_default(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GImmOperand *operand; /* Version GLib de l'opérande */ + bool padding; /* Bourrage en préfixe ? */ + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + padding = g_imm_operand_does_padding_by_default(operand); + + result = Py_BuildValue("p", padding); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = non utilisé ici. * +* * +* Description : Précise si des zéro doivent compléter l'affichage ou non. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_imm_operand_set_padding_by_default(PyObject *self, PyObject *value, void *closure) +{ + bool padding; /* Bourrage en préfixe ? */ + GImmOperand *operand; /* Version GLib de l'opérande */ + + if (!PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, _("Invalid padding state")); + return -1; + } + + padding = (value == Py_True); + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + g_imm_operand_pad_by_default(operand, padding); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique si l'affichage est complété avec des zéros. * +* * +* Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_imm_operand_get_padding(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GImmOperand *operand; /* Version GLib de l'opérande */ + bool padding; /* Bourrage en préfixe ? */ + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + padding = g_imm_operand_does_padding(operand); + + result = Py_BuildValue("p", padding); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = non utilisé ici. * +* * +* Description : Précise si des zéro doivent compléter l'affichage ou non. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_imm_operand_set_padding(PyObject *self, PyObject *value, void *closure) +{ + bool padding; /* Bourrage en préfixe ? */ + GImmOperand *operand; /* Version GLib de l'opérande */ + + if (!PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, _("Invalid padding state")); + return -1; + } + + padding = (value == Py_True); + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + g_imm_operand_pad(operand, padding); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le format textuel par défaut de la valeur. * +* * +* Retour : Format global d'un affichage de valeur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_imm_operand_get_default_display(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GImmOperand *operand; /* Version GLib de l'opérande */ + ImmOperandDisplay display; /* Type d'affichage courant */ + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + display = g_imm_operand_get_default_display(operand); + + result = Py_BuildValue("I", display); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = non utilisé ici. * +* * +* Description : Définit le format textuel par défaut de la valeur. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_imm_operand_set_default_display(PyObject *self, PyObject *value, void *closure) +{ + ImmOperandDisplay display; /* Type d'affichage demandé */ + GImmOperand *operand; /* Version GLib de l'opérande */ + + if (!PyLong_Check(value)) + { + PyErr_SetString(PyExc_TypeError, _("Invalid display type")); + return -1; + } + + display = PyLong_AsUnsignedLong(value); + + if (!(IOD_BIN <= display && display <= IOD_CHAR)) + { + PyErr_SetString(PyExc_TypeError, _("Invalid display type")); + return -1; + } + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + g_imm_operand_set_default_display(operand, display); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique la grande ligne du format textuel de la valeur. * +* * +* Retour : Format global d'un affichage de valeur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_imm_operand_get_display(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GImmOperand *operand; /* Version GLib de l'opérande */ + ImmOperandDisplay display; /* Type d'affichage courant */ + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + display = g_imm_operand_get_display(operand); + + result = Py_BuildValue("I", display); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = non utilisé ici. * +* * +* Description : Définit la grande ligne du format textuel de la valeur. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_imm_operand_set_display(PyObject *self, PyObject *value, void *closure) +{ + ImmOperandDisplay display; /* Type d'affichage demandé */ + GImmOperand *operand; /* Version GLib de l'opérande */ + + if (!PyLong_Check(value)) + { + PyErr_SetString(PyExc_TypeError, _("Invalid display type")); + return -1; + } + + display = PyLong_AsUnsignedLong(value); + + if (!(IOD_BIN <= display && display <= IOD_CHAR)) + { + PyErr_SetString(PyExc_TypeError, _("Invalid display type")); + return -1; + } + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + g_imm_operand_set_display(operand, display); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = operande à manipuler. * +* args = arguments accompagnant l'appel. * +* * +* Description : Construit la chaîne de caractères correspondant à l'opérande.* +* * +* Retour : Chaîne de caractères mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_imm_operand_to_string(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + GImmOperand *operand; /* Version GLib de l'opérande */ + unsigned int raw_syntax; /* Affichage brut à utiliser */ + int ret; /* Bilan de lecture des args. */ + AsmSyntax syntax; /* Affichage final à utiliser */ + char value[IMM_MAX_SIZE]; /* Valeur humainement lisible */ + + operand = G_IMM_OPERAND(pygobject_get(self)); + assert(operand != NULL); + + ret = PyArg_ParseTuple(args, "I", &raw_syntax); + if (!ret) return NULL; + + syntax = raw_syntax; + + if (syntax != ASX_INTEL && syntax != ASX_ATT) + { + PyErr_SetString(PyExc_ValueError, _("Invalid syntax type")); + return NULL; + } + + g_imm_operand_to_string(operand, syntax, value); + + result = PyUnicode_FromString(value); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'ImmOperand'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + unsigned int raw_size; /* Taille obtenue de Python */ + unsigned long long value; /* Valeur brute à représenter */ + int ret; /* Bilan de lecture des args. */ + MemoryDataSize size; /* Taille des données finale */ + GArchOperand *operand; /* Création GLib à transmettre */ + + ret = PyArg_ParseTuple(args, "IK", &raw_size, &value); + if (!ret) return NULL; + + size = raw_size; + + if (size != MDS_UNDEFINED + && !(MDS_4_BITS_UNSIGNED <= size && size <= MDS_64_BITS_UNSIGNED) + && !(MDS_4_BITS_SIGNED <= size && size <= MDS_64_BITS_SIGNED)) + { + PyErr_SetString(PyExc_ValueError, _("Invalid size to build an immediate operand")); + return NULL; + } + + operand = g_imm_operand_new_from_value(size, value); + + result = pygobject_new(G_OBJECT(operand)); + + g_object_unref(operand); + + return (PyObject *)result; + +} + + +/****************************************************************************** +* * +* Paramètres : obj_type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes pour les opérandes d'immédiats. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_imm_operand_define_constants(PyTypeObject *obj_type) +{ + bool result; /* Bilan à retourner */ + + result = true; + + result &= PyDict_AddIntMacro(obj_type, IOD_BIN); + result &= PyDict_AddIntMacro(obj_type, IOD_OCT); + result &= PyDict_AddIntMacro(obj_type, IOD_DEC); + result &= PyDict_AddIntMacro(obj_type, IOD_HEX); + result &= PyDict_AddIntMacro(obj_type, IOD_CHAR); + result &= PyDict_AddIntMacro(obj_type, IOD_COUNT); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_imm_operand_type(void) +{ + static PyMethodDef py_imm_operand_methods[] = { + { + "to_string", py_imm_operand_to_string, + METH_VARARGS, + "to_string($self, syntax, /)\n--\n\nConvert the immediate operand to a string." + }, + { NULL } + }; + + static PyGetSetDef py_imm_operand_getseters[] = { + { + "size", py_imm_operand_get_size, NULL, + "Size of the value contained in the operand.", NULL + }, + { + "value", py_imm_operand_get_value, NULL, + "Value of the immediate operand.", NULL + }, + { + "padding", py_imm_operand_get_padding, py_imm_operand_set_padding, + "Status of padding with zeros in front of the textual representation.", NULL + }, + { + "default_padding", py_imm_operand_get_padding_by_default, py_imm_operand_set_padding_by_default, + "Status of default padding with zeros in front of the textual representation.", NULL + }, + { + "default_display", py_imm_operand_get_default_display, py_imm_operand_set_default_display, + "Definition of the immediate operand default textual representation.", NULL + }, + { + "display", py_imm_operand_get_display, py_imm_operand_set_display, + "Definition of the immediate operand current textual representation.", NULL + }, + { NULL } + }; + + static PyTypeObject py_imm_operand_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.ImmOperand", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = "PyChrysalide immediate operand.", + + .tp_methods = py_imm_operand_methods, + .tp_getset = py_imm_operand_getseters, + .tp_new = py_imm_operand_new + + }; + + return &py_imm_operand_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.ImmOperand'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_imm_operand(PyObject *module) +{ + PyTypeObject *py_imm_operand_type; /* Type Python 'BinContent' */ + PyObject *dict; /* Dictionnaire du module */ + + py_imm_operand_type = get_python_imm_operand_type(); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, + py_imm_operand_type, get_python_arch_operand_type())) + return false; + + if (!py_imm_operand_define_constants(py_imm_operand_type)) + return false; + + return true; + +} diff --git a/plugins/pychrysalide/arch/immediate.h b/plugins/pychrysalide/arch/immediate.h new file mode 100644 index 0000000..d6e5eba --- /dev/null +++ b/plugins/pychrysalide/arch/immediate.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * immediate.h - prototypes pour l'équivalent Python du fichier "arch/immediate.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_PYOIDA_ARCH_IMMEDIATE_H +#define _PLUGINS_PYOIDA_ARCH_IMMEDIATE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_imm_operand_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.ImmOperand'. */ +bool register_python_imm_operand(PyObject *); + + + +#endif /* _PLUGINS_PYOIDA_ARCH_IMMEDIATE_H */ diff --git a/plugins/pychrysalide/arch/instriter.c b/plugins/pychrysalide/arch/instriter.c new file mode 100644 index 0000000..244a825 --- /dev/null +++ b/plugins/pychrysalide/arch/instriter.c @@ -0,0 +1,276 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instriter.c - équivalent Python du fichier "arch/instriter.c" + * + * Copyright (C) 2016-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 "instriter.h" + + +#include <pygobject.h> + + +#include <arch/processor.h> + + +#include "processor.h" + + + +/* Transcription d'un itérateur en Python */ +typedef struct _PyInstrIterator +{ + PyObject_HEAD; /* A laisser en premier */ + + instr_iter_t *native; /* Version native de l'objet */ + bool first_time; /* Premier élément retourné ? */ + +} PyInstrIterator; + + +/* Libère de la mémoire un itérateur sur des instructions. */ +static void py_instr_iterator_dealloc(PyInstrIterator *); + +/* Fournit l'instruction qui en suit une autre. */ +static PyObject *py_instr_iterator_next(PyInstrIterator *); + +/* Initialise un nouvel itérateur. */ +static int py_instr_iterator_init(PyInstrIterator *, PyObject *, PyObject *); + +/* Construit un nouvel itérateur. */ +static PyObject *py_instr_iterator_new(PyTypeObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = itérateur à supprimer. * +* * +* Description : Libère de la mémoire un itérateur sur des instructions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_instr_iterator_dealloc(PyInstrIterator *self) +{ + delete_instruction_iterator(self->native); + + Py_TYPE(self)->tp_free((PyObject *)self); + +} + + +/****************************************************************************** +* * +* Paramètres : self = itérateur à manipuler. * +* * +* Description : Fournit l'instruction qui en suit une autre. * +* * +* Retour : Instruction suivante trouvée, ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_instr_iterator_next(PyInstrIterator *self) +{ + PyObject *result; /* Résultat à retourner */ + GArchInstruction *next; /* Instruction suivante */ + + if (self->first_time) + { + next = get_instruction_iterator_current(self->native); + self->first_time = false; + } + + else + next = get_instruction_iterator_next(self->native); + + if (next != NULL) + { + result = pygobject_new(G_OBJECT(next)); + g_object_unref(G_OBJECT(next)); + } + + else + { + PyErr_SetNone(PyExc_StopIteration); + result = NULL; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance d'objet à initialiser. * +* args = arguments passés pour l'appel. * +* kwds = mots clefs éventuellement fournis en complément. * +* * +* Description : Initialise un nouvel itérateur. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_instr_iterator_init(PyInstrIterator *self, PyObject *args, PyObject *kwds) +{ + int result; /* Bilan à retourner */ + PyObject *proc_obj; /* Processeur version Python */ + unsigned long index; /* Indice de première instruc. */ + int ret; /* Bilan de lecture des args. */ + GArchProcessor *proc; /* Version native du processeur*/ + + result = -1; + + ret = PyArg_ParseTuple(args, "Ok", &proc_obj, &index); + if (ret == 0) goto piii_exit; + + ret = PyObject_IsInstance(proc_obj, (PyObject *)get_python_arch_processor_type()); + if (!ret) goto piii_exit; + + proc = G_ARCH_PROCESSOR(pygobject_get(proc_obj)); + + self->native = create_instruction_iterator(proc, index); + self->first_time = true; + + result = 0; + + piii_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'objet à mettre en place. * +* args = arguments passés pour l'appel. * +* kwds = mots clefs éventuellement fournis en complément. * +* * +* Description : Construit un nouvel itérateur. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_instr_iterator_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyInstrIterator *result; /* Nouvelle instance à renvoyer*/ + int ret; /* Bilan de l'initialisation */ + + result = (PyInstrIterator *)type->tp_alloc(type, 0); + + if (result != NULL) + { + ret = py_instr_iterator_init(result, args, kwds); + + if (ret != 0) + { + Py_DECREF(result); + result = NULL; + } + + } + + return (PyObject *)result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_instr_iterator_type(void) +{ + static PyTypeObject py_instr_iterator_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.InstrIterator", + .tp_basicsize = sizeof(PyInstrIterator), + + .tp_dealloc = (destructor)py_instr_iterator_dealloc, + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "Iterator for Chrysalide instructions loaded in a given processor.", + + .tp_iter = PyObject_SelfIter, + .tp_iternext = (iternextfunc)py_instr_iterator_next, + + .tp_init = (initproc)py_instr_iterator_init, + .tp_new = py_instr_iterator_new, + + }; + + return &py_instr_iterator_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.InstrIterator'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_instr_iterator(PyObject *module) +{ + PyTypeObject *py_instr_iterator_type; /* Type Python 'BinContent' */ + int ret; /* Bilan d'un appel */ + + py_instr_iterator_type = get_python_instr_iterator_type(); + + if (PyType_Ready(py_instr_iterator_type) < 0) + return false; + + Py_INCREF(py_instr_iterator_type); + ret = PyModule_AddObject(module, "InstrIterator", (PyObject *)py_instr_iterator_type); + + return (ret == 0); + +} diff --git a/plugins/pychrysalide/arch/instriter.h b/plugins/pychrysalide/arch/instriter.h new file mode 100644 index 0000000..3cb0e38 --- /dev/null +++ b/plugins/pychrysalide/arch/instriter.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instriter.h - prototypes pour l'équivalent Python du fichier "arch/instriter.h" + * + * Copyright (C) 2016-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_PYCHRYSALIDE_ARCH_INSTRITER_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_INSTRITER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_instr_iterator_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.InstrIterator'. */ +bool register_python_instr_iterator(PyObject *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_INSTRITER_H */ diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c new file mode 100644 index 0000000..bb977ce --- /dev/null +++ b/plugins/pychrysalide/arch/instruction.c @@ -0,0 +1,462 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instruction.c - équivalent Python du fichier "arch/instruction.h" + * + * Copyright (C) 2012-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 "instruction.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <arch/instruction.h> + + +#include "vmpa.h" +#include "../helpers.h" +#include "../glibext/linegen.h" + + + + +/* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */ + + + + + +/* --------------------- INSTRUCTIONS D'ARCHITECTURES EN PYTHON --------------------- */ + + + +/* Fournit la place mémoire d'une instruction. */ +static PyObject *py_arch_instruction_get_range(PyObject *, void *); + +/* Définit la localisation d'une instruction. */ +static int py_arch_instruction_set_range(PyObject *, PyObject *, void *); + + + +/* Fournit le nom humain de l'instruction manipulée. */ +static PyObject *py_arch_instruction_get_keyword(PyObject *, void *); + + + +/* Fournit tous les opérandes d'une instruction. */ +static PyObject *py_arch_instruction_get_operands(PyObject *, void *); + + + + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */ +/* ---------------------------------------------------------------------------------- */ + + + + +/* Fournit les origines d'une instruction donnée. */ +static PyObject *py_arch_instruction_get_sources(PyObject *, void *); + +/* Fournit les destinations d'une instruction donnée. */ +static PyObject *py_arch_instruction_get_destinations(PyObject *, void *); + + + + +/****************************************************************************** +* * +* Paramètres : self = instruction d'architecture à manipuler. * +* unused = adresse non utilisée ici. * +* * +* Description : Fournit les origines d'une instruction donnée. * +* * +* Retour : Nombre de ces origines. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_get_sources(PyObject *self, void *unused) +{ + PyObject *result; /* Instance à retourner */ + GArchInstruction *instr; /* Version native */ + instr_link_t *source; /* Origine des liens */ + size_t count; /* Nombre de liens présents */ + size_t i; /* Boucle de parcours */ + PyObject *linked; /* Source de lien Python */ + PyObject *type; /* Nature du lien en Python */ + int ret; /* Bilan d'une écriture d'arg. */ + + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); + + g_arch_instruction_lock_src(instr); + + count = g_arch_instruction_count_sources(instr); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + source = g_arch_instruction_get_source(instr, i); + + linked = pygobject_new(G_OBJECT(source->linked)); + type = PyLong_FromLong(source->type); + + ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type)); + assert(ret == 0); + + } + + g_arch_instruction_unlock_src(instr); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instruction d'architecture à manipuler. * +* unused = adresse non utilisée ici. * +* * +* Description : Fournit les destinations d'une instruction donnée. * +* * +* Retour : Nombre de ces destinations. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_get_destinations(PyObject *self, void *unused) +{ + PyObject *result; /* Instance à retourner */ + GArchInstruction *instr; /* Version native */ + instr_link_t *dest; /* Destination des liens */ + size_t count; /* Nombre de liens présents */ + size_t i; /* Boucle de parcours */ + PyObject *linked; /* Destination de lien Python */ + PyObject *type; /* Nature du lien en Python */ + int ret; /* Bilan d'une écriture d'arg. */ + + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); + + g_arch_instruction_lock_dest(instr); + + count = g_arch_instruction_count_destinations(instr); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + dest = g_arch_instruction_get_destination(instr, i); + + linked = pygobject_new(G_OBJECT(dest->linked)); + type = PyLong_FromLong(dest->type); + + ret = PyTuple_SetItem(result, i, Py_BuildValue("(OO)", linked, type)); + assert(ret == 0); + + } + + g_arch_instruction_unlock_dest(instr); + + return result; + +} + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une instruction. * +* closure = adresse non utilisée ici. * +* * +* Description : Fournit la place mémoire d'une instruction. * +* * +* Retour : Valeur associée à la propriété consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + GArchInstruction *instr; /* Version native */ + const mrange_t *range; /* Espace mémoire à exporter */ + + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); + range = g_arch_instruction_get_range(instr); + + result = build_from_internal_mrange(range); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Définit la localisation d'une instruction. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_arch_instruction_set_range(PyObject *self, PyObject *value, void *closure) +{ + int ret; /* Bilan d'analyse */ + mrange_t *range; /* Espace mémoire à manipuler */ + GArchInstruction *instr; /* Version native */ + + ret = PyObject_IsInstance(value, (PyObject *)get_python_mrange_type()); + if (!ret) return -1; + + range = get_internal_mrange(value); + + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); + g_arch_instruction_set_range(instr, range); + + return 0; + +} + + + + + + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une instruction. * +* unused = adresse non utilisée ici. * +* * +* Description : Fournit le nom humain de l'instruction manipulée. * +* * +* Retour : Valeur associée à la propriété consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_get_keyword(PyObject *self, void *unused) +{ + PyObject *result; /* Trouvailles à retourner */ + GArchInstruction *instr; /* Version native */ + const char *kw; /* Valeur récupérée */ + + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); + kw = g_arch_instruction_get_keyword(instr, 0/* FIXME*/); + + result = PyUnicode_FromString(kw); + + return result; + +} + + + + + +/****************************************************************************** +* * +* Paramètres : self = objet représentant une instruction. * +* unused = adresse non utilisée ici. * +* * +* Description : Fournit tous les opérandes d'une instruction. * +* * +* Retour : Valeur associée à la propriété consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_get_operands(PyObject *self, void *unused) +{ + PyObject *result; /* Instance à retourner */ + GArchInstruction *instr; /* Version native */ + size_t count; /* Nombre d'opérandes présents */ + size_t i; /* Boucle de parcours */ + GArchOperand *operand; /* Opérande à manipuler */ + PyObject *opobj; /* Version Python */ + int ret; /* Bilan d'une écriture d'arg. */ + + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); + + g_arch_instruction_lock_operands(instr); + + count = _g_arch_instruction_count_operands(instr); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + operand = _g_arch_instruction_get_operand(instr, i); + + opobj = pygobject_new(G_OBJECT(operand)); + + ret = PyTuple_SetItem(result, i, Py_BuildValue("O", opobj)); + assert(ret == 0); + + g_object_unref(G_OBJECT(operand)); + + } + + g_arch_instruction_unlock_operands(instr); + + return result; + +} + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_arch_instruction_type(void) +{ + static PyMethodDef py_arch_instruction_methods[] = { + { NULL } + }; + + static PyGetSetDef py_arch_instruction_getseters[] = { + { + "range", py_arch_instruction_get_range, py_arch_instruction_set_range, + "Give access to the memory range covered by the current instruction.", NULL + }, + { + "keyword", (getter)py_arch_instruction_get_keyword, (setter)NULL, + "Give le name of the assembly instruction.", NULL + }, + { + "operands", (getter)py_arch_instruction_get_operands, (setter)NULL, + "Provide the list of instruction attached operands.", NULL + }, + { + "sources", (getter)py_arch_instruction_get_sources, (setter)NULL, + "Provide the instructions list driving to the current instruction." + }, + { + "destinations", (getter)py_arch_instruction_get_destinations, (setter)NULL, + "Provide the instructions list following the current instruction." + }, + { NULL } + }; + + static PyTypeObject py_arch_instruction_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.ArchInstruction", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = "PyChrysalide instruction for a given architecture.", + + .tp_methods = py_arch_instruction_methods, + .tp_getset = py_arch_instruction_getseters, + + }; + + return &py_arch_instruction_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.ArchInstruction'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_arch_instruction(PyObject *module) +{ + PyTypeObject *py_arch_instruction_type; /* Type Python 'ArchInstruc...'*/ + PyObject *dict; /* Dictionnaire du module */ + PyTypeObject *py_line_generator_type; /* Type Python 'LineGenerator' */ + + py_arch_instruction_type = get_python_arch_instruction_type(); + + APPLY_ABSTRACT_FLAG(py_arch_instruction_type); + + dict = PyModule_GetDict(module); + + py_line_generator_type = get_python_line_generator_type(); + + if (!_register_class_for_pygobject(dict, G_TYPE_ARCH_INSTRUCTION, py_arch_instruction_type, + &PyGObject_Type, py_line_generator_type, NULL)) + return false; + + return true; + +} diff --git a/plugins/pychrysalide/arch/instruction.h b/plugins/pychrysalide/arch/instruction.h new file mode 100644 index 0000000..85a1552 --- /dev/null +++ b/plugins/pychrysalide/arch/instruction.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instruction.h - prototypes pour l'équivalent Python du fichier "arch/instruction.h" + * + * Copyright (C) 2012-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_PYOIDA_ARCH_INSTRUCTION_H +#define _PLUGINS_PYOIDA_ARCH_INSTRUCTION_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_arch_instruction_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.ArchInstruction'. */ +bool register_python_arch_instruction(PyObject *); + + + +#endif /* _PLUGINS_PYOIDA_ARCH_INSTRUCTION_H */ diff --git a/plugins/pychrysalide/arch/module.c b/plugins/pychrysalide/arch/module.c new file mode 100644 index 0000000..54b470c --- /dev/null +++ b/plugins/pychrysalide/arch/module.c @@ -0,0 +1,165 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire arch en tant que module + * + * Copyright (C) 2012-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 "module.h" + + +#include <assert.h> + + +#include <arch/archbase.h> + + +#include "immediate.h" +#include "instriter.h" +#include "instruction.h" +#include "operand.h" +#include "processor.h" +#include "raw.h" +#include "vmpa.h" +#include "../access.h" +#include "../helpers.h" + + + +/* Définit les constantes de base pour une architecture. */ +static bool py_base_define_constants(PyTypeObject *); + + + +/****************************************************************************** +* * +* Paramètres : obj_type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes de base pour une architecture. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_base_define_constants(PyTypeObject *obj_type) +{ + bool result; /* Bilan à retourner */ + + result = true; + + result &= PyDict_AddIntMacro(obj_type, MDS_UNDEFINED); + + result &= PyDict_AddIntMacro(obj_type, MDS_4_BITS_UNSIGNED); + result &= PyDict_AddIntMacro(obj_type, MDS_8_BITS_UNSIGNED); + result &= PyDict_AddIntMacro(obj_type, MDS_16_BITS_UNSIGNED); + result &= PyDict_AddIntMacro(obj_type, MDS_32_BITS_UNSIGNED); + result &= PyDict_AddIntMacro(obj_type, MDS_64_BITS_UNSIGNED); + + result &= PyDict_AddIntMacro(obj_type, MDS_4_BITS_SIGNED); + result &= PyDict_AddIntMacro(obj_type, MDS_8_BITS_SIGNED); + result &= PyDict_AddIntMacro(obj_type, MDS_16_BITS_SIGNED); + result &= PyDict_AddIntMacro(obj_type, MDS_32_BITS_SIGNED); + result &= PyDict_AddIntMacro(obj_type, MDS_64_BITS_SIGNED); + + result &= PyDict_AddIntMacro(obj_type, MDS_4_BITS); + result &= PyDict_AddIntMacro(obj_type, MDS_8_BITS); + result &= PyDict_AddIntMacro(obj_type, MDS_16_BITS); + result &= PyDict_AddIntMacro(obj_type, MDS_32_BITS); + result &= PyDict_AddIntMacro(obj_type, MDS_64_BITS); + + result &= PyDict_AddIntMacro(obj_type, ASX_INTEL); + result &= PyDict_AddIntMacro(obj_type, ASX_ATT); + result &= PyDict_AddIntMacro(obj_type, ASX_COUNT); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'arch' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_arch_module_to_python_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + int ret; /* Bilan d'un appel */ + + static PyModuleDef py_chrysalide_arch_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.arch", + .m_doc = "Python module for Chrysalide.arch", + + .m_size = -1, + + }; + + result = false; + + module = PyModule_Create(&py_chrysalide_arch_module); + if (module == NULL) return false; + + ret = PyState_AddModule(super, &py_chrysalide_arch_module); + if (ret != 0) goto loading_failed; + + ret = _PyImport_FixupBuiltin(module, "pychrysalide.arch"); + if (ret != 0) goto loading_failed; + + Py_INCREF(module); + ret = PyModule_AddObject(super, "arch", module); + if (ret != 0) goto loading_failed; + + result = true; + + result &= py_base_define_constants(Py_TYPE(module)); + + result &= register_python_arch_instruction(module); + result &= register_python_arch_operand(module); + result &= register_python_arch_processor(module); + result &= register_python_instr_iterator(module); + result &= register_python_raw_instruction(module); + result &= register_python_vmpa(module); + result &= register_python_mrange(module); + + result &= register_python_imm_operand(module); + + if (result) + register_access_to_python_module("pychrysalide.arch", module); + + loading_failed: + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/arch/module.h b/plugins/pychrysalide/arch/module.h new file mode 100644 index 0000000..07d3575 --- /dev/null +++ b/plugins/pychrysalide/arch/module.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire arch en tant que module + * + * Copyright (C) 2012-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_PYCHRYSALIDE_ARCH_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'arch' au module Python. */ +bool add_arch_module_to_python_module(PyObject *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_MODULE_H */ diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c new file mode 100644 index 0000000..427f92b --- /dev/null +++ b/plugins/pychrysalide/arch/operand.c @@ -0,0 +1,109 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand.c - équivalent Python du fichier "arch/operand.h" + * + * Copyright (C) 2012-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 "operand.h" + + +#include <pygobject.h> + + +#include <arch/operand.h> + + +#include "../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_arch_operand_type(void) +{ + static PyMethodDef py_arch_operand_methods[] = { + { NULL } + }; + + static PyGetSetDef py_arch_operand_getseters[] = { + { NULL } + }; + + static PyTypeObject py_arch_operand_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.ArchOperand", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = "PyChrysalide instruction operand.", + + .tp_methods = py_arch_operand_methods, + .tp_getset = py_arch_operand_getseters, + + }; + + return &py_arch_operand_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.ArchOperand'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_arch_operand(PyObject *module) +{ + PyTypeObject *py_arch_operand_type; /* Type Python 'BinContent' */ + PyObject *dict; /* Dictionnaire du module */ + + py_arch_operand_type = get_python_arch_operand_type(); + + APPLY_ABSTRACT_FLAG(py_arch_operand_type); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, py_arch_operand_type, &PyGObject_Type)) + return false; + + return true; + +} diff --git a/plugins/pychrysalide/arch/operand.h b/plugins/pychrysalide/arch/operand.h new file mode 100644 index 0000000..3c5ef6a --- /dev/null +++ b/plugins/pychrysalide/arch/operand.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand.h - prototypes pour l'équivalent Python du fichier "arch/operand.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_PYOIDA_ARCH_OPERAND_H +#define _PLUGINS_PYOIDA_ARCH_OPERAND_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_arch_operand_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.ArchOperand'. */ +bool register_python_arch_operand(PyObject *); + + + +#endif /* _PLUGINS_PYOIDA_ARCH_OPERAND_H */ diff --git a/plugins/pychrysalide/arch/processor.c b/plugins/pychrysalide/arch/processor.c new file mode 100644 index 0000000..65431af --- /dev/null +++ b/plugins/pychrysalide/arch/processor.c @@ -0,0 +1,459 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * processor.c - équivalent Python du fichier "arch/processor.c" + * + * Copyright (C) 2012-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 "processor.h" + + +#include <malloc.h> +#include <pygobject.h> + + +#include <i18n.h> + + +#include <arch/processor.h> + + +#include "instriter.h" +#include "instruction.h" +#include "vmpa.h" +#include "../helpers.h" + + + + + + + + + + + + + + + + +/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ + + +/* Etend la liste des soucis détectés avec de nouvelles infos. */ +static PyObject *py_arch_processor_add_error(PyObject *, PyObject *); + +/* Fournit les éléments concernant tous les soucis détectés. */ +static PyObject *py_arch_processor_get_errors(PyObject *, void *); + + + +/* ------------------ MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES ------------------ */ + + +/* Fournit les instructions désassemblées pour une architecture. */ +static PyObject *py_arch_processor_get_instrs(PyObject *, void *); + +/* Note les instructions désassemblées avec une architecture. */ +static int py_arch_processor_set_instrs(PyObject *, PyObject *, void *); + +/* Recherche une instruction d'après son adresse. */ +static PyObject *py_arch_processor_find_instr_by_addr(PyObject *, PyObject *); + + + + + +/* Définit les constantes pour les types d'erreurs. */ +static bool define_python_arch_processor_constants(PyTypeObject *); + + + +/* ---------------------------------------------------------------------------------- */ +/* CONSERVATION DES SOUCIS DURANT LE CHARGEMENT */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = architecture concernée par la procédure. * +* args = instruction représentant le point de départ. * +* * +* Description : Etend la liste des soucis détectés avec de nouvelles infos. * +* * +* Retour : None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_processor_add_error(PyObject *self, PyObject *args) +{ + ArchProcessingError type; /* Type d'erreur détectée */ + vmpa2t addr; /* Position d'une erreur */ + const char *desc; /* Description d'une erreur */ + int ret; /* Bilan de lecture des args. */ + GArchProcessor *proc; /* Processeur manipulé */ + + ret = PyArg_ParseTuple(args, "IO&s", &type, convert_any_to_vmpa, &addr, &desc); + if (!ret) return NULL; + + proc = G_ARCH_PROCESSOR(pygobject_get(self)); + + g_arch_processor_add_error(proc, type, &addr, desc); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit les éléments concernant tous les soucis détectés. * +* * +* Retour : Liste des erreurs relevées au niveau de l'assembleur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_processor_get_errors(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GArchProcessor *proc; /* Architecture visée */ + size_t count; /* Nombre d'éléments à traiter */ + size_t i; /* Boucle de parcours */ +#ifndef NDEBUG + bool status; /* Bilan d'un appel */ +#endif + ArchProcessingError type; /* Type d'erreur détectée */ + vmpa2t addr; /* Position d'une erreur */ + char *desc; /* Description d'une erreur */ + PyObject *error; /* Nouvelle erreur à rajouter */ + + proc = G_ARCH_PROCESSOR(pygobject_get(self)); + + g_arch_processor_lock_errors(proc); + + count = g_arch_processor_count_errors(proc); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { +#ifndef NDEBUG + status = g_arch_processor_get_error(proc, i, &type, &addr, &desc); + assert(status); +#else + g_arch_processor_get_error(proc, i, &type, &addr, &desc); +#endif + + error = Py_BuildValue("IO&s", type, build_from_internal_vmpa, &addr, desc); + + PyTuple_SetItem(result, i, error); + + } + + g_arch_processor_unlock_errors(proc); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit les instructions désassemblées pour une architecture.* +* * +* Retour : Liste des instructions désassemblées ou None si aucune. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_processor_get_instrs(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + PyTypeObject *iterator_type; /* Type Python de l'itérateur */ + PyObject *args; /* Liste des arguments d'appel */ + + iterator_type = get_python_instr_iterator_type(); + + args = Py_BuildValue("On", self, 0); + + result = PyObject_CallObject((PyObject *)iterator_type, args); + + Py_DECREF(args); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = non utilisé ici. * +* * +* Description : Note les instructions désassemblées avec une architecture. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_arch_processor_set_instrs(PyObject *self, PyObject *value, void *closure) +{ + size_t count; /* Nombre d'instructions */ + GArchInstruction **list; /* Liste d'instructions */ + size_t i; /* Boucle de parcours */ + PyObject *instr; /* Instruction en Python */ + GArchProcessor *proc; /* Architecture visée */ + + if (!PyTuple_Check(value)) + { + PyErr_SetString(PyExc_TypeError, _("The attribute value must be a tuple of instructions.")); + return -1; + } + + count = PyTuple_Size(value); + + list = (GArchInstruction **)calloc(count, sizeof(GArchInstruction *)); + + for (i = 0; i < count; i++) + { + instr = PyTuple_GetItem(value, i); + + if (!PyObject_TypeCheck(value, get_python_arch_instruction_type())) + { + PyErr_SetString(PyExc_TypeError, _("The attribute value must be a tuple of instructions.")); + count = i; + goto papsi_error; + } + + list[i] = G_ARCH_INSTRUCTION(pygobject_get(instr)); + g_object_ref(G_OBJECT(list[i])); + + } + + proc = G_ARCH_PROCESSOR(pygobject_get(self)); + + g_arch_processor_set_instructions(proc, list, count); + + return 0; + + papsi_error: + + for (i = 0; i < count; i++) + g_object_unref(G_OBJECT(list[i])); + + free(list); + + return -1; + +} + + +/****************************************************************************** +* * +* Paramètres : self = processeur d'architecture à manipuler. * +* args = instruction représentant le point de départ. * +* * +* Description : Recherche une instruction d'après son adresse. * +* * +* Retour : Instruction trouvée à l'adresse donnée, None si aucune. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_processor_find_instr_by_addr(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + PyObject *addr_obj; /* Objet pour une localisation */ + int ret; /* Bilan de lecture des args. */ + GArchProcessor *proc; /* Processeur manipulé */ + vmpa2t *addr; /* Localisation à retrouver */ + GArchInstruction *found; /* Instruction liée trouvée */ + + ret = PyArg_ParseTuple(args, "O", &addr_obj); + if (!ret) return NULL; + + ret = PyObject_IsInstance(addr_obj, (PyObject *)get_python_vmpa_type()); + if (!ret) return NULL; + + proc = G_ARCH_PROCESSOR(pygobject_get(self)); + addr = get_internal_vmpa(addr_obj); + + found = g_arch_processor_find_instr_by_address(proc, addr); + + if (found != NULL) + { + result = pygobject_new(G_OBJECT(found)); + g_object_unref(G_OBJECT(found)); + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + + + + + +/****************************************************************************** +* * +* Paramètres : obj_type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes pour les types d'erreurs. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool define_python_arch_processor_constants(PyTypeObject *obj_type) +{ + bool result; /* Bilan à retourner */ + + result = true; + + result &= PyDict_AddIntMacro(obj_type, APE_DISASSEMBLY); + result &= PyDict_AddIntMacro(obj_type, APE_LABEL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_arch_processor_type(void) +{ + static PyMethodDef py_arch_processor_methods[] = { + { + "add_error", py_arch_processor_add_error, + METH_VARARGS, + "add_error($self, type, addr, desc, /)\n--\n\nExtend the list of detected disassembling errors." + }, + { + "find_instr_by_addr", py_arch_processor_find_instr_by_addr, + METH_VARARGS, + "find_instr_by_addr($self, addr, /)\n--\n\nLook for an instruction located at a given address." + }, + { NULL } + }; + + static PyGetSetDef py_arch_processor_getseters[] = { + { + "errors", py_arch_processor_get_errors, NULL, + "List of all detected errors which occurred during the disassembling process.", NULL + }, + { + "instrs", py_arch_processor_get_instrs, py_arch_processor_set_instrs, + "Give access to the disassembled instructions run by the current processor.", NULL + }, + { NULL } + }; + + static PyTypeObject py_arch_processor_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.ArchProcessor", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = "PyChrysalide processor for a given architecture.", + + .tp_methods = py_arch_processor_methods, + .tp_getset = py_arch_processor_getseters, + + }; + + return &py_arch_processor_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.ArchProcessor'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_arch_processor(PyObject *module) +{ + PyTypeObject *py_arch_processor_type; /* Type Python 'BinContent' */ + PyObject *dict; /* Dictionnaire du module */ + + py_arch_processor_type = get_python_arch_processor_type(); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, py_arch_processor_type, &PyGObject_Type)) + return false; + + if (!define_python_arch_processor_constants(py_arch_processor_type)) + return false; + + return true; + +} diff --git a/plugins/pychrysalide/arch/processor.h b/plugins/pychrysalide/arch/processor.h new file mode 100644 index 0000000..ff6ccb3 --- /dev/null +++ b/plugins/pychrysalide/arch/processor.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * processor.h - prototypes pour l'équivalent Python du fichier "arch/processor.h" + * + * Copyright (C) 2012-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_PYCHRYSALIDE_ARCH_PROCESSOR_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_PROCESSOR_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_arch_processor_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.ArchProcessor'. */ +bool register_python_arch_processor(PyObject *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_PROCESSOR_H */ diff --git a/plugins/pychrysalide/arch/raw.c b/plugins/pychrysalide/arch/raw.c new file mode 100644 index 0000000..39b5fe7 --- /dev/null +++ b/plugins/pychrysalide/arch/raw.c @@ -0,0 +1,263 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw.c - équivalent Python du fichier "arch/raw.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 + */ + + +#include "raw.h" + + +#include <pygobject.h> + + +#include <arch/raw.h> + + +#include "instruction.h" +#include "../helpers.h" + + + +/* Indique si le contenu de l'instruction est du bourrage. */ +static PyObject *py_arch_instruction_is_padding(PyObject *, void *); + +/* Marque l'instruction comme ne contenant que du bourrage. */ +static int py_arch_instruction_mark_as_padding(PyObject *, PyObject *, void *); + +/* Indique si le contenu de l'instruction est un texte. */ +static PyObject *py_arch_instruction_is_string(PyObject *, void *); + +/* Marque l'instruction comme contenant une chaîne de texte. */ +static int py_arch_instruction_mark_as_string(PyObject *, PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une instruction. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique si le contenu de l'instruction est du bourrage. * +* * +* Retour : Valeur associée à la propriété consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_is_padding(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + GRawInstruction *instr; /* Version native */ + bool state; /* Etat courant à consulter */ + + instr = G_RAW_INSTRUCTION(pygobject_get(self)); + + state = g_raw_instruction_is_padding(instr); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Marque l'instruction comme ne contenant que du bourrage. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_arch_instruction_mark_as_padding(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GRawInstruction *instr; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + instr = G_RAW_INSTRUCTION(pygobject_get(self)); + + g_raw_instruction_mark_as_padding(instr, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une instruction. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique si le contenu de l'instruction est un texte. * +* * +* Retour : Valeur associée à la propriété consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_is_string(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + GRawInstruction *instr; /* Version native */ + bool state; /* Etat courant à consulter */ + + instr = G_RAW_INSTRUCTION(pygobject_get(self)); + + state = g_raw_instruction_is_string(instr); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Marque l'instruction comme contenant une chaîne de texte. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_arch_instruction_mark_as_string(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GRawInstruction *instr; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + instr = G_RAW_INSTRUCTION(pygobject_get(self)); + + g_raw_instruction_mark_as_string(instr, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_raw_instruction_type(void) +{ + static PyMethodDef py_raw_instruction_methods[] = { + { NULL } + }; + + static PyGetSetDef py_raw_instruction_getseters[] = { + { + "is_padding", py_arch_instruction_is_padding, py_arch_instruction_mark_as_padding, + "Report if the instruction is seen as padding.", NULL + }, + { + "is_string", py_arch_instruction_is_string, py_arch_instruction_mark_as_string, + "Report if the instruction is seen as a string.", NULL + }, + { NULL } + }; + + static PyTypeObject py_raw_instruction_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.RawInstruction", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "PyChrysalide raw instruction for a all architectures.", + + .tp_methods = py_raw_instruction_methods, + .tp_getset = py_raw_instruction_getseters, + + }; + + return &py_raw_instruction_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.ArchInstruction'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_raw_instruction(PyObject *module) +{ + PyTypeObject *py_raw_instruction_type; /* Type Python 'RawInstruction'*/ + PyObject *dict; /* Dictionnaire du module */ + PyTypeObject *base; /* Base parente pour héritage */ + + py_raw_instruction_type = get_python_raw_instruction_type(); + + dict = PyModule_GetDict(module); + + base = get_python_arch_instruction_type(); + + if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, py_raw_instruction_type, base)) + return false; + + return true; + +} diff --git a/plugins/pychrysalide/arch/raw.h b/plugins/pychrysalide/arch/raw.h new file mode 100644 index 0000000..32c4e2d --- /dev/null +++ b/plugins/pychrysalide/arch/raw.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw.h - prototypes pour l'équivalent Python du fichier "arch/raw.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_PYCHRYSALIDE_ARCH_RAW_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_RAW_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_raw_instruction_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.RawInstruction'. */ +bool register_python_raw_instruction(PyObject *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_RAW_H */ diff --git a/plugins/pychrysalide/arch/vmpa.c b/plugins/pychrysalide/arch/vmpa.c new file mode 100644 index 0000000..413d67b --- /dev/null +++ b/plugins/pychrysalide/arch/vmpa.c @@ -0,0 +1,1303 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * vmpa.c - équivalent Python du fichier "arch/vmpa.c" + * + * Copyright (C) 2014-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 "vmpa.h" + + +#include <assert.h> +#include <string.h> + + +#include <i18n.h> + + +#include "../helpers.h" + + + + + +#include <common/endianness.h> /* TODO : à bouger vers base ? */ + + + + +/* ---------------------- DEFINITION D'UNE POSITION EN MEMOIRE ---------------------- */ + + + +typedef struct _py_vmpa_t +{ + PyObject_HEAD + + vmpa2t addr; + +} py_vmpa_t; + + + + +/* Fournit une représentation d'une variable 'vmpa_t'. */ +static PyObject *py_vmpa_to_str(PyObject *); + +/* Effectue une comparaison avec un objet Python 'vmpa_t'. */ +static PyObject *py_vmpa_richcompare(PyObject *, PyObject *, int); + +/* Fournit une partie du contenu de la position représentée. */ +static PyObject *py_vmpa_get_value(PyObject *, void *); + +/* Définit une partie du contenu de la position représentée. */ +static int py_vmpa_set_value(PyObject *, PyObject *, void *); + +/* Crée un nouvel objet Python de type 'vmpa2t'. */ +static PyObject *py_vmpa_new(PyTypeObject *, PyObject *, PyObject *); + +/* Effectue une conversion d'un objet Python en type 'vmpa_t'. */ +static bool convert_pyobj_to_vmpa(PyObject *, vmpa2t *); + +/* Effectue une opération de type 'add' avec le type 'vmpa'. */ +static PyObject *py_vmpa_nb_add(PyObject *, PyObject *); + +/* Définit les constantes pour les localisations. */ +static bool py_vmpa_define_constants(PyTypeObject *); + + + +/* ------------------------ DEFINITION D'UNE ZONE EN MEMOIRE ------------------------ */ + + +/* Couverture mémoire */ +typedef struct _py_mrange_t +{ + PyObject_HEAD /* Préambule Python */ + + mrange_t range; /* Informations internes */ + +} py_mrange_t; + + +/* Fournit une représentation d'une variable 'mrange_t'. */ +static PyObject *py_mrange_to_str(PyObject *); + + + +/* Effectue une comparaison avec un objet Python 'mrange_t'. */ +static PyObject *py_mrange_richcompare(PyObject *, PyObject *, int); + + + +/* Indique si une zone en contient une autre ou non. */ +static PyObject *py_mrange_contains(PyObject *, PyObject *); + + + + +/* Fournit la position de départ de la zone mémoire représentée. */ +static PyObject *py_mrange_get_addr(PyObject *, void *); + +/* Définit la position de départ de la zone mémoire représentée. */ +static int py_mrange_set_addr(PyObject *, PyObject *, void *); + +/* Fournit la taille de la zone mémoire représentée. */ +static PyObject *py_mrange_get_length(PyObject *, void *); + +/* Définit la taille de la zone mémoire représentée. */ +static int py_mrange_set_length(PyObject *, PyObject *, void *); + +/* Calcule la position extérieure finale d'une couverture. */ +static PyObject *py_mrange_get_end_addr(PyObject *, void *); + + + + +/* Crée un nouvel objet Python de type 'mrange'. */ +static PyObject *py_mrange_new(PyTypeObject *, PyObject *, PyObject *); + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UNE POSITION EN MEMOIRE */ +/* ---------------------------------------------------------------------------------- */ + + + + +/****************************************************************************** +* * +* Paramètres : obj = objet Python à traiter. * +* * +* Description : Fournit une représentation d'une variable 'vmpa_t'. * +* * +* Retour : Chaîne de caractère pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_vmpa_to_str(PyObject *obj) +{ + PyObject *result; /* Chaîne à retourner */ + vmpa2t *addr; /* Véritable adresse manipulée */ + phys_t physical; /* Position physique */ + virt_t virtual; /* Adresse virtuelle */ + VMPA_BUFFER(phys_str); /* Version humaine de position */ + VMPA_BUFFER(virt_str); /* Version humaine d'adresse */ + + addr = &((py_vmpa_t *)obj)->addr; + + physical = get_phy_addr(addr); + virtual = get_virt_addr(addr); + + vmpa2_phys_to_string(addr, MDS_UNDEFINED, phys_str, NULL); + vmpa2_phys_to_string(addr, MDS_UNDEFINED, virt_str, NULL); + + if (physical == VMPA_NO_PHYSICAL && virtual == VMPA_NO_VIRTUAL) + result = PyUnicode_FromFormat("<phy=None, virt=None>"); + + else if (physical != VMPA_NO_PHYSICAL && virtual == VMPA_NO_VIRTUAL) + result = PyUnicode_FromFormat("<phy=%s, virt=None>", phys_str); + + else if (physical == VMPA_NO_PHYSICAL && virtual != VMPA_NO_VIRTUAL) + result = PyUnicode_FromFormat("<phy=None, virt=%s>", virt_str); + + else + result = PyUnicode_FromFormat("<phy=%s, virt=%s>", phys_str, virt_str); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : a = premier object Python à consulter. * +* b = second object Python à consulter. * +* op = type de comparaison menée. * +* * +* Description : Effectue une comparaison avec un objet Python 'vmpa_t'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_vmpa_richcompare(PyObject *a, PyObject *b, int op) +{ + PyObject *result; /* Bilan à retourner */ + vmpa2t *addr_a; /* Première adresse à traiter */ + vmpa2t addr_b; /* Seconde adresse à traiter */ + int comp; /* Résultat d'une comparaison */ + + addr_a = &((py_vmpa_t *)a)->addr; + + if (!convert_pyobj_to_vmpa(b, &addr_b)) + return NULL; + + comp = cmp_vmpa(addr_a, &addr_b); + + switch (op) + { + case Py_LT: + result = comp < 0 ? Py_True : Py_False; + break; + + case Py_LE: + result = comp <= 0 ? Py_True : Py_False; + break; + + case Py_EQ: + result = comp == 0 ? Py_True : Py_False; + break; + + case Py_NE: + result = comp != 0 ? Py_True : Py_False; + break; + + case Py_GT: + result = comp > 0 ? Py_True : Py_False; + break; + + case Py_GE: + result = comp >= 0 ? Py_True : Py_False; + break; + + default: + assert(false); + result = Py_NotImplemented; + break; + + } + + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = définition d'adresse visée par la procédure. * +* closure = sélection de la valeur à traiter. * +* * +* Description : Fournit une partie du contenu de la position représentée. * +* * +* Retour : Nombre positif ou nul ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_vmpa_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + py_vmpa_t *vmpa; /* Véritable objet Python */ + char *key; /* Contenu à cibler précisément*/ + + vmpa = (py_vmpa_t *)self; + + key = (char *)closure; + + if (strcmp(key, "phys") == 0) + { + if (get_phy_addr(&vmpa->addr) == VMPA_NO_PHYSICAL) + { + result = Py_None; + Py_INCREF(result); + } + else result = Py_BuildValue("K", get_phy_addr(&vmpa->addr)); + } + else + { + if (get_virt_addr(&vmpa->addr) == VMPA_NO_VIRTUAL) + { + result = Py_None; + Py_INCREF(result); + } + else result = Py_BuildValue("K", get_virt_addr(&vmpa->addr)); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = définition d'adresse visée par la procédure. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = sélection de la valeur à traiter. * +* * +* Description : Définit une partie du contenu de la position représentée. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_vmpa_set_value(PyObject *self, PyObject *value, void *closure) +{ + int result; /* Bilan à faire remonter */ + py_vmpa_t *vmpa; /* Véritable objet Python */ + char *key; /* Contenu à cibler précisément*/ + PY_LONG_LONG val; /* Valeur traduite génériquemt */ + int overflow; /* Détection d'une grosse val. */ + + result = 0; + + vmpa = (py_vmpa_t *)self; + + key = (char *)closure; + + if (strcmp(key, "phys") == 0) + { + if (value == Py_None) + init_vmpa(&vmpa->addr, VMPA_NO_PHYSICAL, get_virt_addr(&vmpa->addr)); + + else + { + val = PyLong_AsLongLongAndOverflow(value, &overflow); + + if (val == -1 && (overflow == 1 || PyErr_Occurred())) + { + result = -1; + PyErr_Clear(); + } + else init_vmpa(&vmpa->addr, val, get_virt_addr(&vmpa->addr)); + + } + + } + else + { + if (value == Py_None) + init_vmpa(&vmpa->addr, get_phy_addr(&vmpa->addr), VMPA_NO_VIRTUAL); + + else + { + val = PyLong_AsLongLongAndOverflow(value, &overflow); + + if (val == -1 && (overflow == 1 || PyErr_Occurred())) + { + result = -1; + PyErr_Clear(); + } + else init_vmpa(&vmpa->addr, get_phy_addr(&vmpa->addr), val); + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'vmpa2t'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_vmpa_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + py_vmpa_t *result; /* Instance à retourner */ + unsigned long long phy; /* Position physique */ + unsigned long long virt; /* Adresse en mémoire virtuelle*/ + int ret; /* Bilan de lecture des args. */ + + phy = VMPA_NO_PHYSICAL; + virt = VMPA_NO_VIRTUAL; + + ret = PyArg_ParseTuple(args, "|KK", &phy, &virt); + if (!ret) Py_RETURN_NONE; + + result = (py_vmpa_t *)type->tp_alloc(type, 0); + + init_vmpa(&result->addr, phy, virt); + + return (PyObject *)result; + +} + + + + + + +/****************************************************************************** +* * +* Paramètres : obj = objet Python à tenter de convertir. * +* addr = structure équivalente pour Chrysalide. * +* * +* Description : Effectue une conversion d'un objet Python en type 'vmpa_t'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool convert_pyobj_to_vmpa(PyObject *obj, vmpa2t *addr) +{ + bool result; /* Résulats à retourner */ + PyTypeObject *py_vmpa_type; /* Type Python pour 'vmpa' */ + int ret; /* Bilan d'un appel */ + PY_LONG_LONG value; /* Valeur de type générique */ + int overflow; /* Détection d'une grosse val. */ + + result = false; + + py_vmpa_type = get_python_vmpa_type(); + + ret = PyObject_IsInstance(obj, (PyObject *)py_vmpa_type); + + /* S'il n'y a rien à faire... */ + if (ret == 1) + { + *addr = ((py_vmpa_t *)obj)->addr; + result = true; + } + + /* Sinon on demande à Python... */ + else + { + value = PyLong_AsLongLongAndOverflow(obj, &overflow); + + if (value == -1 && (overflow == 1 || PyErr_Occurred())) + { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, _("Unable to cast object as VMPA.")); + } + + else + { + init_vmpa(addr, value, value); + result = true; + } + + } + + return result; + +} + + + + +/****************************************************************************** +* * +* Paramètres : o1 = premier élément concerné par l'opération. * +* o2 = second élément concerné par l'opération. * +* * +* Description : Effectue une opération de type 'add' avec le type 'vmpa'. * +* * +* Retour : Résultat de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_vmpa_nb_add(PyObject *o1, PyObject *o2) +{ + PyObject *result; /* Résultat à retourner */ + vmpa2t addr1; /* Première adresse à traiter */ + vmpa2t addr2; /* Seconde adresse à traiter */ + PyTypeObject *py_vmpa_type; /* Type Python pour 'vmpa' */ + + if (!convert_pyobj_to_vmpa(o1, &addr1)) + return NULL; + + if (!convert_pyobj_to_vmpa(o2, &addr2)) + return NULL; + + py_vmpa_type = get_python_vmpa_type(); + + result = PyObject_CallObject((PyObject *)py_vmpa_type, NULL); + + init_vmpa(&((py_vmpa_t *)result)->addr, + addr1.physical + addr2.physical, + addr1.virtual + addr2.virtual); + + return result; + +} + + + + + +void change_editor_items_current_view_content(void/*GtkDisplayPanel*/ *view) +{ + /* FIXME */ + +} + + + + +/****************************************************************************** +* * +* Paramètres : obj_type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes pour les localisations. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_vmpa_define_constants(PyTypeObject *obj_type) +{ + bool result; /* Bilan à retourner */ + + result = true; + + result &= PyDict_AddIntMacro(obj_type, VMPA_NO_PHYSICAL); + result &= PyDict_AddIntMacro(obj_type, VMPA_NO_VIRTUAL); + + /* TODO : à bouger vers base ? */ + result &= PyDict_AddIntMacro(obj_type, SRE_LITTLE); + result &= PyDict_AddIntMacro(obj_type, SRE_MIDDLE); + result &= PyDict_AddIntMacro(obj_type, SRE_BIG); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_vmpa_type(void) +{ + static PyNumberMethods py_vmpa_nb_proto = { + + .nb_add = py_vmpa_nb_add, + + /* + binaryfunc nb_add; + binaryfunc nb_subtract; + binaryfunc nb_multiply; + binaryfunc nb_remainder; + binaryfunc nb_divmod; + ternaryfunc nb_power; + unaryfunc nb_negative; + unaryfunc nb_positive; + unaryfunc nb_absolute; + inquiry nb_bool; + unaryfunc nb_invert; + binaryfunc nb_lshift; + binaryfunc nb_rshift; + binaryfunc nb_and; + binaryfunc nb_xor; + binaryfunc nb_or; + unaryfunc nb_int; + void *nb_reserved; + unaryfunc nb_float; + + binaryfunc nb_inplace_add; + binaryfunc nb_inplace_subtract; + binaryfunc nb_inplace_multiply; + binaryfunc nb_inplace_remainder; + ternaryfunc nb_inplace_power; + binaryfunc nb_inplace_lshift; + binaryfunc nb_inplace_rshift; + binaryfunc nb_inplace_and; + binaryfunc nb_inplace_xor; + binaryfunc nb_inplace_or; + + binaryfunc nb_floor_divide; + binaryfunc nb_true_divide; + binaryfunc nb_inplace_floor_divide; + binaryfunc nb_inplace_true_divide; + + unaryfunc nb_index; + + */ + + }; + + static PyGetSetDef py_vmpa_getseters[] = { + + { + "phys", py_vmpa_get_value, py_vmpa_set_value, + "Give access to the physical offset of the location.", "phys" + }, + + { + "virt", py_vmpa_get_value, py_vmpa_set_value, + "Give access to the virtual address of the location.", "virt" + }, + { NULL } + + }; + + static PyTypeObject py_vmpa_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.vmpa", + .tp_basicsize = sizeof(py_vmpa_t), + + .tp_as_number = &py_vmpa_nb_proto, + + .tp_str = py_vmpa_to_str, + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "Python object for vmpa_t.", + + .tp_richcompare = py_vmpa_richcompare, + + .tp_getset = py_vmpa_getseters, + .tp_new = (newfunc)py_vmpa_new + + }; + + return &py_vmpa_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.vmpa'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_vmpa(PyObject *module) +{ + PyTypeObject *py_vmpa_type; /* Type Python pour 'vmpa' */ + int ret; /* Bilan d'un appel */ + + py_vmpa_type = get_python_vmpa_type(); + + if (PyType_Ready(py_vmpa_type) != 0) + return false; + + if (!py_vmpa_define_constants(py_vmpa_type)) + return false; + + Py_INCREF(py_vmpa_type); + ret = PyModule_AddObject(module, "vmpa", (PyObject *)py_vmpa_type); + + return (ret == 0); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = objet Python à traiter. * +* * +* Description : Donne accès au coeur d'un objet 'pychrysalide.arch.vmpa'. * +* * +* Retour : Localistion réelle ou NULL en cas de mauvaise conversion. * +* * +* Remarques : - * +* * +******************************************************************************/ + +vmpa2t *get_internal_vmpa(PyObject *obj) +{ + int ret; /* Bilan d'analyse */ + + ret = PyObject_IsInstance(obj, (PyObject *)get_python_vmpa_type()); + if (!ret) return NULL; + + return &((py_vmpa_t *)obj)->addr; + +} + + +/****************************************************************************** +* * +* Paramètres : addr = structure interne à copier en objet Python. * +* * +* Description : Convertit une structure de type 'vmpa2t' en objet Python. * +* * +* Retour : Object Python résultant de la conversion opérée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *build_from_internal_vmpa(const vmpa2t *addr) +{ + py_vmpa_t *result; /* Instance à retourner */ + PyTypeObject *type; /* Type à instancier */ + + type = get_python_vmpa_type(); + + result = (py_vmpa_t *)type->tp_alloc(type, 0); + + copy_vmpa(&result->addr, addr); + + return (PyObject *)result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en adresse n'importe quoi. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_any_to_vmpa(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + int ret; /* Test intermédiaire */ + vmpa2t *src; /* Modèle de données à copier */ + PY_LONG_LONG value; /* Valeur de type générique */ + int overflow; /* Détection d'une grosse val. */ + + result = 0; + + /* Si l'objet est au bon format, rien à faire ! */ + + ret = PyObject_IsInstance(arg, (PyObject *)get_python_vmpa_type()); + + if (ret == 1) + { + src = get_internal_vmpa(arg); + copy_vmpa((vmpa2t *)dst, src); + + result = 1; + goto catv_done; + + } + + /* Sinon on demande à Python... */ + + value = PyLong_AsLongLongAndOverflow(arg, &overflow); + + if (value == -1 && (overflow == 1 || PyErr_Occurred())) + PyErr_Clear(); + + else + { + init_vmpa((vmpa2t *)dst, VMPA_NO_PHYSICAL, value); + + result = 1; + goto catv_done; + + } + + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to vmpa"); + + catv_done: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UNE ZONE EN MEMOIRE */ +/* ---------------------------------------------------------------------------------- */ + + + + + + + +/****************************************************************************** +* * +* Paramètres : obj = objet Python à traiter. * +* * +* Description : Fournit une représentation d'une variable 'mrange_t'. * +* * +* Retour : Chaîne de caractère pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_mrange_to_str(PyObject *obj) +{ + PyObject *result; /* Chaîne à retourner */ + + result = PyUnicode_FromFormat("<TODO!>"); + + return result; + +} + + + + +/****************************************************************************** +* * +* Paramètres : a = premier object Python à consulter. * +* b = second object Python à consulter. * +* op = type de comparaison menée. * +* * +* Description : Effectue une comparaison avec un objet Python 'mrange_t'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_mrange_richcompare(PyObject *a, PyObject *b, int op) +{ + PyObject *result; /* Bilan à retourner */ + mrange_t *range_a; /* Premier espace à traiter */ + mrange_t *range_b; /* Second espace à traiter */ + int status; /* Résultat d'une comparaison */ + + range_a = get_internal_mrange(a); + + range_b = get_internal_mrange(b); + if (range_b == NULL) return NULL; + + status = cmp_mrange(range_a, range_b); + + result = status_to_rich_cmp_state(status, op); + + Py_INCREF(result); + + return result; + +} + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : self = contenu binaire à manipuler. * +* args = non utilisé ici. * +* * +* Description : Indique si une zone en contient une autre ou non. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_mrange_contains(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + int ret; /* Bilan de lecture des args. */ + PyObject *range_obj; /* Objet pour un intervale */ + mrange_t *range; /* Région mémoire de contenance*/ + mrange_t *sub; /* Région mémoire contenue ? */ + + ret = PyArg_ParseTuple(args, "O", &range_obj); + if (!ret) return NULL; + + ret = PyObject_IsInstance(range_obj, (PyObject *)get_python_mrange_type()); + if (!ret) return NULL; + + range = get_internal_mrange(self); + sub = get_internal_mrange(range_obj); + + result = (mrange_contains_mrange(range, sub) ? Py_True : Py_False); + + Py_INCREF(result); + + return result; + +} + + + + + +/****************************************************************************** +* * +* Paramètres : self = définition de l'espace visé par la procédure. * +* closure = élément non utilisé ici. * +* * +* Description : Fournit la position de départ de la zone mémoire représentée.* +* * +* Retour : Nouvelle objet mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_mrange_get_addr(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + mrange_t *range; /* Espace mémoire à manipuler */ + + range = get_internal_mrange(self); + + result = build_from_internal_vmpa(get_mrange_addr(range)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = définition de l'espace visé par la procédure. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = élément non utilisé ici. * +* * +* Description : Définit la position de départ de la zone mémoire représentée.* +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_mrange_set_addr(PyObject *self, PyObject *value, void *closure) +{ + int result; /* Bilan à faire remonter */ + vmpa2t *addr; /* Localisation version C */ + mrange_t *range; /* Espace mémoire à manipuler */ + + result = 0; + + addr = get_internal_vmpa(value); + if (addr == NULL) return -1; + + range = get_internal_mrange(self); + + init_mrange(range, addr, get_mrange_length(range)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = définition de l'espace visé par la procédure. * +* closure = élément non utilisé ici. * +* * +* Description : Fournit la taille de la zone mémoire représentée. * +* * +* Retour : Nouvelle objet mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_mrange_get_length(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + mrange_t *range; /* Espace mémoire à manipuler */ + + range = get_internal_mrange(self); + + result = Py_BuildValue("K", get_mrange_length(range)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = définition de l'espace visé par la procédure. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = élément non utilisé ici. * +* * +* Description : Définit la taille de la zone mémoire représentée. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_mrange_set_length(PyObject *self, PyObject *value, void *closure) +{ + int result; /* Bilan à faire remonter */ + mrange_t *range; /* Espace mémoire à manipuler */ + PY_LONG_LONG val; /* Valeur traduite génériquemt */ + int overflow; /* Détection d'une grosse val. */ + vmpa2t tmp; /* Copie pour recopie */ + + result = 0; + + range = get_internal_mrange(self); + + val = PyLong_AsLongLongAndOverflow(value, &overflow); + + if (val == -1 && (overflow == 1 || PyErr_Occurred())) + { + result = -1; + PyErr_Clear(); + } + else + { + copy_vmpa(&tmp, get_mrange_addr(range)); + init_mrange(range, &tmp, val); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = définition de l'espace visé par la procédure. * +* closure = élément non utilisé ici. * +* * +* Description : Calcule la position extérieure finale d'une couverture. * +* * +* Retour : Nouvelle objet mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_mrange_get_end_addr(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + mrange_t *range; /* Espace mémoire à manipuler */ + vmpa2t end; /* Adresse à reproduire */ + + range = get_internal_mrange(self); + compute_mrange_end_addr(range, &end); + + result = build_from_internal_vmpa(&end); + + return result; + +} + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'mrange'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_mrange_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + py_mrange_t *result; /* Instance à retourner */ + PyObject *py_vmpa; /* Localisation version Python */ + unsigned long long length; /* Taille physique */ + int ret; /* Bilan de lecture des args. */ + vmpa2t *addr; /* Localisation version C */ + + ret = PyArg_ParseTuple(args, "OK", &py_vmpa, &length); + if (!ret) return NULL; + + ret = PyObject_IsInstance(py_vmpa, (PyObject *)get_python_vmpa_type()); + if (!ret) return NULL; + + addr = get_internal_vmpa(py_vmpa); + if (addr == NULL) return NULL; + + result = (py_mrange_t *)type->tp_alloc(type, 0); + + init_mrange(&result->range, addr, length); + + return (PyObject *)result; + +} + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_mrange_type(void) +{ + static PyMethodDef py_mrange_methods[] = { + { "contains", py_mrange_contains, + METH_VARARGS, + "contains($self, other, /)\n--\nTell if the current range contains another given range or address." + }, +#if 0 + { "read_u8", py_arch_instruction_read_u8, + METH_VARARGS, + "read_u8($self, addr, /)\n--\n\nRead an unsigned byte from a given position." + }, +#endif + { NULL } + }; + + static PyGetSetDef py_mrange_getseters[] = { + { + "addr", py_mrange_get_addr, py_mrange_set_addr, + "Give access to the start location of the memory range.", NULL + }, + { + "length", py_mrange_get_length, py_mrange_set_length, + "Give access to the length of the memory range.", NULL + }, + { + "end", py_mrange_get_end_addr, NULL, + "Provide the final external point of the memory range.", NULL + }, + { NULL } + }; + + static PyTypeObject py_mrange_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.mrange", + .tp_basicsize = sizeof(py_mrange_t), + + .tp_str = py_mrange_to_str, + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "Python object for mrange_t.", + + .tp_richcompare = py_mrange_richcompare, + + .tp_methods = py_mrange_methods, + .tp_getset = py_mrange_getseters, + .tp_new = (newfunc)py_mrange_new + + }; + + return &py_mrange_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.mrange'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_mrange(PyObject *module) +{ + PyTypeObject *py_mrange_type; /* Type Python pour 'mrange' */ + int ret; /* Bilan d'un appel */ + + py_mrange_type = get_python_mrange_type(); + + if (PyType_Ready(py_mrange_type) != 0) + return false; + + Py_INCREF(py_mrange_type); + ret = PyModule_AddObject(module, "mrange", (PyObject *)py_mrange_type); + + return (ret == 0); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = objet Python à traiter. * +* * +* Description : Donne accès au coeur d'un objet 'pychrysalide.arch.mrange'. * +* * +* Retour : Localistion réelle ou NULL en cas de mauvaise conversion. * +* * +* Remarques : - * +* * +******************************************************************************/ + +mrange_t *get_internal_mrange(PyObject *obj) +{ + int ret; /* Bilan d'analyse */ + + ret = PyObject_IsInstance(obj, (PyObject *)get_python_mrange_type()); + if (!ret) return NULL; + + return &((py_mrange_t *)obj)->range; + +} + + +/****************************************************************************** +* * +* Paramètres : range = structure interne à copier en objet Python. * +* * +* Description : Convertit une structure de type 'mrange_t' en objet Python. * +* * +* Retour : Object Python résultant de la conversion opérée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *build_from_internal_mrange(const mrange_t *range) +{ + py_mrange_t *result; /* Instance à retourner */ + PyTypeObject *type; /* Type à instancier */ + + type = get_python_mrange_type(); + + result = (py_mrange_t *)type->tp_alloc(type, 0); + + copy_mrange(&result->range, range); + + return (PyObject *)result; + +} diff --git a/plugins/pychrysalide/arch/vmpa.h b/plugins/pychrysalide/arch/vmpa.h new file mode 100644 index 0000000..46828f5 --- /dev/null +++ b/plugins/pychrysalide/arch/vmpa.h @@ -0,0 +1,71 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * vmpa.h - prototypes pour l'équivalent Python du fichier "arch/vmpa.h" + * + * Copyright (C) 2014-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_PYCHRYSALIDE_ARCH_VMPA_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_VMPA_H + + +#include <Python.h> +#include <stdbool.h> + + +#include <src/arch/vmpa.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_vmpa_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.vmpa'. */ +bool register_python_vmpa(PyObject *); + +/* Donne accès au coeur d'un objet 'pychrysalide.arch.vmpa'. */ +vmpa2t *get_internal_vmpa(PyObject *); + +/* Convertit une structure de type 'vmpa2t' en objet Python. */ +PyObject *build_from_internal_vmpa(const vmpa2t *); + +/* Tente de convertir en adresse n'importe quoi. */ +int convert_any_to_vmpa(PyObject *, void *); + + + +/* ------------------------ DEFINITION D'UNE ZONE EN MEMOIRE ------------------------ */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_mrange_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.mrange'. */ +bool register_python_mrange(PyObject *); + +/* Donne accès au coeur d'un objet 'pychrysalide.arch.mrange'. */ +mrange_t *get_internal_mrange(PyObject *); + +/* Convertit une structure de type 'mrange_t' en objet Python. */ +PyObject *build_from_internal_mrange(const mrange_t *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_VMPA_H */ |