/* Chrysalide - Outil d'analyse de fichiers binaires * hops_armv7.c - recherche d'appels système spécifiques à ARMv7 * * Copyright (C) 2018 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 Chrysalide. If not, see . */ #include "hops_armv7.h" #include #include #include /* Détermine si l'instruction lance un appel syystème. */ static bool is_armv7_linux_syscall(GArchInstruction *); /* Identifie le numéro d'appel système en cours de manipulation. */ static bool resolve_armv7_linux_syscall_number(tracked_path *, GArchProcessor *, const hunting_ops *, unsigned int *); /* Marque les registres associés aux n premiers arguments. */ static bool look_for_armv7_linux_syscall_args(tracked_path *, size_t, size_t); /* Commente autant que possible un appel système brut. */ static void comment_armv7_linux_syscall(tracked_path *, size_t, syscall_info_t *, comment_writer *); /****************************************************************************** * * * Paramètres : - * * * * Description : Fournit les opérations spécifiques à ARMv7 pour une chasse. * * * * Retour : Ensemble d'opérations pour une chasse aux appels système. * * * * Remarques : - * * * ******************************************************************************/ const hunting_ops *get_armv7_hunting_ops(void) { static const hunting_ops armv7_hops = { .arch = "arm", .is_syscall = is_armv7_linux_syscall, .resolve_nr = resolve_armv7_linux_syscall_number, .look_for_args = look_for_armv7_linux_syscall_args, .comment = comment_armv7_linux_syscall }; return &armv7_hops; } /****************************************************************************** * * * Paramètres : instr = instruction à analyser. * * * * Description : Détermine si l'instruction lance un appel syystème. * * * * Retour : Bilan de l'analyse : true s'il s'agit bien d'un appel. * * * * Remarques : - * * * ******************************************************************************/ static bool is_armv7_linux_syscall(GArchInstruction *instr) { bool result; /* Conclusion à diffuser */ const char *kwd; /* Désignation d'instruction */ kwd = g_arch_instruction_get_keyword(instr); result = (strcmp(kwd, "svc") == 0); return result; } /****************************************************************************** * * * Paramètres : exec = suivi de l'utilisation des registres. * * proc = processeur de l'architecture pour les instructions. * * hops = opérations spécialement adaptées à une architecture. * * nr = numéro de l'appel système identifié. [OUT] * * * * Description : Identifie le numéro d'appel système en cours de manipulation.* * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool resolve_armv7_linux_syscall_number(tracked_path *exec, GArchProcessor *proc, const hunting_ops *hops, unsigned int *nr) { bool result; /* Bilan à faire remonter */ GArchRegister *reg; /* Registre portant le numéro */ bool got_nr; /* Bilan d'une recherche */ GArchInstruction *instr; /* Instruction d'importance */ const char *kwd; /* Désignation d'instruction */ GArchOperand *op; /* Opérande avec une constante */ result = false; /* On vise r7... */ reg = g_armv7_basic_register_new(7); mark_register_in_tracker(exec, 0, reg, NULL); assert(count_register_tracker_stacks(exec) == 1); got_nr = look_for_registers(exec, 0, proc, hops); if (got_nr) { instr = get_register_write_location(exec, 0, reg); kwd = g_arch_instruction_get_keyword(instr); /* ... et uniquement les instructions 'mov r7, ' */ if (strncmp(kwd, "mov", 3) != 0) goto ralsn_exit; op = g_arch_instruction_get_operand(instr, 1); if (!G_IS_IMM_OPERAND(op)) goto ralsn_exit; *nr = g_imm_operand_get_raw_value(G_IMM_OPERAND(op)); result = true; } ralsn_exit: g_object_unref(G_OBJECT(reg)); return result; } /****************************************************************************** * * * Paramètres : exec = chemin d'exécution à préparer. * * sid = identifiant de la pile d'exécution à traiter. * * argc = nombre d'arguments à repérer. * * * * Description : Marque les registres associés aux n premiers arguments. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool look_for_armv7_linux_syscall_args(tracked_path *exec, size_t sid, size_t argc) { bool result; /* Bilan à faire remonter */ size_t i; /* Boucle de parcours */ GArchRegister *reg; /* Registre portant le numéro */ /** * man 2 syscall : * * arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 * ────────────────────────────────────────────────────────── * arm/OABI a1 a2 a3 a4 v1 v2 v3 * arm/EABI r0 r1 r2 r3 r4 r5 r6 */ result = (argc <= 7); if (result) for (i = 0; i < argc; i++) { reg = g_armv7_basic_register_new(i); mark_register_in_tracker(exec, sid, reg, NULL); g_object_ref(G_OBJECT(reg)); } return result; } /****************************************************************************** * * * Paramètres : exec = chemin d'exécution identifié. * * sid = identifiant de la pile d'exécution à traiter. * * info = fiche d'identité d'un appel système. * * writer = conservateur des commentaires à écrire au final. * * * * Description : Commente autant que possible un appel système brut. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void comment_armv7_linux_syscall(tracked_path *exec, size_t sid, syscall_info_t *info, comment_writer *writer) { GArchRegister *reg; /* Registre intervenant */ GArchInstruction *instr; /* Instruction impliquée */ size_t i; /* Boucle de parcours */ /* Type d'appel système */ reg = g_armv7_basic_register_new(7); instr = get_register_write_location(exec, sid, reg); if (instr != NULL) { add_comment_at(writer, info->name, instr); g_object_unref(G_OBJECT(instr)); } g_object_unref(G_OBJECT(reg)); /* Eventuels arguments */ for (i = 0; i < info->argc; i++) { reg = g_armv7_basic_register_new(i); instr = get_register_write_location(exec, sid, reg); if (instr != NULL) { add_comment_at(writer, info->argv[i], instr); g_object_unref(G_OBJECT(instr)); } g_object_unref(G_OBJECT(reg)); } }