From ca2bbc076c84aeeced458a3c38a059d220a3e9e5 Mon Sep 17 00:00:00 2001 From: pelijah Date: Thu, 9 May 2024 15:58:18 +0300 Subject: [PATCH] Refactor rz_bin_pe_get_libs() to use SetS and RzPVector --- librz/bin/format/pe/pe.h | 8 +- librz/bin/format/pe/pe_info.c | 159 ++++++++++++---------------------- librz/bin/p/bin_mdmp.c | 25 +++--- librz/bin/p/bin_pe.inc | 61 +++---------- test/db/formats/pe/pe | 10 +-- 5 files changed, 87 insertions(+), 176 deletions(-) diff --git a/librz/bin/format/pe/pe.h b/librz/bin/format/pe/pe.h index 2ddb52e30c..43a1c7d26c 100644 --- a/librz/bin/format/pe/pe.h +++ b/librz/bin/format/pe/pe.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "pe_specs.h" #include "dotnet.h" @@ -114,11 +115,6 @@ struct rz_bin_pe_string_t { int last; }; -struct rz_bin_pe_lib_t { - char name[PE_STRING_LENGTH]; - int last; -}; - typedef struct _PE_RESOURCE { char *timestr; char *type; @@ -233,7 +229,7 @@ struct rz_bin_pe_addr_t *PE_(check_mingw)(RzBinPEObj *bin); struct rz_bin_pe_addr_t *PE_(rz_bin_pe_get_entrypoint)(RzBinPEObj *bin); struct rz_bin_pe_addr_t *PE_(rz_bin_pe_get_main_vaddr)(RzBinPEObj *bin); int PE_(rz_bin_pe_get_image_size)(RzBinPEObj *bin); -struct rz_bin_pe_lib_t *PE_(rz_bin_pe_get_libs)(RzBinPEObj *bin); +RzPVector /**/ *PE_(rz_bin_pe_get_libs)(RzBinPEObj *bin); ut64 PE_(rz_bin_pe_get_image_base)(RzBinPEObj *bin); // pe_overlay.c diff --git a/librz/bin/format/pe/pe_info.c b/librz/bin/format/pe/pe_info.c index dd06a0342f..a4b1ac4c23 100644 --- a/librz/bin/format/pe/pe_info.c +++ b/librz/bin/format/pe/pe_info.c @@ -3,6 +3,7 @@ // SPDX-FileCopyrightText: 2008-2019 inisider // SPDX-License-Identifier: LGPL-3.0-only +#include #include "pe.h" static inline int is_thumb(RzBinPEObj *bin) { @@ -385,125 +386,79 @@ int PE_(rz_bin_pe_is_stripped_debug)(RzBinPEObj *bin) { return HASCHR(PE_IMAGE_FILE_DEBUG_STRIPPED); } -struct rz_bin_pe_lib_t *PE_(rz_bin_pe_get_libs)(RzBinPEObj *bin) { +static inline bool bin_buf_contains(const RzBinPEObj *bin, ut64 offset, ut64 nbytes) { + if (UT64_ADD_OVFCHK(offset, nbytes)) { + return false; + } + return offset + nbytes <= bin->size; +} + +/** + * Check whether an directory entry is empty (filled with zeroes) + */ +static inline bool image_import_directory_is_empty(const PE_(image_import_directory) * dir) { + return !(dir->FirstThunk || dir->Name || dir->TimeDateStamp || dir->Characteristics || dir->ForwarderChain); +} + +RzPVector /**/ *PE_(rz_bin_pe_get_libs)(RzBinPEObj *bin) { if (!bin) { return NULL; } - struct rz_bin_pe_lib_t *libs = NULL; - struct rz_bin_pe_lib_t *new_libs = NULL; + if (!bin_buf_contains(bin, bin->import_directory_offset, bin->import_directory_size)) { + return NULL; + } PE_(image_import_directory) curr_import_dir; PE_(image_delay_import_directory) curr_delay_import_dir; - PE_DWord name_off = 0; - HtSS *lib_map = NULL; - ut64 off; // cache value - int index = 0; - int len = 0; - int max_libs = 20; - libs = calloc(max_libs + 1, sizeof(struct rz_bin_pe_lib_t)); + + SetS *libs = set_s_new(HT_STR_DUP); if (!libs) { - rz_sys_perror("malloc (libs)"); return NULL; } - - if (bin->import_directory_offset + bin->import_directory_size > bin->size) { - RZ_LOG_INFO("import directory offset bigger than file\n"); - goto out_error; - } - lib_map = sdb_ht_new(); - off = bin->import_directory_offset; - if (off < bin->size && off > 0) { - ut64 last; - int iidi = 0; - // normal imports - if (off + sizeof(PE_(image_import_directory)) > bin->size) { - goto out_error; - } - int r = PE_(read_image_import_directory)(bin->b, off + iidi * sizeof(curr_import_dir), - &curr_import_dir); - last = off + bin->import_directory_size; - while (r == sizeof(curr_import_dir) && off + (iidi + 1) * sizeof(curr_import_dir) <= last && (curr_import_dir.FirstThunk || curr_import_dir.Name || curr_import_dir.TimeDateStamp || curr_import_dir.Characteristics || curr_import_dir.ForwarderChain)) { - name_off = PE_(bin_pe_rva_to_paddr)(bin, curr_import_dir.Name); - len = rz_buf_read_at(bin->b, name_off, (ut8 *)libs[index].name, PE_STRING_LENGTH); - if (!libs[index].name[0]) { // minimum string length - goto next; - } - if (len < 2 || libs[index].name[0] == 0) { // minimum string length - RZ_LOG_INFO("read (libs - import dirs) %d\n", len); + char lib_name[PE_STRING_LENGTH]; + ut64 dir_off = bin->import_directory_offset; + if (dir_off != 0 && dir_off < bin->size) { + const ut64 end_off = dir_off + bin->import_directory_size; + for (; dir_off < end_off; dir_off += sizeof(curr_import_dir)) { + if (PE_(read_image_import_directory)(bin->b, dir_off, &curr_import_dir) < 0) { break; } - libs[index].name[len - 1] = '\0'; - rz_str_case(libs[index].name, 0); - if (!sdb_ht_find(lib_map, libs[index].name, NULL)) { - sdb_ht_insert(lib_map, libs[index].name, "a"); - libs[index++].last = 0; - if (index >= max_libs) { - new_libs = realloc(libs, (max_libs * 2) * sizeof(struct rz_bin_pe_lib_t)); - if (!new_libs) { - rz_sys_perror("realloc (libs)"); - goto out_error; - } - libs = new_libs; - new_libs = NULL; - max_libs *= 2; - } - } - next: - iidi++; - r = PE_(read_image_import_directory)(bin->b, off + iidi * sizeof(curr_import_dir), - &curr_import_dir); - } - } - off = bin->delay_import_directory_offset; - if (off < bin->size && off > 0) { - ut64 did = 0; - if (off + sizeof(PE_(image_delay_import_directory)) > bin->size) { - goto out_error; - } - int r = PE_(read_image_delay_import_directory)(bin->b, off, &curr_delay_import_dir); - if (r != sizeof(curr_delay_import_dir)) { - goto out_error; - } - while (r == sizeof(curr_delay_import_dir) && - curr_delay_import_dir.Name != 0 && curr_delay_import_dir.DelayImportNameTable != 0) { - name_off = PE_(bin_pe_rva_to_paddr)(bin, curr_delay_import_dir.Name); - if (name_off > bin->size || name_off + PE_STRING_LENGTH > bin->size) { - goto out_error; - } - len = rz_buf_read_at(bin->b, name_off, (ut8 *)libs[index].name, PE_STRING_LENGTH); - if (len != PE_STRING_LENGTH) { - RZ_LOG_INFO("read (libs - delay import dirs)\n"); + if (image_import_directory_is_empty(&curr_import_dir)) { break; } - libs[index].name[len - 1] = '\0'; - rz_str_case(libs[index].name, 0); - if (!sdb_ht_find(lib_map, libs[index].name, NULL)) { - sdb_ht_insert(lib_map, libs[index].name, "a"); - libs[index++].last = 0; - if (index >= max_libs) { - new_libs = realloc(libs, (max_libs * 2) * sizeof(struct rz_bin_pe_lib_t)); - if (!new_libs) { - rz_sys_perror("realloc (libs)"); - goto out_error; - } - libs = new_libs; - new_libs = NULL; - max_libs *= 2; - } + PE_DWord name_off = PE_(bin_pe_rva_to_paddr)(bin, curr_import_dir.Name); + st64 len = rz_buf_read_at(bin->b, name_off, (ut8 *)lib_name, PE_STRING_LENGTH); + if (len < 2 || !lib_name[0]) { + break; } - did++; - r = PE_(read_image_delay_import_directory)(bin->b, off + did * sizeof(curr_delay_import_dir), - &curr_delay_import_dir); + lib_name[len - 1] = '\0'; + rz_str_case(lib_name, 0); + set_s_add(libs, lib_name); } } - sdb_ht_free(lib_map); - libs[index].last = 1; - return libs; -out_error: - sdb_ht_free(lib_map); - free(libs); - return NULL; + dir_off = bin->delay_import_directory_offset; + if (dir_off != 0 && dir_off < bin->size) { + for (;; dir_off += sizeof(curr_delay_import_dir)) { + if (PE_(read_image_delay_import_directory)(bin->b, dir_off, &curr_delay_import_dir) < 0) { + break; + } + if (curr_delay_import_dir.Name == 0 || curr_delay_import_dir.DelayImportNameTable == 0) { + break; + } + PE_DWord name_off = PE_(bin_pe_rva_to_paddr)(bin, curr_delay_import_dir.Name); + st64 len = rz_buf_read_at(bin->b, name_off, (ut8 *)lib_name, PE_STRING_LENGTH); + if (len < 2 || !lib_name[0]) { + break; + } + lib_name[len - 1] = '\0'; + rz_str_case(lib_name, 0); + set_s_add(libs, lib_name); + } + } + RzPVector *vec = set_s_to_vector(libs); + set_s_free(libs); + return vec; } int PE_(rz_bin_pe_get_image_size)(RzBinPEObj *bin) { diff --git a/librz/bin/p/bin_mdmp.c b/librz/bin/p/bin_mdmp.c index c3f865b5e4..ae34fe284b 100644 --- a/librz/bin/p/bin_mdmp.c +++ b/librz/bin/p/bin_mdmp.c @@ -124,11 +124,8 @@ static RzBinInfo *mdmp_info(RzBinFile *bf) { static RzPVector /**/ *mdmp_libs(RzBinFile *bf) { char *ptr = NULL; - int i; MiniDmpObj *obj; - struct rz_bin_pe_lib_t *libs = NULL; - struct Pe32_rz_bin_mdmp_pe_bin *pe32_bin; - struct Pe64_rz_bin_mdmp_pe_bin *pe64_bin; + RzPVector *libs = NULL; RzPVector *ret = NULL; RzListIter *it; @@ -143,25 +140,29 @@ static RzPVector /**/ *mdmp_libs(RzBinFile *bf) { /* TODO: Resolve module name for lib, or filter to remove duplicates, ** rather than the vaddr :) */ + struct Pe32_rz_bin_mdmp_pe_bin *pe32_bin; rz_list_foreach (obj->pe32_bins, it, pe32_bin) { if (!(libs = Pe32_rz_bin_pe_get_libs(pe32_bin->bin))) { - return ret; + continue; } - for (i = 0; !libs[i].last; i++) { - ptr = rz_str_newf("[0x%.08" PFMT64x "] - %s", pe32_bin->vaddr, libs[i].name); + void **libs_iter; + rz_pvector_foreach (libs, libs_iter) { + ptr = rz_str_newf("[0x%.08" PFMT64x "] - %s", pe32_bin->vaddr, (char *)*libs_iter); rz_pvector_push(ret, ptr); } - free(libs); + rz_pvector_free(libs); } + struct Pe64_rz_bin_mdmp_pe_bin *pe64_bin; rz_list_foreach (obj->pe64_bins, it, pe64_bin) { if (!(libs = Pe64_rz_bin_pe_get_libs(pe64_bin->bin))) { - return ret; + continue; } - for (i = 0; !libs[i].last; i++) { - ptr = rz_str_newf("[0x%.08" PFMT64x "] - %s", pe64_bin->vaddr, libs[i].name); + void **libs_iter; + rz_pvector_foreach (libs, libs_iter) { + ptr = rz_str_newf("[0x%.08" PFMT64x "] - %s", pe64_bin->vaddr, (char *)*libs_iter); rz_pvector_push(ret, ptr); } - free(libs); + rz_pvector_free(libs); } return ret; } diff --git a/librz/bin/p/bin_pe.inc b/librz/bin/p/bin_pe.inc index bbc00c69a8..67e49f675e 100644 --- a/librz/bin/p/bin_pe.inc +++ b/librz/bin/p/bin_pe.inc @@ -498,23 +498,7 @@ static RzPVector /**/ *relocs(RzBinFile *bf) { } static RzPVector /**/ *libs(RzBinFile *bf) { - struct rz_bin_pe_lib_t *libs = NULL; - RzPVector *ret = NULL; - char *ptr = NULL; - int i; - - if (!(ret = rz_pvector_new(free))) { - return NULL; - } - if (!(libs = PE_(rz_bin_pe_get_libs)(bf->o->bin_obj))) { - return ret; - } - for (i = 0; !libs[i].last; i++) { - ptr = strdup(libs[i].name); - rz_pvector_push(ret, ptr); - } - free(libs); - return ret; + return PE_(rz_bin_pe_get_libs)(bf->o->bin_obj); } static RzPVector /**/ *resources(RzBinFile *bf) { @@ -569,38 +553,6 @@ err: return NULL; } -static bool is_dot_net(RzBinFile *bf) { - struct rz_bin_pe_lib_t *libs = NULL; - int i; - if (!(libs = PE_(rz_bin_pe_get_libs)(bf->o->bin_obj))) { - return false; - } - for (i = 0; !libs[i].last; i++) { - if (!strcmp(libs[i].name, "mscoree.dll")) { - free(libs); - return true; - } - } - free(libs); - return false; -} - -static bool is_vb6(RzBinFile *bf) { - struct rz_bin_pe_lib_t *libs = NULL; - int i; - if (!(libs = PE_(rz_bin_pe_get_libs)(bf->o->bin_obj))) { - return false; - } - for (i = 0; !libs[i].last; i++) { - if (!strcmp(libs[i].name, "msvbvm60.dll")) { - free(libs); - return true; - } - } - free(libs); - return false; -} - static int has_canary(RzBinFile *bf) { // XXX: We only need imports here but this causes leaks, we need to wait for the below. This is a horrible solution! // TODO: use O(1) when imports sdbized @@ -636,6 +588,10 @@ static inline bool haschr(const struct PE_(rz_bin_pe_obj_t) * bin, ut16 dllChara return bin->nt_headers->optional_header.DllCharacteristics & dllCharacteristic; } +static int compare_strings(const void *a, const void *b, RZ_UNUSED void *user) { + return strcmp((const char *)a, (const char *)b); +} + static RzBinInfo *info(RzBinFile *bf) { struct PE_(rz_bin_pe_obj_t) * bin; SDebugInfo di = { { 0 } }; @@ -654,12 +610,15 @@ static RzBinInfo *info(RzBinFile *bf) { ret->machine = PE_(rz_bin_pe_get_machine)(bf->o->bin_obj); ret->subsystem = PE_(rz_bin_pe_get_subsystem)(bf->o->bin_obj); ret->default_cc = PE_(rz_bin_pe_get_cc)(bf->o->bin_obj); - if (is_dot_net(bf)) { + + RzPVector *libs = PE_(rz_bin_pe_get_libs)(bf->o->bin_obj); + if (libs && rz_pvector_find(libs, "mscoree.dll", compare_strings, NULL)) { ret->lang = "cil"; } - if (is_vb6(bf)) { + if (libs && rz_pvector_find(libs, "msvbvm60.dll", compare_strings, NULL)) { ret->lang = "vb"; } + rz_pvector_free(libs); if (PE_(rz_bin_pe_is_dll)(bf->o->bin_obj)) { ret->type = strdup("DLL (Dynamic Link Library)"); diff --git a/test/db/formats/pe/pe b/test/db/formats/pe/pe index 2db6632c62..cde77a7157 100644 --- a/test/db/formats/pe/pe +++ b/test/db/formats/pe/pe @@ -111,15 +111,15 @@ CMDS=il EXPECT=<