diff --git a/libr/bin/format/pe/pe.c b/libr/bin/format/pe/pe.c index 99bfbac4f0..2768dde129 100644 --- a/libr/bin/format/pe/pe.c +++ b/libr/bin/format/pe/pe.c @@ -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; diff --git a/libr/bin/format/pe/pe.h b/libr/bin/format/pe/pe.h index 309d8a7e22..6ddec6c043 100644 --- a/libr/bin/format/pe/pe.h +++ b/libr/bin/format/pe/pe.h @@ -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 diff --git a/libr/bin/format/pe/pe_specs.h b/libr/bin/format/pe/pe_specs.h index 57632039bb..53e06c8f48 100644 --- a/libr/bin/format/pe/pe_specs.h +++ b/libr/bin/format/pe/pe_specs.h @@ -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; diff --git a/libr/bin/p/bin_pe.c b/libr/bin/p/bin_pe.c index 8625cef1ff..cd8dd13cca 100644 --- a/libr/bin/p/bin_pe.c +++ b/libr/bin/p/bin_pe.c @@ -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; } diff --git a/libr/include/r_bin.h b/libr/include/r_bin.h index 414d106069..c339c1e19d 100644 --- a/libr/include/r_bin.h +++ b/libr/include/r_bin.h @@ -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 {