int main(int argc, char** argv) { if (argc < 2) { fprintf(stderr, "no input elf specified\n"); return EXIT_FAILURE; } elf_t elf; int ret = elf_read(argv[1], &elf); if (ret != 0) { fprintf(stderr, "unable to parse elf: %d\n", ret); return EXIT_FAILURE; } elf_print_sections(&elf); elf_print_symbols(&elf); int symbol; uint64_t faddr; uint32_t* val; ret = elf_get_symbol_by_name(&elf, "SOME_GLOBAL", &symbol); if (ret != 0) { fprintf(stderr, "no such symbol 'SOME_GLOBAL'\n"); return EXIT_FAILURE; } ret = elf_get_symbol_faddr(&elf, symbol, &faddr); if (ret != 0) { fprintf(stderr, "unable to map symbol: %d\n", ret); return EXIT_FAILURE; } val = (uint32_t*)(elf.elf_data + faddr); printf("Value of SOME_GLOBAL: 0x%x\n", *val); elf_free(&elf); return EXIT_SUCCESS; }
int do_extract(const char *output, int argc, char **argv) { if(argc != 1) { printf("You need to specify exactly one input file to extract from.\n"); return 3; } FILE *fout = NULL; if(output) { fout = fopen(output, "w"); if(fout == NULL) { printf("Cannot open output file '%s'\n", output); return 4; } } /* read elf file */ g_elf_buf = read_file(argv[0], g_elf_size); if(g_elf_buf == nullptr) { printf("Cannot open input file '%s'\n", argv[0]); return 1; } if(!elf_init()) { printf("This is not a valid ELF file\n"); return 1; } if(g_elf_symtab == nullptr) { printf("This ELF file does not have a symbol table\n"); return 1; } /* look for symbol 'AreaInfo' */ Elf32_Sym *sym_AreaInfo = elf_get_symbol_by_name("AreaInfo"); if(sym_AreaInfo == nullptr) { printf("Cannot find symbol 'AreaInfo'\n"); return 1; } printf("AreaInfo:\n"); if(g_verbose) { printf("[%u bytes at address %#x in section %u (%s)]\n", (unsigned)sym_AreaInfo->st_size, (unsigned)sym_AreaInfo->st_value, (unsigned)sym_AreaInfo->st_shndx, elf_get_section_name(sym_AreaInfo->st_shndx)); } /* guess version */ int ver = guess_version(elf_get_symbol_ptr(sym_AreaInfo, sizeof(area_info_v1_t))); if(g_verbose) printf("[guessed version: %d]\n", ver); size_t sizeof_area_info = (ver == 1) ? sizeof(area_info_v1_t) : sizeof(area_info_v2_t); size_t sizeof_zone_info = (ver == 1) ? sizeof(zone_info_v1_t) : sizeof(zone_info_v2_t); /* sanity check AreaInfo */ size_t area_count = sym_AreaInfo->st_size / sizeof_area_info; if(!g_unsafe && (sym_AreaInfo->st_size % sizeof_area_info) != 0) { printf("AreaInfo size (%u) is a not a multiple of area_info_t size (%zu).\n", (unsigned)sym_AreaInfo->st_size, sizeof_area_info); printf("Use unsafe option to override this check\n"); return 1; } area_info_v1_t *AreaInfo_v1 = (area_info_v1_t *)elf_get_symbol_ptr(sym_AreaInfo, sym_AreaInfo->st_size); area_info_v2_t *AreaInfo_v2 = (area_info_v2_t *)AreaInfo_v1; if(AreaInfo_v1 == nullptr) { printf("Symbol does not point to a valid address\n"); return 1; } for(size_t i = 0; i < area_count; i++) { uint32_t type; uint32_t *zoneinfo_ptr; uint32_t zonecount; uint32_t *name_ptr; if(ver == 1) { type = AreaInfo_v1[i].type; zoneinfo_ptr = &AreaInfo_v1[i].zoneinfo; zonecount = AreaInfo_v1[i].zonecount; name_ptr = &AreaInfo_v1[i].name; } else { type = AreaInfo_v2[i].type; zoneinfo_ptr = &AreaInfo_v2[i].zoneinfo; zonecount = AreaInfo_v2[i].zonecount; name_ptr = &AreaInfo_v2[i].name; } if(g_verbose) { printf(" [type=%u info=%#x count=%u name=%#x]\n", type, *zoneinfo_ptr, zonecount, *name_ptr); } /* translate name address */ const char *name = (const char *)elf_reloc_addr32_ptr(name_ptr); if(name == nullptr || !elf_is_str_ptr_safe(name)) { printf(" Entry name is not a string\n"); continue; } /* skip reserved entries */ if(*zoneinfo_ptr == 0) { printf(" %s\n", name); continue; } /* relocate the zoneinfo pointer */ void *Zone = elf_reloc_addr32_ptr(zoneinfo_ptr);; if(Zone == nullptr) { printf(" %s\n", name); printf(" Zone info pointer is not valid\n"); continue; } /* in safe mode, make sure the zone info pointer is a symbol */ Elf32_Sym *zoneinfo_sym = elf_get_symbol_by_ptr((void *)Zone); const char *zoneinfo_sym_name = "<no symbol>"; if(zoneinfo_sym) zoneinfo_sym_name = elf_get_symbol_name(zoneinfo_sym); printf(" %s (%s)\n", name, zoneinfo_sym_name); if(!g_unsafe && !zoneinfo_sym) { printf(" Zone info pointer does not correspond to any symbol.\n"); printf(" Use unsafe option to override this check\n"); continue; } /* if we have the symbol, make sure the claimed size match */ if(!g_unsafe && zoneinfo_sym) { if(zoneinfo_sym->st_size != sizeof_zone_info * zonecount) { printf(" Zone info symbol size (%u) does not match expected size (%zu)\n", (unsigned)zoneinfo_sym->st_size, sizeof_zone_info * zonecount); printf(" Use unsafe option to override this check\n"); continue; } } /* sanity check */ if(!elf_is_ptr_safe((void *)Zone, sizeof_zone_info * zonecount)) { printf(" Zone info pointer is not valid\n"); continue; } /* read zone */ zone_info_v1_t *Zone_v1 = (zone_info_v1_t *)Zone; zone_info_v2_t *Zone_v2 = (zone_info_v2_t *)Zone; for(size_t j = 0; j < zonecount; j++) { uint32_t node, start, count, size; uint32_t *name_ptr; if(ver == 1) { node = Zone_v1[j].node; start = Zone_v1[j].start; count = Zone_v1[j].count; size = Zone_v1[j].size; name_ptr = &Zone_v1[j].name; } else { node = Zone_v2[j].node; start = Zone_v2[j].start; count = Zone_v2[j].count; size = Zone_v2[j].size; name_ptr = &Zone_v2[j].name; } if(g_verbose) { printf(" [node=%u start=%#x count=%u size=%u name=%#x]\n", node, start, count, size, *name_ptr); } /* translate name address */ const char *name = (const char *)elf_reloc_addr32_ptr(name_ptr); if(name == nullptr || !elf_is_str_ptr_safe(name)) { printf(" Entry name is not a string\n"); continue; } printf(" %s: node %03u, size %u\n", name, node, size); if(fout) fprintf(fout, "%u,%u,%s\n", node, size, name); } } if(fout) fclose(fout); /* success */ return 0; }