/* Chrysalide - Outil d'analyse de fichiers binaires
* symbols.c - gestion des symboles d'un PE
*
* Copyright (C) 2010-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 Chrysalide. If not, see .
*/
#include "symbols.h"
#include
#include
#include "pe-int.h"
#include "routine.h"
/* Charge en mémoire la liste humaine des symboles exportés. */
static bool load_pe_exported_symbols(GPeFormat *, wgroup_id_t, GtkStatusStack *);
/* Charge en mémoire la liste humaine des symboles importés. */
static bool load_pe_imported_symbols(GPeFormat *, wgroup_id_t, GtkStatusStack *);
/* Assure l'inscription du point d'entrée d'un binaire PE. */
static bool load_pe_entry_point(GPeFormat *, GtkStatusStack *);
/******************************************************************************
* *
* Paramètres : format = format chargé dont l'analyse est lancée. *
* gid = groupe de travail dédié. *
* status = barre de statut à tenir informée. *
* *
* Description : Charge en mémoire la liste humaine des symboles exportés. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool load_pe_exported_symbols(GPeFormat *format, wgroup_id_t gid, GtkStatusStack *status)
{
bool result; /* Bilan à retourner */
image_export_directory *export; /* Répertoire de type 0 */
const image_data_directory *dir; /* Localisation du répertoire */
GBinFormat *base; /* Version basique du format */
GExeFormat *exe; /* Autre vision du format */
bool ret; /* Bilan d'un traitement */
vmpa2t functions; /* Localisation des adresses */
vmpa2t names; /* Localisation de RVA de noms */
vmpa2t ordinals; /* Localisation des ordinaux */
const GBinContent *content; /* Contenu binaire à lire */
uint32_t i; /* Boucle de parcours */
uint32_t rva; /* Adresse relative à traiter */
vmpa2t pos; /* Position correspondante */
const bin_t *name; /* Pointeur vers des données */
uint16_t ordinal; /* Indice de l'exportation */
bool forwarded; /* Le symbole est renvoyé ? */
GPeExportedRoutine *routine; /* Nouvelle routine trouvée */
GBinSymbol *symbol; /* Equivalence en symbole */
mrange_t range; /* Couverture mémoire associée */
result = false;
export = g_pe_format_get_directory(format, IMAGE_DIRECTORY_ENTRY_EXPORT);
if (export == NULL) goto exit;
dir = g_pe_format_get_directories(format, NULL);
dir += IMAGE_DIRECTORY_ENTRY_EXPORT;
base = G_BIN_FORMAT(format);
exe = G_EXE_FORMAT(format);
ret = g_exe_format_translate_address_into_vmpa(exe, export->address_of_functions, &functions);
if (!ret) goto exit_loading;
ret = g_exe_format_translate_address_into_vmpa(exe, export->address_of_names, &names);
if (!ret) goto exit_loading;
ret = g_exe_format_translate_address_into_vmpa(exe, export->address_of_name_ordinals, &ordinals);
if (!ret) goto exit_loading;
content = G_KNOWN_FORMAT(format)->content;
for (i = 0; i < export->number_of_names; i++)
{
/* Dénomination */
ret = g_binary_content_read_u32(content, &names, SRE_LITTLE, &rva);
if (!ret) goto exit_loading;
ret = g_exe_format_translate_address_into_vmpa(exe, rva, &pos);
if (!ret) goto exit_loading;
name = g_binary_content_get_raw_access(content, &pos, 1);
if (name == NULL) goto exit_loading;
/* Ordinal */
ret = g_binary_content_read_u16(content, &ordinals, SRE_LITTLE, &ordinal);
if (!ret) goto exit_loading;
ordinal += export->base;
/* Adresse */
copy_vmpa(&pos, &functions);
advance_vmpa(&pos, ordinal * sizeof(uint32_t));
ret = g_binary_content_read_u32(content, &pos, SRE_LITTLE, &rva);
if (!ret) goto exit_loading;
/**
* Entrée de type "Forwarder RVA" ?
*/
forwarded = (dir->virtual_address <= rva && rva < (dir->virtual_address + dir->size));
ret = g_exe_format_translate_address_into_vmpa(exe, rva, &pos);
if (!ret) continue;
/* Mise en place du symbole */
routine = g_pe_exported_routine_new((char *)name);
g_pe_exported_routine_set_ordinal(routine, ordinal);
symbol = G_BIN_SYMBOL(routine);
if (forwarded)
g_binary_symbol_set_flag(symbol, PSF_FORWARDED);
g_binary_symbol_set_status(symbol, SSS_EXPORTED);
init_mrange(&range, &pos, 0);
g_binary_symbol_set_range(symbol, &range);
g_binary_format_add_symbol(base, symbol);
}
result = true;
exit_loading:
free(export);
exit:
return result;
}
/******************************************************************************
* *
* Paramètres : format = format chargé dont l'analyse est lancée. *
* gid = groupe de travail dédié. *
* status = barre de statut à tenir informée. *
* *
* Description : Charge en mémoire la liste humaine des symboles importés. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool load_pe_imported_symbols(GPeFormat *format, wgroup_id_t gid, GtkStatusStack *status)
{
bool result; /* Bilan à retourner */
bool is_32b; /* Exécutable 32 bits ? */
image_import_descriptor *imports; /* Répertoire de type 1 */
GBinFormat *base; /* Version basique du format */
GExeFormat *exe; /* Autre vision du format */
const GBinContent *content; /* Contenu binaire à lire */
size_t counter; /* Compteur d'importations */
image_import_descriptor *iter; /* Boucle de parcours */
vmpa2t dll; /* Nom de la DLL concernée */
bool ret; /* Bilan d'un traitement */
const bin_t *library; /* Pointeur vers des données */
vmpa2t lookup; /* Informations d'importation */
vmpa2t overwritten; /* Emplacement d'adresse finale*/
uint32_t val32; /* Indications sur 32 bits */
uint64_t val64; /* Indications sur 64 bits */
uint32_t rva; /* Adresse relative à traiter */
vmpa2t name; /* Désignation humaine */
const bin_t *hint; /* Pointeur vers des données */
GPeImportedRoutine *routine; /* Nouvelle routine trouvée */
GBinSymbol *symbol; /* Equivalence en symbole */
mrange_t range; /* Couverture mémoire associée */
result = false;
is_32b = g_pe_format_get_is_32b(format);
imports = g_pe_format_get_directory(format, IMAGE_DIRECTORY_ENTRY_IMPORT);
if (imports == NULL) goto exit;
base = G_BIN_FORMAT(format);
exe = G_EXE_FORMAT(format);
content = G_KNOWN_FORMAT(format)->content;
counter = 0;
for (iter = imports; iter->original_first_thunk != 0; iter++)
{
/* Bibliothèque impactée */
ret = g_exe_format_translate_address_into_vmpa(exe, iter->module_name, &dll);
if (!ret) goto exit_loading;
library = g_binary_content_get_raw_access(content, &dll, 1);
if (library == NULL) goto exit_loading;
/* Liste des fonctions importées */
ret = g_exe_format_translate_address_into_vmpa(exe, iter->original_first_thunk, &lookup);
if (!ret) goto exit_loading;
ret = g_exe_format_translate_address_into_vmpa(exe, iter->first_thunk, &overwritten);
if (!ret) goto exit_loading;
do
{
if (is_32b)
{
ret = g_binary_content_read_u32(content, &lookup, SRE_LITTLE, &val32);
if (!ret) goto exit_loading;
val64 = ((uint64_t)(val32 & 0x80000000)) << 32 | val32;
}
else
{
ret = g_binary_content_read_u64(content, &lookup, SRE_LITTLE, &val64);
if (!ret) goto exit_loading;
}
if (val64 == 0)
break;
if (val64 & 0x8000000000000000)
{
routine = g_pe_imported_routine_new(NULL, counter++);
g_pe_exported_routine_set_ordinal(G_PE_EXPORTED_ROUTINE(routine), val64 & 0xffff);
}
else
{
rva = (val64 & 0x7fffffff);
ret = g_exe_format_translate_address_into_vmpa(exe, rva, &name);
if (!ret) goto exit_loading;
hint = g_binary_content_get_raw_access(content, &name, 3);
if (hint == NULL) goto exit_loading;
hint += 2;
//routine = g_binary_format_decode_routine(base, hint);
routine = g_pe_imported_routine_new((char *)hint, counter++);
}
g_pe_imported_routine_set_library(routine, (char *)library);
symbol = G_BIN_SYMBOL(routine);
g_binary_symbol_set_status(symbol, SSS_IMPORTED);
init_mrange(&range, &overwritten, sizeof(uint32_t));
advance_vmpa(&overwritten, sizeof(uint32_t));
g_binary_symbol_set_range(symbol, &range);
g_binary_format_add_symbol(base, symbol);
}
while (true);
}
result = true;
exit_loading:
free(imports);
exit:
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* status = barre de statut à tenir informée. *
* *
* Description : Assure l'inscription du point d'entrée d'un binaire PE. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool load_pe_entry_point(GPeFormat *format, GtkStatusStack *status)
{
bool result; /* Bilan à renvoyer */
activity_id_t msg; /* Message de progression */
const image_nt_headers *headers; /* Informations d'entête */
virt_t ep; /* Point d'entrée détecté */
vmpa2t addr; /* Localisation d'une routine */
GBinFormat *base; /* Autre version du format */
GBinSymbol *symbol; /* Nouveau symbole construit */
GBinRoutine *routine; /* Routine à associer au point */
mrange_t range; /* Couverture mémoire associée */
msg = gtk_status_stack_add_activity(status, _("Registering entry point..."), 0);
headers = g_pe_format_get_nt_headers(format);
ep = headers->optional_header.header_32.address_of_entry_point;
result = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), ep, &addr);
if (!result) goto exit;
base = G_BIN_FORMAT(format);
if (!g_binary_format_find_symbol_at(base, &addr, &symbol))
{
routine = g_binary_format_decode_routine(base, "entry_point");
symbol = G_BIN_SYMBOL(routine);
g_object_ref(G_OBJECT(symbol));
init_mrange(&range, &addr, 0);
g_binary_symbol_set_range(symbol, &range);
g_binary_format_add_symbol(base, symbol);
}
g_binary_symbol_set_stype(symbol, STP_ENTRY_POINT);
g_object_unref(G_OBJECT(symbol));
/* Comptabilisation pour le désassemblage brut */
g_binary_format_register_code_point(base, get_virt_addr(&addr), DPL_ENTRY_POINT);
exit:
gtk_status_stack_remove_activity(status, msg);
return result;
}
/******************************************************************************
* *
* Paramètres : format = format chargé dont l'analyse est lancée. *
* gid = groupe de travail dédié. *
* status = barre de statut à tenir informée. *
* *
* Description : Charge en mémoire la liste humaine des symboles. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool load_pe_symbols(GPeFormat *format, wgroup_id_t gid, GtkStatusStack *status)
{
bool result; /* Bilan à retourner */
result = load_pe_exported_symbols(format, gid, status);
if (result)
result = load_pe_imported_symbols(format, gid, status);
/* Symbole d'entrée, si encore besoin */
if (result)
result = load_pe_entry_point(format, status);
return result;
}