Refactor rz_bin_pe_get_libs() to use SetS and RzPVector

This commit is contained in:
pelijah 2024-05-09 15:58:18 +03:00 committed by Anton Kochkov
parent 61c8074cbf
commit ca2bbc076c
5 changed files with 87 additions and 176 deletions

View file

@ -5,6 +5,7 @@
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_bin.h>
#include <rz_vector.h>
#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 /*<char *>*/ *PE_(rz_bin_pe_get_libs)(RzBinPEObj *bin);
ut64 PE_(rz_bin_pe_get_image_base)(RzBinPEObj *bin);
// pe_overlay.c

View file

@ -3,6 +3,7 @@
// SPDX-FileCopyrightText: 2008-2019 inisider <inisider@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_util/set.h>
#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 /*<char *>*/ *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) {

View file

@ -124,11 +124,8 @@ static RzBinInfo *mdmp_info(RzBinFile *bf) {
static RzPVector /*<char *>*/ *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 /*<char *>*/ *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;
}

View file

@ -498,23 +498,7 @@ static RzPVector /*<RzBinReloc *>*/ *relocs(RzBinFile *bf) {
}
static RzPVector /*<char *>*/ *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 /*<RzBinResource *>*/ *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)");

View file

@ -111,15 +111,15 @@ CMDS=il
EXPECT=<<EOF
library
-------------
kernel32.dll
user32.dll
advapi32.dll
oleaut32.dll
ole32.dll
kernel32.dll
pstorec.dll
rasapi32.dll
shell32.dll
crypt32.dll
oleaut32.dll
advapi32.dll
ole32.dll
rasapi32.dll
EOF
RUN