From b7c83221f2a60be8ee5d44a7599dbe6869af005f Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 3 Aug 2012 13:03:26 +0000
Subject: Loaded the permissions used by an APK file.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@255 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                               |  66 +++++++
 configure.ac                            |   1 +
 plugins/pychrysa/analysis/Makefile.am   |   3 +-
 plugins/pychrysa/analysis/binary.c      | 211 +++++++-------------
 plugins/pychrysa/analysis/binary.h      |   8 +-
 plugins/pychrysa/analysis/module.c      |  18 +-
 plugins/pychrysa/debug/debugger.c       |  11 +-
 plugins/pychrysa/plugin.c               |  43 ++---
 plugins/pychrysa/pychrysa.c             |  47 +++--
 plugins/pychrysa/pychrysa.h             |   5 +-
 plugins/python/Makefile.am              |   2 +-
 plugins/python/androperms/Makefile.am   |  12 ++
 plugins/python/androperms/__init__.py   |   2 +
 plugins/python/androperms/androperms.py |  41 ++++
 plugins/python/androperms/defs.py       |  53 ++++++
 plugins/python/androperms/manifest.py   |  75 ++++++++
 plugins/python/androperms/parser.py     | 328 ++++++++++++++++++++++++++++++++
 plugins/python/androperms/reader.py     |  41 ++++
 plugins/python/androperms/stack.py      | 108 +++++++++++
 plugins/python/androperms/string.py     |  82 ++++++++
 plugins/python/apkfiles/apkfiles.py     |   7 +-
 src/analysis/binary.c                   |  18 +-
 src/analysis/decomp/decompiler.c        |   2 -
 src/analysis/disass/disassembler.c      |  21 +-
 src/analysis/disass/disassembler.h      |   2 +-
 src/format/dex/method.c                 |   4 +-
 src/gui/panels/log.c                    |   4 +-
 src/gui/panels/log.h                    |   4 +
 src/plugins/plugin-def.h                |  11 +-
 src/plugins/plugin-int.h                |  15 +-
 src/plugins/plugin.c                    | 147 +++++++++++++-
 src/plugins/plugin.h                    |   3 +
 32 files changed, 1145 insertions(+), 250 deletions(-)
 create mode 100644 plugins/python/androperms/Makefile.am
 create mode 100644 plugins/python/androperms/__init__.py
 create mode 100644 plugins/python/androperms/androperms.py
 create mode 100644 plugins/python/androperms/defs.py
 create mode 100644 plugins/python/androperms/manifest.py
 create mode 100644 plugins/python/androperms/parser.py
 create mode 100644 plugins/python/androperms/reader.py
 create mode 100644 plugins/python/androperms/stack.py
 create mode 100644 plugins/python/androperms/string.py

diff --git a/ChangeLog b/ChangeLog
index c78422d..78e5694 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,71 @@
 12-08-03  Cyrille Bagard <nocbos@gmail.com>
 
+	* configure.ac:
+	Add the new Makefile from the 'plugins/python/androperms' directory
+	to AC_CONFIG_FILES.
+
+	* plugins/pychrysa/analysis/binary.c:
+	* plugins/pychrysa/analysis/binary.h:
+	Rewrite all the code.
+
+	* plugins/pychrysa/analysis/Makefile.am:
+	Add LIBPYGOBJECT_CFLAGS to INCLUDES.
+
+	* plugins/pychrysa/analysis/module.c:
+	Update code and remove old one.
+
+	* plugins/pychrysa/debug/debugger.c:
+	Typo.
+
+	* plugins/pychrysa/plugin.c:
+	Define PGA_DISASS_PROCESS. Execute actions on binaries in Python plugins.
+
+	* plugins/pychrysa/pychrysa.c:
+	* plugins/pychrysa/pychrysa.h:
+	Define the final name of the plugin and print loading messages.
+
+	* plugins/python/androperms/androperms.py:
+	* plugins/python/androperms/defs.py:
+	* plugins/python/androperms/__init__.py:
+	* plugins/python/androperms/Makefile.am:
+	* plugins/python/androperms/manifest.py:
+	* plugins/python/androperms/parser.py:
+	* plugins/python/androperms/reader.py:
+	* plugins/python/androperms/stack.py:
+	* plugins/python/androperms/string.py:
+	New entries: load the permissions used by an APK file.
+
+	* plugins/python/apkfiles/apkfiles.py:
+	Check for an AndroidManifest.xml file to validate the format.
+
+	* plugins/python/Makefile.am:
+	Add androperms to SUBDIRS.
+
+	* src/analysis/binary.c:
+	Move code into disass/disassembler.c.
+
+	* src/analysis/decomp/decompiler.c:
+	Disable debug messages.
+
+	* src/analysis/disass/disassembler.c:
+	* src/analysis/disass/disassembler.h:
+	Execute plugin actions on the disassembly is done.
+
+	* src/format/dex/method.c:
+	Disable debug messages.
+
+	* src/gui/panels/log.c:
+	* src/gui/panels/log.h:
+	Redefine the steps for rebuilding variadic messages.
+
+	* src/plugins/plugin.c:
+	* src/plugins/plugin-def.h:
+	* src/plugins/plugin.h:
+	* src/plugins/plugin-int.h:
+	Allow plugins to log messages.
+
+12-08-03  Cyrille Bagard <nocbos@gmail.com>
+
 	* src/arch/dalvik/instruction.c:
 	* src/arch/dalvik/instruction-def.h:
 	* src/arch/dalvik/opcodes/add.c:
