mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-04 11:43:39 +00:00
Fix ELF support for 32-64bit relro relocations, fix negative allocation in PE and null deref
This commit is contained in:
parent
65af037198
commit
45f193bb6a
@ -19,6 +19,9 @@
|
||||
#define ELF_PAGE_MASK 0xFFFFFFFFFFFFF000LL
|
||||
#define ELF_PAGE_SIZE 12
|
||||
|
||||
#define R_ELF_FULL_RELRO 2
|
||||
#define R_ELF_PART_RELRO 1
|
||||
|
||||
#define READ8(x, i) r_read_ble8(x + i); i += 1;
|
||||
#define READ16(x, i) r_read_ble16(x + i, bin->endian); i += 2;
|
||||
#define READ32(x, i) r_read_ble32(x + i, bin->endian); i += 4;
|
||||
@ -338,13 +341,13 @@ static int init_strtab(ELFOBJ *bin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int init_dynamic_section (struct Elf_(r_bin_elf_obj_t) *bin) {
|
||||
static int init_dynamic_section(struct Elf_(r_bin_elf_obj_t) *bin) {
|
||||
Elf_(Dyn) *dyn = NULL;
|
||||
Elf_(Dyn) d = {};
|
||||
Elf_(Addr) strtabaddr = 0;
|
||||
ut64 offset = 0;
|
||||
char *strtab = NULL;
|
||||
size_t strsize = 0;
|
||||
size_t relentry, strsize = 0;
|
||||
int entries;
|
||||
int i, j, len, r;
|
||||
ut8 sdyn[sizeof (Elf_(Dyn))] = {0};
|
||||
@ -421,6 +424,7 @@ static int init_dynamic_section (struct Elf_(r_bin_elf_obj_t) *bin) {
|
||||
case DT_STRTAB: strtabaddr = Elf_(r_bin_elf_v2p) (bin, dyn[i].d_un.d_ptr); break;
|
||||
case DT_STRSZ: strsize = dyn[i].d_un.d_val; break;
|
||||
case DT_PLTREL: bin->is_rela = dyn[i].d_un.d_val; break;
|
||||
case DT_RELAENT: relentry = dyn[i].d_un.d_val; break;
|
||||
default:
|
||||
if ((dyn[i].d_tag >= DT_VERSYM) && (dyn[i].d_tag <= DT_VERNEEDNUM)) {
|
||||
bin->version_info[DT_VERSIONTAGIDX (dyn[i].d_tag)] = dyn[i].d_un.d_val;
|
||||
@ -428,6 +432,9 @@ static int init_dynamic_section (struct Elf_(r_bin_elf_obj_t) *bin) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bin->is_rela) {
|
||||
bin->is_rela = sizeof (Elf_(Rela)) == relentry? DT_RELA : DT_REL;
|
||||
}
|
||||
if (!strtabaddr || strtabaddr > bin->size || strsize > ST32_MAX || !strsize || strsize > bin->size) {
|
||||
if (!strtabaddr) {
|
||||
eprintf ("Warning: section.shstrtab not found or invalid\n");
|
||||
@ -452,12 +459,16 @@ static int init_dynamic_section (struct Elf_(r_bin_elf_obj_t) *bin) {
|
||||
bin->strtab = strtab;
|
||||
bin->strtab_size = strsize;
|
||||
r = Elf_(r_bin_elf_has_relro)(bin);
|
||||
if (r == 2) {
|
||||
switch (r) {
|
||||
case R_ELF_FULL_RELRO:
|
||||
sdb_set (bin->kv, "elf.relro", "full relro", 0);
|
||||
} else if (r == 1) {
|
||||
break;
|
||||
case R_ELF_PART_RELRO:
|
||||
sdb_set (bin->kv, "elf.relro", "partial relro", 0);
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
sdb_set (bin->kv, "elf.relro", "no relro", 0);
|
||||
break;
|
||||
}
|
||||
sdb_num_set (bin->kv, "elf_strtab.offset", strtabaddr, 0);
|
||||
sdb_num_set (bin->kv, "elf_strtab.size", strsize, 0);
|
||||
@ -1085,6 +1096,7 @@ static ut64 get_import_addr(ELFOBJ *bin, int sym) {
|
||||
ut64 plt_addr;
|
||||
int j, k, tsize, len, nrel;
|
||||
bool is_rela = false;
|
||||
const char *rel_sect[] = { ".rel.plt", ".rela.plt", ".rela.dyn", ".rel.dyn", NULL };
|
||||
|
||||
if ((!bin->shdr || !bin->strtab) && !bin->phdr) {
|
||||
return -1;
|
||||
@ -1098,15 +1110,15 @@ static ut64 get_import_addr(ELFOBJ *bin, int sym) {
|
||||
return -1;
|
||||
}
|
||||
if (bin->is_rela == DT_REL) {
|
||||
rel_sec = get_section_by_name (bin, ".rel.plt");
|
||||
if (!rel_sec) {
|
||||
rel_sec = get_section_by_name (bin, ".rela.plt");
|
||||
j = 0;
|
||||
while (!rel_sec && rel_sect[j]) {
|
||||
rel_sec = get_section_by_name (bin, rel_sect[j++]);
|
||||
}
|
||||
tsize = sizeof (Elf_(Rel));
|
||||
} else if (bin->is_rela == DT_RELA) {
|
||||
rel_sec = get_section_by_name (bin, ".rela.plt");
|
||||
if (!rel_sec) {
|
||||
rel_sec = get_section_by_name (bin, ".rel.plt");
|
||||
j = 0;
|
||||
while (!rel_sec && rel_sect[j]) {
|
||||
rel_sec = get_section_by_name (bin, rel_sect[j++]);
|
||||
}
|
||||
is_rela = true;
|
||||
tsize = sizeof (Elf_(Rela));
|
||||
@ -1134,8 +1146,12 @@ static ut64 get_import_addr(ELFOBJ *bin, int sym) {
|
||||
}
|
||||
for (j = k = 0; j < rel_sec->size && k < nrel; j += tsize, k++) {
|
||||
int l = 0;
|
||||
if (rel_sec->offset + j > bin->size) goto out;
|
||||
if (rel_sec->offset + j + tsize > bin->size) goto out;
|
||||
if (rel_sec->offset + j > bin->size) {
|
||||
goto out;
|
||||
}
|
||||
if (rel_sec->offset + j + tsize > bin->size) {
|
||||
goto out;
|
||||
}
|
||||
len = r_buf_read_at (bin->b, rel_sec->offset + j, is_rela? rla: rl, is_rela? sizeof (Elf_(Rela)): sizeof (Elf_(Rel)));
|
||||
if (len < 1) {
|
||||
goto out;
|
||||
@ -1217,7 +1233,9 @@ static ut64 get_import_addr(ELFOBJ *bin, int sym) {
|
||||
{
|
||||
plt_addr += k * 12 + 20;
|
||||
// thumb symbol
|
||||
if (plt_addr & 1) plt_addr--;
|
||||
if (plt_addr & 1) {
|
||||
plt_addr--;
|
||||
}
|
||||
free (REL);
|
||||
return plt_addr;
|
||||
}
|
||||
@ -1237,9 +1255,7 @@ static ut64 get_import_addr(ELFOBJ *bin, int sym) {
|
||||
case R_386_JMP_SLOT:
|
||||
{
|
||||
ut8 buf[8];
|
||||
if (of + sizeof(Elf_(Addr)) >= bin->b->length) {
|
||||
// do nothing
|
||||
} else {
|
||||
if (of + sizeof(Elf_(Addr)) < bin->size) {
|
||||
// ONLY FOR X86
|
||||
if (of > bin->size || of + sizeof (Elf_(Addr)) > bin->size) {
|
||||
goto out;
|
||||
@ -1251,9 +1267,55 @@ static ut64 get_import_addr(ELFOBJ *bin, int sym) {
|
||||
plt_sym_addr = sizeof (Elf_(Addr)) == 4
|
||||
? r_read_le32 (buf)
|
||||
: r_read_le64 (buf);
|
||||
|
||||
if (!plt_sym_addr) {
|
||||
//XXX HACK ALERT!!!! full relro?? try to fix it
|
||||
//will there always be .plt.got, what would happen if is .got.plt?
|
||||
RBinElfSection *s = get_section_by_name (bin, ".plt.got");
|
||||
if (Elf_(r_bin_elf_has_relro)(bin) != R_ELF_FULL_RELRO || !s) {
|
||||
goto done;
|
||||
}
|
||||
plt_addr = s->offset;
|
||||
of = of + got_addr - got_offset;
|
||||
while (plt_addr + 2 + 4 < s->offset + s->size) {
|
||||
/*we try to locate the plt entry that correspond with the relocation
|
||||
since got does not point back to .plt. In this case it has the following
|
||||
form
|
||||
|
||||
ff253a152000 JMP QWORD [RIP + 0x20153A]
|
||||
6690 NOP
|
||||
----
|
||||
ff25ec9f0408 JMP DWORD [reloc.puts_236]
|
||||
|
||||
plt_addr + 2 to remove jmp opcode and get the imm reading 4
|
||||
and if RIP (plt_addr + 6) + imm == rel->offset
|
||||
return plt_addr, that will be our sym addr
|
||||
|
||||
perhaps this hack doesn't work on 32 bits
|
||||
*/
|
||||
len = r_buf_read_at (bin->b, plt_addr + 2, buf, 4);
|
||||
if (len < -1) {
|
||||
goto out;
|
||||
}
|
||||
plt_sym_addr = sizeof (Elf_(Addr)) == 4
|
||||
? r_read_le32 (buf)
|
||||
: r_read_le64 (buf);
|
||||
|
||||
//relative address
|
||||
if ((plt_addr + 6 + Elf_(r_bin_elf_v2p) (bin, plt_sym_addr)) == of) {
|
||||
plt_sym_addr = plt_addr;
|
||||
goto done;
|
||||
} else if (plt_sym_addr == of) {
|
||||
plt_sym_addr = plt_addr;
|
||||
goto done;
|
||||
}
|
||||
plt_addr += 8;
|
||||
}
|
||||
} else {
|
||||
plt_sym_addr -= 6;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
plt_sym_addr -= 6;
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -1850,6 +1912,9 @@ char* Elf_(r_bin_elf_get_elf_class)(ELFOBJ *bin) {
|
||||
|
||||
int Elf_(r_bin_elf_get_bits)(ELFOBJ *bin) {
|
||||
/* Hack for ARCompact */
|
||||
if (bin->bits) {
|
||||
return bin->bits;
|
||||
}
|
||||
if (bin->ehdr.e_machine == EM_ARC_A5) {
|
||||
return 16;
|
||||
}
|
||||
@ -1862,7 +1927,8 @@ int Elf_(r_bin_elf_get_bits)(ELFOBJ *bin) {
|
||||
for (i = 0; !symbol[i].last; i++) {
|
||||
ut64 paddr = symbol[i].offset;
|
||||
if (paddr & 1) {
|
||||
return 16;
|
||||
bin->bits = 16;
|
||||
return bin->bits;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1870,16 +1936,18 @@ int Elf_(r_bin_elf_get_bits)(ELFOBJ *bin) {
|
||||
{
|
||||
ut64 entry = Elf_(r_bin_elf_get_entry_offset) (bin);
|
||||
if (entry & 1) {
|
||||
return 16;
|
||||
bin->bits = 16;
|
||||
return bin->bits;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (bin->ehdr.e_ident[EI_CLASS]) {
|
||||
case ELFCLASS32: return 32;
|
||||
case ELFCLASS64: return 64;
|
||||
case ELFCLASS32: bin->bits = 32;
|
||||
case ELFCLASS64: bin->bits = 64;
|
||||
case ELFCLASSNONE:
|
||||
default: return 32; // defaults
|
||||
default: bin->bits = 32; // defaults
|
||||
}
|
||||
return bin->bits;
|
||||
}
|
||||
|
||||
static inline int noodle(ELFOBJ *bin, const char *s) {
|
||||
@ -2501,7 +2569,6 @@ static int Elf_(fix_symbols)(ELFOBJ *bin, int nsym, int type, RBinElfSymbol **sy
|
||||
/* find match in phdr */
|
||||
p = phdr_symbols;
|
||||
while (!p->last) {
|
||||
// eprintf ("-> %s\n", p->name);
|
||||
if (d->offset == p->offset) {
|
||||
p->in_shdr = true;
|
||||
if (*p->name && strcmp (d->name, p->name)) {
|
||||
@ -2689,7 +2756,7 @@ static RBinElfSymbol* Elf_(_r_bin_elf_get_symbols_imports)(ELFOBJ *bin, int type
|
||||
if (st_name < 0 || st_name >= maxsize) {
|
||||
ret[ret_ctr].name[0] = 0;
|
||||
} else {
|
||||
const size_t len = __strnlen (strtab+sym[k].st_name, rest);
|
||||
const size_t len = __strnlen (strtab + sym[k].st_name, rest);
|
||||
memcpy (ret[ret_ctr].name, &strtab[sym[k].st_name], len);
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +99,7 @@ struct Elf_(r_bin_elf_obj_t) {
|
||||
size_t symbols_by_ord_size;
|
||||
|
||||
int bss;
|
||||
int bits;
|
||||
ut64 size;
|
||||
ut64 baddr;
|
||||
ut64 boffset;
|
||||
|
@ -1823,6 +1823,9 @@ struct r_bin_pe_export_t* PE_(r_bin_pe_get_exports)(struct PE_(r_bin_pe_obj_t)*
|
||||
export_dir_size = data_dir_export->Size;
|
||||
if (bin->export_directory) {
|
||||
exports_sz = (bin->export_directory->NumberOfFunctions + 1) * sizeof (struct r_bin_pe_export_t);
|
||||
if (exports_sz < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (!(exports = malloc (exports_sz))) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -995,14 +995,17 @@ static int __disasm(void *_core, ut64 addr) {
|
||||
static void update_sdb(RCore *core) {
|
||||
Sdb *d;
|
||||
RBinObject *o;
|
||||
if (!core)
|
||||
if (!core) {
|
||||
return;
|
||||
}
|
||||
//SDB// anal/
|
||||
if (core->anal && core->anal->sdb)
|
||||
if (core->anal && core->anal->sdb) {
|
||||
sdb_ns_set (DB, "anal", core->anal->sdb);
|
||||
}
|
||||
//SDB// bin/
|
||||
if (core->bin && core->bin->sdb)
|
||||
if (core->bin && core->bin->sdb) {
|
||||
sdb_ns_set (DB, "bin", core->bin->sdb);
|
||||
}
|
||||
//SDB// bin/info
|
||||
o = r_bin_get_object (core->bin);
|
||||
if (o) {
|
||||
@ -1016,8 +1019,10 @@ static void update_sdb(RCore *core) {
|
||||
sdb_ns_set (DB, "syscall", core->assembler->syscall->db);
|
||||
}
|
||||
d = sdb_ns (DB, "debug", 1);
|
||||
core->dbg->sgnls->refs++;
|
||||
sdb_ns_set (d, "signals", core->dbg->sgnls);
|
||||
if (core->dbg->sgnls) {
|
||||
core->dbg->sgnls->refs++;
|
||||
sdb_ns_set (d, "signals", core->dbg->sgnls);
|
||||
}
|
||||
}
|
||||
|
||||
// dupped in cmd_type.c
|
||||
|
@ -311,8 +311,11 @@ static void list_section_visual_paddr (RIO *io, ut64 seek, ut64 len, int use_col
|
||||
|
||||
/* TODO: move to print ??? support pretty print of ranges following an array of offsetof */
|
||||
R_API void r_io_section_list_visual(RIO *io, ut64 seek, ut64 len, int use_color, int cols) {
|
||||
if (io->va) list_section_visual_vaddr (io, seek, len, use_color, cols);
|
||||
else list_section_visual_paddr (io, seek, len, use_color, cols);
|
||||
if (io->va) {
|
||||
list_section_visual_vaddr (io, seek, len, use_color, cols);
|
||||
} else {
|
||||
list_section_visual_paddr (io, seek, len, use_color, cols);
|
||||
}
|
||||
}
|
||||
|
||||
R_API RIOSection *r_io_section_vget(RIO *io, ut64 vaddr) {
|
||||
|
Loading…
Reference in New Issue
Block a user