Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libr/bin/bfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@ R_IPI RBinFile *r_bin_file_new(RBin *bin, const char *file, ut64 file_sz, RBinFi
bf->rbin = bin;
bf->file = file ? r_arena_push_str (arena, file) : NULL;
bf->rawstr = opt->rawstr;
bf->inmem = opt->inmem;
bf->fd = opt->fd;
bf->curxtr = opt->pluginname? r_libstore_find_name_in (bin->libstore, bin->libstore->xtrs, opt->pluginname) : NULL;
if ((st64)file_sz < 0) {
Expand Down
2 changes: 2 additions & 0 deletions libr/bin/bin.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ R_API bool r_bin_reload(RBin *bin, ut32 bf_id, ut64 baseaddr) {
RBinFileOptions opt;
r_bin_file_options_init (&opt, bf->fd, baseaddr, bf->loadaddr, bin->options.rawstr);
opt.filename = bf->file;
opt.inmem = bf->inmem;
if (!bf->buf) {
r_bin_file_delete (bin, bf->id);
return false;
Expand Down Expand Up @@ -507,6 +508,7 @@ R_API bool r_bin_open_io(RBin *bin, RBinFileOptions *opt) {
if (buf) {
// reading from the backing file on disk, not process memory
is_debugger = false;
opt->inmem = false;
opt->loadaddr = 0;
opt->sz = 0;
}
Expand Down
125 changes: 107 additions & 18 deletions libr/bin/format/elf/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,8 +490,9 @@ static Elf_(Phdr) *get_dynamic_segment(ELFOBJ *eo) {
if (p->p_type != PT_DYNAMIC) {
continue;
}
if (p->p_filesz > eo->size || p->p_offset > eo->size
|| p->p_offset + sizeof (Elf_(Dyn)) > eo->size) {
// init_dynamic_section bounds a memory image through v2p
if (!eo->inmem && (p->p_filesz > eo->size || p->p_offset > eo->size
|| p->p_offset + sizeof (Elf_(Dyn)) > eo->size)) {
return NULL;
}
return p;
Expand Down Expand Up @@ -547,6 +548,36 @@ static inline size_t get_maximum_number_of_dynamic_entries(ut64 dyn_size) {
return dyn_size / sizeof (Elf_(Dyn));
}

static bool backing_at(ELFOBJ *eo, ut64 vaddr, ut64 *off, ut64 *left);

// glibc rewrites these in place to runtime addresses in a loaded image
static inline bool is_loader_rebased(ut64 tag) {
switch (tag) {
case DT_HASH:
case DT_PLTGOT:
case DT_STRTAB:
case DT_SYMTAB:
case DT_RELA:
case DT_REL:
case DT_JMPREL:
case DT_RELR:
case DT_VERSYM:
case DT_GNU_HASH:
return true;
}
return false;
}

static ut64 dyn_link_ptr(ELFOBJ *eo, ut64 tag, ut64 ptr) {
if (!eo->inmem || eo->user_baddr == UT64_MAX || !is_loader_rebased (tag)) {
return ptr;
}
const ut64 bias = eo->user_baddr - eo->memory_base;
ut64 off, left;
return (bias && !backing_at (eo, ptr, &off, &left) && backing_at (eo, ptr - bias, &off, &left))
? ptr - bias: ptr;
}

static bool fill_dynamic_entry(ELFOBJ *eo, ut64 entry_offset, Elf_(Dyn) *d) {
ut8 sdyn[sizeof (Elf_(Dyn))] = {0};
int len = r_buf_read_at (eo->b, entry_offset, sdyn, sizeof (sdyn));
Expand All @@ -555,7 +586,8 @@ static bool fill_dynamic_entry(ELFOBJ *eo, ut64 entry_offset, Elf_(Dyn) *d) {
}
int j = 0; // required because its used in a macro
d->d_tag = R_BIN_ELF_READWORD (sdyn, j);
d->d_un.d_ptr = R_BIN_ELF_READWORD (sdyn, j);
const ut64 value = R_BIN_ELF_READWORD (sdyn, j);
d->d_un.d_ptr = dyn_link_ptr (eo, d->d_tag, value);
return true;
}

Expand Down Expand Up @@ -716,20 +748,32 @@ static void fill_dynamic_entries(ELFOBJ *eo, ut64 loaded_offset, ut64 dyn_size)
}
}

// the file-backed bytes of the PT_LOAD holding vaddr, from vaddr on
static ut64 loaded_bytes_at(ELFOBJ *eo, ut64 vaddr) {
static bool segment_backing(ELFOBJ *eo, const Elf_(Phdr) *p, ut64 vaddr, ut64 *off, ut64 *left) {
if (p->p_type != PT_LOAD || vaddr < p->p_vaddr) {
return false;
}
const ut64 delta = vaddr - p->p_vaddr;
const ut64 span = eo->inmem? p->p_memsz: p->p_filesz;
if (span > UT64_MAX - p->p_vaddr || delta >= span || (eo->inmem && p->p_vaddr < eo->memory_base)) {
return false;
}
const ut64 base = eo->inmem? p->p_vaddr - eo->memory_base: p->p_offset;
if (base > eo->size || delta >= eo->size - base) {
return false;
}
*off = base + delta;
*left = R_MIN (span - delta, eo->size - *off);
return true;
}

static bool backing_at(ELFOBJ *eo, ut64 vaddr, ut64 *off, ut64 *left) {
size_t i;
for (i = 0; i < eo->phnum; i++) {
const Elf_(Phdr) *p = &eo->phdr[i];
if (p->p_type != PT_LOAD || vaddr < p->p_vaddr || vaddr - p->p_vaddr >= p->p_filesz
|| p->p_filesz > UT64_MAX - p->p_vaddr || p->p_offset >= eo->size) {
continue;
if (segment_backing (eo, &eo->phdr[i], vaddr, off, left)) {
return true;
}
const ut64 end = R_MIN (p->p_filesz, eo->size - p->p_offset);
const ut64 at = vaddr - p->p_vaddr;
return at < end? end - at: 0;
}
return 0;
return false;
}

static ut64 reloc_section_size_at(ELFOBJ *eo, ut64 vaddr, ut32 sh_type) {
Expand All @@ -749,7 +793,8 @@ static Elf_(Xword) reloc_read_size(ELFOBJ *eo, ut64 vaddr, Elf_(Xword) size, ut3
if (vaddr == R_BIN_ELF_ADDR_MAX || !size) {
return size;
}
const ut64 loaded = loaded_bytes_at (eo, vaddr);
ut64 off, loaded = 0;
backing_at (eo, vaddr, &off, &loaded);
if (size <= loaded) {
return size;
}
Expand Down Expand Up @@ -777,7 +822,7 @@ static int init_dynamic_section(ELFOBJ *eo) {

ut64 dyn_size = dyn_phdr->p_filesz;

if (!dyn_size || loaded_offset + dyn_size > eo->size) {
if (!dyn_size || loaded_offset > eo->size || dyn_size > eo->size - loaded_offset) {
return false;
}

Expand Down Expand Up @@ -1704,6 +1749,21 @@ static void relro_insdb(ELFOBJ *eo) {
/* Look down */
static void sdb_init_const(ELFOBJ *eo);

static bool init_memory_base(ELFOBJ *eo) {
const ut64 headers_end = eo->ehdr.e_phoff + ((ut64)eo->phnum * sizeof (Elf_(Phdr)));
size_t i;
for (i = 0; eo->phdr && i < eo->phnum; i++) {
const Elf_(Phdr) *p = &eo->phdr[i];
if (p->p_type == PT_LOAD && !p->p_offset && p->p_filesz >= headers_end) {
eo->memory_base = p->p_vaddr;
// a loader never maps the section table
eo->ehdr.e_shnum = 0;
return true;
}
}
return false;
}

static bool elf_init(ELFOBJ *eo) {
// eo is not an ELF
if (!init_ehdr (eo)) {
Expand All @@ -1715,6 +1775,12 @@ static bool elf_init(ELFOBJ *eo) {
if (!init_phdr (eo) && !is_bin_etrel (eo)) {
R_LOG_DEBUG ("Cannot initialize program headers");
}
if (eo->inmem && !init_memory_base (eo)) {
if (eo->ehdr.e_type == ET_EXEC || eo->ehdr.e_type == ET_DYN) {
R_LOG_WARN ("No PT_LOAD maps the ELF header, reading it as a file");
}
eo->inmem = false;
}

if (eo->ehdr.e_type != ET_CORE) {
if (!init_shdr (eo)) {
Expand Down Expand Up @@ -2373,6 +2439,10 @@ char *Elf_(intrp)(ELFOBJ *eo) {
}

ut64 addr = p->p_offset;
ut64 left;
if (eo->inmem && (!backing_at (eo, p->p_vaddr, &addr, &left) || left < p->p_filesz)) {
return NULL;
}
int sz = p->p_filesz;
sdb_num_set (eo->kv, "elf_header.intrp_addr", addr, 0);
sdb_num_set (eo->kv, "elf_header.intrp_size", sz, 0);
Expand Down Expand Up @@ -4474,7 +4544,7 @@ static bool parse_pt_dynamic(RBinFile *bf, RBinSection *ptr) {
switch (entry.d_tag) {
case DT_RELR:
R_LOG_DEBUG ("RELR section found at 0x%08"PFMT64x, entry.d_un.d_ptr);
eo->dyn_info.dt_relr = entry.d_un.d_ptr;
eo->dyn_info.dt_relr = dyn_link_ptr (eo, entry.d_tag, entry.d_un.d_ptr);
break;
case DT_RELRSZ:
R_LOG_DEBUG ("RELR section size: 0x%08"PFMT64x, entry.d_un.d_val);
Expand Down Expand Up @@ -4667,6 +4737,16 @@ static bool _add_sections_from_phdr(RBinFile *bf, ELFOBJ *eo, bool *found_load)
ptr->vsize = phdr[i].p_memsz;
ptr->paddr = phdr[i].p_offset;
ptr->vaddr = phdr[i].p_vaddr;
if (eo->inmem) {
ut64 left = 0;
const bool backed = phdr[i].p_type == PT_LOAD
? segment_backing (eo, &phdr[i], ptr->vaddr, &ptr->paddr, &left)
: backing_at (eo, ptr->vaddr, &ptr->paddr, &left);
if (!backed && ptr->vaddr >= eo->memory_base) {
ptr->paddr = ptr->vaddr - eo->memory_base;
}
ptr->size = phdr[i].p_type == PT_LOAD? left: R_MIN (ptr->size, left);
}

ptr->perm = phdr[i].p_flags; // perm are rwx like x=1, w=2, r=4, aka no need to convert from r2's R_PERM
ptr->is_segment = true;
Expand Down Expand Up @@ -5327,7 +5407,7 @@ static RVecRBinElfSymbol *parse_gnu_debugdata(ELFOBJ *eo, size_t *ret_size) {
ut8 *odata = r_sys_unxz (data, size, &osize);
if (odata) {
RBuffer *newelf = r_buf_new_with_pointers (odata, osize, false);
ELFOBJ* newobj = Elf_(new_buf) (newelf, eo->user_baddr, false);
ELFOBJ* newobj = Elf_(new_buf) (newelf, eo->user_baddr, false, false);
RVecRBinElfSymbol *symbols = NULL;
if (newobj) {
newobj->limit = eo->limit;
Expand Down Expand Up @@ -5974,14 +6054,15 @@ void Elf_(free)(ELFOBJ* eo) {
free (eo);
}

ELFOBJ* Elf_(new_buf)(RBuffer *buf, ut64 baddr, bool verbose) {
ELFOBJ* Elf_(new_buf)(RBuffer *buf, ut64 baddr, bool verbose, bool inmem) {
ELFOBJ *eo = R_NEW0 (ELFOBJ);
RVecRBinTrycatch_init (&eo->trycatch);
eo->kv = sdb_new0 ();
eo->size = r_buf_size (buf);
eo->verbose = verbose;
eo->b = r_ref (buf);
eo->user_baddr = baddr;
eo->inmem = inmem;
if (!elf_init (eo)) {
Elf_(free) (eo);
return NULL;
Expand All @@ -5999,6 +6080,10 @@ static int is_in_vphdr(Elf_(Phdr) *p, ut64 addr) {

ut64 Elf_(p2v)(ELFOBJ *eo, ut64 paddr) {
R_RETURN_VAL_IF_FAIL (eo, UT64_MAX);
if (eo->inmem) {
const ut64 vaddr = paddr + eo->memory_base;
return Elf_(v2p) (eo, vaddr) == paddr? vaddr: UT64_MAX;
}
if (eo->phdr) {
// When multiple PT_LOAD segments overlap in file-offset space (UPX)
// p_vaddr match so p2v/v2p round-trip at the real code region.
Expand Down Expand Up @@ -6036,6 +6121,10 @@ ut64 Elf_(p2v)(ELFOBJ *eo, ut64 paddr) {

ut64 Elf_(v2p)(ELFOBJ *eo, ut64 vaddr) {
R_RETURN_VAL_IF_FAIL (eo, UT64_MAX);
if (eo->inmem) {
ut64 off, left;
return backing_at (eo, vaddr, &off, &left)? off: UT64_MAX;
}
if (eo->phdr) {
size_t i;
for (i = 0; i < eo->phnum; i++) {
Expand Down
4 changes: 3 additions & 1 deletion libr/bin/format/elf/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,11 @@ struct Elf_(obj_t) {
ut64 size;
ut64 baddr;
ut64 user_baddr;
ut64 memory_base;
ut64 boffset;
int endian;
bool verbose;
bool inmem;
bool load_unnamed;
bool has_nobtcfi;
bool has_nx;
Expand Down Expand Up @@ -260,7 +262,7 @@ const RVecRBinElfField *Elf_(load_fields)(struct Elf_(obj_t) *bin);
char *Elf_(get_rpath)(struct Elf_(obj_t) *bin);

struct Elf_(obj_t)* Elf_(new)(const char* file, bool verbose);
struct Elf_(obj_t)* Elf_(new_buf)(RBuffer *buf, ut64 user_baddr, bool verbose);
struct Elf_(obj_t)* Elf_(new_buf)(RBuffer *buf, ut64 user_baddr, bool verbose, bool inmem);
void Elf_(free)(struct Elf_(obj_t)* bin);

ut64 Elf_(resize_section)(RBinFile *bf, const char *name, ut64 size);
Expand Down
3 changes: 2 additions & 1 deletion libr/bin/p/bin_elf.inc.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ static Sdb* get_sdb(RBinFile *bf) {
}

static bool load(RBinFile *bf, RBuffer *buf, ut64 loadaddr) {
ELFOBJ *res = Elf_(new_buf) (buf, bf->user_baddr, bf->rbin->options.verbose);
ELFOBJ *res = Elf_(new_buf) (buf, bf->user_baddr, bf->rbin->options.verbose, bf->inmem);
if (res) {
bf->inmem = res->inmem; // so a reload keeps the layout it settled on
// sdb_ns_set (sdb, "info", res->kv);
res->limit = bf->rbin->options.limit;
res->load_unnamed = bf->rbin->options.load_unnamed;
Expand Down
4 changes: 2 additions & 2 deletions libr/bin/p/bin_mdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static RBinMdtPart *load_segment_part(ELFOBJ *header, int idx) {
magic[2] == ELFMAG2 && magic[3] == ELFMAG3) {
part->format = R_BIN_MDT_PART_ELF;
// Load nested ELF
part->obj.elf = Elf_(new_buf) (vfile_buffer, 0, false);
part->obj.elf = Elf_(new_buf) (vfile_buffer, 0, false, false);
// symbols are read from the nested ELF in symbols_vec
} else if ((segment->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_SIGNATURE) {
part->format = R_BIN_MDT_PART_MBN;
Expand Down Expand Up @@ -231,7 +231,7 @@ static bool load(RBinFile *bf, RBuffer *b, ut64 loadaddr) {
mdt->name = strdup (bf->file ? r_file_basename (bf->file) : "firmware");

// Load header ELF
mdt->header = Elf_(new_buf) (b, 0, false);
mdt->header = Elf_(new_buf) (b, 0, false, false);
if (!mdt->header) {
R_LOG_ERROR ("Failed to parse .mdt ELF header");
goto error;
Expand Down
1 change: 1 addition & 0 deletions libr/core/cconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -4417,6 +4417,7 @@ R_API int r_core_config_init(RCore *core) {
SETB ("bin.relocs", "true", "load relocs information at startup if available");
SETB ("bin.relocs.apply", "false", "apply reloc information");
SETB ("bin.relocs.xrefs", "true", "register xrefs from reloc information");
SETB ("bin.inmem", "false", "read oba input as a mapped memory image");
SETICB ("bin.maxsymlen", 0, &cb_binmaxsymlen, "maximum length for symbol names");
SETICB ("bin.str.min", 0, &cb_binminstr, "minimum string length for r_bin");
SETICB ("bin.str.max", 0, &cb_binmaxstr, "maximum string length for r_bin");
Expand Down
29 changes: 7 additions & 22 deletions libr/core/cmd_open.inc.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ static RCoreHelpMessage help_msg_omb = {
static RCoreHelpMessage help_msg_oba = {
"Usage: oba", "[addr] ([filename])", "Load bininfo and update flags",
"oba", " [addr]", "open bin info from the given address",
"oba", " [addr] [baddr]", "open file and load bin info at given address",
"oba", " [addr] [baddr]", "open file and load bin info at given address (bin.inmem reads it as a memory image)",
"oba", " [addr] [/abs/filename|base64:filename]", "open file and load bin info at given address",
NULL
};
Expand All @@ -111,7 +111,7 @@ static RCoreHelpMessage help_msg_ob = {
"ob--", "", "delete the last binfile",
"ob.", " ([addr])", "show bfid at current address",
"ob=", "", "show ascii art table having the list of open files",
"oba", " [addr] [baddr]", "open file and load bin info at given address",
"oba", " [addr] [baddr]", "open file and load bin info at given address (bin.inmem reads it as a memory image)",
"oba", " [addr] [filename]", "open file and load bin info at given address",
"oba", " [addr]", "open bin info from the given address",
"obf", " ([file|base64:file])", "load bininfo for current file (useful for r2 -n)",
Expand Down Expand Up @@ -301,34 +301,19 @@ static void cmd_oba(RCore *core, const char *input) {
R_LOG_ERROR ("Cannot oba open '%s'", r_str_trim_head_ro (filename));
} else if (encoded_filename) {
R_LOG_ERROR ("Cannot oba open decoded filename");
} else if (R_STR_ISNOTEMPTY (filename)) {
ut64 baddr = r_num_math (core->num, filename);
} else {
ut64 addr = r_num_math (core->num, input + 2); // mapaddr
ut64 baddr = R_STR_ISNOTEMPTY (filename)? r_num_math (core->num, filename): addr;
int fd = r_io_fd_get_current (core->io);
RIODesc *desc = r_io_desc_get (core->io, fd);
if (desc) {
RBinFileOptions opt;
r_bin_file_options_init (&opt, desc->fd, baddr, addr, rawstr);
opt.inmem = r_config_get_b (core->config, "bin.inmem");
opt.sz = oba_memsize (core->dbg, addr);
if (!opt.sz) {
opt.sz = 1024 * 1024;
}
r_bin_open_io (core->bin, &opt);
oba_finish_load (core);
r_core_cmd0 (core, ".is*");
} else {
R_LOG_ERROR ("No file to load bin from?");
}
} else {
ut64 addr = r_num_math (core->num, input + 2);
int fd = r_io_fd_get_current (core->io);
RIODesc *desc = r_io_desc_get (core->io, fd);
if (desc) {
RBinFileOptions opt;
r_bin_file_options_init (&opt, desc->fd, addr, addr, rawstr);
opt.sz = oba_memsize (core->dbg, addr);
if (!opt.sz) {
opt.sz = 1024 * 1024;
const ut64 desc_size = r_io_desc_size (desc);
opt.sz = (opt.inmem && addr < desc_size)? desc_size - addr: 1024 * 1024;
}
r_bin_open_io (core->bin, &opt);
oba_finish_load (core);
Expand Down
2 changes: 2 additions & 0 deletions libr/include/r_bin.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ typedef struct r_bin_file_options_t {
int rawstr;
bool nofuncstarts;
bool skip_symbols; // skip symbol loading (e.g., for companion debug files)
bool inmem;
const char *filename;
} RBinFileOptions;

Expand Down Expand Up @@ -594,6 +595,7 @@ typedef struct r_bin_file_t {
} dwarf_metadata;
struct r_bin_t *rbin;
int string_count;
bool inmem;
RArena *arena;
} RBinFile;

Expand Down
Loading
Loading