static void r_binfmt_macho64_load_segment(r_binfmt_s *bin, r_binfmt_macho64_segment_s *s) { r_binfmt_segment_s *seg; u64 vaddr, filesz, fileoff; u32 flags, initprot; seg = r_binfmt_segment_new(); R_BINFMT_GET_INT(vaddr, s->vm_addr, bin->endian); R_BINFMT_GET_INT(filesz, s->file_size, bin->endian); R_BINFMT_GET_INT(fileoff, s->file_off, bin->endian); R_BINFMT_GET_INT(initprot, s->init_prot, bin->endian); flags = 0; if(initprot & R_BINFMT_MACHO_PROT_R) flags |= R_BINFMT_SEGMENT_FLAG_PROT_R; if(initprot & R_BINFMT_MACHO_PROT_W) flags |= R_BINFMT_SEGMENT_FLAG_PROT_W; if(initprot & R_BINFMT_MACHO_PROT_X) flags |= R_BINFMT_SEGMENT_FLAG_PROT_X; seg->addr = vaddr; seg->length = filesz; seg->start = bin->mapped + fileoff; seg->flags = flags; r_utils_list_push(&bin->segments, seg); }
void r_binfmt_elf32_load_symtab(r_binfmt_s *bin, r_binfmt_elf32_s *elf) { Elf32_Word i, sh_type, sh_size; Elf32_Off sh_offset; R_BINFMT_ASSERT(elf->ehdr != NULL); R_BINFMT_ASSERT(elf->shdr != NULL); for(i = 0; i < elf->shdr_entries; i++) { R_BINFMT_GET_INT(sh_type, elf->shdr[i].sh_type, bin->endian); if(sh_type == SHT_SYMTAB) { R_BINFMT_GET_INT(sh_size, elf->shdr[i].sh_size, bin->endian); R_BINFMT_ASSERT((sh_size % sizeof(Elf32_Sym)) == 0); R_BINFMT_GET_INT(sh_offset, elf->shdr[i].sh_offset, bin->endian); R_BINFMT_ASSERT(r_utils_add32(NULL, sh_offset, sh_size) && sh_offset + sh_size <= bin->mapped_size); elf->symtab = (Elf32_Sym*)(bin->mapped + sh_offset); elf->symtab_entries = sh_size / sizeof(Elf32_Sym); break; } } }
/* Fill bin->sections structure */ static void r_binfmt_elf64_load_sections(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { r_binfmt_section_s *section; Elf64_Word sh_name, sh_size, i; Elf64_Off strndx_off; Elf64_Addr sh_addr; Elf64_Half e_shstrndx; R_BINFMT_ASSERT(elf->ehdr != NULL); R_BINFMT_ASSERT(elf->shdr != NULL); R_BINFMT_GET_INT(e_shstrndx, elf->ehdr->e_shstrndx, bin->endian); R_BINFMT_ASSERT(e_shstrndx < elf->shdr_entries); R_BINFMT_GET_INT(strndx_off, elf->shdr[e_shstrndx].sh_offset, bin->endian); for(i = 0; i < elf->shdr_entries; i++) { R_BINFMT_GET_INT(sh_addr, elf->shdr[i].sh_addr, bin->endian); R_BINFMT_GET_INT(sh_size, elf->shdr[i].sh_size, bin->endian); R_BINFMT_GET_INT(sh_name, elf->shdr[i].sh_name, bin->endian); R_BINFMT_ASSERT(r_utils_add64(NULL, strndx_off, sh_name) && strndx_off + sh_name <= bin->mapped_size); section = r_binfmt_section_new(); section->addr = sh_addr; section->size = sh_size; section->name = r_binfmt_elf64_get_name(bin, elf, e_shstrndx, sh_name); r_utils_linklist_push(&bin->sections, section); } }
void r_binfmt_elf64_load_dyntab(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { Elf64_Word i, sh_type, sh_size; Elf64_Off sh_offset; R_BINFMT_ASSERT(elf->ehdr != NULL); R_BINFMT_ASSERT(elf->shdr != NULL); for(i = 0; i < elf->shdr_entries; i++) { R_BINFMT_GET_INT(sh_type, elf->shdr[i].sh_type, bin->endian); if(sh_type == SHT_DYNAMIC) { R_BINFMT_GET_INT(sh_size, elf->shdr[i].sh_size, bin->endian); R_BINFMT_ASSERT((sh_size % sizeof(Elf64_Dyn)) == 0); R_BINFMT_GET_INT(sh_offset, elf->shdr[i].sh_offset, bin->endian); R_BINFMT_ASSERT(r_utils_add64(NULL, sh_offset, sh_size) && sh_offset + sh_size <= bin->mapped_size); elf->dyntab = (Elf64_Dyn*)(bin->mapped + sh_offset); elf->dyntab_entries = sh_size / sizeof(Elf64_Dyn); break; } } }
Elf64_Phdr* r_binfmt_elf64_get_segment(r_binfmt_s *bin, r_binfmt_elf64_s *elf, Elf64_Word type, Elf64_Word flags) { Elf64_Word i, p_type, p_flags; R_BINFMT_ASSERT_RET(NULL, elf->ehdr != NULL); R_BINFMT_ASSERT_RET(NULL, elf->phdr != NULL); for(i = 0; i < elf->phdr_entries; i++) { R_BINFMT_GET_INT(p_type, elf->phdr[i].p_type, bin->endian); R_BINFMT_GET_INT(p_flags, elf->phdr[i].p_flags, bin->endian); if(p_type == type && p_flags & flags) return &elf->phdr[i]; } return NULL; }
static const char* r_binfmt_elf64_get_name(r_binfmt_s *bin, r_binfmt_elf64_s *elf, Elf64_Half section_id, Elf64_Word name) { Elf64_Off sh_offset; Elf64_Word sh_size; R_BINFMT_GET_INT(sh_offset, elf->shdr[section_id].sh_offset, bin->endian); R_BINFMT_GET_INT(sh_size, elf->shdr[section_id].sh_size, bin->endian); R_BINFMT_ASSERT_RET("", r_utils_add64(NULL, sh_offset, sh_size) && sh_offset + sh_size <= bin->mapped_size); R_BINFMT_ASSERT_RET("", name < sh_size); return (const char*)(bin->mapped + sh_offset + name); }
void r_binfmt_elf64_load_shdr(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { Elf64_Off e_shoff; Elf64_Half e_shnum; R_BINFMT_ASSERT(elf->ehdr != NULL); R_BINFMT_GET_INT(e_shoff, elf->ehdr->e_shoff, bin->endian); R_BINFMT_ASSERT(e_shoff < bin->mapped_size); R_BINFMT_GET_INT(e_shnum, elf->ehdr->e_shnum, bin->endian); R_BINFMT_ASSERT(r_utils_add64(NULL, e_shnum*sizeof(Elf64_Shdr), e_shoff) && e_shnum*sizeof(Elf64_Shdr) + e_shoff <= bin->mapped_size); elf->shdr = (Elf64_Shdr*)(bin->mapped + e_shoff); elf->shdr_entries = e_shnum; }
/* Get entry point */ static addr_t r_binfmt_elf64_getentry(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { Elf64_Addr e_entry; R_BINFMT_ASSERT_RET(0, elf->ehdr != NULL); R_BINFMT_GET_INT(e_entry, elf->ehdr->e_entry, bin->endian); return e_entry; }
/* Check evil or malformed files */ static int r_binfmt_macho64_check(r_binfmt_s *bin) { r_binfmt_macho64_header_s *hdr; r_binfmt_macho_cmd_s *cmd; u32 tmp, i, cmd_num, cmd_size, off, type; /* Already checked in r_binfmt_machoXX_is(), but if the check is removed in the future, the r_binfmt_machoXX_check() function must handle this case */ if(bin->mapped_size < sizeof(*hdr)) return 0; hdr = (r_binfmt_macho64_header_s*)(bin->mapped); R_BINFMT_GET_INT(cmd_num, hdr->h_cmd_num, bin->endian); /* Check each command */ off = 0; for(i = 0; i < cmd_num; i++) { /* Check if off+sizeof(*hdr)+sizeof(*cmd) isn't greater than bin->mapped_size */ if(!r_utils_add32(&tmp, sizeof(*hdr)+sizeof(*cmd), off)) return 0; if(bin->mapped_size < tmp) return 0; cmd = (r_binfmt_macho_cmd_s*)(bin->mapped + off + sizeof(*hdr)); /* Now check command */ R_BINFMT_GET_INT(type, cmd->type, bin->endian); if(type == R_BINFMT_MACHO_CMD_TYPE_SEGMENT64) { if(!r_binfmt_macho64_check_segment(bin, (r_binfmt_macho64_segment_s*)cmd)) return 0; } R_BINFMT_GET_INT(cmd_size, cmd->size, bin->endian); if(!cmd_size) return 0; if(!r_utils_add32(&off, off, cmd_size)) return 0; } return 1; }
static void r_binfmt_macho32_load_segments(r_binfmt_s *bin) { r_binfmt_macho32_header_s *hdr; r_binfmt_macho_cmd_s *cmd; u32 i, cmd_num, type, off; hdr = (r_binfmt_macho32_header_s*)(bin->mapped); R_BINFMT_GET_INT(cmd_num, hdr->h_cmd_num, bin->endian); off = 0; for(i = 0; i < cmd_num; i++) { cmd = (r_binfmt_macho_cmd_s*)(bin->mapped + sizeof(r_binfmt_macho32_header_s) + off); R_BINFMT_GET_INT(type, cmd->type, bin->endian); if(type == R_BINFMT_MACHO_CMD_TYPE_SEGMENT) { r_binfmt_macho32_load_segment(bin, (r_binfmt_macho32_segment_s*)cmd); } off += r_binfmt_get_int32((byte_t*)&cmd->size, bin->endian); } }
static r_binfmt_arch_e r_binfmt_macho64_getarch(r_binfmt_s *bin) { r_binfmt_macho64_header_s *hdr; u32 cpu; hdr = (r_binfmt_macho64_header_s*)(bin->mapped); R_BINFMT_GET_INT(cpu, hdr->h_cpu, bin->endian); if(cpu == R_BINFMT_MACHO_CPU_X86_64) return R_BINFMT_ARCH_X86_64; return R_BINFMT_ARCH_UNDEF; }
static r_binfmt_pie_e r_binfmt_elf64_check_pie(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { Elf64_Half e_type; R_BINFMT_ASSERT_RET(R_BINFMT_PIE_UNKNOWN, elf->ehdr != NULL); R_BINFMT_GET_INT(e_type, elf->ehdr->e_type, bin->endian); if(e_type != ET_DYN) return R_BINFMT_PIE_DISABLED; return R_BINFMT_PIE_ENABLED; }
/* Check the fields of the machoXX segment */ static int r_binfmt_macho64_check_segment(r_binfmt_s *bin, r_binfmt_macho64_segment_s *seg) { u64 filesz, fileoff; u64 off; off = ((byte_t*)seg) - bin->mapped; if(!r_utils_add64(NULL, off, sizeof(*seg))) return 0; if(bin->mapped_size < off + sizeof(*seg)) return 0; R_BINFMT_GET_INT(filesz, seg->file_size, bin->endian); R_BINFMT_GET_INT(fileoff, seg->file_off, bin->endian); if(!r_utils_add64(&off, fileoff, filesz)) return 0; if(bin->mapped_size < off) return 0; return 1; }
static void r_binfmt_elf64_load_syms_dyntab(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { r_binfmt_sym_s *sym; Elf64_Half sh_link, st_name; Elf64_Off link_off; Elf64_Word i, sh_type; R_BINFMT_ASSERT(elf->ehdr != NULL); R_BINFMT_ASSERT(elf->shdr != NULL); R_BINFMT_ASSERT(elf->dynsym != NULL); sh_link = 0xFFFF; for(i = 0; i < elf->shdr_entries; i++) { R_BINFMT_GET_INT(sh_type, elf->shdr[i].sh_type, bin->endian); if(sh_type == SHT_DYNSYM) { R_BINFMT_GET_INT(sh_link, elf->shdr[i].sh_link, bin->endian); R_BINFMT_ASSERT(sh_link < elf->shdr_entries); break; } } if(sh_link == 0xFFFF) return; for(i = 0; i < elf->dynsym_entries; i++) { R_BINFMT_GET_INT(st_name, elf->dynsym[i].st_name, bin->endian); R_BINFMT_GET_INT(link_off, elf->shdr[sh_link].sh_offset, bin->endian); R_BINFMT_ASSERT(r_utils_add64(NULL, link_off, st_name) && link_off + st_name <= bin->mapped_size); sym = r_binfmt_sym_new(); sym->name = r_binfmt_elf64_get_name(bin, elf, sh_link, st_name); sym->addr = elf->dynsym[i].st_value; r_utils_arraylist_push(&bin->syms, sym); } }
static r_binfmt_rpath_e r_binfmt_elf64_check_runpath(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { Elf64_Word i; Elf64_Sword d_tag; R_BINFMT_ASSERT_RET(R_BINFMT_RUNPATH_UNKNOWN, elf->dyntab != NULL); for(i = 0; i < elf->dyntab_entries; i++) { R_BINFMT_GET_INT(d_tag, elf->dyntab[i].d_tag, bin->endian); if(d_tag == DT_RUNPATH) return R_BINFMT_RUNPATH_ENABLED; } return R_BINFMT_RUNPATH_DISABLED; }
static r_binfmt_relro_e r_binfmt_elf64_check_relro(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { Elf64_Word i; Elf64_Sword d_tag; R_BINFMT_ASSERT_RET(R_BINFMT_RELRO_UNKNOWN, elf->ehdr != NULL); R_BINFMT_ASSERT_RET(R_BINFMT_RELRO_UNKNOWN, elf->phdr != NULL); R_BINFMT_ASSERT_RET(R_BINFMT_RELRO_UNKNOWN, elf->dyntab != NULL); if(r_binfmt_elf64_get_segment(bin, elf, PT_GNU_RELRO, ~0) == NULL) { return R_BINFMT_RELRO_DISABLED; } for(i = 0; i < elf->dyntab_entries; i++) { R_BINFMT_GET_INT(d_tag, elf->dyntab[i].d_tag, bin->endian); if(d_tag == DT_BIND_NOW) return R_BINFMT_RELRO_FULL; } return R_BINFMT_RELRO_PARTIAL; }
/* Fill bin->segments structure */ static void r_binfmt_elf64_load_segments(r_binfmt_s *bin, r_binfmt_elf64_s *elf) { r_binfmt_segment_s *seg; Elf64_Word i, p_type, p_flags, p_filesz; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Half e_phnum; R_BINFMT_ASSERT(elf->ehdr != NULL); R_BINFMT_ASSERT(elf->phdr != NULL); R_BINFMT_GET_INT(e_phnum, elf->ehdr->e_phnum, bin->endian); for(i = 0; i < e_phnum; i++) { R_BINFMT_GET_INT(p_type, elf->phdr[i].p_type, bin->endian); R_BINFMT_GET_INT(p_flags, elf->phdr[i].p_flags, bin->endian); R_BINFMT_GET_INT(p_vaddr, elf->phdr[i].p_vaddr, bin->endian); R_BINFMT_GET_INT(p_offset, elf->phdr[i].p_offset, bin->endian); R_BINFMT_GET_INT(p_filesz, elf->phdr[i].p_filesz, bin->endian); R_BINFMT_ASSERT(r_utils_add64(NULL, p_offset, p_filesz) && p_offset + p_filesz <= bin->mapped_size); if(p_type == PT_LOAD) { seg = r_binfmt_segment_new(); seg->flags = 0; if(p_flags & PF_X) seg->flags |= R_BINFMT_SEGMENT_FLAG_PROT_X; if(p_flags & PF_R) seg->flags |= R_BINFMT_SEGMENT_FLAG_PROT_R; if(p_flags & PF_W) seg->flags |= R_BINFMT_SEGMENT_FLAG_PROT_W; seg->addr = p_vaddr; seg->length = p_filesz; seg->start = bin->mapped + p_offset; r_utils_linklist_push(&bin->segments, seg); } } }