diff --git a/configure.ac b/configure.ac
index d894657..c6dc2f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -242,6 +242,7 @@ AC_CONFIG_FILES([Makefile
                  plugins/pychrysa/debug/Makefile
                  plugins/pychrysa/format/Makefile
                  plugins/python/Makefile
+                 plugins/python/androperms/Makefile
                  plugins/python/apkfiles/Makefile
                  plugins/python/exectracer/Makefile
                  plugins/stackvars/Makefile
diff --git a/plugins/pychrysa/analysis/Makefile.am b/plugins/pychrysa/analysis/Makefile.am
index b18d16d..123279b 100644
--- a/plugins/pychrysa/analysis/Makefile.am
+++ b/plugins/pychrysa/analysis/Makefile.am
@@ -13,7 +13,8 @@ libpychrysaanalysis_la_SOURCES =		\
 libpychrysaanalysis_la_LDFLAGS = 
 
 
-INCLUDES = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) -I../../../src
+INCLUDES = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \
+	-I../../../src
 
 AM_CPPFLAGS = 
 
diff --git a/plugins/pychrysa/analysis/binary.c b/plugins/pychrysa/analysis/binary.c
index d378496..4cfb615 100644
--- a/plugins/pychrysa/analysis/binary.c
+++ b/plugins/pychrysa/analysis/binary.c
@@ -25,41 +25,18 @@
 #include "binary.h"
 
 
-#include "line.h"
-#include "../format/executable.h"
+#include <pygobject.h>
 
 
-
-
-/* Classe 'analysis.binary' pour Python */
-typedef struct _py_binary
-{
-    PyObject_HEAD
-
-    GOpenidaBinary *binary;                 /* Référence GLib              */
-
-} py_binary;
-
-
-
-
-/* Crée un nouvel objet Python de type 'py_binary'. */
-static PyObject *py_binary_new(PyTypeObject *, PyObject *, PyObject *);
-
+#include "../quirks.h"
 
 
 
-/* Fournit le format de fichier reconnu dans le contenu binaire. */
-static PyObject *py_binary_get_format(py_binary *);
-
-/* Fournit les lignes de rendu associé pour Python. */
-static PyObject *py_binary_get_lines(py_binary *);
-
-
-
-/* Fournit le type d'objet 'analysis.binary' pour Python. */
-static PyTypeObject *get_analysis_binary_type(void);
+/* Crée un nouvel objet Python de type 'LoadedBinary'. */
+static PyObject *py_loaded_binary_new(PyTypeObject *, PyObject *, PyObject *);
 
+/* Fournit le fichier correspondant à l'élément binaire. */
+static PyObject *py_loaded_binary_get_filename(PyObject *self, PyObject *args);
 
 
 
@@ -69,19 +46,28 @@ static PyTypeObject *get_analysis_binary_type(void);
 *                args = arguments fournis à l'appel.                          *
 *                kwds = arguments de type key=val fournis.                    *
 *                                                                             *
-*  Description : Crée un nouvel objet Python de type 'py_binary'.             *
+*  Description : Crée un nouvel objet Python de type 'LoadedBinary'.          *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Instance Python mise en place.                               *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_binary_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static PyObject *py_loaded_binary_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
-    py_binary *result;                      /* Instance à retourner        */
+    PyObject *result;                       /* Instance à retourner        */
+    char *filename;                         /* Nom du fichier à charger    */
+    int ret;                                /* Bilan de lecture des args.  */
+    GOpenidaBinary *binary;                 /* Version GLib du format      */
 
-    result = (py_binary *)type->tp_alloc(type, 0);
+    ret = PyArg_ParseTuple(args, "s", &filename);
+    if (!ret) return Py_None;
+
+    binary = g_openida_binary_new_from_file(filename);
+
+    result = py_loaded_binary_from_c(binary);
+    g_object_unref(binary);
 
     return (PyObject *)result;
 
@@ -90,38 +76,28 @@ static PyObject *py_binary_new(PyTypeObject *type, PyObject *args, PyObject *kwd
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : binary = objet GLib existant à transposer.                   *
+*  Paramètres  : binary = instance existante GLib.                            *
 *                                                                             *
-*  Description : Crée un nouvel objet Python de type 'py_binary'.             *
+*  Description : Crée un nouvel objet Python de type 'LoadedBinary'.          *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Instance Python mise en place.                               *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-PyObject *py_binary_new_from_existing(GOpenidaBinary *binary)
+PyObject *py_loaded_binary_from_c(GOpenidaBinary *binary)
 {
-    py_binary *result;                      /* Instance à retourner        */
-    PyTypeObject *type;                     /* Type Python à instancier    */
-
-    result = (py_binary *)g_object_get_data(G_OBJECT(binary), "python_object");
-
-    if (result == NULL)
-    {
-        type = get_analysis_binary_type();
+    PyObject *module;                       /* Module d'appartenance       */
+    PyTypeObject *type;                     /* Type Python correspondant   */
 
-        result = (py_binary *)type->tp_alloc(type, 0);
+    module = PyImport_ImportModule("pychrysalide.analysis");
+    type = (PyTypeObject*)PyObject_GetAttrString(module, "LoadedBinary");
+    Py_DECREF(module);
 
-        result->binary = binary;
-        g_object_ref(binary);
+    pychrysalide_set_instance_data(G_OBJECT(binary), type);
 
-        g_object_set_data(G_OBJECT(binary), "python_object", result);
-
-    }
-    else Py_INCREF((PyObject *)result);
-
-    return (PyObject *)result;
+    return pygobject_new(G_OBJECT(binary));
 
 }
 
@@ -129,52 +105,32 @@ PyObject *py_binary_new_from_existing(GOpenidaBinary *binary)
 
 
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : self = instance manipulée à traiter.                         *
-*                                                                             *
-*  Description : Fournit le format de fichier reconnu dans le contenu binaire.*
-*                                                                             *
-*  Retour      : Nouvelle instance d'objet Python ou NULL en cas d'échec.     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_binary_get_format(py_binary *self)
-{
-    PyObject *result;                       /* Liste à retourner           */
-    GExeFormat *format;                     /* Format récupéré à convertir */
-
-    format = g_openida_binary_get_format(self->binary);
-
-    result = py_executable_convert(format);
-
-    return result;
-
-}
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = instance manipulée à traiter.                         *
+*  Paramètres  : self = classe représentant un débogueur.                     *
+*                args = arguments fournis à l'appel.                          *
 *                                                                             *
-*  Description : Fournit les lignes de rendu associé pour Python.             *
+*  Description : Fournit le fichier correspondant à l'élément binaire.        *
 *                                                                             *
-*  Retour      : Nouvelle instance d'objet Python ou NULL en cas d'échec.     *
+*  Retour      : Nom de fichier avec chemin absolu.                           *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_binary_get_lines(py_binary *self)
+static PyObject *py_loaded_binary_get_filename(PyObject *self, PyObject *args)
 {
-    PyObject *result;                       /* Liste à retourner           */
-    GRenderingLine *lines;                  /* Liste récupérée à convertir */
+    PyObject *result;                       /* Trouvailles à retourner     */
+    GOpenidaBinary *binary;                 /* Version native              */
+    const char *filename;                   /* Fichier associé au binaire  */
+
+    binary = G_OPENIDA_BINARY(pygobject_get(self));
 
-    lines = g_openida_binary_get_lines(self->binary);
+    filename = g_openida_binary_get_filename(binary);
 
-    result = py_line_new_from_existing(lines);
+    result = PyString_FromString(filename);
 
     return result;
 
@@ -183,96 +139,59 @@ static PyObject *py_binary_get_lines(py_binary *self)
 
 
 
-
-
-
-
-
-
-
-
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : -                                                            *
+*  Paramètres  : module = module dont la définition est à compléter.          *
 *                                                                             *
-*  Description : Fournit le type d'objet 'analysis.binary' pour Python.       *
+*  Description : Prend en charge l'objet 'pychrysalide.analysis.LoadedBinary'.*
 *                                                                             *
-*  Retour      : Adresse du type vivant à manipuler.                          *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyTypeObject *get_analysis_binary_type(void)
+bool register_python_loaded_binary(PyObject *module)
 {
-    static PyTypeObject *result = NULL;     /* Type pour objet à retourner */
+    PyObject *pygobj_mod;                   /* Module Python-GObject       */
+    int ret;                                /* Bilan d'un appel            */
 
-    static PyMethodDef py_binary_methods[] = {
+    static PyMethodDef py_loaded_binary_methods[] = {
         {
-            "get_format", (PyCFunction)py_binary_get_format,
+            "get_filename", (PyCFunction)py_loaded_binary_get_filename,
             METH_NOARGS,
-            "Give the file format recognized in the binary content."
+            "Provide the filename of the loaded binary."
         },
-        {
-            "get_lines", (PyCFunction)py_binary_get_lines,
-            METH_NOARGS,
-            "Provide the rendering lines used by the binary."
-        },
-        { NULL }
-    };
-
-    static PyGetSetDef py_binary_getset[] = {
         { NULL }
     };
 
-    static PyTypeObject py_binary_type = {
+    static PyTypeObject py_loaded_binary_type = {
 
         PyObject_HEAD_INIT(NULL)
 
-        .tp_name        = "pyoida.analysis.Binary",
-        .tp_basicsize   = sizeof(py_binary),
+        .tp_name        = "pychrysalide.analysis.LoadedBinary",
+        .tp_basicsize   = sizeof(PyGObject),
 
         .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 
-        .tp_doc         = "PyOIDA loaded binary to analyse",
+        .tp_doc         = "PyChrysalide loaded binary",
 
-        .tp_methods     = py_binary_methods,
-        .tp_getset      = py_binary_getset,
-        .tp_new         = (newfunc)py_binary_new
+        .tp_methods     = py_loaded_binary_methods,
+        .tp_new         = (newfunc)py_loaded_binary_new
 
     };
 
-    if (result == NULL) result = &py_binary_type;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : module = module dont la définition est à compléter.          *
-*                                                                             *
-*  Description : Ajoute l'objet 'analysis.binary' au module Python.           *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-bool add_analysis_binary_to_python_module(PyObject *module)
-{
-    PyTypeObject *py_binary_type;           /* Type défini pour Python     */
-    int ret;                                /* Bilan d'un appel            */
+    pygobj_mod = PyImport_ImportModule("gobject");
+    if (pygobj_mod == NULL) return false;
 
-    py_binary_type = get_analysis_binary_type();
+    py_loaded_binary_type.tp_base = (PyTypeObject *)PyObject_GetAttrString(pygobj_mod, "GObject");
+    Py_DECREF(pygobj_mod);
 
-    if (PyType_Ready(py_binary_type) < 0)
+    if (PyType_Ready(&py_loaded_binary_type) < 0)
         return false;
 
-    Py_INCREF(py_binary_type);
-    ret = PyModule_AddObject(module, "Binary", (PyObject *)py_binary_type);
+    Py_INCREF(&py_loaded_binary_type);
+    ret = PyModule_AddObject(module, "LoadedBinary", (PyObject *)&py_loaded_binary_type);
 
     return (ret == 0);
 
diff --git a/plugins/pychrysa/analysis/binary.h b/plugins/pychrysa/analysis/binary.h
index 1500a06..cc96a5b 100644
--- a/plugins/pychrysa/analysis/binary.h
+++ b/plugins/pychrysa/analysis/binary.h
@@ -33,11 +33,11 @@
 
 
 
-/* Crée un nouvel objet Python de type 'py_binary'. */
-PyObject *py_binary_new_from_existing(GOpenidaBinary *);
+/* Crée un nouvel objet Python de type 'LoadedBinary'. */
+PyObject *py_loaded_binary_from_c(GOpenidaBinary *);
 
-/* Ajoute l'objet 'analysis.binary' au module Python. */
-bool add_analysis_binary_to_python_module(PyObject *);
+/* Prend en charge l'objet 'pychrysalide.analysis.LoadedBinary'. */
+bool register_python_loaded_binary(PyObject *);
 
 
 
diff --git a/plugins/pychrysa/analysis/module.c b/plugins/pychrysa/analysis/module.c
index 8f07002..42b888e 100644
--- a/plugins/pychrysa/analysis/module.c
+++ b/plugins/pychrysa/analysis/module.c
@@ -2,7 +2,7 @@
 /* OpenIDA - Outil d'analyse de fichiers binaires
  * module.c - intégration du répertoire analysis en tant que module
  *
- * Copyright (C) 2010 Cyrille Bagard
+ * Copyright (C) 2010-2012 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -26,11 +26,6 @@
 
 
 #include "binary.h"
-#include "exporter.h"
-#include "line.h"
-#include "roptions.h"
-
-
 
 
 
@@ -56,20 +51,15 @@ bool add_analysis_module_to_python_module(PyObject *super)
         { NULL }
     };
 
-    module = Py_InitModule("pyoida.analysis", py_analysis_methods);
+    module = Py_InitModule("pychrysalide.analysis", py_analysis_methods);
     if (module == NULL) return false;
 
     Py_INCREF(module);
-    ret = PyModule_AddObject(super, "pyoida.analysis", module);
+    ret = PyModule_AddObject(super, "pychrysalide.analysis", module);
 
     result = (ret != 0);
 
-    result &= add_analysis_binary_to_python_module(module);
-    result &= add_analysis_exporter_to_python_module(module);
-    result &= add_analysis_line_to_python_module(module);
-    result &= add_analysis_line_iter_to_python_module(module);
-    result &= add_analysis_line_riter_to_python_module(module);
-    result &= add_analysis_roptions_to_python_module(module);
+    result &= register_python_loaded_binary(module);
 
     return result;
 
diff --git a/plugins/pychrysa/debug/debugger.c b/plugins/pychrysa/debug/debugger.c
index 3e42ab7..c27d30d 100644
--- a/plugins/pychrysa/debug/debugger.c
+++ b/plugins/pychrysa/debug/debugger.c
@@ -33,6 +33,9 @@
 
 
 
+/* Crée un nouvel objet Python de type 'BinaryDebugger'. */
+static PyObject *py_binary_debugger_new(PyTypeObject *, PyObject *, PyObject *);
+
 /*  Fournit les identifiants de tous les threads actifs. */
 static PyObject *py_binary_debugger_list_all_threads(PyObject *, PyObject *);
 
@@ -48,9 +51,9 @@ static PyObject *py_binary_debugger_get_frames_stack(PyObject *, PyObject *);
 *                args = arguments fournis à l'appel.                          *
 *                kwds = arguments de type key=val fournis.                    *
 *                                                                             *
-*  Description : Crée un nouvel objet Python de type 'py_rendering_options'.  *
+*  Description : Crée un nouvel objet Python de type 'BinaryDebugger'.        *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Instance Python mise en place.                               *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -82,7 +85,7 @@ static PyObject *py_binary_debugger_new(PyTypeObject *type, PyObject *args, PyOb
 *                                                                             *
 *  Description : Crée un nouvel objet Python de type 'BinaryDebugger'.        *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Instance Python mise en place.                               *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -93,7 +96,7 @@ PyObject *py_binary_debugger_from_c(GBinaryDebugger *debugger)
     PyObject *module;                       /* Module d'appartenance       */
     PyTypeObject *type;                     /* Type Python correspondant   */
 
-    module = PyImport_ImportModule("pyoida.debug");
+    module = PyImport_ImportModule("pychrysalide.debug");
     type = (PyTypeObject*)PyObject_GetAttrString(module, "BinaryDebugger");
     Py_DECREF(module);
 
diff --git a/plugins/pychrysa/plugin.c b/plugins/pychrysa/plugin.c
index b04dd09..9dc0c29 100644
--- a/plugins/pychrysa/plugin.c
+++ b/plugins/pychrysa/plugin.c
@@ -72,7 +72,7 @@ static PluginAction g_python_plugin_get_action(const GPythonPlugin *);
 static MatchingFormatAction g_python_plugin_is_matching(const GPythonPlugin *, char **, bin_t **, off_t *);
 
 /* Exécute une action définie sur un binaire chargé. */
-static bool g_python_plugin_execute(GPythonPlugin *, GOpenidaBinary *, PluginAction);
+static bool g_python_plugin_execute_on_binary(GPythonPlugin *, GOpenidaBinary *, PluginAction);
 
 
 /* Exécute une action relative à un débogueur. */
@@ -247,7 +247,7 @@ static void g_python_plugin_init(GPythonPlugin *plugin)
 
     plugin_parent = G_PLUGIN_MODULE(plugin);
 
-    plugin_parent->exec_on_bin = (execute_action_on_binary_fc)g_python_plugin_execute;
+    plugin_parent->exec_on_bin = (execute_action_on_binary_fc)g_python_plugin_execute_on_binary;
     plugin_parent->handle_debugger = (execute_on_debugger_fc)g_python_plugin_handle_debugger;
 
 }
@@ -331,6 +331,9 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename)
 
     result = g_object_new(G_TYPE_PYTHON_PLUGIN, NULL);
 
+    G_PLUGIN_MODULE(result)->name = strdup(modname);
+    G_PLUGIN_MODULE(result)->name = stradd(G_PLUGIN_MODULE(result)->name, ".py");
+
     G_PLUGIN_MODULE(result)->get_action = g_python_plugin_get_action;
 
     G_PLUGIN_MODULE(result)->is_matching = g_python_plugin_is_matching;
@@ -494,38 +497,25 @@ static MatchingFormatAction g_python_plugin_is_matching(const GPythonPlugin *plu
 *                                                                             *
 ******************************************************************************/
 
-static bool g_python_plugin_execute(GPythonPlugin *plugin, GOpenidaBinary *binary, PluginAction action)
+static bool g_python_plugin_execute_on_binary(GPythonPlugin *plugin, GOpenidaBinary *binary, PluginAction action)
 {
+    bool result;                            /* Bilan à remonter            */
     PyObject *args;                         /* Arguments pour l'appel      */
-    PyObject *arg;                          /* Un des arguments de l'appel */
-    PyObject *value;                        /* Valeur obtenue              */
-
-
-
-    printf("I am running !!");
-
-    args = PyTuple_New(1);
-
+    PyObject *value;                        /* Valeurs obtenues            */
 
-    arg = Py_BuildValue("O&", py_binary_new_from_existing, binary);
-    PyTuple_SetItem(args, 0, arg);
+    args = PyTuple_New(2);
 
+    PyTuple_SetItem(args, 0, py_loaded_binary_from_c(binary));
+    PyTuple_SetItem(args, 1, PyInt_FromLong(action));
 
-    value = run_python_method(plugin->module, "get_instance", args);
-
-    if (value != NULL)
-    {
-        printf("Result of call: %ld\n", PyLong_AsLong(value));
-        Py_DECREF(value);
-    }
+    value = run_python_method(plugin->instance, "execute_on_binary", args);
 
+    result = (value == Py_True);
 
+    Py_XDECREF(value);
     Py_DECREF(args);
 
-
-
-
-
+    return result;
 
 }
 
@@ -638,6 +628,9 @@ static bool pychrysa_plugin_define_constants(PyObject *dict)
     ret = PyDict_SetItemString(dict, "PGA_DISASSEMBLE", PyInt_FromLong(PGA_DISASSEMBLE));
     if (ret == -1) return false;
 
+    ret = PyDict_SetItemString(dict, "PGA_DISASS_PROCESS", PyInt_FromLong(PGA_DISASS_PROCESS));
+    if (ret == -1) return false;
+
     ret = PyDict_SetItemString(dict, "PGA_CODE_PROCESS", PyInt_FromLong(PGA_CODE_PROCESS));
     if (ret == -1) return false;
 
diff --git a/plugins/pychrysa/pychrysa.c b/plugins/pychrysa/pychrysa.c
index 84400a1..7bb1e00 100644
--- a/plugins/pychrysa/pychrysa.c
+++ b/plugins/pychrysa/pychrysa.c
@@ -26,6 +26,7 @@
 
 #include <dirent.h>
 #include <pygobject.h>
+#include <string.h>
 
 
 #include <config.h>
@@ -62,7 +63,27 @@ static PyMethodDef SpamMethods[] = {
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : ref = espace de référencement global.                        *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Précise le nom associé au greffon.                           *
+*                                                                             *
+*  Retour      : Nom à libérer de la mémoire.                                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *get_plugin_name(void)
+{
+    return strdup("PyChrysalide");
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = instance représentant le greffon en chargement.     *
+*                ref    = espace de référencement global.                     *
 *                                                                             *
 *  Description : Initialise le greffon permettant l'usage de Python.          *
 *                                                                             *
@@ -72,7 +93,7 @@ static PyMethodDef SpamMethods[] = {
 *                                                                             *
 ******************************************************************************/
 
-bool init_plugin(GObject *ref)
+bool init_plugin(GPluginModule *plugin, GObject *ref)
 {
     char *paths;                            /* Emplacements de greffons    */
     char *path;                             /* Chemin à fouiller           */
@@ -86,7 +107,7 @@ bool init_plugin(GObject *ref)
 
 
 
-    GPluginModule *plugin;
+    GPluginModule *pyplugin;
 
 
 
@@ -133,14 +154,18 @@ bool init_plugin(GObject *ref)
             filename = stradd(filename, ".");
             filename = stradd(filename, "__init__");
 
-            plugin = g_python_plugin_new(entry.d_name, filename);
+            pyplugin = g_python_plugin_new(entry.d_name, filename);
 
-            if (plugin == NULL)
-                 printf("No suitable Python plugin found in '%s'\n", filename);  /* FIXME : LOG(...) */
+            if (pyplugin == NULL)
+                g_plugin_module_log_variadic_message(plugin, LMT_ERROR, 
+                                                     _("No suitable Python plugin found in '%s'"),
+                                                     filename);
             else
             {
-                printf("ok pour %s\n", filename);
-                add_plugin_to_main_list(plugin);
+                g_plugin_module_log_variadic_message(plugin, LMT_PROCESS, 
+                                                     _("Loaded Python plugin '<b>%s</b>' from the '<b>%s</b>' directory"),
+                                                     g_plugin_module_get_name(G_PLUGIN_MODULE(pyplugin)), path);
+                add_plugin_to_main_list(pyplugin);
             }
 
             free(filename);
@@ -202,8 +227,8 @@ PyMODINIT_FUNC PyInit_pychrysa(void)
 {
     static struct PyModuleDef spammodule = {
         PyModuleDef_HEAD_INIT,
-        "pychrysa",
-        "pychrysa_doc",
+        "pychrysalide",
+        "pychrysalide_doc",
         -1,
         SpamMethods
     };
@@ -233,7 +258,7 @@ PyMODINIT_FUNC initpychrysa(void)
     pygobject_init(-1, -1, -1);
     pychrysalide_init_quirks();
 
-    module = Py_InitModule("pychrysa", SpamMethods);
+    module = Py_InitModule("pychrysalide", SpamMethods);
 
     //add_analysis_roptions_to_python_module(module);
     add_analysis_module_to_python_module(module);
diff --git a/plugins/pychrysa/pychrysa.h b/plugins/pychrysa/pychrysa.h
index e4605e5..daa0ccf 100644
--- a/plugins/pychrysa/pychrysa.h
+++ b/plugins/pychrysa/pychrysa.h
@@ -34,8 +34,11 @@
 
 
 
+/* Précise le nom associé au greffon. */
+char *get_plugin_name(void);
+
 /* Initialise le greffon permettant l'usage de Python. */
-bool init_plugin(GObject *);
+bool init_plugin(GPluginModule *, GObject *);
 
 /* Indique les opérations offertes par un greffon donné. */
 PluginAction get_plugin_action(const GPluginModule *);
diff --git a/plugins/python/Makefile.am b/plugins/python/Makefile.am
index efbb704..3583a21 100644
--- a/plugins/python/Makefile.am
+++ b/plugins/python/Makefile.am
@@ -1,2 +1,2 @@
 
-SUBDIRS = apkfiles
+SUBDIRS = androperms apkfiles
diff --git a/plugins/python/androperms/Makefile.am b/plugins/python/androperms/Makefile.am
new file mode 100644
index 0000000..3d1755c
--- /dev/null
+++ b/plugins/python/androperms/Makefile.am
@@ -0,0 +1,12 @@
+
+andropermsdir = $(datadir)/openida/plugins/python/androperms
+
+androperms_DATA = 							\
+	__init__.py								\
+	androperms.py							\
+	defs.py									\
+	manifest.py								\
+	parser.py								\
+	reader.py								\
+	stack.py								\
+	string.py
diff --git a/plugins/python/androperms/__init__.py b/plugins/python/androperms/__init__.py
new file mode 100644
index 0000000..8a5a159
--- /dev/null
+++ b/plugins/python/androperms/__init__.py
@@ -0,0 +1,2 @@
+
+from androperms import AndroPerms as androperms
diff --git a/plugins/python/androperms/androperms.py b/plugins/python/androperms/androperms.py
new file mode 100644
index 0000000..f85d402
--- /dev/null
+++ b/plugins/python/androperms/androperms.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from pychrysalide import Plugin
+from manifest import AndroidManifest
+from xml.dom import minidom
+
+import zipfile
+
+
+class AndroPerms(Plugin):
+    """List all permissions given to an APK files."""
+
+
+    def get_action(self):
+        """Register the plugin for given actions."""
+
+        return Plugin.PGA_DISASS_PROCESS
+
+
+    def execute_on_binary(self, binary, action):
+        """Process once a binary is disassembled."""
+
+        zf = zipfile.ZipFile(binary.get_filename())
+
+        f = zf.open('AndroidManifest.xml', 'r')
+        data = f.read()
+        f.closed
+
+        manifest = AndroidManifest(data)
+        xml = minidom.parseString(manifest.getXML())
+
+        print
+        print "Permissions for ", binary.get_filename(), " :"
+        print "-------------"
+        print
+
+        for p in xml.getElementsByTagName("uses-permission"):
+            print p.getAttribute("android:name")
+
+        print
diff --git a/plugins/python/androperms/defs.py b/plugins/python/androperms/defs.py
new file mode 100644
index 0000000..e23511e
--- /dev/null
+++ b/plugins/python/androperms/defs.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python -u
+# -*- coding: utf-8 -*-
+
+
+ATTRIBUTE_IX_NAMESPACE_URI = 0
+ATTRIBUTE_IX_NAME          = 1
+ATTRIBUTE_IX_VALUE_STRING  = 2
+ATTRIBUTE_IX_VALUE_TYPE    = 3
+ATTRIBUTE_IX_VALUE_DATA    = 4
+ATTRIBUTE_LENGHT           = 5
+
+TYPE_NULL               = 0
+TYPE_REFERENCE          = 1
+TYPE_ATTRIBUTE          = 2
+TYPE_STRING             = 3
+TYPE_FLOAT              = 4
+TYPE_DIMENSION          = 5
+TYPE_FRACTION           = 6
+TYPE_FIRST_INT          = 16
+TYPE_INT_DEC            = 16
+TYPE_INT_HEX            = 17
+TYPE_INT_BOOLEAN        = 18
+TYPE_FIRST_COLOR_INT    = 28
+TYPE_INT_COLOR_ARGB8    = 28
+TYPE_INT_COLOR_RGB8     = 29
+TYPE_INT_COLOR_ARGB4    = 30
+TYPE_INT_COLOR_RGB4     = 31
+TYPE_LAST_COLOR_INT     = 31
+TYPE_LAST_INT           = 31
+
+RADIX_MULTS       = [ 0.00390625, 3.051758E-005, 1.192093E-007, 4.656613E-010 ]
+DIMENSION_UNITS   = [ "px", "dip", "sp", "pt", "in", "mm", "", "" ]
+FRACTION_UNITS    = [ "%", "%p", "", "", "", "", "", "" ]
+COMPLEX_UNIT_MASK = 15
+
+
+CHUNK_AXML_FILE           = 0x00080003
+CHUNK_RESOURCEIDS         = 0x00080180
+CHUNK_XML_FIRST           = 0x00100100
+CHUNK_XML_START_NAMESPACE = 0x00100100
+CHUNK_XML_END_NAMESPACE   = 0x00100101
+CHUNK_XML_START_TAG       = 0x00100102
+CHUNK_XML_END_TAG         = 0x00100103
+CHUNK_XML_TEXT            = 0x00100104
+CHUNK_XML_LAST            = 0x00100104
+CHUNK_TYPE                = 0x001C0001
+
+
+START_DOCUMENT = 0
+END_DOCUMENT   = 1
+START_TAG      = 2
+END_TAG        = 3
+TEXT           = 4
diff --git a/plugins/python/androperms/manifest.py b/plugins/python/androperms/manifest.py
new file mode 100644
index 0000000..63536b2
--- /dev/null
+++ b/plugins/python/androperms/manifest.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from defs import *
+from reader import AXMLReader
+from parser import AXMLParser
+
+
+class AndroidManifest():
+
+
+    def __init__(self, data):
+
+        self._buffer = ""
+
+        reader = AXMLReader(data)
+        parser = AXMLParser(reader)
+
+        has_ns = False
+        empty = False
+
+        while 1 :
+
+            tag = parser.next()
+
+            if tag == START_DOCUMENT :
+                self._buffer += '<?xml version="1.0" encoding="utf-8"?>\n'
+
+            elif tag == START_TAG:
+
+                if empty:
+                    self._buffer += '>\n'
+
+                self._buffer += '   ' * (parser._namespaces.getDepth() - 2)
+                self._buffer += "<%s%s" % (parser.getTagPrefix(), parser.getTagName())
+
+                if not has_ns:
+                    self._buffer += ' xmlns:%s="%s"' % (parser.getNamespacePrefix(0), parser.getNamespaceUri(0))
+                    has_ns = True
+
+                for i in range(0, parser.countAttributes()):
+                    self._buffer += ' %s%s="%s"' % (parser.getAttribPrefix(i), parser.getAttribName(i), parser.getAttribValue(i))
+
+                empty = True
+
+            elif tag == END_TAG:
+
+                if empty:
+                    self._buffer += '/>\n'
+                    empty = False
+
+                else:
+                    self._buffer += '   ' * (parser._namespaces.getDepth() - 2)
+                    self._buffer += "</%s%s>\n" % (parser.getTagPrefix(), parser.getTagName())
+
+            elif tag == TEXT:
+
+                if empty:
+                    self._buffer += '>\n'
+                    empty = False
+
+                self._buffer += '   ' * (parser._namespaces.getDepth() - 1)
+                self._buffer += "%s\n" % parser.getText()
+
+            elif tag == END_DOCUMENT :
+                break
+
+            else:
+                break
+
+
+    def getXML(self):
+        """Provide the XML content."""
+
+        return self._buffer
diff --git a/plugins/python/androperms/parser.py b/plugins/python/androperms/parser.py
new file mode 100644
index 0000000..1939bbe
--- /dev/null
+++ b/plugins/python/androperms/parser.py
@@ -0,0 +1,328 @@
+#!/usr/bin/python -u
+# -*- coding: utf-8 -*-
+
+
+from defs import *
+from stack import NamespaceStack
+from string import StringBlock
+
+from struct import unpack
+
+
+class AXMLParser():
+
+
+    def __init__(self, reader):
+
+        self._reader = reader
+
+        magic = reader.readInt()
+        if magic != CHUNK_AXML_FILE:
+            raise Exception('Bad Magic Number (0x%08lx)!' % magic)
+
+        # chunkSize
+        reader.skipInt()
+
+        self._strings = StringBlock(reader)
+        self._namespaces = NamespaceStack()
+        self._operational = True
+
+        self.resetEventInfo()
+
+
+    def resetEventInfo(self):
+
+        self._event = -1
+        self._line_number = -1
+        self._name = -1
+        self._namespace_uri = -1
+        self._attributes = None
+        self._id_attrib = -1
+        self._class_attrib = -1
+        self._style_attrib = -1
+
+        self._decreaseDepth = False
+
+
+
+    def next(self):
+
+        self.doNext()
+        return self._event
+
+
+    def doNext(self):
+
+
+
+
+
+        event = self._event
+
+
+        while True:
+
+            if self._decreaseDepth:
+                self._decreaseDepth = False
+                self._namespaces.decDepth()
+
+            # Fake END_DOCUMENT event.
+            if event == END_TAG and self._namespaces.getDepth() == 1 and self._namespaces.count() == 0:
+                self._event = END_DOCUMENT
+                break
+
+            if event == START_DOCUMENT:
+                # Fake event, see CHUNK_XML_START_TAG handler.
+                chunk = CHUNK_XML_START_TAG
+
+            else:
+                chunk = self._reader.readInt()
+
+            if chunk == CHUNK_RESOURCEIDS:
+
+                size = self._reader.readInt()
+                if size < 8 or size % 4 != 0:
+                    raise Exception('Invalid resource ids size (%d).' % size)
+
+                self._resource_ids = self._reader.readIntArray(size / 4 - 2)
+
+                continue
+
+            if chunk < CHUNK_XML_FIRST or chunk > CHUNK_XML_LAST:
+                raise Exception('Invalid chunk type 0x%08lx.' % chunk)
+
+            # Fake START_DOCUMENT event.
+            if chunk == CHUNK_XML_START_TAG and event == -1:
+                self._event = START_DOCUMENT
+                break
+
+            # Common header.
+            self._reader.skipInt() # chunkSize
+            self._line_number = self._reader.readInt()
+            self._reader.skipInt() # 0xffffffff
+
+            if chunk == CHUNK_XML_START_NAMESPACE or chunk == CHUNK_XML_END_NAMESPACE:
+
+                if chunk == CHUNK_XML_START_NAMESPACE:
+
+                    prefix = self._reader.readInt()
+                    uri = self._reader.readInt()
+                    self._namespaces.push(prefix, uri)
+
+                else:
+
+                    self._reader.skipInt() # prefix
+                    self._reader.skipInt() # uri
+                    self._namespaces.pop()
+
+                continue
+
+            elif chunk == CHUNK_XML_START_TAG:
+
+                self._namespace_uri = self._reader.readInt()
+                self._name = self._reader.readInt()
+                self._reader.skipInt() # flags ?
+
+                attribs_count = self._reader.readInt()
+                self._id_attrib = (attribs_count >> 16) - 1
+                attribs_count &= 0xffff
+
+                self._class_attrib = self._reader.readInt()
+                self._style_attrib = (self._class_attrib >> 16) - 1
+                self._class_attrib = (self._class_attrib & 0xffff) - 1
+
+                self._attributes = self._reader.readIntArray(attribs_count * ATTRIBUTE_LENGHT)
+
+                for i in range(ATTRIBUTE_IX_VALUE_TYPE, len(self._attributes), ATTRIBUTE_LENGHT):
+                    self._attributes[i] >>= 24
+
+                self._namespaces.incDepth()
+                self._event = START_TAG
+
+                break
+
+            elif chunk == CHUNK_XML_END_TAG:
+
+                self._namespaceUri = self._reader.readInt()
+                self._name = self._reader.readInt()
+
+                self._event = END_TAG
+                self._decreaseDepth = True
+
+                break
+
+            elif chunk == CHUNK_XML_TEXT:
+
+                self._name = self._reader.readInt()
+                self._reader.skipInt() # ???
+                self._reader.skipInt() # ???
+
+                self._event=TEXT
+
+                break				
+
+            else:
+                raise Exception('Unknown chunck (0x%08lx)' % chunk)
+
+
+    ### ESPACES ###
+
+    def getNamespacePrefix(self, index):
+
+        name = self._namespaces.getPrefix(index)
+
+        if name == -1:
+            return ''
+
+        else:
+            return self._strings.getRaw(name)
+
+
+    def getNamespaceUri(self, index):
+
+        name = self._namespaces.getUri(index)
+
+        if name == -1:
+            return ''
+
+        else:
+            return self._strings.getRaw(name)
+
+
+    ### NAMES ###
+
+    def getTagPrefix(self):
+        """Provide the prefix linked to START_TAG or END_TAG."""
+
+        name = self._namespaces.findPrefix(self._namespace_uri)
+
+        if name == -1:
+            return ''
+
+        else:
+            return self._strings.getRaw(name) + ':'
+
+
+    def getTagName(self):
+        """Provide the name linked to START_TAG or END_TAG."""
+
+        if self._name == -1 or (self._event != START_TAG and self._event != END_TAG):
+            raise Exception('Invalid tag name.')
+
+        return self._strings.getRaw(self._name)
+
+
+    def getText(self):
+        """Provide the content linked to TEXT."""
+
+        if self._name == -1 or self._event != START_TEXT:
+            raise Exception('Invalid text content.')
+
+        return self._strings.getRaw(self._name)
+
+
+    ### ATRIBUTES ###
+
+    def countAttributes(self):
+        """Count the properties of the current tag."""
+
+        if self._event != START_TAG:
+            raise Exception('Invalid event.')
+
+        return len(self._attributes) / ATTRIBUTE_LENGHT
+
+
+    def getAttribPrefix(self, index):
+        """Get the prefix of a given attribute."""
+
+        index *= ATTRIBUTE_LENGHT
+
+        if index >= len(self._attributes):
+            raise Exception('Bad attribute index.')
+
+        uri = self._attributes[index + ATTRIBUTE_IX_NAMESPACE_URI]
+        name = self._namespaces.findPrefix(uri)
+
+        if name == -1:
+            return ''
+
+        else:
+            return self._strings.getRaw(name) + ':'
+
+
+    def getAttribName(self, index):
+        """Get the name of a given attribute."""
+
+        index *= ATTRIBUTE_LENGHT
+
+        if index >= len(self._attributes):
+            raise Exception('Bad attribute index.')
+
+        name = self._attributes[index + ATTRIBUTE_IX_NAME]
+
+        if name == -1:
+            return '???'
+
+        else:
+            return self._strings.getRaw(name)
+
+
+    def getAttribValue(self, index):
+        """Get the value of a given attribute."""
+
+        index *= ATTRIBUTE_LENGHT
+
+        if index >= len(self._attributes):
+            raise Exception('Bad attribute index.')
+
+        vtype = self._attributes[index + ATTRIBUTE_IX_VALUE_TYPE]
+        vdata = self._attributes[index + ATTRIBUTE_IX_VALUE_DATA]
+
+        if vtype == TYPE_NULL:
+            return '???'
+
+        elif vtype == TYPE_REFERENCE:
+            return '@%s%08X' % (self.getPackage(vdata), vdata)
+
+        elif vtype == TYPE_ATTRIBUTE:
+            return '?%s%08X' % (self.getPackage(vdata), vdata)
+
+        if vtype == TYPE_STRING:
+            vdata = self._attributes[index + ATTRIBUTE_IX_VALUE_STRING]
+            return self._strings.getRaw(vdata)
+
+        elif vtype == TYPE_FLOAT:
+            return '%f' % unpack('=f', pack('=L', vdata))[0] 
+
+        elif vtype == TYPE_DIMENSION:
+            return '%f%s' % (self.complexToFloat(vdata), DIMENSION_UNITS[vdata & COMPLEX_UNIT_MASK])
+
+        elif vtype == TYPE_FRACTION:
+            return '%f%s' % (self.complexToFloat(vdata), FRACTION_UNITS[vdata & COMPLEX_UNIT_MASK])
+
+        elif vtype == TYPE_INT_HEX:
+            return '0x%08x' % vdata
+
+        elif vtype == TYPE_INT_BOOLEAN:
+            if vdata == 0:
+                return 'false'
+            else:
+                return 'true'
+
+        elif vtype >= TYPE_FIRST_COLOR_INT and vtype <= TYPE_LAST_COLOR_INT:
+            return '#%08x' % vdata
+
+        elif vtype >= TYPE_FIRST_INT and vtype <= TYPE_LAST_INT:
+            return str(vdata)
+
+        return "<0x%x, 0x%02x>" % (vdata, vtype)
+
+
+    def complexToFloat(self, xcomplex):
+        return (float)(xcomplex & 0xffffff00) * RADIX_MULTS[(xcomplex >> 4) & 3];
+
+    def getPackage(self, id):
+        if id >> 24 == 1:
+            return "android:"
+        else:
+            return ""
diff --git a/plugins/python/androperms/reader.py b/plugins/python/androperms/reader.py
new file mode 100644
index 0000000..f126850
--- /dev/null
+++ b/plugins/python/androperms/reader.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python -u
+# -*- coding: utf-8 -*-
+
+
+from struct import unpack
+
+
+class AXMLReader():
+    """Provide various read helpers."""
+
+    def __init__(self, data):
+
+        self._data = data
+
+        self._position = 0
+        self._length = len(self._data)
+
+
+    def readInt(self):
+        """Read a 4-bytes value."""
+
+        self.skipInt()
+
+        value = unpack('<L', self._data[self._position - 4 : self._position])[0]
+
+        return value
+
+
+    def skipInt(self):
+        """Skip a 4-bytes value."""
+
+        self._position += 4
+
+        if self._position > self._length:
+            raise Exception("Reader out of bound (%d > %d)!" % (self._position, self._length))
+
+
+    def readIntArray(self, length):
+        """Read an array composed of 4-bytes values."""
+
+        return [ self.readInt() for i in range(0, length) ]
diff --git a/plugins/python/androperms/stack.py b/plugins/python/androperms/stack.py
new file mode 100644
index 0000000..38431dc
--- /dev/null
+++ b/plugins/python/androperms/stack.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python -u
+# -*- coding: utf-8 -*-
+
+
+class NamespaceStack():
+
+
+    def __init__(self):
+
+        #        self.increaseDepth()
+
+
+        self._depth = 1
+
+        self._prefix_2_uri = {}
+        self._uri_2_prefix = {}
+
+        self._pairs = []
+
+        pass
+
+
+
+    def getDepth(self):
+
+        return self._depth
+
+
+    def incDepth(self):
+
+        self._depth += 1
+
+
+    def decDepth(self):
+
+        self._depth -= 1
+
+
+
+
+
+    def count(self):
+        """Provider the current number of active namespaces."""
+
+        return len(self._pairs)
+
+
+
+
+
+
+
+    def push(self, prefix, uri):
+
+        self._prefix_2_uri[prefix] = uri
+        self._uri_2_prefix[uri] = prefix
+
+        self._pairs.append((prefix, uri))
+
+        #print "PUSH", prefix, uri
+
+
+
+
+    def pop(self):
+
+        self._pairs.pop()
+
+        #print "POP"
+
+
+
+
+
+    def getPrefix(self, index):
+
+        if index < len(self._pairs):
+            return self._pairs[index][0]
+
+        else:
+            return -1
+
+
+    def findPrefix(self, uri):
+
+        if uri in self._uri_2_prefix:
+            return self._uri_2_prefix[uri]
+
+        else:
+            return -1
+
+
+    def getUri(self, index):
+
+        if index < len(self._pairs):
+            return self._pairs[index][1]
+
+        else:
+            return -1
+
+
+    def findUri(self, prefix):
+
+        if prefix in self._prefix_2_uri:
+            return self._prefix_2_uri[prefix]
+
+        else:
+            return -1
diff --git a/plugins/python/androperms/string.py b/plugins/python/androperms/string.py
new file mode 100644
index 0000000..09a7b93
--- /dev/null
+++ b/plugins/python/androperms/string.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python -u
+# -*- coding: utf-8 -*-
+
+
+from defs import CHUNK_TYPE
+
+
+class StringBlock():
+
+
+    def __init__(self, reader):
+
+        magic = reader.readInt()
+        if magic != CHUNK_TYPE:
+            raise Exception("Bad Magic Number (0x%08lx)!" % magic)
+
+	chunk_size = reader.readInt()
+        str_count = reader.readInt()
+        style_offset_count = reader.readInt()
+        reader.readInt() # ???
+        str_offset = reader.readInt()
+        styles_offset = reader.readInt()
+
+        self._str_offsets = reader.readIntArray(str_count);
+        self._style_offsets = reader.readIntArray(style_offset_count);
+
+        if styles_offset == 0:
+            size = chunk_size - str_offset
+        else:
+            size = styles_offset - str_offset
+
+        if size % 4 != 0:
+            raise Exception("String data size is not multiple of 4 (%d)!" % size)
+
+        self._strings = reader.readIntArray(size / 4)
+
+        if styles_offset > 0:
+
+            size = chunk_size - styles_offset
+
+            if size % 4 != 0:
+                raise Exception("Style data size is not multiple of 4 (%d)!" % size)
+
+            self._styles = reader.readIntArray(size / 4)
+
+        self._str_data = [ self.getRaw(i) for i in range(self.count()) ]
+
+
+    def count(self):
+        """Count the number of strings in the current block."""
+
+        return len(self._str_offsets)
+
+
+    def getRaw(self, index):
+        """Provide a raw string (without any styling information) at specified index."""
+
+        if index < 0 or index >= len(self._str_offsets):
+            raise Exception("Invalid Index (%d)!" % index)
+
+        offset = self._str_offsets[index]
+        length = self.getShort(self._strings, offset)
+
+        data = ''
+
+        for i in range(length):
+            offset += 2
+            data += unichr(self.getShort(self._strings, offset))
+
+        return data
+
+
+    def getShort(self, array, offset):
+
+        value = array[offset / 4]
+
+        if ((offset % 4) / 2) == 0:
+            value &= 0xFFFF
+        else:
+            value >>= 16
+
+        return value
diff --git a/plugins/python/apkfiles/apkfiles.py b/plugins/python/apkfiles/apkfiles.py
index 38d0e59..7c05ca9 100644
--- a/plugins/python/apkfiles/apkfiles.py
+++ b/plugins/python/apkfiles/apkfiles.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-from pychrysa import Plugin
+from pychrysalide import Plugin
 
 import zipfile
 
@@ -9,11 +9,13 @@ import zipfile
 class ApkFiles(Plugin):
     """Open and process APK files."""
 
+
     def get_action(self):
         """Register the plugin for given actions."""
 
         return Plugin.PGA_FORMAT_MATCHER
 
+
     def is_matching(self, filename, data):
         """Define if the given file can be handled."""
 
@@ -22,7 +24,8 @@ class ApkFiles(Plugin):
 
         zf = zipfile.ZipFile(filename)
 
-        if zf.namelist().count('classes.dex') > 0:
+        if zf.namelist().count('classes.dex') > 0 \
+                and zf.namelist().count('AndroidManifest.xml') > 0:
 
             f = zf.open('classes.dex', 'r')
             data = f.read()
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 2b84b57..21b4b14 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -48,7 +48,7 @@
 #include "../debug/break.h"
 #include "../format/format.h"
 #include "../gui/panels/log.h"
-#include "../plugins/pglist.h"
+#include "../plugins/pglist.h"  /* TODO : supprimer ? */
 
 
 #include "../format/dbg_format.h"
@@ -1001,8 +1001,7 @@ bin_t *map_binary_file(const char *filename, off_t *length)
 void ack_completed_disassembly(void/*GDelayedDisassembly*/ *disass, GOpenidaBinary *binary)
 {
     GRenderingLine *line;                   /* "Première" ligne de rendu   */
-    GPluginModule **pglist;                 /* Liste de greffons           */
-    size_t pgcount;                         /* Taille de cette liste       */
+
     size_t i;                               /* Boucle de parcours          */
 
     const char * const *files;              /* Liste de fichiers source    */
@@ -1034,19 +1033,6 @@ void ack_completed_disassembly(void/*GDelayedDisassembly*/ *disass, GOpenidaBina
                                             g_exe_format_get_entry_point(binary->format));
     if (line != NULL) g_rendering_line_add_flag(line, RLF_ENTRY_POINT);
 
-    /* Action post-désassemblage */
-
-    pglist = get_all_plugins_for_action(PGA_CODE_PROCESS, &pgcount);
-
-    if (pgcount > 0)
-    {
-        for (i = 0; i < pgcount; i++)
-            g_plugin_module_execute_action_on_binary(pglist[i], binary, PGA_CODE_PROCESS);
-
-        free(pglist);
-
-    }
-
     /* On réintègre le flot premier */
 #endif
 
diff --git a/src/analysis/decomp/decompiler.c b/src/analysis/decomp/decompiler.c
index 24cd242..42dc1ff 100644
--- a/src/analysis/decomp/decompiler.c
+++ b/src/analysis/decomp/decompiler.c
@@ -152,8 +152,6 @@ static void prepare_all_routines_for_decomp(const GOpenidaBinary *binary, const
     {
         context = g_arch_processor_get_decomp_context(proc);
 
-        printf(" -- %s --\n", g_binary_routine_get_name(routines[i]));
-
         instr = g_binary_format_decompile_routine(G_BIN_FORMAT(format), routines[i], context);
 
         if (context != NULL)
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c
index dc374db..75e411f 100644
--- a/src/analysis/disass/disassembler.c
+++ b/src/analysis/disass/disassembler.c
@@ -40,6 +40,7 @@
 #include "../../format/format.h"
 #include "../../glibext/delayed-int.h"
 #include "../../gui/panels/log.h"
+#include "../../plugins/pglist.h"
 
 
 
@@ -379,13 +380,18 @@ static void build_disass_prologue(GCodeBuffer *buffer, const char *filename, con
 *                                                                             *
 ******************************************************************************/
 
-GCodeBuffer *disassemble_binary(const GOpenidaBinary *binary, GBinPart **parts, size_t parts_count, GArchInstruction **instrs)
+GCodeBuffer *disassemble_binary(GOpenidaBinary *binary, GBinPart **parts, size_t parts_count, GArchInstruction **instrs)
 {
     GCodeBuffer *result;                    /* Tampon constitué à renvoyer */
     const uint8_t *data;                    /* Données binaires brutes     */
     off_t length;                           /* Quantité de ces données     */
     GDelayedDisassembly *disass;            /* Désassemblage à mener       */
     GWorkQueue *queue;                      /* Gestionnaire de différés    */
+    GPluginModule **pglist;                 /* Liste de greffons           */
+    size_t pgcount;                         /* Taille de cette liste       */
+    size_t i;                               /* Boucle de parcours          */
+
+    /* Déroulement de l'opération principale */
 
     result = g_code_buffer_new();
 
@@ -403,6 +409,19 @@ GCodeBuffer *disassemble_binary(const GOpenidaBinary *binary, GBinPart **parts,
 
     g_object_unref(G_OBJECT(disass));
 
+    /* Actions post-désassemblage */
+
+    pglist = get_all_plugins_for_action(PGA_DISASS_PROCESS, &pgcount);
+
+    if (pgcount > 0)
+    {
+        for (i = 0; i < pgcount; i++)
+            g_plugin_module_execute_action_on_binary(pglist[i], binary, PGA_DISASS_PROCESS);
+
+        free(pglist);
+
+    }
+
     return result;
 
 }
diff --git a/src/analysis/disass/disassembler.h b/src/analysis/disass/disassembler.h
index 2a0f72a..54da069 100644
--- a/src/analysis/disass/disassembler.h
+++ b/src/analysis/disass/disassembler.h
@@ -31,7 +31,7 @@
 
 
 /* Procède à la décompilation des routines d'un fichier donné. */
-GCodeBuffer *disassemble_binary(const GOpenidaBinary *, GBinPart **parts, size_t parts_count, GArchInstruction **);
+GCodeBuffer *disassemble_binary(GOpenidaBinary *, GBinPart **parts, size_t parts_count, GArchInstruction **);
 
 
 
diff --git a/src/format/dex/method.c b/src/format/dex/method.c
index c22c11f..25145f5 100644
--- a/src/format/dex/method.c
+++ b/src/format/dex/method.c
@@ -147,14 +147,16 @@ GDexMethod *g_dex_method_new(const GDexFormat *format, const encoded_method *see
     result->info = *seed;
     result->body = item;
 
-    printf(" ==== %s ====\n", g_binary_routine_get_name(routine));
+    //printf(" ==== %s ====\n", g_binary_routine_get_name(routine));
 
     //printf(" method idx :: %d\n", seed->method_idx_diff);
     //printf(" code size  :: %d\n", item.insns_size);
 
+    /*
     printf(" code regs  :: %d\n", item.registers_size);
     printf(" code ins   :: %d\n", item.ins_size);
     printf(" code outs  :: %d\n", item.outs_size);
+    */
 
     //printf(" method idx :: %lld\n", *last);
 
diff --git a/src/gui/panels/log.c b/src/gui/panels/log.c
index 2ab6d0c..6bda922 100644
--- a/src/gui/panels/log.c
+++ b/src/gui/panels/log.c
@@ -124,7 +124,7 @@ static GtkWidget *build_log_panel(void)
 
     renderer = gtk_cell_renderer_text_new();
     gtk_tree_view_column_pack_start(column, renderer, TRUE);
-    gtk_tree_view_column_add_attribute(column, renderer, "text", LGC_STRING);
+    gtk_tree_view_column_add_attribute(column, renderer, "markup", LGC_STRING);
 
     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
@@ -239,7 +239,7 @@ void log_variadic_message(LogMessageType type, const char *fmt, ...)
     char *ptr;                              /* Nouvelle allocation         */
     va_list ap;                             /* Liste d'arguments variable  */
 
-    len = 100;
+    len = VARIADIC_LOG_BUFSIZE;
     buffer = calloc(len, sizeof(char));
 
     while (buffer != NULL)
diff --git a/src/gui/panels/log.h b/src/gui/panels/log.h
index c8fe790..264078c 100644
--- a/src/gui/panels/log.h
+++ b/src/gui/panels/log.h
@@ -36,6 +36,10 @@
 #define PANEL_LOG_ID _("Messages")
 
 
+/* Tranche d'allocation pour les messages complexes */
+#define VARIADIC_LOG_BUFSIZE 256
+
+
 /* Type de messages disponibles */
 typedef enum _LogMessageType
 {
diff --git a/src/plugins/plugin-def.h b/src/plugins/plugin-def.h
index 0c7ff1c..c1579b2 100644
--- a/src/plugins/plugin-def.h
+++ b/src/plugins/plugin-def.h
@@ -49,10 +49,12 @@ typedef enum _PluginAction
 
     PGA_DISASSEMBLE     = (1 << 1),         /* Désassemblage (non trivial) */
 
-    PGA_CODE_PROCESS    = (1 << 2),         /* Traitement du code existant */
+    PGA_DISASS_PROCESS  = (1 << 2),         /* Traitement niveau assembleur*/
+    PGA_CODE_PROCESS    = (1 << 3),         /* Traitement du code existant */
+
+    PGA_DEBUGGER_ATTACH = (1 << 4),         /* Activation d'un débogueur   */
+    PGA_DEBUGGER_DETACH = (1 << 5)          /* Désactivation d'un débogueur*/
 
-    PGA_DEBUGGER_ATTACH = (1 << 3),         /* Activation d'un débogueur   */
-    PGA_DEBUGGER_DETACH = (1 << 4)          /* Désactivation d'un débogueur*/
 
 } PluginAction;
 
@@ -64,9 +66,6 @@ typedef PluginType (* get_plugin_type_fc) (void);
 /* Fournit une indication sur le type d'opération(s) menée(s). */
 //typedef PluginAction (* get_plugin_action_fc) (void);
 
-/* Exécute une action définie sur un binaire chargé. */
-typedef bool (* execute_action_on_binary_fc) (GOpenidaBinary *, PluginAction);
-
 
 /* PGA_FORMAT_MATCHER */
 
diff --git a/src/plugins/plugin-int.h b/src/plugins/plugin-int.h
index a4f3cb6..56753e0 100644
--- a/src/plugins/plugin-int.h
+++ b/src/plugins/plugin-int.h
@@ -29,12 +29,16 @@
 
 
 #include "plugin-def.h"
+#include "../gui/panels/log.h"
 
 
 
 
+/* Précise le nom associé au greffon. */
+typedef char * (* get_plugin_name_fc) (void);
+
 /* Procède à l'initialisation du greffon */
-typedef bool (* init_plugin_fc) (GObject *);
+typedef bool (* init_plugin_fc) (GPluginModule *, GObject *);
 
 /* Fournit une indication sur le type d'opération(s) menée(s). */
 typedef PluginAction (* get_plugin_action_fc) (const GPluginModule *);
@@ -42,6 +46,9 @@ typedef PluginAction (* get_plugin_action_fc) (const GPluginModule *);
 /* Identifie un format à associer à un contenu binaire. */
 typedef MatchingFormatAction (* is_matching_fc) (const GPluginModule *, char **, bin_t **, off_t *);
 
+/* Exécute une action définie sur un binaire chargé. */
+typedef bool (* execute_action_on_binary_fc) (const GPluginModule *, GOpenidaBinary *, PluginAction);
+
 /* Exécute une action relative à un débogueur. */
 typedef bool (* execute_on_debugger_fc) (const GPluginModule *, GBinaryDebugger *, PluginAction);
 
@@ -53,6 +60,7 @@ struct _GPluginModule
 
     GModule *module;                        /* Abstration de manipulation  */
 
+    char *name;                             /* Nom associé au greffon      */
     PluginType type;                        /* Type(s) du greffon          */
 
     init_plugin_fc init;                    /* Procédure d'initialisation  */
@@ -75,8 +83,11 @@ struct _GPluginModuleClass
 
 
 
+/* Présente dans le journal un message simple. */
+void g_plugin_module_log_simple_message(const GPluginModule *, LogMessageType, const char *);
 
-
+/* Présente dans le journal un message complexe. */
+void g_plugin_module_log_variadic_message(const GPluginModule *, LogMessageType, const char *, ...);
 
 
 
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index 7521008..e769df6 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -26,7 +26,12 @@
 
 
 #include <gmodule.h>
+#include <libgen.h>
+#include <malloc.h>
+#include <stdarg.h>
 #include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
 
 
 #include "plugin-int.h"
@@ -98,22 +103,26 @@ static void g_plugin_module_init(GPluginModule *line)
 GPluginModule *g_plugin_module_new(const gchar *filename, GObject *ref)
 {
     GPluginModule *result;                  /* Structure à retourner       */
+    get_plugin_name_fc get_name;            /* Nom du greffon              */
     get_plugin_action_fc __get_type;        /* Type(s) de greffon          */
     get_plugin_action_fc get_action;        /* Actions du greffon          */
-
+    char *dir;                              /* Répertoire modifiable       */
 
     result = g_object_new(G_TYPE_PLUGIN_MODULE, NULL);
 
 
     result->module = g_module_open(filename, G_MODULE_BIND_LAZY);
+    if (!result->module) goto bad_plugin;
 
-    if (!result->module)
+    if (!g_module_symbol(result->module, "get_plugin_name", (gpointer *)&get_name))
     {
-        printf("err null mod\n");
-        return NULL;
-
+        log_variadic_message(LMT_ERROR, 
+                             _("No 'get_plugin_name' entry in plugin candidate '%s'"),
+                             filename);
+        goto bad_plugin;
     }
 
+    result->name = get_name();
 
     if (!g_module_symbol(result->module, "init_plugin", (gpointer *)&result->init))
     {
@@ -166,12 +175,21 @@ GPluginModule *g_plugin_module_new(const gchar *filename, GObject *ref)
 
 
 
-    if (!result->init(ref))
-        printf("Err loading pg\n");
-    else printf("Loaded '%s' : ok (%p)\n", filename, result);
+    if (!result->init(result, ref))
+    {
+        log_variadic_message(LMT_ERROR, _("Initialization of plugin '%s' failed !"), filename);
+        goto bad_plugin;
+    }
+
+    dir = strdup(filename);
+    dir = dirname(dir);
 
-    return result;
+    log_variadic_message(LMT_PROCESS, _("Loaded the '<b>%s</b>' from the '<b>%s</b>' directory"),
+                         strrchr(filename, G_DIR_SEPARATOR) + 1, dir);
 
+    free(dir);
+
+    return result;
 
  bad_plugin:
 
@@ -186,6 +204,115 @@ GPluginModule *g_plugin_module_new(const gchar *filename, GObject *ref)
 *                                                                             *
 *  Paramètres  : plugin = greffon à consulter.                                *
 *                                                                             *
+*  Description : Fournit le nom associé au greffon.                           *
+*                                                                             *
+*  Retour      : Désignation humaine.                                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const char *g_plugin_module_get_name(const GPluginModule *plugin)
+{
+    return plugin->name;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                msg    = message à faire apparaître à l'écran.               *
+*                                                                             *
+*  Description : Présente dans le journal un message simple.                  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_plugin_module_log_simple_message(const GPluginModule *plugin, LogMessageType type, const char *msg)
+{
+    size_t len;                             /* Taille tampon disponible    */
+    char *buffer;                           /* Tampon du msg reconstitué   */
+
+    len = 1 + strlen(plugin->name) + 2 + strlen(msg) + 1;
+    buffer = calloc(len, sizeof(char));
+
+    strcpy(buffer, "[");
+    strcat(buffer, plugin->name);
+    strcat(buffer, "] ");
+    strcat(buffer, msg);
+
+    log_simple_message(type, buffer);
+
+    free(buffer);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                type   = espèce du message à ajouter.                        *
+*                fmt    = format du message à faire apparaître à l'écran.     *
+*                ...    = éventuels arguments venant compléter le message.    *
+*                                                                             *
+*  Description : Présente dans le journal un message complexe.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_plugin_module_log_variadic_message(const GPluginModule *plugin, LogMessageType type, const char *fmt, ...)
+{
+    size_t len;                             /* Taille tampon disponible    */
+    char *buffer;                           /* Tampon du msg reconstitué   */
+    int ret;                                /* Bilan d'une impression      */
+    char *ptr;                              /* Nouvelle allocation         */
+    va_list ap;                             /* Liste d'arguments variable  */
+
+    len = VARIADIC_LOG_BUFSIZE;
+    buffer = calloc(len, sizeof(char));
+
+    while (buffer != NULL)
+    {
+        va_start(ap, fmt);
+        ret = vsnprintf(buffer, len, fmt, ap);
+        va_end(ap);
+
+        if (ret >= 0 && ret < len) break;
+
+        else
+        {
+            if (ret > -1) len += 1;     /* glibc 2.1 */
+            else len *= 2;              /* glibc 2.0 */
+
+            if ((ptr = realloc(buffer, len)) == NULL)
+            {
+                free(buffer);
+                buffer = NULL;
+            }
+            else buffer = ptr;
+
+        }
+
+    }
+
+    g_plugin_module_log_simple_message(plugin, type, buffer);
+
+    free(buffer);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à consulter.                                *
+*                                                                             *
 *  Description : Indique les opérations offertes par un greffon donné.        *
 *                                                                             *
 *  Retour      : Action(s) offerte(s) par le greffon.                         *
@@ -262,7 +389,7 @@ MatchingFormatAction g_plugin_module_is_matching(const GPluginModule *plugin, ch
 
 bool g_plugin_module_execute_action_on_binary(const GPluginModule *plugin, GOpenidaBinary *binary, PluginAction action)
 {
-    return plugin->exec_on_bin(binary, action);
+    return plugin->exec_on_bin(plugin, binary, action);
 
 }
 
diff --git a/src/plugins/plugin.h b/src/plugins/plugin.h
index dbd27fd..aa90ee1 100644
--- a/src/plugins/plugin.h
+++ b/src/plugins/plugin.h
@@ -54,6 +54,9 @@ GType g_plugin_module_get_type(void);
 /* Crée un module pour un greffon donné. */
 GPluginModule *g_plugin_module_new(const gchar *, GObject *);
 
+/* Fournit le nom associé au greffon. */
+const char *g_plugin_module_get_name(const GPluginModule *);
+
 /* Indique les opérations offertes par un greffon donné. */
 PluginAction g_plugin_module_get_action(const GPluginModule *);
 
-- 
cgit v0.11.2-87-g4458