/* 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); cmd_num = r_binfmt_get_int32((byte_t*)&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 */ type = r_binfmt_get_int32((byte_t*)&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; } cmd_size = r_binfmt_get_int32((byte_t*)&cmd->size, bin->endian); if(!cmd_size) return 0; if(!r_utils_add32(&off, off, cmd_size)) return 0; } return 1; }
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); cpu = r_binfmt_get_int32((byte_t*)&hdr->h_cpu, bin->endian); if(cpu == R_BINFMT_MACHO_CPU_X86_64) return R_BINFMT_ARCH_X86_64; return R_BINFMT_ARCH_UNDEF; }
/* Load the ELF binary in the bin->mlist */ static void elf64_load_mlist(r_binfmt_s *bin) { Elf64_Ehdr *ehdr = (Elf64_Ehdr*)bin->mapped; Elf64_Phdr *phdr; int i; uint64_t flags; uint64_t p_vaddr, p_offset, p_filesz; uint32_t p_type, p_flags; uint16_t e_phnum; bin->mlist = r_binfmt_mlist_new(); phdr = (Elf64_Phdr*)(bin->mapped + r_binfmt_get_int64((byte_t*)&ehdr->e_phoff, bin->endian)); e_phnum = r_binfmt_get_int16((byte_t*)&ehdr->e_phnum, bin->endian); for(i = 0; i < e_phnum; i++) { p_type = r_binfmt_get_int32((byte_t*)&phdr[i].p_type, bin->endian); p_flags = r_binfmt_get_int32((byte_t*)&phdr[i].p_flags, bin->endian); p_vaddr = r_binfmt_get_int64((byte_t*)&phdr[i].p_vaddr, bin->endian); p_offset = r_binfmt_get_int64((byte_t*)&phdr[i].p_offset, bin->endian); p_filesz = r_binfmt_get_int64((byte_t*)&phdr[i].p_filesz, bin->endian); if(p_type == PT_LOAD) { flags = 0; if(p_flags & PF_X) flags |= R_BINFMT_MEM_FLAG_PROT_X; if(p_flags & PF_R) flags |= R_BINFMT_MEM_FLAG_PROT_R; if(p_flags & PF_W) flags |= R_BINFMT_MEM_FLAG_PROT_W; r_binfmt_mlist_add(bin->mlist, p_vaddr, bin->mapped + p_offset, p_filesz, flags); } } }
static void r_binfmt_macho64_load_mlist(r_binfmt_s *bin) { r_binfmt_macho64_header_s *hdr; r_binfmt_macho_cmd_s *cmd; u32 i, cmd_num, type, off; bin->mlist = r_binfmt_mlist_new(); hdr = (r_binfmt_macho64_header_s*)(bin->mapped); cmd_num = r_binfmt_get_int32((byte_t*)&hdr->h_cmd_num, bin->endian); off = 0; for(i = 0; i < cmd_num; i++) { cmd = (r_binfmt_macho_cmd_s*)(bin->mapped + sizeof(*hdr) + off); type = r_binfmt_get_int32((byte_t*)&cmd->type, bin->endian); if(type == R_BINFMT_MACHO_CMD_TYPE_SEGMENT64) { r_binfmt_macho64_load_segment(bin, (r_binfmt_macho64_segment_s*)cmd); } off += r_binfmt_get_int32((byte_t*)&cmd->size, bin->endian); } }
/* Check if NX bit is enabled */ static r_binfmt_nx_e r_binfmt_elf64_check_nx(r_binfmt_s *bin) { Elf64_Ehdr *ehdr = (Elf64_Ehdr*)(bin->mapped); Elf64_Phdr *phdr; u32 i, p_type; u16 e_phnum; phdr = (Elf64_Phdr*)(bin->mapped + r_binfmt_get_int64((byte_t*)&ehdr->e_phoff, bin->endian)); e_phnum = r_binfmt_get_int16((byte_t*)&ehdr->e_phnum, bin->endian); for(i = 0; i < e_phnum; i++) { p_type = r_binfmt_get_int32((byte_t*)&phdr[i].p_type, bin->endian); if(p_type == PT_GNU_STACK) return R_BINFMT_NX_ENABLED; } return R_BINFMT_NX_DISABLED; }
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 void r_binfmt_macho64_load_segment(r_binfmt_s *bin, r_binfmt_macho64_segment_s *seg) { u64 vaddr, filesz, fileoff; u32 flags, initprot; vaddr = r_binfmt_get_int64((byte_t*)&seg->vm_addr, bin->endian); filesz = r_binfmt_get_int64((byte_t*)&seg->file_size, bin->endian); fileoff = r_binfmt_get_int64((byte_t*)&seg->file_off, bin->endian); initprot = r_binfmt_get_int32((byte_t*)&seg->init_prot, bin->endian); flags = 0; if(initprot & R_BINFMT_MACHO_PROT_R) flags |= R_BINFMT_MEM_FLAG_PROT_R; if(initprot & R_BINFMT_MACHO_PROT_W) flags |= R_BINFMT_MEM_FLAG_PROT_W; if(initprot & R_BINFMT_MACHO_PROT_X) flags |= R_BINFMT_MEM_FLAG_PROT_X; r_binfmt_mlist_add(bin->mlist, vaddr, bin->mapped + fileoff, filesz, flags); }