/* Chrysalide - Outil d'analyse de fichiers binaires
* pychrysa.c - plugin permettant des extensions en Python
*
* Copyright (C) 2009-2014 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* OpenIDA 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.
*
* OpenIDA 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 Foobar. If not, see .
*/
#include "pychrysa.h"
#if 0
#include
#include
#include
//#include
#include
#include "quirks.h"
#include "analysis/module.h"
#include "arch/module.h"
#include "debug/module.h"
#include "format/module.h"
#include "glibext/module.h"
#include "gtkext/module.h"
#include "gui/module.h"
/*
#include "analysis/py_binary.h"
#include "analysis/py_line.h"
#include "analysis/py_line_code.h"
#include "analysis/roptions.h"
*/
#include "../../src/common/environment.h"
#include "../../src/common/extstr.h"
#include "../../src/plugins/plugin-int.h"
static PyMethodDef SpamMethods[] = {
{NULL, NULL, 0, NULL} /* Sentinel */
};
/******************************************************************************
* *
* 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. *
* *
* Retour : true. *
* *
* Remarques : - *
* *
******************************************************************************/
bool init_plugin(GPluginModule *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 *pyplugin;
/* 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;
define_internal_ref(ref);
Py_Initialize();
//pychrysalide_set_gc_threshold(INT_MAX, INT_MAX, INT_MAX);
//pychrysalide_set_gc_threshold(1, 1, 1);
initpychrysa();
/* Chargement des greffons */
save = NULL; /* gcc... */
for (path = strtok_r(paths, ";", &save);
path != NULL;
path = strtok_r(NULL, ";", &save))
{
dir = opendir(path);
if (dir == NULL)
{
perror("opendir");
continue;
}
for (ret = readdir_r(dir, &entry, &next);
ret == 0 && next != NULL;
ret = readdir_r(dir, &entry, &next))
{
if (entry.d_name[0] == '.') continue;
//if (strcmp(entry.d_name, "test") != 0) continue;
printf("NAME :: '%s'\n", entry.d_name);
if (strcmp(entry.d_name, "apkfiles") != 0) continue;
filename = strdup(entry.d_name);
filename = stradd(filename, ".");
filename = stradd(filename, "__init__");
pyplugin = g_python_plugin_new(entry.d_name, filename);
if (pyplugin == NULL)
g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
_("No suitable Python plugin found in '%s'"),
filename);
else
{
g_plugin_module_log_variadic_message(plugin, LMT_PROCESS,
_("Loaded Python plugin '%s' from the '%s' directory"),
g_plugin_module_get_name(G_PLUGIN_MODULE(pyplugin)), path);
add_plugin_to_main_list(pyplugin);
}
free(filename);
}
closedir(dir);
}
return true;
}
/******************************************************************************
* *
* Paramètres : plugin = instance représentant le greffon en déchargement. *
* *
* Description : Libère le greffon permettant l'usage de Python. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void exit_plugin(GPluginModule *plugin)
{
/* FIXME */
//Py_Finalize();
}
/******************************************************************************
* *
* 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
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Point d'entrée pour l'initialisation de Python. *
* *
* Retour : ? *
* *
* Remarques : - *
* *
******************************************************************************/
PyMODINIT_FUNC initpychrysa/*PyInit_pychrysa*/(void)
{
PyObject *module;
//init_pygobject();
//init_pygtk();
pychrysalide_init_quirks();
module = Py_InitModule("pychrysalide", SpamMethods);
//add_analysis_roptions_to_python_module(module);
add_analysis_module_to_python_module(module);
add_arch_module_to_python_module(module);
add_debug_module_to_python_module(module);
add_format_module_to_python_module(module);
add_glibext_module_to_python_module(module);
add_gtkext_module_to_python_module(module);
add_gui_module_to_python_module(module);
add_plugin_to_python_module(module);
/*
static struct PyModuleDef spammodule = {
PyModuleDef_HEAD_INIT,
"pychrysalide",
"pychrysalide_doc",
-1,
SpamMethods
};
PyModule_Create(&spammodule);
*/
}
#else
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Point d'entrée pour l'initialisation de Python. *
* *
* Retour : ? *
* *
* Remarques : - *
* *
******************************************************************************/
PyMODINIT_FUNC initpychrysa(void)
{
PyObject *module;
init_pygobject();
//init_pygtk();
pychrysalide_init_quirks();
module = Py_InitModule("pychrysalide", SpamMethods);
//add_analysis_roptions_to_python_module(module);
add_analysis_module_to_python_module(module);
add_arch_module_to_python_module(module);
add_debug_module_to_python_module(module);
add_format_module_to_python_module(module);
add_glibext_module_to_python_module(module);
add_gtkext_module_to_python_module(module);
add_gui_module_to_python_module(module);
add_plugin_to_python_module(module);
}
#endif
#endif
#include
#include
#include "analysis/module.h"
#include "arch/module.h"
#include "core/module.h"
#include "glibext/module.h"
// TODO : à bouger ?
#include "../../src/arch/processor.h"
#include "../../src/format/format.h"
///////////////////////////
#include
#include
#include
#include
#include
#include
#include
#include "../../revision.h"
DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("PyChrysalide", "Provides bindings to Python", "0.1.0", PGA_ALL);
/* Fournit la version du programme global. */
static PyObject *py_chrysalide_version(PyObject *, PyObject *);
/* Fournit la version du greffon pour Python. */
static PyObject *py_chrysalide_mod_version(PyObject *, PyObject *);
/* Détermine si l'interpréteur lancé est celui pris en compte. */
static bool is_current_abi_suitable(void);
/******************************************************************************
* *
* Paramètres : self = NULL car méthode statique. *
* args = non utilisé ici. *
* *
* Description : Fournit la version du programme global. *
* *
* Retour : Numéro de révision. *
* *
* Remarques : - *
* *
******************************************************************************/
static PyObject *py_chrysalide_version(PyObject *self, PyObject *args)
{
char version[16];
int major;
int minor;
int revision;
major = REVISION / 1000;
minor = (REVISION - (major * 1000)) / 100;
revision = REVISION % 100;
snprintf(version, sizeof(version), "%d.%d.%d", major, minor, revision);
return PyUnicode_FromString(version);
}
/******************************************************************************
* *
* Paramètres : self = NULL car méthode statique. *
* args = non utilisé ici. *
* *
* Description : Fournit la version du greffon pour Python. *
* *
* Retour : Numéro de révision. *
* *
* Remarques : - *
* *
******************************************************************************/
static PyObject *py_chrysalide_mod_version(PyObject *self, PyObject *args)
{
char version[16];
snprintf(version, sizeof(version), "%s", _chrysalide_plugin.version);
return PyUnicode_FromString(version);
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Détermine si l'interpréteur lancé est celui pris en compte. *
* *
* Retour : true si l'exécution peut se poursuivre, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool is_current_abi_suitable(void)
{
bool result;
int fds[2];
int ret;
char cmds[128];
char content[64];
ssize_t got;
#define GRAB_ABI_FLAGS_IN_PYTHON \
"import sys" "\n" \
"import os" "\n" \
"os.write(%d, bytes(sys.abiflags, 'UTF-8'))" "\n"
result = false;
ret = pipe(fds);
if (ret == -1)
{
perror("pipe()");
return false;
}
snprintf(cmds, sizeof(cmds), GRAB_ABI_FLAGS_IN_PYTHON, fds[1]);
ret = PyRun_SimpleString(cmds);
if (ret != 0) goto icas_exit;
got = read(fds[0], content, sizeof(content));
if (got < 0)
{
perror("read()");
goto icas_exit;
}
content[got] = '\0';
result = (strcmp(content, LIBPYTHON_ABI_FLAGS) == 0);
icas_exit:
if (!result)
PyErr_SetString(PyExc_SystemError, "the ABI flags of the current interpreter do not match " \
"the ones of the Python library used during the module compilation.");
return result;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Point d'entrée pour l'initialisation de Python. *
* *
* Retour : ? *
* *
* Remarques : - *
* *
******************************************************************************/
PyMODINIT_FUNC PyInit_pychrysalide(void)
{
PyObject *result; /* Module Python à retourner */
PyObject *pygobj_mod; /* Module Python-GObject */
bool status; /* Bilan des inclusions */
static PyMethodDef py_chrysalide_methods[] = {
{ "version", py_chrysalide_version,
METH_NOARGS,
"Provide the revision number of Chrysalide."
},
{ "mod_version", py_chrysalide_mod_version,
METH_NOARGS,
"Provide the revision number of Chrysalide module for Python."
},
{ NULL }
};
static PyModuleDef py_chrysalide_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "pychrysalide",
.m_doc = "Python module for Chrysalide",
.m_size = -1,
.m_methods = py_chrysalide_methods
};
// TODO : à bouger !
//init_all_processors();
//init_all_formats();
if (!is_current_abi_suitable())
return NULL;
if (pygobject_init(-1, -1, -1) == NULL)
{
PyErr_SetString(PyExc_SystemError, "unable to init GObject in Python.");
return NULL;
}
if (!load_all_basic_components())
{
PyErr_SetString(PyExc_SystemError, "unable to load all basic components.");
return NULL;
}
/**
* Pour une raison non identifiée, si le module n'est pas préchargé,
* le flot d'exécution plante dans la fonction insertdict() de Objects/dictobject.c:818.
*/
pygobj_mod = PyImport_ImportModule("gi.repository.GObject");
if (pygobj_mod == NULL)
return NULL;
result = PyModule_Create(&py_chrysalide_module);
status = true;
status &= add_analysis_module_to_python_module(result);
status &= add_arch_module_to_python_module(result);
status &= add_core_module_to_python_module(result);
status &= add_glibext_module_to_python_module(result);
if (!status)
{
PyErr_SetString(PyExc_SystemError, "fail to load all PyChrysalide components.");
return NULL;
}
return result;
}