/*****************************************************************************/
/* pemagination: a (virtual) tour into portable bits and executable bytes */
/* Copyright (C) 2013,2014,2015 Z. Gilboa */
/* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */
/*****************************************************************************/
#include <psxtypes/psxtypes.h>
#include <pemagine/pemagine.h>
/* private args structure */
struct pe_symbol_name_ctx {
const void * addr;
char * name;
};
/* private forward declarations */
static int pe_enum_exports_callback(
const void * base,
struct pe_raw_export_hdr * exp_hdr,
struct pe_export_sym * sym,
enum pe_callback_reason reason,
void * context);
#if defined (__NT32)
static char * pe_get_imported_symbol_info_32(
const void * sym_addr,
struct pe_ldr_tbl_entry ** ldr_tbl_entry);
#endif
#if defined (__NT64)
static char * pe_get_imported_symbol_info_64(
const void * sym_addr,
struct pe_ldr_tbl_entry ** ldr_tbl_entry);
#endif
pe_api
char * pe_get_symbol_name(const void * base, const void * sym_addr)
{
struct pe_export_sym exp_item;
struct pe_symbol_name_ctx ctx;
ctx.name = 0;
ctx.addr = sym_addr;
pe_enum_image_exports(
base,
pe_enum_exports_callback,
&exp_item,
&ctx);
return ctx.name;
}
pe_api
char * pe_get_import_symbol_info(
const void * sym_addr,
struct pe_ldr_tbl_entry ** ldr_tbl_entry)
{
#if defined(__NT32)
return pe_get_imported_symbol_info_32(
sym_addr,
ldr_tbl_entry);
#elif defined (__NT64)
return pe_get_imported_symbol_info_64(
sym_addr,
ldr_tbl_entry);
#endif
}
static int pe_enum_exports_callback(
const void * base,
struct pe_raw_export_hdr * exp_hdr,
struct pe_export_sym * sym,
enum pe_callback_reason reason,
void * context)
{
struct pe_symbol_name_ctx * ctx;
(void)base;
(void)exp_hdr;
if (reason != PE_CALLBACK_REASON_ITEM)
return 1;
ctx = (struct pe_symbol_name_ctx *)context;
if (sym->addr == ctx->addr) {
ctx->name = sym->name;
return 0;
} else
return 1;
}
#ifdef __NT32
static char * pe_get_imported_symbol_info_32(
const void * sym_addr,
struct pe_ldr_tbl_entry ** ldr_tbl_entry)
{
struct symbol {
unsigned char call;
unsigned char ds;
unsigned char sym_addr[4];
unsigned char padding[2];
};
char * fn_name;
struct pe_ldr_tbl_entry * mod_info;
void * mod_base;
uint32_t *** sym_redirected_addr;
struct symbol * sym;
fn_name = 0;
sym = (struct symbol *)sym_addr;
if ((sym->call == 0xff) && (sym->ds == 0x25))
if ((sym_redirected_addr = (uint32_t ***)sym->sym_addr))
if ((mod_info = pe_get_symbol_module_info(
**sym_redirected_addr)))
if ((mod_base = mod_info->dll_base))
fn_name = pe_get_symbol_name(
mod_base,
**sym_redirected_addr);
if (fn_name && ldr_tbl_entry)
*ldr_tbl_entry = mod_info;
return fn_name;
}
#endif
#ifdef __NT64
static char * pe_get_imported_symbol_info_64(
const void * sym_addr,
struct pe_ldr_tbl_entry ** ldr_tbl_entry)
{
struct symbol {
unsigned char call;
unsigned char ds;
unsigned char sym_addr[4];
unsigned char padding[2];
};
char * fn_name;
struct pe_ldr_tbl_entry * mod_info;
void * mod_base;
uint32_t * sym_offset;
uint32_t offset;
struct symbol * sym;
fn_name = 0;
sym = (struct symbol *)sym_addr;
if ((sym->call == 0xff) && (sym->ds == 0x25)) {
if ((sym_offset = (uint32_t *)sym->sym_addr)) {
offset = *sym_offset;
sym_addr = *(void **)(offset + (uintptr_t)(++sym_offset));
} else
sym_addr = 0;
if (sym_addr && (mod_info = pe_get_symbol_module_info(sym_addr)))
if ((mod_base = mod_info->dll_base))
fn_name = pe_get_symbol_name(
mod_base,
sym_addr);
}
if (fn_name && ldr_tbl_entry)
*ldr_tbl_entry = mod_info;
return fn_name;
}
#endif