From 5fce21379baac06b7b9359c4b0fcb7fb3867c301 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Fri, 12 May 2017 23:28:01 +0200 Subject: Added the ELF strings to the preloaded instruction list. --- ChangeLog | 41 ++++++ plugins/pychrysa/arch/Makefile.am | 1 + plugins/pychrysa/arch/instruction.c | 3 +- plugins/pychrysa/arch/module.c | 2 + plugins/pychrysa/arch/raw.c | 263 ++++++++++++++++++++++++++++++++++++ plugins/pychrysa/arch/raw.h | 42 ++++++ src/common/array.c | 81 +++++++++++ src/common/array.h | 6 + src/format/dex/dex.c | 3 + src/format/elf/elf.c | 13 ++ src/format/elf/strings.c | 14 +- src/format/format-int.h | 3 + src/format/format.c | 17 ++- src/format/preload.c | 29 ++++ src/format/preload.h | 3 + tests/format/elf/Makefile | 9 +- tests/format/elf/strings.asm | 77 +++++++++++ tests/format/elf/strings.py | 74 ++++++++++ 18 files changed, 668 insertions(+), 13 deletions(-) create mode 100644 plugins/pychrysa/arch/raw.c create mode 100644 plugins/pychrysa/arch/raw.h create mode 100644 tests/format/elf/strings.asm create mode 100644 tests/format/elf/strings.py diff --git a/ChangeLog b/ChangeLog index 818be7e..e894d2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,44 @@ +17-05-12 Cyrille Bagard + + * plugins/pychrysa/arch/Makefile.am: + Add the 'raw.[ch]' files to libpychrysaarch_la_SOURCES. + + * plugins/pychrysa/arch/instruction.c: + Typo. + + * plugins/pychrysa/arch/module.c: + Register the new bindings. + + * plugins/pychrysa/arch/raw.c: + * plugins/pychrysa/arch/raw.h: + New entries: add support for raw instructions with Python. + + * src/common/array.c: + * src/common/array.h: + Provide a way to copy flat array content. + + * src/format/dex/dex.c: + * src/format/elf/elf.c: + Update code. + + * src/format/elf/strings.c: + Add the ELF strings to the preloaded instruction list. + + * src/format/format-int.h: + * src/format/format.c: + Update code. + + * src/format/preload.c: + * src/format/preload.h: + Copy preloaded information when requested. + + * tests/format/elf/Makefile: + Include 'strings' as executable to build. + + * tests/format/elf/strings.asm: + * tests/format/elf/strings.py: + New entries: extend the test suite for ELF strings. + 17-05-11 Cyrille Bagard * src/analysis/disass/area.c: diff --git a/plugins/pychrysa/arch/Makefile.am b/plugins/pychrysa/arch/Makefile.am index 21e3856..9421e04 100644 --- a/plugins/pychrysa/arch/Makefile.am +++ b/plugins/pychrysa/arch/Makefile.am @@ -8,6 +8,7 @@ libpychrysaarch_la_SOURCES = \ module.h module.c \ operand.h operand.c \ processor.h processor.c \ + raw.h raw.c \ vmpa.h vmpa.c libpychrysaarch_la_LIBADD = \ diff --git a/plugins/pychrysa/arch/instruction.c b/plugins/pychrysa/arch/instruction.c index 0e10728..0efca5a 100644 --- a/plugins/pychrysa/arch/instruction.c +++ b/plugins/pychrysa/arch/instruction.c @@ -229,6 +229,7 @@ static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure) } + /****************************************************************************** * * * Paramètres : self = objet Python concerné par l'appel. * @@ -437,7 +438,7 @@ PyTypeObject *get_python_arch_instruction_type(void) bool register_python_arch_instruction(PyObject *module) { - PyTypeObject *py_arch_instruction_type; /* Type Python 'BinContent' */ + PyTypeObject *py_arch_instruction_type; /* Type Python 'ArchInstruc...'*/ PyObject *dict; /* Dictionnaire du module */ py_arch_instruction_type = get_python_arch_instruction_type(); diff --git a/plugins/pychrysa/arch/module.c b/plugins/pychrysa/arch/module.c index 68f702d..d9eabed 100644 --- a/plugins/pychrysa/arch/module.c +++ b/plugins/pychrysa/arch/module.c @@ -36,6 +36,7 @@ #include "instruction.h" #include "operand.h" #include "processor.h" +#include "raw.h" #include "vmpa.h" #include "arm/module.h" #include "../helpers.h" @@ -146,6 +147,7 @@ bool add_arch_module_to_python_module(PyObject *super) result &= register_python_arch_operand(module); result &= register_python_arch_processor(module); result &= register_python_instr_iterator(module); + result &= register_python_raw_instruction(module); result &= register_python_vmpa(module); result &= register_python_mrange(module); diff --git a/plugins/pychrysa/arch/raw.c b/plugins/pychrysa/arch/raw.c new file mode 100644 index 0000000..39b5fe7 --- /dev/null +++ b/plugins/pychrysa/arch/raw.c @@ -0,0 +1,263 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw.c - équivalent Python du fichier "arch/raw.h" + * + * Copyright (C) 2017 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "raw.h" + + +#include + + +#include + + +#include "instruction.h" +#include "../helpers.h" + + + +/* Indique si le contenu de l'instruction est du bourrage. */ +static PyObject *py_arch_instruction_is_padding(PyObject *, void *); + +/* Marque l'instruction comme ne contenant que du bourrage. */ +static int py_arch_instruction_mark_as_padding(PyObject *, PyObject *, void *); + +/* Indique si le contenu de l'instruction est un texte. */ +static PyObject *py_arch_instruction_is_string(PyObject *, void *); + +/* Marque l'instruction comme contenant une chaîne de texte. */ +static int py_arch_instruction_mark_as_string(PyObject *, PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une instruction. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique si le contenu de l'instruction est du bourrage. * +* * +* Retour : Valeur associée à la propriété consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_is_padding(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + GRawInstruction *instr; /* Version native */ + bool state; /* Etat courant à consulter */ + + instr = G_RAW_INSTRUCTION(pygobject_get(self)); + + state = g_raw_instruction_is_padding(instr); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Marque l'instruction comme ne contenant que du bourrage. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_arch_instruction_mark_as_padding(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GRawInstruction *instr; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + instr = G_RAW_INSTRUCTION(pygobject_get(self)); + + g_raw_instruction_mark_as_padding(instr, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une instruction. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique si le contenu de l'instruction est un texte. * +* * +* Retour : Valeur associée à la propriété consultée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_instruction_is_string(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + GRawInstruction *instr; /* Version native */ + bool state; /* Etat courant à consulter */ + + instr = G_RAW_INSTRUCTION(pygobject_get(self)); + + state = g_raw_instruction_is_string(instr); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Marque l'instruction comme contenant une chaîne de texte. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_arch_instruction_mark_as_string(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GRawInstruction *instr; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + instr = G_RAW_INSTRUCTION(pygobject_get(self)); + + g_raw_instruction_mark_as_string(instr, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_raw_instruction_type(void) +{ + static PyMethodDef py_raw_instruction_methods[] = { + { NULL } + }; + + static PyGetSetDef py_raw_instruction_getseters[] = { + { + "is_padding", py_arch_instruction_is_padding, py_arch_instruction_mark_as_padding, + "Report if the instruction is seen as padding.", NULL + }, + { + "is_string", py_arch_instruction_is_string, py_arch_instruction_mark_as_string, + "Report if the instruction is seen as a string.", NULL + }, + { NULL } + }; + + static PyTypeObject py_raw_instruction_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.RawInstruction", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "PyChrysalide raw instruction for a all architectures.", + + .tp_methods = py_raw_instruction_methods, + .tp_getset = py_raw_instruction_getseters, + + }; + + return &py_raw_instruction_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.ArchInstruction'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_raw_instruction(PyObject *module) +{ + PyTypeObject *py_raw_instruction_type; /* Type Python 'RawInstruction'*/ + PyObject *dict; /* Dictionnaire du module */ + PyTypeObject *base; /* Base parente pour héritage */ + + py_raw_instruction_type = get_python_raw_instruction_type(); + + dict = PyModule_GetDict(module); + + base = get_python_arch_instruction_type(); + + if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, py_raw_instruction_type, base)) + return false; + + return true; + +} diff --git a/plugins/pychrysa/arch/raw.h b/plugins/pychrysa/arch/raw.h new file mode 100644 index 0000000..4c1db7a --- /dev/null +++ b/plugins/pychrysa/arch/raw.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * raw.h - prototypes pour l'équivalent Python du fichier "arch/raw.h" + * + * Copyright (C) 2017 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSA_ARCH_RAW_H +#define _PLUGINS_PYCHRYSA_ARCH_RAW_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_raw_instruction_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.RawInstruction'. */ +bool register_python_raw_instruction(PyObject *); + + + +#endif /* _PLUGINS_PYCHRYSA_ARCH_RAW_H */ diff --git a/src/common/array.c b/src/common/array.c index f520d1d..dcb9344 100644 --- a/src/common/array.c +++ b/src/common/array.c @@ -215,6 +215,87 @@ void reset_flat_array(flat_array_t **array) /****************************************************************************** * * +* Paramètres : src = tableau compressé à consulter. * +* dest = tableau compressé à constituer. [OUT] * +* size = taille de ce nouvel élément. * +* notify = éventuelle fonction à appeler sur chaque élément. * +* * +* Description : Copie le contenu d'un tableau d'éléments dans un autre. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void copy_flat_array_items(flat_array_t **src, flat_array_t **dest, size_t size, item_notify_cb notify) +{ + void *item; /* Elément manipulé */ + ext_flat_array_t *extended; /* Version de tableau étendue */ + ext_flat_array_t *new; /* Nouvelle copie créée */ + size_t i; /* Boucle de parcours */ + + assert(!FLAT_ARRAY_IS_LOCKED(*src)); + assert(!FLAT_ARRAY_IS_LOCKED(*dest)); + + lock_flat_array(src); + lock_flat_array(dest); + + assert(FLAT_ARRAY_IS_EMPTY(*dest)); + + if (FLAT_ARRAY_IS_EMPTY(*src)) + goto cfai_done; + + if (FLAT_ARRAY_HAS_NO_INDEX(*src)) + { + item = GET_LONELY_ITEM(*src); + + if (notify != NULL) + notify(item); + + *dest = malloc(size); + memcpy(*dest, item, size); + + lock_flat_array(dest); + + } + + else + { + extended = EXTENDED_ARRAY(*src); + + new = (ext_flat_array_t *)malloc(sizeof(ext_flat_array_t)); + + new->items = malloc(extended->count * size); + new->count = extended->count; + + memcpy(new->items, extended->items, new->count * size); + + if (notify != NULL) + for (i = 0; i < new->count; i++) + { + item = (void *)(((char *)new->items) + i * size); + notify(item); + } + + FLAT_ARRAY_SET_INDEX(new); + + *dest = (flat_array_t *)new; + + lock_flat_array(dest); + + } + + cfai_done: + + unlock_flat_array(src); + unlock_flat_array(dest); + +} + + +/****************************************************************************** +* * * Paramètres : array = tableau compressé à consulter. * * * * Description : Indique la quantité d'éléments présents dans le tableau. * diff --git a/src/common/array.h b/src/common/array.h index bdb1ae4..546de1a 100644 --- a/src/common/array.h +++ b/src/common/array.h @@ -33,6 +33,9 @@ /* Type déclaratif de tableau compressé, à 0 ou 1 élément */ typedef void *flat_array_t; +/* Parcours d'éléments */ +typedef void (* item_notify_cb) (void *); + /* Verrouille l'accès à un tableau compressé. */ void lock_flat_array(flat_array_t **); @@ -43,6 +46,9 @@ void unlock_flat_array(flat_array_t **); /* Réinitialise un tableau sans traitement excessif. */ void reset_flat_array(flat_array_t **); +/* Copie le contenu d'un tableau d'éléments dans un autre. */ +void copy_flat_array_items(flat_array_t **, flat_array_t **, size_t, item_notify_cb); + /* Indique la quantité d'éléments présents dans le tableau. */ size_t count_flat_array_items(const flat_array_t *); diff --git a/src/format/dex/dex.c b/src/format/dex/dex.c index e34318f..b0b32a7 100755 --- a/src/format/dex/dex.c +++ b/src/format/dex/dex.c @@ -32,6 +32,7 @@ #include "dex-int.h" #include "pool.h" +#include "../../plugins/pglist.h" @@ -287,6 +288,8 @@ GBinFormat *g_dex_format_new(GBinContent *content, GExeFormat *parent, GtkStatus if (!load_all_dex_classes(result, gid, status)) goto gdfn_error; + preload_binary_format(PGA_FORMAT_PRELOAD, base, base->info, status); + if (!g_executable_format_complete_loading(exe_format, status)) goto gdfn_error; diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c index bc48eb5..0336ba3 100644 --- a/src/format/elf/elf.c +++ b/src/format/elf/elf.c @@ -39,6 +39,7 @@ #include "strings.h" #include "symbols.h" #include "../../gui/panels/log.h" +#include "../../plugins/pglist.h" @@ -293,6 +294,18 @@ GBinFormat *g_elf_format_new(GBinContent *content, GExeFormat *parent, GtkStatus + /** + * On inscrit les éléments préchargés avant tout ! + * + * Cela permet de partir d'une base vide, et d'ajouter les instructions et + * leurs commentaires par paires. + * + * Ensuite, on inscrit le reste (comme les chaînes de caractères). + */ + + preload_binary_format(PGA_FORMAT_PRELOAD, base, base->info, status); + + if (!load_elf_symbols(result, status)) { /* TODO */ diff --git a/src/format/elf/strings.c b/src/format/elf/strings.c index 8901db9..d350200 100644 --- a/src/format/elf/strings.c +++ b/src/format/elf/strings.c @@ -37,7 +37,7 @@ /* Enregistre toutes les chaînes de caractères trouvées. */ -bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_t); +static bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_t); @@ -148,9 +148,10 @@ bool find_all_elf_strings(GElfFormat *format) * * ******************************************************************************/ -bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address) +static bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address) { bool result; /* Bilan à faire remonter */ + GBinFormat *base; /* Autre version du format */ GBinContent *content; /* Contenu binaire à lire */ const bin_t *data; /* Contenu complet et original */ vmpa2t pos; /* Tête de lecture */ @@ -168,7 +169,9 @@ bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t /* Préparation des accès */ - content = g_binary_format_get_content(G_BIN_FORMAT(format)); + base = G_BIN_FORMAT(format); + + content = g_binary_format_get_content(base); init_vmpa(&pos, start, address); @@ -199,6 +202,9 @@ bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true); + g_preload_info_add_instruction(base->info, instr); + + g_object_ref(G_OBJECT(instr)); ADD_STR_AS_SYM(format, symbol, instr); /* Jointure avec la chaîne précédente ? */ @@ -207,7 +213,7 @@ bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t { init_vmpa(&pos, start + i, address + i); - label = create_string_label(G_BIN_FORMAT(format), &pos, end - i); + label = create_string_label(base, &pos, end - i); g_binary_symbol_set_alt_label(symbol, label); diff --git a/src/format/format-int.h b/src/format/format-int.h index f82190f..30fb666 100644 --- a/src/format/format-int.h +++ b/src/format/format-int.h @@ -28,6 +28,7 @@ #include "format.h" +#include "preload.h" #include "../gtkext/gtkstatusstack.h" @@ -62,6 +63,8 @@ struct _GBinFormat GRWLock pt_lock; /* Accès à la liste des points */ + GPreloadInfo *info; /* Préchargements du format */ + GBinSymbol **symbols; /* Liste des symboles trouvés */ size_t symbols_count; /* Quantité de ces symboles */ GRWLock syms_lock; /* Accès à la liste de symboles*/ diff --git a/src/format/format.c b/src/format/format.c index 1eef759..d5cbda4 100644 --- a/src/format/format.c +++ b/src/format/format.c @@ -99,11 +99,20 @@ static void g_binary_format_init(GBinFormat *format) { g_rw_lock_init(&format->pt_lock); + format->info = g_preload_info_new(); + g_rw_lock_init(&format->syms_lock); } + +/* FIXME : g_object_unref(format->info); */ + +/* FIXME : g_rw_lock_clear(&format->syms_lock);*/ + + + /****************************************************************************** * * * Paramètres : format = instance à traiter. * @@ -128,12 +137,6 @@ bool g_binary_format_complete_loading(GBinFormat *format, GtkStatusStack *status } - - -/* FIXME : g_rw_lock_clear(&format->syms_lock);*/ - - - /****************************************************************************** * * * Paramètres : format = description de l'exécutable à consulter. * @@ -260,7 +263,7 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool ent void g_binary_format_preload_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status) { - preload_binary_format(PGA_FORMAT_PRELOAD, format, G_PRELOAD_INFO(ctx), status); + g_preload_info_copy(format->info, G_PRELOAD_INFO(ctx)); } diff --git a/src/format/preload.c b/src/format/preload.c index 750a67c..2eec92e 100644 --- a/src/format/preload.c +++ b/src/format/preload.c @@ -181,6 +181,35 @@ GPreloadInfo *g_preload_info_new(void) /****************************************************************************** * * +* Paramètres : src = collecte à consulter. * +* dest = collecte à constituer. [OUT] * +* * +* Description : Copie le contenu d'une collecte d'informations préchargées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_preload_info_copy(GPreloadInfo *src, GPreloadInfo *dest) +{ + void inc_preloaded_item_ref(GObject **item) + { + g_object_ref(*item); + } + + copy_flat_array_items(&src->instructions, &dest->instructions, + sizeof(GArchInstruction *), (item_notify_cb)inc_preloaded_item_ref); + + copy_flat_array_items(&src->comments, &dest->comments, + sizeof(GDbComment *), (item_notify_cb)inc_preloaded_item_ref); + +} + + +/****************************************************************************** +* * * Paramètres : info = préchargements à mettre à jour. * * * * Description : Verrouille les accès à la liste des instructions. * diff --git a/src/format/preload.h b/src/format/preload.h index d88366a..59c81b7 100644 --- a/src/format/preload.h +++ b/src/format/preload.h @@ -54,6 +54,9 @@ GType g_preload_info_get_type(void); /* Crée une nouvelle collecte d'informations préchargées. */ GPreloadInfo *g_preload_info_new(void); +/* Copie le contenu d'une collecte d'informations préchargées. */ +void g_preload_info_copy(GPreloadInfo *, GPreloadInfo *); + /* Verrouille les accès à la liste des instructions. */ void g_preload_info_lock_instructions(GPreloadInfo *); diff --git a/tests/format/elf/Makefile b/tests/format/elf/Makefile index 8695bb1..0511308 100644 --- a/tests/format/elf/Makefile +++ b/tests/format/elf/Makefile @@ -1,5 +1,5 @@ -EXECUTABLES=oob_section_name overlapping_areas +EXECUTABLES=oob_section_name overlapping_areas strings all: $(EXECUTABLES) @@ -9,6 +9,13 @@ oob_section_name: oob_section_name.o overlapping_areas: overlapping_areas.o $(ARM_CROSS)objcopy $< -O binary $@ +strings: strings.asm + grep .global strings.asm | cut -d ' ' -f 2 > keep.lst + $(ARM_CROSS)as -o strings.o strings.asm + $(ARM_CROSS)ld -s --retain-symbols-file=keep.lst -o strings strings.o + rm -f keep.lst + + %.o: %.asm $(ARM_CROSS)as -c $< -o $@ diff --git a/tests/format/elf/strings.asm b/tests/format/elf/strings.asm new file mode 100644 index 0000000..d9a75d3 --- /dev/null +++ b/tests/format/elf/strings.asm @@ -0,0 +1,77 @@ + +.data + +.global msg +.global no_arg_msg +.global got_arg_msg + +msg: + .ascii "Hello, ARM!\n" + +len = . - msg + +no_arg_msg: + .ascii "No command line argument...\n" + +no_arg_len = . - no_arg_msg + +got_arg_msg: + .ascii "Got command line argument(s)...\n" + +got_arg_len = . - got_arg_msg + +.text + +.global do_syscalls + +do_syscalls: + + /** + * syscall write(int fd, const void *buf, size_t count) + */ + + mov %r0, $1 /* fd -> stdout */ + ldr %r1, =msg /* buf -> msg */ + ldr %r2, =len /* count -> len(msg) */ + mov %r7, $4 /* write is syscall #4 */ + swi $0 /* invoke syscall */ + + /** + * syscall write(int fd, const void *buf, size_t count) + */ + + mov %r0, $2 /* fd -> stderr */ + mov %r7, $4 /* write is syscall #4 */ + + ldr %r3, [sp] /* argc */ + cmp %r3, $1 + + beq no_arg + + ldr %r1, =got_arg_msg /* buf -> msg */ + ldr %r2, =got_arg_len /* count -> len(msg) */ + + b process_arg + +no_arg: + + ldr %r1, =no_arg_msg /* buf -> msg */ + ldr %r2, =no_arg_len /* count -> len(msg) */ + +process_arg: + + swi $0 /* invoke syscall */ + + /** + * syscall exit(int status) + */ + + mov %r0, $123 /* status -> 0 */ + mov %r7, $1 /* exit is syscall #1 */ + swi $0 /* invoke syscall */ + +.global _start + +_start: + + bl do_syscalls diff --git a/tests/format/elf/strings.py b/tests/format/elf/strings.py new file mode 100644 index 0000000..0e09d75 --- /dev/null +++ b/tests/format/elf/strings.py @@ -0,0 +1,74 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + + +# S'assure que les chaînes présentes sont bien chargées en tant que telles. + + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.contents import FileContent +from pychrysalide.analysis import LoadedBinary +from pychrysalide.arch import RawInstruction +from threading import Event +import os +import sys + + +class TestElfString(ChrysalideTestCase): + """TestCase for ELF strings.""" + + @classmethod + def setUpClass(cls): + + super(TestElfString, cls).setUpClass() + + cls.log('Compile binary "strings" if needed...') + + fullname = sys.modules[cls.__module__].__file__ + dirpath = os.path.dirname(fullname) + + os.system('make -C %s strings 2>&1 > /dev/null' % dirpath) + + + def testElfStrings(self): + """Ensure available strings are loaded as strings.""" + + fullname = sys.modules[self.__class__.__module__].__file__ + filename = os.path.basename(fullname) + + baselen = len(fullname) - len(filename) + + cnt = FileContent(fullname[:baselen] + 'strings') + self.assertIsNotNone(cnt) + + binary = LoadedBinary(cnt) + self.assertIsNotNone(binary) + + def disass_done(binary): + worker.set() + + binary.connect('disassembly-done', disass_done) + + worker = Event() + + binary.analyse() + + worker.wait() + + expected = { + 'hello_arm_str' : False, + 'no_command_line_str' : False, + 'got_command_line_str' : False + } + + for sym in binary.format.symbols: + + if sym.label in expected.keys(): + + ins = binary.processor.find_instr_by_addr(sym.range.addr) + + if type(ins) is RawInstruction: + expected[sym.label] = ins.is_string + + for k in expected.keys(): + self.assertTrue(expected[k]) -- cgit v0.11.2-87-g4458