PE: Add support for parsing TLS and add TLS callback addresses to the list of entry points.

Only add the address if its valid.
This commit is contained in:
Aneesh Dogra 2016-03-11 07:56:30 +05:30 committed by pancake
parent 36e42b33fe
commit 0e3d4bf773
5 changed files with 107 additions and 1 deletions

View File

@ -103,6 +103,11 @@ static PE_DWord bin_pe_rva_to_va(RBinPEObj* bin, PE_DWord rva) {
return bin->nt_headers->optional_header.ImageBase + rva;
}
static PE_DWord bin_pe_va_to_rva(RBinPEObj* bin, PE_DWord va) {
if (va < bin->nt_headers->optional_header.ImageBase) return va;
return va - bin->nt_headers->optional_header.ImageBase;
}
#if 0
static PE_DWord PE_(r_bin_pe_paddr_to_vaddr)(struct PE_(r_bin_pe_obj_t)* bin, PE_DWord paddr)
{
@ -824,6 +829,57 @@ static int bin_pe_init_resource(struct PE_(r_bin_pe_obj_t)* bin) {
return true;
}
static void bin_pe_store_tls_callbacks(struct PE_(r_bin_pe_obj_t) *bin, PE_DWord callbacks) {
PE_DWord paddr;
int count = 0;
PE_DWord addressOfTLSCallback = 1;
char *key;
while (addressOfTLSCallback != 0) {
if (r_buf_read_at (bin->b, callbacks, (ut8*)&addressOfTLSCallback, sizeof (addressOfTLSCallback)) != sizeof (addressOfTLSCallback)) {
eprintf("Warning: read (tls_callback)\n");
return;
}
if (addressOfTLSCallback == 0) break;
if (bin->nt_headers->optional_header.SizeOfImage) {
int rva_callback = bin_pe_va_to_rva (bin, (PE_DWord) addressOfTLSCallback);
if (rva_callback > bin->nt_headers->optional_header.SizeOfImage) break;
}
key = sdb_fmt (0, "pe.tls_callback%d_vaddr", count);
sdb_num_set (bin->kv, key, addressOfTLSCallback, 0);
key = sdb_fmt (0, "pe.tls_callback%d_paddr", count);
paddr = bin_pe_rva_to_paddr (bin, bin_pe_va_to_rva(bin, (PE_DWord) addressOfTLSCallback));
sdb_num_set (bin->kv, key, paddr, 0);
count++;
callbacks += sizeof (addressOfTLSCallback);
}
}
static int bin_pe_init_tls(struct PE_(r_bin_pe_obj_t) *bin) {
PE_(image_tls_directory) *image_tls_directory;
PE_(image_data_directory) *data_dir_tls = \
&bin->nt_headers->optional_header.DataDirectory[ \
PE_IMAGE_DIRECTORY_ENTRY_TLS];
PE_DWord tls_paddr = bin_pe_rva_to_paddr (bin,
data_dir_tls->VirtualAddress);
image_tls_directory = R_NEW (PE_(image_tls_directory));
if (r_buf_read_at (bin->b, tls_paddr, (ut8*)image_tls_directory, sizeof (PE_(image_tls_directory))) != sizeof (PE_(image_tls_directory))) {
eprintf ("Warning: read (image_tls_directory)\n");
free(image_tls_directory);
return 0;
}
bin->tls_directory = image_tls_directory;
if (!image_tls_directory->AddressOfCallBacks) return 0;
PE_DWord callbacks_paddr = bin_pe_rva_to_paddr (bin, bin_pe_va_to_rva(bin, (PE_DWord) image_tls_directory->AddressOfCallBacks));
bin_pe_store_tls_callbacks (bin, callbacks_paddr);
return 0;
}
static void free_Var(Var *var) {
if (var) {
free(var->szKey);
@ -1693,6 +1749,8 @@ static int bin_pe_init(struct PE_(r_bin_pe_obj_t)* bin) {
bin_pe_init_imports(bin);
bin_pe_init_exports(bin);
bin_pe_init_resource(bin);
bin_pe_init_tls(bin);
PE_(r_bin_store_all_resource_version_info)(bin);
bin->relocs = NULL;
return true;

View File

@ -70,6 +70,7 @@ struct PE_(r_bin_pe_obj_t) {
PE_(image_section_header) *section_header;
PE_(image_export_directory) *export_directory;
PE_(image_import_directory) *import_directory;
PE_(image_tls_directory) *tls_directory;
Pe_image_resource_directory *resource_directory;
PE_(image_delay_import_directory) *delay_import_directory;
// these values define the real offset into the untouched binary

View File

@ -289,6 +289,15 @@ typedef struct {
ut32 TimeStamp;
} Pe32_image_delay_import_directory, Pe64_image_delay_import_directory;
typedef struct {
ut32 StartAddressOfRawData;
ut32 EndAddressOfRawData;
ut32 AddressOfIndex;
ut32 AddressOfCallBacks;
ut32 SizeOfZeroFill;
ut32 Characteristics;
} Pe32_image_tls_directory, Pe64_image_tls_directory;
typedef struct {
ut32 Signature;
Pe32_image_file_header file_header;

View File

@ -70,6 +70,33 @@ static RBinAddr* binsym(RBinFile *arch, int type) {
return ret;
}
static void add_tls_callbacks(RBinFile *arch, RList* list) {
PE_DWord paddr, vaddr;
int count = 0;
RBinAddr *ptr = NULL;
struct PE_(r_bin_pe_obj_t) *bin = (struct PE_(r_bin_pe_obj_t) *) (arch->o->bin_obj);
char *key;
do {
key = sdb_fmt (0, "pe.tls_callback%d_paddr", count);
paddr = sdb_num_get (bin->kv, key, 0);
if (!paddr) break;
key = sdb_fmt (0, "pe.tls_callback%d_vaddr", count);
vaddr = sdb_num_get (bin->kv, key, 0);
if (!vaddr) break;
if ((ptr = R_NEW0 (RBinAddr))) {
ptr->paddr = paddr;
ptr->vaddr = vaddr;
ptr->type = R_BIN_ENTRY_TYPE_TLS;
r_list_append (list, ptr);
}
count++;
} while (vaddr != 0);
}
static RList* entries(RBinFile *arch) {
RList* ret;
RBinAddr *ptr = NULL;
@ -80,12 +107,17 @@ static RList* entries(RBinFile *arch) {
ret->free = free;
if (!(entry = PE_(r_bin_pe_get_entrypoint) (arch->o->bin_obj)))
return ret;
if ((ptr = R_NEW (RBinAddr))) {
if ((ptr = R_NEW0 (RBinAddr))) {
ptr->paddr = entry->paddr;
ptr->vaddr = entry->vaddr;
ptr->type = R_BIN_ENTRY_TYPE_PROGRAM;
r_list_append (ret, ptr);
}
free (entry);
// get TLS callback addresses
add_tls_callbacks (arch, ret);
return ret;
}

View File

@ -29,6 +29,11 @@ R_LIB_VERSION_HEADER (r_bin);
#define R_BIN_DBG_SYMS 0x08
#define R_BIN_DBG_RELOCS 0x10
#define R_BIN_ENTRY_TYPE_PROGRAM 0
#define R_BIN_ENTRY_TYPE_INIT 1
#define R_BIN_ENTRY_TYPE_FINI 2
#define R_BIN_ENTRY_TYPE_TLS 3
#define R_BIN_SIZEOF_STRINGS 512
#define R_BIN_MAX_ARCH 1024
@ -71,6 +76,7 @@ enum {
typedef struct r_bin_addr_t {
ut64 vaddr;
ut64 paddr;
int type;
} RBinAddr;
typedef struct r_bin_hash_t {