diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/pyoida/plugin.c | 250 | ||||
-rw-r--r-- | plugins/pyoida/plugin.h | 2 | ||||
-rw-r--r-- | plugins/pyoida/pyoida.c | 118 | ||||
-rw-r--r-- | plugins/python/apkfiles/__init__.py | 2 | ||||
-rw-r--r-- | plugins/python/apkfiles/apkfiles.py | 34 |
5 files changed, 383 insertions, 23 deletions
diff --git a/plugins/pyoida/plugin.c b/plugins/pyoida/plugin.c index 23934a9..e652949 100644 --- a/plugins/pyoida/plugin.c +++ b/plugins/pyoida/plugin.c @@ -46,6 +46,7 @@ struct _GPythonPlugin GPluginModule parent; /* Instance parente */ PyObject *module; /* Script Python chargé */ + PyObject *instance; /* Instance Python du greffon */ }; @@ -64,6 +65,12 @@ static void g_python_plugin_class_init(GPythonPluginClass *); /* Initialise l'instance d'un greffon Python. */ static void g_python_plugin_init(GPythonPlugin *); +/* Indique l'utilité pratique du greffon. */ +static PluginAction g_python_plugin_get_action(const GPythonPlugin *); + +/* Indentifie un format à associer à un contenu binaire. */ +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); @@ -94,7 +101,11 @@ static PyObject *pyoida_plugin_run(PyObject *, PyObject *); /* Définit les constantes pour les greffons en Python. */ static bool pyoida_plugin_define_constants(PyObject *); +/* Définit le comportement par défaut d'un greffon Python. */ +static PyObject *pyoida_plugin_get_action(PyObject *, PyObject *); +/* Définit l'issue de la recherche d'un format par défaut. */ +static PyObject *pyoida_plugin_is_matching(PyObject *, PyObject *); @@ -260,7 +271,8 @@ PyObject *run_python_method(PyObject *module, const char *method, PyObject *args /****************************************************************************** * * -* Paramètres : filename = chemin d'accès au code Python à charger. * +* Paramètres : modname = nom du module à charger. * +* filename = chemin d'accès au code Python à charger. * * * * Description : Crée un greffon à partir de code Python. * * * @@ -270,18 +282,20 @@ PyObject *run_python_method(PyObject *module, const char *method, PyObject *args * * ******************************************************************************/ -GPluginModule *g_python_plugin_new(const char *filename) +GPluginModule *g_python_plugin_new(const char *modname, const char *filename) { GPythonPlugin *result; /* Structure à retourner */ PyObject *name; /* Chemin d'accès pour Python */ PyObject *module; /* Script Python chargé */ + PyObject *dict; /* Dictionnaire associé */ + PyObject *class; /* Classe à instancier */ + PyObject *instance; /* Instance Python du greffon */ #if PY_VERSION_HEX >= 0x03000000 name = PyUnicode_FromString(filename); #else name = PyString_FromString(filename); #endif - name = PyString_FromString/*PyUnicode_FromString*/(filename); if (name == NULL) goto gppn_bad_exit; module = PyImport_Import(name); @@ -293,20 +307,37 @@ GPluginModule *g_python_plugin_new(const char *filename) goto gppn_bad_exit; } + dict = PyModule_GetDict(module); + class = PyDict_GetItemString(dict, modname); + Py_DECREF(dict); + if (class == NULL) goto gppn_no_class; + if (!PyType_Check(class->ob_type)) goto gppn_no_class; - //Py_DECREF(module); - + instance = PyObject_CallFunction(class, NULL); + if (instance == NULL) goto gppn_no_instance; + Py_DECREF(class); result = g_object_new(G_TYPE_PYTHON_PLUGIN, NULL); - G_PLUGIN_MODULE(result)->action = PGA_CODE_PROCESS; + G_PLUGIN_MODULE(result)->get_action = g_python_plugin_get_action; + + G_PLUGIN_MODULE(result)->is_matching = g_python_plugin_is_matching; result->module = module; + result->instance = instance; return G_PLUGIN_MODULE(result); + gppn_no_instance: + + Py_DECREF(class); + + gppn_no_class: + + Py_DECREF(module); + gppn_bad_exit: return NULL; @@ -317,6 +348,138 @@ GPluginModule *g_python_plugin_new(const char *filename) /****************************************************************************** * * * Paramètres : plugin = greffon de prise en charge à utiliser. * +* * +* Description : Indique l'utilité pratique du greffon. * +* * +* Retour : Action(s) codifiée(s), PGA_NONE par défaut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PluginAction g_python_plugin_get_action(const GPythonPlugin *plugin) +{ + PluginAction result; /* Valeur à retourner */ + PyObject *value; /* Valeur obtenue */ + + value = run_python_method(plugin->instance, "get_action", NULL); + + result = PyLong_AsLong(value); + Py_DECREF(value); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon de prise en charge à utiliser. * +* filename = éventuel nom de fichier associé ou NULL. [OUT] * +* data = données chargées. [OUT] * +* length = quantité de ces données. [OUT] * +* * +* Description : Indentifie un format à associer à un contenu binaire. * +* * +* Retour : Bilan de la recherche de correspondances. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static MatchingFormatAction g_python_plugin_is_matching(const GPythonPlugin *plugin, char **filename, bin_t **data, off_t *length) +{ + MatchingFormatAction result; /* Valeur à retourner */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ + PyObject *action; /* Action à faire suivre */ + PyObject *new_filename; /* Nouveau fichier */ + PyObject *new_data; /* Nouvelles données */ + char *tmp; /* Stockage avant recopie */ + + if (*filename == NULL) + return MFA_NONE; + + args = PyTuple_New(2); + + PyTuple_SetItem(args, 0, PyString_FromString(*filename)); + PyTuple_SetItem(args, 1, PyByteArray_FromStringAndSize(*data, *length)); + + value = run_python_method(plugin->instance, "is_matching", args); + + if (value != NULL && PyTuple_Check(value) && PyTuple_Size(value) == 3) + { + action = PyTuple_GetItem(value, 0); + new_filename = PyTuple_GetItem(value, 1); + new_data = PyTuple_GetItem(value, 2); + + if (action == NULL || new_filename == NULL || new_data == NULL) + goto is_matching_bad; + + if (!PyInt_Check(action) + || (new_filename != Py_None && !PyString_Check(new_filename)) + || (new_data != Py_None && !PyByteArray_Check(new_data))) + goto is_matching_bad; + + result = PyInt_AsLong(action); + if (result >= MFA_COUNT) goto is_matching_bad; + + if (result != MFA_NONE && new_data == Py_None) goto is_matching_bad; + + if (new_filename != Py_None) + *filename = strdup(PyString_AsString(new_filename)); + /** + * La suppression de la part du greffon n'est permise que + * si une prise en charge est assurée. + */ + else if (result != MFA_NONE) + *filename = NULL; + + /** + * Pareil que précédemment. + */ + if (new_data != Py_None) + { + tmp = PyByteArray_AsString(new_data); + *length = PyByteArray_Size(new_data); + + *data = (bin_t *)calloc(*length, sizeof(bin_t)); + memcpy(*data, tmp, *length * sizeof(bin_t)); + + } + + goto is_matching_ok; + + } + + is_matching_bad: + + printf("<LOG>Bad result from is_matching() plugin function.\n"); + + result = MFA_NONE; + + is_matching_ok: + + Py_XDECREF(value); + Py_DECREF(args); + + return result; + +} + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon de prise en charge à utiliser. * * binary = représentation binaire à traiter. * * action = action attendue. * * * @@ -421,12 +584,29 @@ static bool pyoida_plugin_define_constants(PyObject *dict) { int ret; /* Bilan d'un ajout */ + ret = PyDict_SetItemString(dict, "PGA_NONE", PyInt_FromLong(PGA_NONE)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "PGA_FORMAT_MATCHER", PyInt_FromLong(PGA_FORMAT_MATCHER)); + if (ret == -1) return false; + ret = PyDict_SetItemString(dict, "PGA_DISASSEMBLE", PyInt_FromLong(PGA_DISASSEMBLE)); if (ret == -1) return false; ret = PyDict_SetItemString(dict, "PGA_CODE_PROCESS", PyInt_FromLong(PGA_CODE_PROCESS)); if (ret == -1) return false; + /* PGA_FORMAT_MATCHER */ + + ret = PyDict_SetItemString(dict, "MFA_NONE", PyInt_FromLong(MFA_NONE)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "MFA_MATCHED", PyInt_FromLong(MFA_MATCHED)); + if (ret == -1) return false; + + ret = PyDict_SetItemString(dict, "MFA_RELOAD", PyInt_FromLong(MFA_RELOAD)); + if (ret == -1) return false; + return true; } @@ -437,6 +617,58 @@ static bool pyoida_plugin_define_constants(PyObject *dict) * Paramètres : self = classe assurant le lien avec l'éditeur de messages. * * args = arguments fournis à l'appel. * * * +* Description : Définit le comportement par défaut d'un greffon Python. * +* * +* Retour : Rien en équivalent Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *pyoida_plugin_get_action(PyObject *self, PyObject *args) +{ + return PyInt_FromLong(PGA_NONE); + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * +* args = arguments fournis à l'appel. * +* * +* Description : Définit l'issue de la recherche d'un format par défaut. * +* * +* Retour : Rien en équivalent Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *pyoida_plugin_is_matching(PyObject *self, PyObject *args) +{ + PyObject *result; /* Liste à retourner */ + + result = PyTuple_New(3); + + PyTuple_SetItem(result, 0, PyInt_FromLong(MFA_NONE)); + PyTuple_SetItem(result, 1, Py_None); + PyTuple_SetItem(result, 2, Py_None); + + return result; + +} + + + + + + +/****************************************************************************** +* * +* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * +* args = arguments fournis à l'appel. * +* * * Description : Exécute une action valide pour le greffon Python. * * * * Retour : Rien en équivalent Python. * @@ -474,6 +706,12 @@ bool add_plugin_to_python_module(PyObject *module) static PyMethodDef pyoida_plugin_methods[] = { + { "get_action", (PyCFunction)pyoida_plugin_get_action, METH_NOARGS, + "Register the plugin for given actions." + }, + { "is_matching", (PyCFunction)pyoida_plugin_is_matching, METH_VARARGS, + "Define if the given file can be handled." + }, { "run", (PyCFunction)pyoida_plugin_run, METH_VARARGS, "Run the plugin for a specific action." }, diff --git a/plugins/pyoida/plugin.h b/plugins/pyoida/plugin.h index f5d4ab4..b8b76d9 100644 --- a/plugins/pyoida/plugin.h +++ b/plugins/pyoida/plugin.h @@ -60,7 +60,7 @@ typedef struct _GPythonPluginClass GPythonPluginClass; GType g_python_plugin_get_type(void); /* Crée un greffon à partir de code Python. */ -GPluginModule *g_python_plugin_new(const char *); +GPluginModule *g_python_plugin_new(const char *, const char *); diff --git a/plugins/pyoida/pyoida.c b/plugins/pyoida/pyoida.c index 4a79bfd..be75b7c 100644 --- a/plugins/pyoida/pyoida.c +++ b/plugins/pyoida/pyoida.c @@ -24,6 +24,10 @@ #include "pyoida.h" +#include <config.h> +#include <dirent.h> + + #include <Python.h> @@ -69,6 +73,7 @@ static PyMethodDef SpamMethods[] = { +static PyObject *__mod; /****************************************************************************** @@ -85,17 +90,37 @@ static PyMethodDef SpamMethods[] = { bool init_plugin(GObject *ref) { + char *paths; /* Emplacements de greffons */ + char *path; /* Chemin à fouiller */ + char *save; /* Sauvegarde pour ré-entrance */ + DIR *dir; /* Répertoire à parcourir */ + struct dirent entry; /* Elément trouvé */ + struct dirent *next; /* Prochain élément fourni */ + int ret; /* Bilan d'un appel système */ + char *filename; /* Chemin d'accès reconstruit */ + + + + GPluginModule *plugin; - int ret; + + printf("Init pyoida\n"); _ref = ref; - add_to_env_var("PYTHONPATH", "/home/ocb/prog/openida/plugins/python", ";"); + + /* Définition des zones d'influence */ + + add_to_env_var("PYTHONPATH", PLUGINS_DIR G_DIR_SEPARATOR_S "python", ";"); + + paths = get_env_var("PYTHONPATH"); + + /* Intialisations Python */ - return false; + //return false; Py_Initialize(); @@ -104,33 +129,92 @@ bool init_plugin(GObject *ref) + /* Chargement des greffons */ - plugin = g_python_plugin_new("lnxsyscalls/lnxsyscalls"); - add_plugin_to_main_list(plugin); + printf("Paths :: '%s'\n", paths); + for (path = strtok_r(paths, ";", &save); + path != NULL; + path = strtok_r(NULL, ";", &save)) + { + dir = opendir(path); + if (dir == NULL) + { + perror("opendir"); + continue; + } + printf("CHEMIN :: '%s'\n", path); -#if 0 + for (ret = readdir_r(dir, &entry, &next); + ret == 0 && next != NULL; + ret = readdir_r(dir, &entry, &next)) + { + if (entry.d_name[0] == '.') continue; -#if 0 - //main2("/home/ocb/prog/openida/plugins/pyoida/lnxsyscalls/lnxsyscalls.py", "get_instance"); - main2("lnxsyscalls", "get_instance"); -#else - //main2("/home/ocb/prog/openida/plugins/pyoida/lnxsyscalls/lnxsyscalls.py", "get_instance"); - main2("lnxsyscalls/lnxsyscalls", "get_instance"); -#endif + filename = strdup(entry.d_name); + filename = stradd(filename, "."); + filename = stradd(filename, "__init__"); -#endif + printf(" - entry :: '%s'\n", filename); - //Py_Finalize(); - //exit(-1); + plugin = g_python_plugin_new(entry.d_name, filename); + + if (plugin == NULL) + printf("No suitable Python plugin found in '%s'\n", filename); /* FIXME : LOG(...) */ + else + { + printf("ok pour %s\n", filename); + add_plugin_to_main_list(plugin); + } + + free(filename); + + } + + closedir(dir); + + break; /* FIXME */ + + } + + //Py_Finalize(); return true; } +/****************************************************************************** +* * +* Paramètres : plugin = greffon à consulter. * +* * +* Description : Indique les opérations offertes par un greffon donné. * +* * +* Retour : Action(s) offerte(s) par le greffon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PluginAction get_plugin_action(const GPluginModule *plugin) +{ + PluginAction result; /* Combinaison à retourner */ + + result = PGA_NONE; + + + + + return result; + +} + + + + + #if PY_VERSION_HEX >= 0x03000000 /* Python 3.x code */ @@ -169,6 +253,8 @@ initpyoida(void) printf("Passage 2\n"); module = Py_InitModule("pyoida", SpamMethods); + __mod = module; + //add_analysis_roptions_to_python_module(module); add_analysis_module_to_python_module(module); add_arch_module_to_python_module(module); diff --git a/plugins/python/apkfiles/__init__.py b/plugins/python/apkfiles/__init__.py new file mode 100644 index 0000000..2ebf824 --- /dev/null +++ b/plugins/python/apkfiles/__init__.py @@ -0,0 +1,2 @@ + +from apkfiles import ApkFiles as apkfiles diff --git a/plugins/python/apkfiles/apkfiles.py b/plugins/python/apkfiles/apkfiles.py new file mode 100644 index 0000000..fe7deb8 --- /dev/null +++ b/plugins/python/apkfiles/apkfiles.py @@ -0,0 +1,34 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from pyoida import Plugin + +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.""" + + if not zipfile.is_zipfile(filename): + return Plugin.MFA_NONE, None, None + + zf = zipfile.ZipFile(filename) + + if zf.namelist().count('classes.dex') > 0: + + f = zf.open('classes.dex', 'r') + data = f.read() + f.closed + + return Plugin.MFA_RELOAD, None, bytearray(data) + + else: + return Plugin.MFA_NONE, None, None |