Skip to content

Commit

Permalink
Added storing vs_versioninfo structures in sdb. Some fixes.
Browse files Browse the repository at this point in the history
Added storing vs_versioninfo structures in sdb (UTF-16 to base64).
Some fixes: refactoring, r_buf_read_at checks, structures aligning,
freeing of resource directory stored in bin
Added key len in string (version info string structure) stucture.
Changed resource directory traversal logic
  • Loading branch information
AntonDevil committed Apr 14, 2015
1 parent 003d694 commit 6de941d
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 49 deletions.
263 changes: 216 additions & 47 deletions libr/bin/format/pe/pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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;
}


Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions libr/bin/format/pe/pe.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ 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_(free_VS_VERSIONINFO)(VS_VERSIONINFO *vs_VersionInfo);
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);
Expand Down
1 change: 1 addition & 0 deletions libr/bin/format/pe/pe_specs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 6de941d

Please sign in to comment.