Fix ELF support for 32-64bit relro relocations, fix negative allocation in PE and null deref

This commit is contained in:
Álvaro Felipe Melchor 2016-10-11 14:32:35 +02:00 committed by radare
parent 65af037198
commit 45f193bb6a
5 changed files with 112 additions and 33 deletions

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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) {