/* Chrysalide - Outil d'analyse de fichiers binaires
* db.c - constitution d'identités d'appels depuis une base de données
*
* 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 "db.h"
#include
#include
#include
#include
#include
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Ouvre la base de connaissances quant aux appels système. *
* *
* Retour : Base de données SQLite disponible ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
sqlite3 *open_syscalls_database(void)
{
sqlite3 *result; /* Base de données à renvoyer */
char *filename; /* Chemin vers la base */
int ret; /* Bilan d'un appel */
filename = find_plugin_data_file("lnxsyscalls", "linux-syscalls.db");
if (filename == NULL)
{
log_plugin_simple_message(LMT_ERROR, _("Unable to find the syscalls database"));
result = NULL;
}
else
{
ret = sqlite3_open(filename, &result);
if (ret != SQLITE_OK)
{
log_plugin_simple_message(LMT_ERROR, _("Unable to load the syscalls database"));
result = NULL;
}
free(filename);
}
return result;
}
/******************************************************************************
* *
* Paramètres : db = base de données SQLite à clôturer. *
* *
* Description : Ferme la base de connaissances quant aux appels système. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void close_syscalls_database(sqlite3 *db)
{
#ifndef NDEBUG
int ret; /* Bilan d'un appel */
#endif
#ifndef NDEBUG
ret = sqlite3_close(db);
assert(ret == SQLITE_OK);
#else
sqlite3_close(db);
#endif
}
/******************************************************************************
* *
* Paramètres : db = base de données SQLite à consulter. *
* *
* Description : Présente le contenu de la base des appels système. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void introduce_syscalls_database(sqlite3 *db)
{
const char *sql; /* Requête SQL à construire */
sqlite3_stmt *stmt; /* Déclaration mise en place */
int ret; /* Bilan d'un appel à SQLite */
sql = "SELECT arch, COUNT(nr) FROM Syscalls GROUP BY arch ORDER BY arch;";
ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (ret != SQLITE_OK)
{
log_plugin_variadic_message(LMT_ERROR, _("Can't prepare statment '%s' (ret=%d): %s"),
sql, ret, sqlite3_errmsg(db));
goto isd_exit;
}
for (ret = sqlite3_step(stmt); ret == SQLITE_ROW; ret = sqlite3_step(stmt))
{
log_plugin_variadic_message(LMT_INFO, _("The database contains %d syscalls for the '%s' architecture"),
sqlite3_column_int(stmt, 1),
(char *)sqlite3_column_text(stmt, 0));
}
sqlite3_finalize(stmt);
isd_exit:
;
}
/******************************************************************************
* *
* Paramètres : db = base de données SQLite à consulter. *
* arch = architecture visée par la procédure. *
* nr = indice de l'appel système à décrire. *
* *
* Description : Construit l'identité d'un appel système pour un indice donné.*
* *
* Retour : Structure mise en place ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
syscall_info_t *extract_from_syscalls_database(sqlite3 *db, const char *arch, unsigned int nr)
{
syscall_info_t *result; /* Description à retourner */
const char *sql; /* Requête SQL à construire */
size_t i; /* Boucle de parcours */
sqlite3_stmt *stmt; /* Déclaration mise en place */
int ret; /* Bilan d'un appel à SQLite */
const char *arg; /* Eventuel argument d'appel */
result = NULL;
sql = "SELECT name, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6, filename, line" \
" FROM Syscalls" \
" WHERE arch = ? AND nr = ?;";
ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (ret != SQLITE_OK)
{
log_plugin_variadic_message(LMT_ERROR, _("Can't prepare statment '%s' (ret=%d): %s"),
sql, ret, sqlite3_errmsg(db));
goto efsd_exit;
}
ret = sqlite3_bind_text(stmt, 1, arch, -1, NULL);
if (ret != SQLITE_OK)
{
log_plugin_variadic_message(LMT_ERROR, _("Can't bind value for parameter nb 0 in '%s' (ret=%d): %s"),
sql, ret, sqlite3_errmsg(db));
goto efsd_clean_exit;
}
ret = sqlite3_bind_int(stmt, 2, nr);
if (ret != SQLITE_OK)
{
log_plugin_variadic_message(LMT_ERROR, _("Can't bind value for parameter nb 1 in '%s' (ret=%d): %s"),
sql, ret, sqlite3_errmsg(db));
goto efsd_clean_exit;
}
ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW)
{
result = create_syscall_info(nr, (char *)sqlite3_column_text(stmt, 0));
for (i = 0; i < 6; i++)
{
arg = (char *)sqlite3_column_text(stmt, 1 + i);
if (arg != NULL)
append_arg_to_syscall_info(result, arg);
}
}
efsd_clean_exit:
sqlite3_finalize(stmt);
efsd_exit:
return result;
}