diff --git a/libr/bin/format/pe/pe.c b/libr/bin/format/pe/pe.c index 82b892e96a1db..1b0285680e226 100644 --- a/libr/bin/format/pe/pe.c +++ b/libr/bin/format/pe/pe.c @@ -739,12 +739,12 @@ static int PE_(r_bin_pe_init_resource)(struct PE_(r_bin_pe_obj_t)* bin) { if (resource_dir_paddr == 0) { return R_FALSE; } - if (!(bin->resource_directory = malloc (sizeof(Pe_image_resource_directory)))) { + if (!(bin->resource_directory = malloc (sizeof(*bin->resource_directory)))) { r_sys_perror ("malloc (resource directory)"); return R_FALSE; } if (r_buf_read_at (bin->b, resource_dir_paddr, (ut8*)bin->resource_directory, - sizeof (Pe_image_resource_directory)) == -1) { + sizeof (*bin->resource_directory)) != sizeof (*bin->resource_directory)) { eprintf ("Error: read (resource directory)\n"); free (bin->resource_directory); bin->resource_directory = NULL; @@ -980,6 +980,7 @@ static VarFileInfo *Pe_r_bin_pe_parse_var_file_info(struct PE_(r_bin_pe_obj_t)* return NULL; } varFileInfo->numOfChildren++; + align32(*curAddr); } return varFileInfo; } @@ -1018,20 +1019,20 @@ static String *Pe_r_bin_pe_parse_string(struct PE_(r_bin_pe_obj_t)* bin, PE_DWor return NULL; } - int keyLen = string->wLength - string->wValueLength * 2 - sizeof(string->wLength) * 3; - string->szKey = (ut16 *) malloc (keyLen); //If there was padding, we would read it in string + string->wKeyLen = string->wLength - string->wValueLength * 2 - sizeof(string->wLength) * 3; + string->szKey = (ut16 *) malloc (string->wKeyLen); //If there was padding, we would read it in string if (string->szKey == NULL) { eprintf ("Error: malloc (String szKey)\n"); free_String(string); return NULL; } - if (r_buf_read_at(bin->b, *curAddr, (ut8*)string->szKey, keyLen) != keyLen) { + if (r_buf_read_at(bin->b, *curAddr, (ut8*)string->szKey, string->wKeyLen) != string->wKeyLen) { eprintf ("Error: read (String szKey)\n"); free_String(string); return NULL; } - *curAddr += keyLen; + *curAddr += string->wKeyLen; align32(*curAddr); @@ -1124,6 +1125,7 @@ static StringTable *Pe_r_bin_pe_parse_string_table(struct PE_(r_bin_pe_obj_t)* b return NULL; } stringTable->numOfChildren++; + align32(*curAddr); } return stringTable; @@ -1208,6 +1210,7 @@ static StringFileInfo *Pe_r_bin_pe_parse_string_file_info(struct PE_(r_bin_pe_ob return NULL; } stringFileInfo->numOfChildren++; + align32(*curAddr); } return stringFileInfo; @@ -1223,7 +1226,7 @@ static VS_VERSIONINFO *Pe_r_bin_pe_parse_version_info(struct PE_(r_bin_pe_obj_t) PE_DWord startAddr = version_info_paddr; PE_DWord curAddr = version_info_paddr; - align32(curAddr); // XXX: do we really need this? Because in msdn + //align32(curAddr); // XXX: do we really need this? Because in msdn //wLength is The length, in bytes, of the VS_VERSIONINFO structure. //This length does not include any padding that aligns any subsequent //version resource data on a 32-bit boundary. @@ -1361,54 +1364,218 @@ static VS_VERSIONINFO *Pe_r_bin_pe_parse_version_info(struct PE_(r_bin_pe_obj_t) return vs_VersionInfo; } -VS_VERSIONINFO *PE_(r_bin_get_first_resource_version_info)(struct PE_(r_bin_pe_obj_t)* bin) { - if (bin->resource_directory == NULL) +static Sdb *Pe_r_bin_store_var(Var *var) { + char key[20]; + if (var == NULL) return NULL; + Sdb *sdb = sdb_new0(); + if (sdb == NULL) + return NULL; + int i = 0; + for (; i < var->numOfValues; i++) { + snprintf(key, 20, "%d", i); + sdb_num_set(sdb, key, var->Value[i], 0); + } + return sdb; +} + +static Sdb *Pe_r_bin_store_var_file_info(VarFileInfo *varFileInfo) { + char key[20]; + if (varFileInfo == NULL) + return NULL; + Sdb *sdb = sdb_new0(); + if (sdb == NULL) + return NULL; + int i = 0; + for (; i < varFileInfo->numOfChildren; i++) { + snprintf(key, 20, "var%d", i); + sdb_ns_set (sdb, key, Pe_r_bin_store_var(varFileInfo->Children[i])); + } + return sdb; +} + +static Sdb *Pe_r_bin_store_string(String *string) { + if (string == NULL) + return NULL; + Sdb *sdb = sdb_new0(); + if (sdb == NULL) + return NULL; + char *encodedKey = sdb_encode((unsigned char *) string->szKey, string->wKeyLen); + if (encodedKey == NULL) { + sdb_free(sdb); + return NULL; + } + char *encodedVal = sdb_encode((unsigned char *) string->Value, string->wValueLength * 2); + if (encodedVal == NULL) { + free(encodedKey); + sdb_free(sdb); + return NULL; + } + sdb_set(sdb, "key", encodedKey, 0); + sdb_set(sdb, "value", encodedVal, 0); + return sdb; +} + +static Sdb *Pe_r_bin_store_string_table(StringTable *stringTable) { + char key[20]; + if (stringTable == NULL) + return NULL; + Sdb *sdb = sdb_new0(); + if (sdb == NULL) + return NULL; + char *encodedKey = sdb_encode((unsigned char *) stringTable->szKey, EIGHT_HEX_DIG_UTF_16_LEN); + if (encodedKey == NULL) { + sdb_free(sdb); + return NULL; + } + sdb_set(sdb, "key", encodedKey, 0); + int i = 0; + for (; i < stringTable->numOfChildren; i++) { + snprintf(key, 20, "string%d", i); + sdb_ns_set (sdb, key, Pe_r_bin_store_string(stringTable->Children[i])); + } + return sdb; +} + +static Sdb *Pe_r_bin_store_string_file_info(StringFileInfo *stringFileInfo) { + char key[30]; + if (stringFileInfo == NULL) + return NULL; + Sdb *sdb = sdb_new0(); + if (sdb == NULL) + return NULL; + int i = 0; + for (; i < stringFileInfo->numOfChildren; i++) { + snprintf(key, 30, "stringtable%d", i); + sdb_ns_set (sdb, key, Pe_r_bin_store_string_table(stringFileInfo->Children[i])); + } + return sdb; +} + +static Sdb *Pe_r_bin_store_fixed_file_info(VS_FIXEDFILEINFO *vs_fixedFileInfo) { + if (vs_fixedFileInfo == NULL) + return NULL; + Sdb *sdb = sdb_new0(); + if (sdb == NULL) + return NULL; + sdb_num_set(sdb, "Signature", vs_fixedFileInfo->dwSignature, 0); + sdb_num_set(sdb, "StrucVersion", vs_fixedFileInfo->dwStrucVersion, 0); + sdb_num_set(sdb, "FileVersionMS", vs_fixedFileInfo->dwFileVersionMS, 0); + sdb_num_set(sdb, "FileVersionLS", vs_fixedFileInfo->dwFileVersionLS, 0); + sdb_num_set(sdb, "ProductVersionMS", vs_fixedFileInfo->dwProductVersionMS, 0); + sdb_num_set(sdb, "ProductVersionLS", vs_fixedFileInfo->dwProductVersionLS, 0); + sdb_num_set(sdb, "FileFlagsMask", vs_fixedFileInfo->dwFileFlagsMask, 0); + sdb_num_set(sdb, "FileFlags", vs_fixedFileInfo->dwFileFlags, 0); + sdb_num_set(sdb, "FileOS", vs_fixedFileInfo->dwFileOS, 0); + sdb_num_set(sdb, "FileType", vs_fixedFileInfo->dwFileType, 0); + sdb_num_set(sdb, "FileSubtype", vs_fixedFileInfo->dwFileSubtype, 0); + sdb_num_set(sdb, "FileDateMS", vs_fixedFileInfo->dwFileDateMS, 0); + sdb_num_set(sdb, "FileDateLS", vs_fixedFileInfo->dwFileDateLS, 0); + return sdb; +} + +static Sdb *Pe_r_bin_store_resource_version_info(VS_VERSIONINFO *vs_VersionInfo) { + if (vs_VersionInfo == NULL) + return NULL; + Sdb *sdb = sdb_new0(); + if (sdb == NULL) + return NULL; + if (vs_VersionInfo->Value) + sdb_ns_set (sdb, "fixed_file_info", Pe_r_bin_store_fixed_file_info(vs_VersionInfo->Value)); + if (vs_VersionInfo->varFileInfo) + sdb_ns_set (sdb, "var_file_info", Pe_r_bin_store_var_file_info(vs_VersionInfo->varFileInfo)); + if (vs_VersionInfo->stringFileInfo) + sdb_ns_set (sdb, "string_file_info", Pe_r_bin_store_string_file_info(vs_VersionInfo->stringFileInfo)); + return sdb; +} + +void PE_(r_bin_store_all_resource_version_info)(struct PE_(r_bin_pe_obj_t)* bin) { + char key[30]; + if (bin == NULL || bin->resource_directory == NULL) + return; + int counter = 0; + Sdb *sdb = sdb_new0(); + if (sdb == NULL) + return; // XXX: assume there is only 3 layers in the tree - ut32 total = bin->resource_directory->NumberOfNamedEntries + bin->resource_directory->NumberOfIdEntries; - ut32 cur = bin->resource_directory->NumberOfNamedEntries; - for (; cur < total; cur++) { - Pe_image_resource_directory_entry entry; - if (r_buf_read_at (bin->b, bin->resource_directory_offset + sizeof (*bin->resource_directory) + cur * sizeof (entry), - (ut8*)&entry, sizeof (entry)) == -1) { - eprintf ("Error: read (resource directory entry)\n"); - // XXX: mb continue to read? - return NULL; + ut32 totalRes = bin->resource_directory->NumberOfNamedEntries + bin->resource_directory->NumberOfIdEntries; + ut32 curRes = bin->resource_directory->NumberOfNamedEntries; + for (; curRes < totalRes; curRes++) { + Pe_image_resource_directory_entry typeEntry; + if (r_buf_read_at (bin->b, bin->resource_directory_offset + sizeof (*bin->resource_directory) + curRes * sizeof (typeEntry), + (ut8*)&typeEntry, sizeof (typeEntry)) != sizeof (typeEntry)) { + eprintf ("Error: read (resource type directory entry)\n"); + return; } - if (entry.u1.Id == PE_RESOURCE_ENTRY_VERSION) { - Pe_image_resource_directory dir; - while (entry.u2.s.DataIsDirectory) { - if (r_buf_read_at (bin->b, bin->resource_directory_offset + entry.u2.s.OffsetToDirectory, - (ut8*)&dir, sizeof (dir)) == -1) { - eprintf ("Error: read (resource directory)\n"); - // XXX: mb continue to read? - return NULL; + if (!typeEntry.u1.s.NameIsString && typeEntry.u1.Id == PE_RESOURCE_ENTRY_VERSION) { + Pe_image_resource_directory identDir; + if (r_buf_read_at (bin->b, bin->resource_directory_offset + typeEntry.u2.s.OffsetToDirectory, + (ut8*)&identDir, sizeof (identDir)) != sizeof (identDir)) { + eprintf ("Error: read (resource identifier directory)\n"); + return; + } + ut32 totalIdent = identDir.NumberOfNamedEntries + identDir.NumberOfIdEntries; + ut32 curIdent = 0; + for (; curIdent < totalIdent; curIdent++) { + Pe_image_resource_directory_entry identEntry; + if (r_buf_read_at (bin->b, bin->resource_directory_offset + typeEntry.u2.s.OffsetToDirectory + sizeof (identDir) + + curIdent * sizeof (identEntry), (ut8*)&identEntry, sizeof (identEntry)) != sizeof (identEntry)) { + eprintf ("Error: read (resource identifier entry)\n"); + return; } - if (r_buf_read_at (bin->b, bin->resource_directory_offset + entry.u2.s.OffsetToDirectory + sizeof (dir), - (ut8*)&entry, sizeof (entry)) == -1) { - eprintf ("Error: read (resource directory entry)\n"); - // XXX: mb continue to read? - return NULL; + if (!identEntry.u2.s.DataIsDirectory) + continue; + Pe_image_resource_directory langDir; + if (r_buf_read_at (bin->b, bin->resource_directory_offset + identEntry.u2.s.OffsetToDirectory, + (ut8*)&langDir, sizeof (langDir)) != sizeof (langDir)) { + eprintf ("Error: read (resource language directory)\n"); + return; + } + ut32 totalLang = langDir.NumberOfNamedEntries + langDir.NumberOfIdEntries; + ut32 curLang = 0; + for (; curLang < totalLang; curLang++) { + Pe_image_resource_directory_entry langEntry; + if (r_buf_read_at (bin->b, bin->resource_directory_offset + identEntry.u2.s.OffsetToDirectory + sizeof (langDir) + + curLang * sizeof (langEntry), (ut8*)&langEntry, sizeof (langEntry)) != sizeof (langEntry)) { + eprintf ("Error: read (resource language entry)\n"); + return; + } + if (langEntry.u2.s.DataIsDirectory) + continue; + Pe_image_resource_data_entry data; + if (r_buf_read_at (bin->b, bin->resource_directory_offset + langEntry.u2.OffsetToData, + (ut8*)&data, sizeof (data)) != sizeof (data)) { + eprintf ("Error: read (resource data entry)\n"); + return; + } + PE_DWord data_paddr = PE_(r_bin_pe_vaddr_to_paddr)(bin, data.OffsetToData); + if (data_paddr == 0) { + eprintf ("Error: bad RVA in resource data entry\n"); + return; + } + PE_DWord cur_paddr = data_paddr; + if ((cur_paddr & 0x3) != 0) { + // XXX: mb align address and read structure? + eprintf ("Error: not aligned version info address\n"); + continue; + } + while(cur_paddr < data_paddr + data.Size) { + VS_VERSIONINFO *vs_VersionInfo = Pe_r_bin_pe_parse_version_info(bin, cur_paddr); + if (vs_VersionInfo) { + snprintf(key, 30, "VS_VERSIONINFO%d", counter++); + sdb_ns_set (sdb, key, Pe_r_bin_store_resource_version_info(vs_VersionInfo)); + } else + break; + cur_paddr += vs_VersionInfo->wLength; + free_VS_VERSIONINFO(vs_VersionInfo); + align32(cur_paddr); + } } } - Pe_image_resource_data_entry data; - if (r_buf_read_at (bin->b, bin->resource_directory_offset + entry.u2.OffsetToData, - (ut8*)&data, sizeof (data)) == -1) { - eprintf ("Error: read (resource data entry)\n"); - // XXX: mb continue to read? - return NULL; - } - PE_DWord data_paddr = PE_(r_bin_pe_vaddr_to_paddr)(bin, data.OffsetToData); - if (data_paddr == 0) { - eprintf ("Error: bad RVA in resource data entry\n"); - // XXX: mb continue to read? - return NULL; - } - // XXX: what if there several version info resources? - return Pe_r_bin_pe_parse_version_info(bin, data_paddr); } } - return NULL; + sdb_ns_set(bin->kv, "vs_version_info", sdb); + return; } @@ -1432,6 +1599,7 @@ static int PE_(r_bin_pe_init)(struct PE_(r_bin_pe_obj_t)* bin) { PE_(r_bin_pe_init_imports)(bin); PE_(r_bin_pe_init_exports)(bin); PE_(r_bin_pe_init_resource)(bin); + PE_(r_bin_store_all_resource_version_info)(bin); bin->relocs = NULL; return R_TRUE; } @@ -2080,6 +2248,7 @@ void* PE_(r_bin_pe_free)(struct PE_(r_bin_pe_obj_t)* bin) { free (bin->section_header); free (bin->export_directory); free (bin->import_directory); + free (bin->resource_directory); free (bin->delay_import_directory); r_buf_free (bin->b); bin->b = NULL; diff --git a/libr/bin/format/pe/pe.h b/libr/bin/format/pe/pe.h index b19ac6cd4396f..69678fd0d198f 100644 --- a/libr/bin/format/pe/pe.h +++ b/libr/bin/format/pe/pe.h @@ -96,8 +96,7 @@ typedef struct SDebugInfo{ char file_name[DBG_FILE_NAME_LEN]; } SDebugInfo; -void PE_(free_VS_VERSIONINFO)(VS_VERSIONINFO *vs_VersionInfo); -VS_VERSIONINFO *PE_(r_bin_get_first_resource_version_info)(struct PE_(r_bin_pe_obj_t)* bin); +void PE_(r_bin_store_all_resource_version_info)(struct PE_(r_bin_pe_obj_t)* bin); char* PE_(r_bin_pe_get_arch)(struct PE_(r_bin_pe_obj_t)* bin); struct r_bin_pe_addr_t* PE_(r_bin_pe_get_entrypoint)(struct PE_(r_bin_pe_obj_t)* bin); struct r_bin_pe_addr_t *PE_(r_bin_pe_get_main_vaddr)(struct PE_(r_bin_pe_obj_t) *bin); diff --git a/libr/bin/format/pe/pe_specs.h b/libr/bin/format/pe/pe_specs.h index eaa6348d01b95..c9c3355d0dd47 100644 --- a/libr/bin/format/pe/pe_specs.h +++ b/libr/bin/format/pe/pe_specs.h @@ -408,6 +408,7 @@ typedef struct { ut16 wLength; //The length, in bytes, of this String structure. ut16 wValueLength; //The size, in words, of the Value member. ut16 wType; //1 text; 0 binary + ut16 wKeyLen; ut16 *szKey; //An arbitrary Unicode string //ut16 Padding; ut16 *Value; //A zero-terminated string.