|
|
feffc7 |
/*****************************************************************************/
|
|
|
feffc7 |
/* pemagination: a (virtual) tour into portable bits and executable bytes */
|
|
|
feffc7 |
/* Copyright (C) 2013,2014,2015 Z. Gilboa */
|
|
|
feffc7 |
/* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */
|
|
|
feffc7 |
/*****************************************************************************/
|
|
|
feffc7 |
|
|
|
feffc7 |
#include <psxtypes/psxtypes.h>
|
|
|
feffc7 |
#include <pemagine/pe_consts.h>
|
|
|
feffc7 |
#include <pemagine/pe_structs.h>
|
|
|
feffc7 |
#include <pemagine/pemagine.h>
|
|
|
feffc7 |
#include "pe_impl.h"
|
|
|
feffc7 |
|
|
|
feffc7 |
static __inline__ int pe_addr_within_bounds(void * addr, void * bottom, void * top)
|
|
|
feffc7 |
{
|
|
|
feffc7 |
return (((uintptr_t)addr >= (uintptr_t)bottom) && ((uintptr_t)addr < (uintptr_t)top));
|
|
|
feffc7 |
}
|
|
|
feffc7 |
|
|
|
feffc7 |
pe_api
|
|
|
feffc7 |
int pe_get_export_symbol_info(
|
|
|
feffc7 |
const void * base,
|
|
|
feffc7 |
const char * name,
|
|
|
feffc7 |
struct pe_export_sym * sym)
|
|
|
feffc7 |
{
|
|
|
feffc7 |
struct pe_export_hdr * exp_hdr;
|
|
|
feffc7 |
|
|
|
8860e9 |
ssize_t len;
|
|
|
feffc7 |
uint32_t * rva_offset;
|
|
|
feffc7 |
uintptr_t * addr_offset;
|
|
|
feffc7 |
|
|
|
feffc7 |
uint32_t sec_size;
|
|
|
feffc7 |
void * sec_addr_cap;
|
|
|
feffc7 |
|
|
|
feffc7 |
uint32_t * fn_addr;
|
|
|
feffc7 |
uint32_t * fn_names;
|
|
|
feffc7 |
uint16_t * fn_ordinals;
|
|
|
feffc7 |
uint32_t * addr_entries;
|
|
|
feffc7 |
uint32_t * name_entries;
|
|
|
feffc7 |
|
|
|
feffc7 |
char * exp_name;
|
|
|
feffc7 |
const char * src;
|
|
|
feffc7 |
const char * dst;
|
|
|
feffc7 |
size_t match;
|
|
|
feffc7 |
|
|
|
feffc7 |
uint32_t lower;
|
|
|
feffc7 |
uint32_t upper;
|
|
|
feffc7 |
uint32_t idx;
|
|
|
feffc7 |
|
|
|
feffc7 |
/* initialize pe_exp_item */
|
|
|
feffc7 |
sym->ordinal_base = (uint32_t *)0;
|
|
|
feffc7 |
sym->ordinal = (uint16_t *)0;
|
|
|
feffc7 |
sym->addr = (void *)0;
|
|
|
feffc7 |
sym->forwarder_rva = (void *)0;
|
|
|
feffc7 |
sym->name = (char *)0;
|
|
|
feffc7 |
sym->status = 0;
|
|
|
feffc7 |
|
|
|
feffc7 |
if (!(exp_hdr = pe_get_image_export_hdr_addr(base,&sec_size)))
|
|
|
feffc7 |
return -1;
|
|
|
feffc7 |
|
|
|
feffc7 |
sec_addr_cap = pe_va_from_rva(exp_hdr,sec_size);
|
|
|
feffc7 |
rva_offset = (uint32_t *)(exp_hdr->export_addr_tbl_rva);
|
|
|
feffc7 |
fn_addr = (uint32_t *)pe_va_from_rva(base,*rva_offset);
|
|
|
feffc7 |
|
|
|
feffc7 |
rva_offset = (uint32_t *)(exp_hdr->name_ptr_rva);
|
|
|
feffc7 |
fn_names = (uint32_t *)pe_va_from_rva(base,*rva_offset);
|
|
|
feffc7 |
|
|
|
feffc7 |
rva_offset = (uint32_t *)(exp_hdr->ordinal_tbl_rva);
|
|
|
feffc7 |
fn_ordinals = (uint16_t *)pe_va_from_rva(base,*rva_offset);
|
|
|
feffc7 |
|
|
|
feffc7 |
addr_entries = (uint32_t *)exp_hdr->addr_tbl_entries;
|
|
|
feffc7 |
name_entries = (uint32_t *)exp_hdr->num_of_name_ptrs;
|
|
|
feffc7 |
|
|
|
feffc7 |
/* by ordinal? */
|
|
|
feffc7 |
if ((intptr_t)name < 0x10000) {
|
|
|
feffc7 |
sym->ordinal_base = (uint32_t *)exp_hdr->ordinal_base;
|
|
|
feffc7 |
|
|
|
feffc7 |
/* the array is zero-based, but ordinals are normally one-based... */
|
|
|
feffc7 |
if (((intptr_t)name - *sym->ordinal_base + 1) > *addr_entries)
|
|
|
feffc7 |
return -1;
|
|
|
feffc7 |
|
|
|
feffc7 |
rva_offset = (uint32_t *)pe_va_from_rva(fn_addr,((uintptr_t)name-*sym->ordinal_base)*sizeof(uint32_t));
|
|
|
feffc7 |
addr_offset = (uintptr_t *)pe_va_from_rva(base,*rva_offset);
|
|
|
feffc7 |
|
|
|
feffc7 |
if (pe_addr_within_bounds(addr_offset,exp_hdr,sec_addr_cap)) {
|
|
|
feffc7 |
sym->forwarder_rva = 0;
|
|
|
feffc7 |
sym->addr = addr_offset;
|
|
|
feffc7 |
} else
|
|
|
feffc7 |
/* todo: resolve forwarder address */
|
|
|
feffc7 |
sym->addr = addr_offset;
|
|
|
feffc7 |
|
|
|
feffc7 |
return 0;
|
|
|
feffc7 |
}
|
|
|
feffc7 |
|
|
|
feffc7 |
if ((len = pe_impl_strlen_ansi(name)) < 0)
|
|
|
feffc7 |
return -1;
|
|
|
feffc7 |
|
|
|
feffc7 |
len++;
|
|
|
feffc7 |
lower = 0;
|
|
|
feffc7 |
upper = *name_entries;
|
|
|
feffc7 |
|
|
|
feffc7 |
while (lower < upper) {
|
|
|
feffc7 |
idx = (lower + upper) / 2;
|
|
|
feffc7 |
rva_offset = (uint32_t *)pe_va_from_rva(fn_names,idx*sizeof(uint32_t));
|
|
|
feffc7 |
exp_name = (char *)pe_va_from_rva(base,*rva_offset);
|
|
|
feffc7 |
|
|
|
feffc7 |
src = name;
|
|
|
feffc7 |
dst = exp_name;
|
|
|
feffc7 |
|
|
|
feffc7 |
for (match=0; (match
|
|
|
feffc7 |
src++;
|
|
|
feffc7 |
dst++;
|
|
|
feffc7 |
}
|
|
|
feffc7 |
|
|
|
feffc7 |
if (match == len) {
|
|
|
feffc7 |
sym->ordinal_base = (uint32_t *)exp_hdr->ordinal_base;
|
|
|
feffc7 |
sym->ordinal = (uint16_t *)pe_va_from_rva(fn_ordinals,idx*sizeof(uint16_t));
|
|
|
feffc7 |
|
|
|
feffc7 |
rva_offset = (uint32_t *)pe_va_from_rva(fn_addr,(*sym->ordinal)*sizeof(uint32_t));
|
|
|
feffc7 |
addr_offset = (uintptr_t *)pe_va_from_rva(base,*rva_offset);
|
|
|
feffc7 |
|
|
|
feffc7 |
if (pe_addr_within_bounds(addr_offset,exp_hdr,sec_addr_cap)) {
|
|
|
feffc7 |
/* todo: resolve forwarder address */
|
|
|
feffc7 |
sym->forwarder_rva = 0;
|
|
|
feffc7 |
sym->addr = 0;
|
|
|
feffc7 |
} else {
|
|
|
feffc7 |
sym->forwarder_rva = 0;
|
|
|
feffc7 |
sym->addr = addr_offset;
|
|
|
feffc7 |
}
|
|
|
feffc7 |
|
|
|
feffc7 |
return 0;
|
|
|
feffc7 |
}
|
|
|
feffc7 |
|
|
|
feffc7 |
else {
|
|
|
feffc7 |
if (*src > *dst)
|
|
|
feffc7 |
lower = idx + 1;
|
|
|
feffc7 |
else
|
|
|
feffc7 |
upper = idx;
|
|
|
feffc7 |
}
|
|
|
feffc7 |
}
|
|
|
feffc7 |
|
|
|
feffc7 |
/* export name not found */
|
|
|
feffc7 |
return -1;
|
|
|
feffc7 |
}
|