From 5567da9538b6710bc7122ecb4e2dbab2e4072414 Mon Sep 17 00:00:00 2001 From: Nibble Date: Fri, 10 Sep 2010 11:11:38 +0200 Subject: [PATCH] * Add support for parsing relocs to r_bin * Add flag -R to rabin2 to list relocs * Implement reloc resolution in r_bin_elf for 32 & 64 bits --- TODO | 4 +- binr/rabin2/rabin2.c | 36 +++++++++++++++- libr/bin/bin.c | 8 ++++ libr/bin/format/elf/elf.c | 85 ++++++++++++++++++++++++++++++++++++- libr/bin/format/elf/elf.h | 9 ++++ libr/bin/format/java/java.c | 1 + libr/bin/format/pe/pe.c | 1 + libr/bin/p/bin_dummy.c | 1 + libr/bin/p/bin_elf.c | 26 ++++++++++++ libr/bin/p/bin_elf64.c | 1 + libr/bin/p/bin_fatmach0.c | 1 + libr/bin/p/bin_java.c | 1 + libr/bin/p/bin_mach0.c | 1 + libr/bin/p/bin_mach064.c | 1 + libr/bin/p/bin_pe.c | 1 + libr/bin/p/bin_pe64.c | 1 + libr/include/r_bin.h | 11 +++++ 17 files changed, 184 insertions(+), 5 deletions(-) diff --git a/TODO b/TODO index f660d1ec5b..5026a8582f 100644 --- a/TODO +++ b/TODO @@ -41,10 +41,10 @@ Build system: TODO nibble ----------- +* r_bin->relocs // RList of relocations +* use r_anal_value everywhere in r_anal * make x86_x86im the default backend for x86 analysis * implement analysis for more instructions in x86_x86im -* use r_anal_value everywhere in r_anal -* r_bin->relocs // RList of relocations * big-ssl.c big-gmp.c ... * native fat bins support (push uncommited changes) * diff code analysis diff --git a/binr/rabin2/rabin2.c b/binr/rabin2/rabin2.c index 0c6c52bb06..28e7ee1173 100644 --- a/binr/rabin2/rabin2.c +++ b/binr/rabin2/rabin2.c @@ -29,6 +29,7 @@ #define ACTION_SRCLINE 0x0400 #define ACTION_MAIN 0x0800 #define ACTION_EXTRACT 0x1000 +#define ACTION_RELOCS 0x2000 static struct r_lib_t *l; static struct r_bin_t *bin = NULL; @@ -53,6 +54,7 @@ static int rabin_show_help() { " -I Binary info\n" " -H Header fields\n" " -l Linked libraries\n" + " -R Relocations\n" " -O [str] Write/Extract operations (str=help for help)\n" " -o [file] Output file for write operations (a.out by default)\n" " -f [format] Override file format autodetection\n" @@ -144,6 +146,33 @@ static int rabin_show_libs() { return R_TRUE; } +static int rabin_show_relocs() { + RList *relocs; + RListIter *iter; + RBinReloc *reloc; + int i = 0; + + ut64 baddr = gbaddr?gbaddr:r_bin_get_baddr (bin); + + if ((relocs = r_bin_get_relocs (bin)) == NULL) + return R_FALSE; + + if (rad) printf ("fs relocs\n"); + else printf ("[Relocations]\n"); + + r_list_foreach (relocs, iter, reloc) { + if (rad) { + printf ("f reloc.%s @ 0x%08"PFMT64x"\n", reloc->name, va?baddr+reloc->rva:reloc->offset); + } else printf ("sym=%02i address=0x%08"PFMT64x" offset=0x%08"PFMT64x" type=0x%08x %s\n", + reloc->sym, baddr+reloc->rva, reloc->offset, reloc->type, reloc->name); + i++; + } + + if (!rad) printf ("\n%i relocations\n", i); + + return R_TRUE; +} + static int rabin_show_imports() { RList *imports; RListIter *iter; @@ -573,7 +602,7 @@ int main(int argc, char **argv) r_lib_opendir (l, LIBDIR"/radare2/"); } - while ((c = getopt (argc, argv, "b:Mm:n:@:VisSzIHelwO:o:f:rvLhx")) != -1) { + while ((c = getopt (argc, argv, "b:Mm:n:@:VisSzIHelRwO:o:f:rvLhx")) != -1) { switch(c) { case 'm': at = r_num_math (NULL, optarg); @@ -605,6 +634,9 @@ int main(int argc, char **argv) case 'l': action |= ACTION_LIBS; break; + case 'R': + action |= ACTION_RELOCS; + break; case 'x': action |= ACTION_EXTRACT; break; @@ -679,6 +711,8 @@ int main(int argc, char **argv) rabin_show_fields(); if (action&ACTION_LIBS) rabin_show_libs(); + if (action&ACTION_RELOCS) + rabin_show_relocs(); if (action&ACTION_SRCLINE) rabin_show_srcline(at); if (action&ACTION_EXTRACT) diff --git a/libr/bin/bin.c b/libr/bin/bin.c index 8ed03a1c0f..2b78453dac 100644 --- a/libr/bin/bin.c +++ b/libr/bin/bin.c @@ -91,6 +91,8 @@ static void r_bin_init_items(RBin *bin) { bin->info = bin->cur->info (bin); if (bin->cur->libs) bin->libs = bin->cur->libs (bin); + if (bin->cur->relocs) + bin->relocs = bin->cur->relocs (bin); if (bin->cur->sections) bin->sections = bin->cur->sections (bin); if (bin->cur->strings) @@ -112,6 +114,8 @@ static void r_bin_free_items(RBin *bin) { free (bin->info); if (bin->libs) r_list_free (bin->libs); + if (bin->relocs) + r_list_free (bin->relocs); if (bin->sections) r_list_free (bin->sections); if (bin->strings) @@ -207,6 +211,10 @@ R_API RList* r_bin_get_libs(RBin *bin) { return bin->libs; } +R_API RList* r_bin_get_relocs(RBin *bin) { + return bin->relocs; +} + R_API RList* r_bin_get_sections(RBin *bin) { return bin->sections; } diff --git a/libr/bin/format/elf/elf.c b/libr/bin/format/elf/elf.c index f96933ab4f..698a00d1ca 100644 --- a/libr/bin/format/elf/elf.c +++ b/libr/bin/format/elf/elf.c @@ -486,6 +486,86 @@ char *Elf_(r_bin_elf_get_rpath)(struct Elf_(r_bin_elf_obj_t) *bin) { return ret; } +struct r_bin_elf_reloc_t* Elf_(r_bin_elf_get_relocs)(struct Elf_(r_bin_elf_obj_t) *bin) { + struct r_bin_elf_reloc_t *ret = NULL; + Elf_(Shdr) *strtab_section; + Elf_(Sym) *sym; + Elf_(Rel) *rel; + char *strtab; + int i, j, nrel, tsize, len, nsym; + + if (!bin->shdr || !bin->strtab) + return NULL; + for (i = 0, nsym = 0; i < bin->ehdr.e_shnum; i++) + if (bin->shdr[i].sh_type == (bin->ehdr.e_type == ET_REL ? SHT_SYMTAB : SHT_DYNSYM)) { + strtab_section = &bin->shdr[bin->shdr[i].sh_link]; + if ((strtab = (char *)malloc (8+strtab_section->sh_size)) == NULL) { + perror ("malloc (syms strtab)"); + return NULL; + } + if (r_buf_read_at (bin->b, strtab_section->sh_offset, (ut8*)strtab, strtab_section->sh_size) == -1) { + eprintf ("Error: read (syms strtab)\n"); + return NULL; + } + if ((sym = (Elf_(Sym) *)malloc (1+bin->shdr[i].sh_size)) == NULL) { + perror ("malloc (syms)"); + return NULL; + } + nsym = (int)(bin->shdr[i].sh_size/sizeof (Elf_(Sym))); + if (r_buf_fread_at (bin->b, bin->shdr[i].sh_offset, (ut8*)sym, +#if R_BIN_ELF64 + bin->endian?"I2cS2L":"i2cs2l", +#else + bin->endian?"3I2cS":"3i2cs", +#endif + nsym) == -1) { + eprintf ("Error: read (sym)\n"); + return NULL; + } + } + for (i = 0; i < bin->ehdr.e_shnum; i++) { + if (!strcmp (&bin->strtab[bin->shdr[i].sh_name], ".rel.plt")) + tsize = sizeof (Elf_(Rel)); + else if (!strcmp (&bin->strtab[bin->shdr[i].sh_name], ".rela.plt")) + tsize = sizeof (Elf_(Rela)); + else continue; + if ((rel = (Elf_(Rel) *)malloc ((int)(bin->shdr[i].sh_size / tsize) * sizeof (Elf_(Rel)))) == NULL) { + perror ("malloc (rel)"); + return NULL; + } + for (j = nrel = 0; j < bin->shdr[i].sh_size; j += tsize, nrel++) { + len = r_buf_fread_at (bin->b, bin->shdr[i].sh_offset + j, (ut8*)&rel[nrel], +#if R_BIN_ELF64 + bin->endian?"2L":"2l", +#else + bin->endian?"2I":"2i", +#endif + 1); + if (len == -1) { + eprintf ("Error: read (rel)\n"); + return NULL; + } + } + if ((ret = (struct r_bin_elf_reloc_t *)malloc (nrel * sizeof (struct r_bin_elf_reloc_t))) == NULL) { + perror ("malloc (reloc)"); + return NULL; + } + for (j = 0; j < nrel; j++) { + if (j < nsym) { + len = __strnlen (&strtab[sym[ELF_R_SYM (rel[j].r_info)].st_name], ELF_STRING_LENGTH-1); + memcpy (ret[j].name, &strtab[sym[ELF_R_SYM (rel[j].r_info)].st_name], len); + } else strncpy (ret[j].name, "unknown", ELF_STRING_LENGTH); + ret[j].sym = ELF_R_SYM (rel[j].r_info); + ret[j].type = ELF_R_TYPE (rel[j].r_info); + ret[j].offset = rel[j].r_offset - bin->baddr; + ret[j].last = 0; + } + ret[j].last = 1; + break; + } + return ret; +} + struct r_bin_elf_lib_t* Elf_(r_bin_elf_get_libs)(struct Elf_(r_bin_elf_obj_t) *bin) { struct r_bin_elf_lib_t *ret = NULL; Elf_(Dyn) *dyn = NULL; @@ -597,7 +677,7 @@ struct r_bin_elf_symbol_t* Elf_(r_bin_elf_get_symbols)(struct Elf_(r_bin_elf_obj return NULL; } if (r_buf_read_at (bin->b, strtab_section->sh_offset, (ut8*)strtab, strtab_section->sh_size) == -1) { - eprintf ("Error: read (magic)\n"); + eprintf ("Error: read (syms strtab)\n"); return NULL; } @@ -613,7 +693,7 @@ struct r_bin_elf_symbol_t* Elf_(r_bin_elf_get_symbols)(struct Elf_(r_bin_elf_obj bin->endian?"3I2cS":"3i2cs", #endif nsym) == -1) { - eprintf ("Error: read (ehdr)\n"); + eprintf ("Error: read (sym)\n"); return NULL; } for (j = k = ret_ctr = 0; j < bin->shdr[i].sh_size; j += sizeof (Elf_(Sym)), k++) { @@ -725,6 +805,7 @@ struct Elf_(r_bin_elf_obj_t)* Elf_(r_bin_elf_new)(const char* file) { if (!(bin = malloc (sizeof (struct Elf_(r_bin_elf_obj_t))))) return NULL; + memset (bin, 0, sizeof (struct Elf_(r_bin_elf_obj_t))); bin->file = file; if (!(buf = (ut8*)r_file_slurp (file, &bin->size))) return Elf_(r_bin_elf_free) (bin); diff --git a/libr/bin/format/elf/elf.h b/libr/bin/format/elf/elf.h index a27ca11de2..c6dbfa8006 100644 --- a/libr/bin/format/elf/elf.h +++ b/libr/bin/format/elf/elf.h @@ -34,6 +34,14 @@ typedef struct r_bin_elf_symbol_t { int last; } RBinElfSymbol; +typedef struct r_bin_elf_reloc_t { + int sym; + int type; + ut64 offset; + int last; + char name[ELF_STRING_LENGTH]; +} RBinElfReloc; + typedef struct r_bin_elf_field_t { ut64 offset; char name[ELF_STRING_LENGTH]; @@ -79,6 +87,7 @@ char* Elf_(r_bin_elf_get_elf_class)(struct Elf_(r_bin_elf_obj_t) *bin); int Elf_(r_bin_elf_get_bits)(struct Elf_(r_bin_elf_obj_t) *bin); char* Elf_(r_bin_elf_get_osabi_name)(struct Elf_(r_bin_elf_obj_t) *bin); int Elf_(r_bin_elf_is_big_endian)(struct Elf_(r_bin_elf_obj_t) *bin); +struct r_bin_elf_reloc_t* Elf_(r_bin_elf_get_relocs)(struct Elf_(r_bin_elf_obj_t) *bin); struct r_bin_elf_lib_t* Elf_(r_bin_elf_get_libs)(struct Elf_(r_bin_elf_obj_t) *bin); struct r_bin_elf_section_t* Elf_(r_bin_elf_get_sections)(struct Elf_(r_bin_elf_obj_t) *bin); struct r_bin_elf_symbol_t* Elf_(r_bin_elf_get_symbols)(struct Elf_(r_bin_elf_obj_t) *bin, int type); diff --git a/libr/bin/format/java/java.c b/libr/bin/format/java/java.c index 89a4ea68bd..e37f804323 100644 --- a/libr/bin/format/java/java.c +++ b/libr/bin/format/java/java.c @@ -421,6 +421,7 @@ struct r_bin_java_obj_t* r_bin_java_new(const char* file) { if (!(bin = malloc(sizeof(struct r_bin_java_obj_t)))) return NULL; + memset (bin, 0, sizeof (struct r_bin_java_obj_t)); bin->file = file; if (!(buf = (ut8*)r_file_slurp(file, &bin->size))) return r_bin_java_free(bin); diff --git a/libr/bin/format/pe/pe.c b/libr/bin/format/pe/pe.c index 19528272e8..197e9934d0 100644 --- a/libr/bin/format/pe/pe.c +++ b/libr/bin/format/pe/pe.c @@ -745,6 +745,7 @@ struct PE_(r_bin_pe_obj_t)* PE_(r_bin_pe_new)(const char* file) if (!(bin = malloc(sizeof(struct PE_(r_bin_pe_obj_t))))) return NULL; + memset (bin, 0, sizeof (struct PE_(r_bin_pe_obj_t))); bin->file = file; if (!(buf = (ut8*)r_file_slurp(file, &bin->size))) return PE_(r_bin_pe_free)(bin); diff --git a/libr/bin/p/bin_dummy.c b/libr/bin/p/bin_dummy.c index 0e19a8ad97..a300fab8dd 100644 --- a/libr/bin/p/bin_dummy.c +++ b/libr/bin/p/bin_dummy.c @@ -46,6 +46,7 @@ struct r_bin_plugin_t r_bin_plugin_dummy = { .info = NULL, .fields = NULL, .libs = NULL, + .relocs = NULL, .meta = NULL, .write = NULL, }; diff --git a/libr/bin/p/bin_elf.c b/libr/bin/p/bin_elf.c index 1977c483d1..2b4f29432b 100644 --- a/libr/bin/p/bin_elf.c +++ b/libr/bin/p/bin_elf.c @@ -155,6 +155,31 @@ static RList* libs(RBin *bin) { return ret; } +static RList* relocs(RBin *bin) { + RList *ret = NULL; + RBinReloc *ptr = NULL; + struct r_bin_elf_reloc_t *relocs = NULL; + int i; + + if (!(ret = r_list_new ())) + return NULL; + ret->free = free; + if (!(relocs = Elf_(r_bin_elf_get_relocs) (bin->bin_obj))) + return ret; + for (i = 0; !relocs[i].last; i++) { + if (!(ptr = R_NEW (RBinReloc))) + break; + strncpy (ptr->name, relocs[i].name, R_BIN_SIZEOF_STRINGS); + ptr->rva = relocs[i].offset; + ptr->offset = relocs[i].offset; + ptr->type = relocs[i].type; + ptr->sym = relocs[i].sym; + r_list_append (ret, ptr); + } + free (relocs); + return ret; +} + static RBinInfo* info(RBin *bin) { RBinInfo *ret = NULL; char *str; @@ -265,6 +290,7 @@ struct r_bin_plugin_t r_bin_plugin_elf = { .info = &info, .fields = &fields, .libs = &libs, + .relocs = &relocs, .meta = &r_bin_meta_elf, .write = &r_bin_write_elf, }; diff --git a/libr/bin/p/bin_elf64.c b/libr/bin/p/bin_elf64.c index 9b7384f920..5bed8ab2f2 100644 --- a/libr/bin/p/bin_elf64.c +++ b/libr/bin/p/bin_elf64.c @@ -38,6 +38,7 @@ struct r_bin_plugin_t r_bin_plugin_elf64 = { .info = &info, .fields = &fields, .libs = &libs, + .relocs = &relocs, .meta = &r_bin_meta_elf64, .write = &r_bin_write_elf64, }; diff --git a/libr/bin/p/bin_fatmach0.c b/libr/bin/p/bin_fatmach0.c index eed1c3d66a..40642d76ad 100644 --- a/libr/bin/p/bin_fatmach0.c +++ b/libr/bin/p/bin_fatmach0.c @@ -65,6 +65,7 @@ struct r_bin_plugin_t r_bin_plugin_fatmach0 = { .info = NULL, .fields = NULL, .libs = NULL, + .relocs = NULL, .meta = NULL, .write = NULL, }; diff --git a/libr/bin/p/bin_java.c b/libr/bin/p/bin_java.c index 0fc57cd1e1..6c9c3ea894 100644 --- a/libr/bin/p/bin_java.c +++ b/libr/bin/p/bin_java.c @@ -154,6 +154,7 @@ struct r_bin_plugin_t r_bin_plugin_java = { .info = &info, .fields = NULL, .libs = NULL, + .relocs = NULL, .meta = NULL, .write = NULL, }; diff --git a/libr/bin/p/bin_mach0.c b/libr/bin/p/bin_mach0.c index aff3bc859d..cfd262c214 100644 --- a/libr/bin/p/bin_mach0.c +++ b/libr/bin/p/bin_mach0.c @@ -217,6 +217,7 @@ struct r_bin_plugin_t r_bin_plugin_mach0 = { .info = &info, .fields = NULL, .libs = &libs, + .relocs = NULL, .meta = NULL, .write = NULL, }; diff --git a/libr/bin/p/bin_mach064.c b/libr/bin/p/bin_mach064.c index 4e11add2f0..037cb67311 100644 --- a/libr/bin/p/bin_mach064.c +++ b/libr/bin/p/bin_mach064.c @@ -35,6 +35,7 @@ struct r_bin_plugin_t r_bin_plugin_mach064 = { .info = &info, .fields = NULL, .libs = &libs, + .relocs = NULL, .meta = NULL, .write = NULL, }; diff --git a/libr/bin/p/bin_pe.c b/libr/bin/p/bin_pe.c index b608218d1b..13e5e90b36 100644 --- a/libr/bin/p/bin_pe.c +++ b/libr/bin/p/bin_pe.c @@ -243,6 +243,7 @@ struct r_bin_plugin_t r_bin_plugin_pe = { .info = &info, .fields = NULL, .libs = &libs, + .relocs = NULL, .meta = NULL, .write = NULL, }; diff --git a/libr/bin/p/bin_pe64.c b/libr/bin/p/bin_pe64.c index fbc402dc5a..9f587a270d 100644 --- a/libr/bin/p/bin_pe64.c +++ b/libr/bin/p/bin_pe64.c @@ -38,6 +38,7 @@ struct r_bin_plugin_t r_bin_plugin_pe64 = { .info = &info, .fields = NULL, .libs = &libs, + .relocs = NULL, .meta = NULL, .write = NULL, }; diff --git a/libr/include/r_bin.h b/libr/include/r_bin.h index 6cc7f36a02..248b77994a 100644 --- a/libr/include/r_bin.h +++ b/libr/include/r_bin.h @@ -35,6 +35,7 @@ typedef struct r_bin_t { RList* strings; RList* fields; RList* libs; + RList* relocs; RBuffer *buf; void *user; struct r_bin_plugin_t *cur; @@ -60,6 +61,7 @@ typedef struct r_bin_plugin_t { struct r_bin_info_t* (*info)(RBin *bin); RList* (*fields)(RBin *bin); RList* (*libs)(RBin *bin); + RList* (*relocs)(RBin *bin); struct r_bin_meta_t *meta; struct r_bin_write_t *write; struct list_head list; @@ -107,6 +109,14 @@ typedef struct r_bin_import_t { ut64 hint; } RBinImport; +typedef struct r_bin_reloc_t { + char name[R_BIN_SIZEOF_STRINGS]; + ut64 rva; + ut64 offset; + int sym; + int type; +} RBinReloc; + typedef struct r_bin_string_t { char string[R_BIN_SIZEOF_STRINGS]; ut64 rva; @@ -160,6 +170,7 @@ R_API RList* r_bin_get_fields(RBin *bin); R_API RList* r_bin_get_imports(RBin *bin); R_API RBinInfo* r_bin_get_info(RBin *bin); R_API RList* r_bin_get_libs(RBin *bin); +R_API RList* r_bin_get_relocs(RBin *bin); R_API RList* r_bin_get_sections(RBin *bin); R_API RBinSection* r_bin_get_section_at(RBin *bin, ut64 off, int va); R_API RList* r_bin_get_strings(RBin *bin);