//
// _OVWork.cpp
// asm
//
// Created by 罗何 on 16/12/20.
// Copyright © 2016年 罗何. All rights reserved.
//
#import <UIKit/UIKit.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <mach-o/arch.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#if !__x86_64__ || !__i386__
#include "x86_64_reloc.h"
#endif
#include <mach-o/arm/reloc.h>
#include <mach-o/arm64/reloc.h>
#include <mach-o/ranlib.h>
#include <mach-o/compact_unwind_encoding.h>
#include <mach-o/swap.h>
#import <objc/runtime.h>
#include <pthread.h>
#include <dlfcn.h>
#include <err.h>
#include <sys/mman.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <algorithm>
static int _get_main_cup_type(int *sub_type){
*sub_type = -1;
host_basic_info_data_t hostInfo;
mach_msg_type_number_t infoCount = HOST_BASIC_INFO_COUNT;
kern_return_t ret = host_info(mach_host_self(),HOST_BASIC_INFO,(host_info_t)&hostInfo,&infoCount);
return ret == KERN_SUCCESS ?(*sub_type = hostInfo.cpu_subtype,hostInfo.cpu_type ): -1;
}
#define MY_MMAP ((void * (*)(void *,size_t, int, int, int, off_t))dlsym(RTLD_DEFAULT, "mmap"))
#define MY_MPROTECT ((int (*)(void *,size_t,int))dlsym(RTLD_DEFAULT, "mprotect"))
#define MY_MUNMAP ((int (*)(void *,size_t))dlsym(RTLD_DEFAULT, "munmap"))
#define MATCH_STRUCT(obj,location) \
struct obj const * obj = (struct obj *)(bytes + location);
static uint8_t read_uint8(NSRange &range,uint8_t *bytes){
uint8_t buffer = *(uint8_t *)(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range),sizeof(uint8_t));
return buffer;
}
static uint16_t read_uint16(NSRange &range,uint8_t *bytes){
uint16_t buffer = *(uint16_t *)(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range),sizeof(uint16_t));
return buffer;
}
static uint32_t read_uint32(NSRange &range,uint8_t *bytes){
uint32_t buffer = *(uint32_t *)(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range),sizeof(uint32_t));
return buffer;
}
static uint64_t read_uint64(NSRange &range,uint8_t *bytes){
uint64_t buffer = *(uint64_t *)(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range),sizeof(uint64_t));
return buffer;
}
static int8_t read_int8(NSRange &range,uint8_t *bytes){
int8_t buffer = *(int8_t *)(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range),sizeof(int8_t));
return buffer;
}
static int16_t read_int16(NSRange &range,uint8_t *bytes){
int16_t buffer = *(int16_t *)(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range),sizeof(int16_t));
return buffer;
}
static int32_t read_int32(NSRange &range,uint8_t *bytes){
int32_t buffer = *(int32_t *)(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range),sizeof(int32_t));
return buffer;
}
static int64_t read_int64(NSRange &range,uint8_t *bytes){
int64_t buffer = *(int64_t *)(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range),sizeof(int64_t));
return buffer;
}
static uint64_t read_sleb128(NSRange &range,uint8_t *bytes){
range.location = NSMaxRange(range);
uint8_t * p = bytes + range.location, *start = p;
int64_t result = 0;
int bit = 0;
uint8_t byte;
do {
byte = *p++;
result |= ((byte & 0x7f) << bit);
bit += 7;
} while (byte & 0x80);
// sign extend negative numbers
if ( (byte & 0x40) != 0 )
{
result |= (-1LL) << bit;
}
range.length = (p - start);
return result;
}
static uint64_t read_uleb128(NSRange &range,uint8_t *bytes){
range.location = NSMaxRange(range);
uint8_t * p = bytes + range.location, *start = p;
uint64_t result = 0;
int bit = 0;
do {
uint64_t slice = *p & 0x7f;
if (bit >= 64 || slice << bit >> bit != slice)
[NSException raise:@"uleb128 error" format:@"uleb128 too big"];
else {
result |= (slice << bit);
bit += 7;
}
}
while (*p++ & 0x80);
range.length = (p - start);
return result;
}
const char *read_string(NSRange &range,uint8_t *bytes){
range.location = NSMaxRange(range);
const char *string = (const char *)(bytes + range.location);
range.length = strlen(string) + 1;
return string;
}
static uint64_t alignMem(uint64_t p, uint64_t a) {
a--;
return (p + a) & ~a;
}
static void undefinedFunction() {
fprintf(stderr, "Undefined function called\n");
abort();
}
//------------------------------------------------//
static void doRebase(uint64_t address,uint64_t slider,std::vector<uint64_t> &sel_ref){
uint8_t **ptr = (uint8_t **)(slider + address);
std::vector<uint64_t>::iterator iter = std::find(sel_ref.begin(), sel_ref.end(), (uint64_t)*ptr);
if(iter != sel_ref.end()){
const char *real_name = (const char *)(slider + *ptr);
char * exisit_sel = (char *)sel_getUid(real_name);
if(!exisit_sel){ exisit_sel = (char *)sel_registerName(real_name); }
*ptr = (uint8_t *)exisit_sel;
}else{
*ptr += slider;
}
}
static void doBind(uint64_t address,uint64_t addend,uint64_t slide,const char *symbolName){
if(symbolName && symbolName[0]=='_'){
const char *sym_string = symbolName + 1;
int8_t **ptr = (int8_t **)(slide + address);
int8_t* sym = (int8_t*)dlsym(RTLD_DEFAULT, sym_string);
if(!sym){
sym = (int8_t*)&undefinedFunction;
}
sym += addend;
*ptr = sym;
}
}
enum BindNodeType {NodeTypeBind, NodeTypeWeakBind, NodeTypeLazyBind};
void createBinding(uint64_t slide,uint32_t location,uint32_t length,uint64_t baseAddress,bool is_64,uint8_t *bytes,uint32_t ncmds,uint64_t segmentOffset,BindNodeType nodeType,
std::map<uint64_t,std::pair<uint32_t,const char *> > &bind_64,
std::map<uint64_t,std::pair<uint32_t,const char *> > &bind){
NSRange range = NSMakeRange(location,0);
BOOL isDone = NO;
int32_t libOrdinal = 0;
uint32_t type = 0;
int64_t addend = 0;
const char * symbolName = nil;
uint32_t symbolFlags = 0;
uint32_t doBindLocation = location;
uint64_t ptrSize = (!is_64 ? sizeof(uint32_t) : sizeof(uint64_t));
uint64_t address = baseAddress;
while (NSMaxRange(range) < location + length && isDone == NO) {
uint8_t byte = *(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range), sizeof(uint8_t));
uint8_t opcode = byte & BIND_OPCODE_MASK;
uint8_t immediate = byte & BIND_IMMEDIATE_MASK;
switch (opcode) {
case BIND_OPCODE_DONE:
if(nodeType != NodeTypeLazyBind){
isDone = YES;
}
doBindLocation = NSMaxRange(range);
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
libOrdinal = immediate;
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
libOrdinal = read_uleb128(range,bytes);
break;
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: {
if (immediate == 0) { libOrdinal = 0; }
else {
int8_t signExtended = immediate | BIND_OPCODE_MASK; // This sign extends the value
libOrdinal = signExtended;
}
} break;
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
symbolFlags = immediate;
symbolName = read_string(range, bytes);
break;
case BIND_OPCODE_SET_TYPE_IMM:
type = immediate;
break;
case BIND_OPCODE_SET_ADDEND_SLEB:
addend = read_sleb128(range,bytes);
break;
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: {
uint32_t segmentIndex = immediate;
uint64_t val = read_uleb128(range,bytes);
if (segmentIndex >= ncmds){
[NSException raise:@"Segment" format:@"index is out of range %u", segmentIndex];
}
for(uint32_t i = 0;i < ncmds;i++){
MATCH_STRUCT(load_command,segmentOffset)
if(i == segmentIndex){
switch (load_command->cmd) {
case LC_SEGMENT:{
MATCH_STRUCT(segment_command, segmentOffset)
address = segment_command->vmaddr + val;
}break;
case LC_SEGMENT_64:{
MATCH_STRUCT(segment_command_64,segmentOffset)
address = segment_command_64->vmaddr + val;
}break;
default:break;
}
}
segmentOffset += load_command->cmdsize;
}
} break;
case BIND_OPCODE_ADD_ADDR_ULEB: {
uint64_t val = read_uleb128(range,bytes);
address += val;
} break;
case BIND_OPCODE_DO_BIND: {
// is_64 ? bind_64.insert(std::make_pair(address, std::make_pair(addend, symbolName))) : bind.insert(std::make_pair(address, std::make_pair(addend, symbolName)));
doBind(address, addend, slide, symbolName);
doBindLocation = NSMaxRange(range);
address += ptrSize;
} break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: {
uint32_t startNextBind = NSMaxRange(range);
uint64_t val = read_uleb128(range,bytes);
// is_64 ? bind_64.insert(std::make_pair(address, std::make_pair(addend, symbolName))) : bind.insert(std::make_pair(address, std::make_pair(addend, symbolName)));
doBind(address, addend, slide, symbolName);
doBindLocation = startNextBind;
address += ptrSize + val;
} break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: {
uint32_t scale = immediate;
// is_64 ? bind_64.insert(std::make_pair(address, std::make_pair(addend, symbolName))) : bind.insert(std::make_pair(address, std::make_pair(addend, symbolName)));
doBind(address, addend, slide, symbolName);
doBindLocation = NSMaxRange(range);
address += ptrSize + scale * ptrSize;
} break;
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: {
uint32_t startNextBind = NSMaxRange(range);
uint64_t count = read_uleb128(range,bytes);
uint64_t skip = read_uleb128(range,bytes);
for (uint64_t index = 0; index < count; index++) {
// is_64 ? bind_64.insert(std::make_pair(address, std::make_pair(addend, symbolName))) : bind.insert(std::make_pair(address, std::make_pair(addend, symbolName)));
doBind(address, addend, slide, symbolName);
doBindLocation = startNextBind;
address += ptrSize + skip;
}
} break;
default:
[NSException raise:@"Bind info" format:@"Unknown opcode (%u %u)",
((uint32_t)-1 & opcode), ((uint32_t)-1 & immediate)];
}
}
}
void printSymbols(const char *symbolName, uint32_t location,uint32_t skip,uint64_t baseAddress,uint8_t *bytes){
NSRange range = NSMakeRange(location + skip,0);
uint8_t terminalSize = *(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range), sizeof(uint8_t));
if (terminalSize != 0) {
uint32_t terminalLocation = NSMaxRange(range);
uint64_t flags = read_uleb128(range,bytes);
uint64_t offset = read_uleb128(range,bytes);
printf("address:%lld symbolName:%s\n",baseAddress + offset,symbolName);
range = NSMakeRange(terminalLocation, terminalSize);
}
uint8_t childCount = read_uint8(range,bytes);
while (childCount-- > 0) {
const char *label = read_string(range, bytes);
uint64_t skip = read_uleb128(range, bytes);
printSymbols(label, location, skip, baseAddress, bytes);
}
}
void parserSymbol_total(NSURL *absoluteURL,NSString *typeName, NSError **outError){
if(!absoluteURL) return;
int cpu_type = -1,cpu_sub_type = -1;
cpu_type = _get_main_cup_type(&cpu_sub_type);
if(cpu_type == -1){ return; }
bool is_64 = sizeof(void *) == 8 ? true : false;
if(is_64){cpu_type |= CPU_ARCH_ABI64;}
NSMutableData *map_data = [NSMutableData dataWithContentsOfURL:absoluteURL options:NSDataReadingMappedAlways error:outError];
uint8_t *bytes = (uint8_t *)[map_data bytes];
uint32_t imageOffset = 0;
uint32_t ncmds = 0;
uint32_t magic = *(uint32_t*)(bytes);
switch (magic){
case FAT_MAGIC:
case FAT_CIGAM:{
struct fat_header fat_header = *(struct fat_header *)bytes;
if(magic == FAT_CIGAM){swap_fat_header(&fat_header, NX_LittleEndian);}
for(uint32_t nimg = 0;nimg < fat_header.nfat_arch;nimg++){
struct fat_arch fat_arch = *(struct fat_arch *)(bytes + sizeof(struct fat_header) + nimg * sizeof(struct fat_arch));
swap_fat_arch(&fat_arch, 1, NX_LittleEndian);
imageOffset = fat_arch.offset;
uint32_t inline_magic = *(uint32_t*)(bytes + fat_arch.offset);
switch (inline_magic) {
case MH_MAGIC:
case MH_CIGAM:{
struct mach_header mach_header = *(struct mach_header *)(bytes + fat_arch.offset);
if (inline_magic == MH_CIGAM){swap_mach_header(&mach_header, NX_LittleEndian);}
if(mach_header.cputype == cpu_type){
ncmds = mach_header.ncmds;
}
}break;
case MH_MAGIC_64:
case MH_CIGAM_64:{
struct mach_header_64 mach_header_64 = *(struct mach_header_64 *)(bytes + fat_arch.offset);
if (inline_magic == MH_CIGAM_64){swap_mach_header_64(&mach_header_64, NX_LittleEndian);}
if(mach_header_64.cputype == cpu_type){
ncmds = mach_header_64.ncmds;
}
}break;
default:{ break;}
}
}
} break;
case MH_MAGIC:
case MH_CIGAM: {
struct mach_header mach_header = *(struct mach_header *)bytes;
if (magic == MH_CIGAM){swap_mach_header(&mach_header, NX_LittleEndian);}
if(mach_header.cputype == cpu_type){ ncmds = mach_header.ncmds; }
} break;
case MH_MAGIC_64:
case MH_CIGAM_64: {
struct mach_header_64 mach_header_64 = *(struct mach_header_64 *)bytes;
if (magic == MH_CIGAM_64){swap_mach_header_64(&mach_header_64, NX_LittleEndian);}
if(mach_header_64.cputype == cpu_type){ ncmds = mach_header_64.ncmds; }
} break;
default:{break;}
}
if(!ncmds) return;
//----------------------------------------------------------------------------------------//
uint64_t vmsize_total = 0;
uint32_t fileOffset = imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64));
for (uint32_t ncmd = 0; ncmd < ncmds; ++ncmd){
MATCH_STRUCT(load_command,fileOffset)
switch (load_command->cmd) {
case LC_SEGMENT:{
MATCH_STRUCT(segment_command, fileOffset)
if (!strcmp(segment_command->segname, SEG_PAGEZERO)) { continue; }
vmsize_total += alignMem(segment_command->vmsize, 0x1000);
}break;
case LC_SEGMENT_64:{
MATCH_STRUCT(segment_command_64,fileOffset)
if (!strcmp(segment_command_64->segname, SEG_PAGEZERO)) { continue; }
vmsize_total += alignMem(segment_command_64->vmsize, 0x1000);
}break;
default:break;
}
fileOffset += load_command->cmdsize;
}
if(vmsize_total == 0) return;
void *mapped = MY_MMAP(NULL, vmsize_total, VM_PROT_READ | VM_PROT_WRITE, MAP_SHARED | MAP_ANON, 0, 0);
if (mapped == MAP_FAILED) { err(1, "mmap(file) failed"); }
uint64_t slide = (uint64_t)mapped;
//----------------------------------------------------------------------------------------//
// std::vector<uint64_t> rebases_64;
// std::vector<uint64_t> rebases;
std::map<uint64_t,std::pair<uint32_t,const char *> > bind_64;
std::map<uint64_t,std::pair<uint32_t,const char *> > bind;
std::vector<uint64_t> sel_ref_64;
std::vector<uint64_t> sel_ref;
std::vector<uint64_t> dylibs_name_offset;
struct section_64 const * __class_list_64 = nullptr,*__category_list_64 = nullptr;
struct section const * __class_list = nullptr,*__category_list = nullptr;
struct dyld_info_command const * dyld_info_command = nullptr;
uint64_t base_addr = 0;
fileOffset = imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64));
for (uint32_t ncmd = 0; ncmd < ncmds; ++ncmd){
MATCH_STRUCT(load_command,fileOffset)
switch (load_command->cmd) {
case LC_SEGMENT:{
MATCH_STRUCT(segment_command, fileOffset)
if (!strcmp(segment_command->segname, SEG_PAGEZERO)) { continue; }
int prot = 0;
if (segment_command->initprot & VM_PROT_READ) { prot |= PROT_READ; }
if (segment_command->initprot & VM_PROT_WRITE) { prot |= PROT_WRITE; }
if (segment_command->initprot & VM_PROT_EXECUTE) { prot |= PROT_EXEC; }
uint64_t filesize = segment_command->filesize;// alignMem(seg->filesize, 0x1000);
if(filesize <= 0)continue;
uint64_t vmaddr = segment_command->vmaddr + slide;
void *ret = memcpy((void *)vmaddr, bytes + segment_command->fileoff + imageOffset, filesize);
if(!ret){err(1, "memcpy fail\n");}
if(MY_MPROTECT((void*)vmaddr, alignMem(segment_command->vmsize, 0x1000), prot) != 0){
printf("*********warning:********* change protect fail:%d\n",errno);
}
if (segment_command->fileoff == 0 && segment_command->filesize != 0){
base_addr = segment_command->vmaddr;
}
for (uint32_t nsect = 0; nsect < segment_command->nsects; ++nsect){
uint32_t sectionloc = fileOffset + sizeof(struct segment_command) + nsect * sizeof(struct section);
MATCH_STRUCT(section,sectionloc)
if(!strcmp(section->segname, "__OBJC2") ||
!strcmp(section->segname, "__DATA")){
if(!strcmp(section->sectname, "__class_list") ||
!strcmp(section->sectname, "__objc_classlist")){
__class_list = section;
}
else if (!strcmp(section->sectname, "__category_list") ||
!strcmp(section->sectname, "__objc_catlist")){
__category_list = section;
}
}
switch (section->flags & SECTION_TYPE) {
case S_LITERAL_POINTERS:{
NSRange range = NSMakeRange(section->offset + imageOffset,0);
while (NSMaxRange(range) < section->offset + imageOffset + section->size) {
uint64_t ptr = read_uint32(range,bytes);
sel_ref.push_back(ptr);
}
} break;
case S_MOD_INIT_FUNC_POINTERS:
case S_MOD_TERM_FUNC_POINTERS:
case S_LAZY_SYMBOL_POINTERS:
case S_NON_LAZY_SYMBOL_POINTERS:
case S_LAZY_DYLIB_SYMBOL_POINTERS:
case S_SYMBOL_STUBS:
break;
default:
break;
}
}
}break;
case LC_SEGMENT_64:{
MATCH_STRUCT(segment_command_64,fileOffset)
if (!strcmp(segment_command_64->segname, SEG_PAGEZERO)) { continue; }
int prot = 0;
if (segment_command_64->initprot & VM_PROT_READ) { prot |= PROT_READ; }
if (segment_command_64->initprot & VM_PROT_WRITE) { prot |= PROT_WRITE; }
if (segment_command_64->initprot & VM_PROT_EXECUTE) { prot |= PROT_EXEC; }
uint64_t filesize = segment_command_64->filesize;// alignMem(seg->filesize, 0x1000);
if(filesize <= 0)continue;
uint64_t vmaddr = segment_command_64->vmaddr + slide;
void *ret = memcpy((void *)vmaddr, bytes + segment_command_64->fileoff + imageOffset, filesize);
if(!ret){err(1, "memcpy fail\n");}
if(MY_MPROTECT((void*)vmaddr, alignMem(segment_command_64->vmsize, 0x1000), prot) != 0){
printf("*********warning:********* change protect fail:%d\n",errno);
}
if (segment_command_64->fileoff == 0 && segment_command_64->filesize != 0){
base_addr = segment_command_64->vmaddr;
}
for (uint32_t nsect = 0; nsect < segment_command_64->nsects; ++nsect){
uint32_t sectionloc = fileOffset + sizeof(struct segment_command_64) + nsect * sizeof(struct section_64);
MATCH_STRUCT(section_64,sectionloc)
if(!strcmp(section_64->segname, "__OBJC2") ||
!strcmp(section_64->segname, "__DATA")){
if(!strcmp(section_64->sectname, "__class_list") ||
!strcmp(section_64->sectname, "__objc_classlist__DATA")){
__class_list_64 = section_64;
}
else if (!strcmp(section_64->sectname, "__category_list__DATA") ||
!strcmp(section_64->sectname, "__objc_catlist")){
__category_list_64 = section_64;
}
}
switch (section_64->flags & SECTION_TYPE) {
case S_LITERAL_POINTERS:{
NSRange range = NSMakeRange(section_64->offset + imageOffset,0);
while (NSMaxRange(range) < section_64->offset + imageOffset + section_64->size) {
uint64_t ptr = read_uint64(range,bytes);
sel_ref_64.push_back(ptr);
}
} break;
case S_MOD_INIT_FUNC_POINTERS:
case S_MOD_TERM_FUNC_POINTERS:
case S_LAZY_SYMBOL_POINTERS:
case S_NON_LAZY_SYMBOL_POINTERS:
case S_LAZY_DYLIB_SYMBOL_POINTERS:
case S_SYMBOL_STUBS:
break;
default:
break;
}
}
}break;
case LC_ID_DYLIB:
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
case LC_LAZY_LOAD_DYLIB:
case LC_LOAD_UPWARD_DYLIB:{
MATCH_STRUCT(dylib_command,fileOffset)
if (load_command->cmd != LC_ID_DYLIB) {
// dylibs_name_offset.push_back(fileOffset + dylib_command->dylib.name.offset);
NSRange range = NSMakeRange(fileOffset + dylib_command->dylib.name.offset, 0);
const char *dllName = read_string(range, bytes);
void *handle = dlopen(dllName, RTLD_LAZY | RTLD_GLOBAL);
if(!handle){
printf("warning: open dll fail ==> %s\n",dllName);
}
}
}break;
case LC_DYLD_INFO:
case LC_DYLD_INFO_ONLY: dyld_info_command = (struct dyld_info_command const *)load_command; break;
default:
break;
}
fileOffset += load_command->cmdsize;
}
if(!dyld_info_command){return;}
if (dyld_info_command->rebase_off * dyld_info_command->rebase_size > 0){
uint64_t ptrSize = (!is_64 ? sizeof(uint32_t) : sizeof(uint64_t));
uint64_t address = base_addr;
uint32_t type = 0;
bool isDone = false;
uint32_t doRebaseLocation = dyld_info_command->rebase_off + imageOffset;
NSRange range = NSMakeRange(doRebaseLocation,0);
while (NSMaxRange(range) < dyld_info_command->rebase_off + imageOffset + dyld_info_command->rebase_size && !isDone) {
uint8_t byte = *(bytes + NSMaxRange(range));
range = NSMakeRange(NSMaxRange(range), sizeof(uint8_t));
uint8_t opcode = byte & REBASE_OPCODE_MASK;
uint8_t immediate = byte & REBASE_IMMEDIATE_MASK;
switch (opcode) {
case REBASE_OPCODE_DONE:
isDone = YES;
break;
case REBASE_OPCODE_SET_TYPE_IMM:
type = immediate;
break;
case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:{
uint32_t segmentIndex = immediate;
uint64_t offset = read_uleb128(range, bytes);
if (segmentIndex >= ncmds){
[NSException raise:@"Segment" format:@"index is out of range %u", segmentIndex];
}
fileOffset = imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64));
for(uint32_t i = 0;i < ncmds;i++){
MATCH_STRUCT(load_command,fileOffset)
if(i == segmentIndex){
switch (load_command->cmd) {
case LC_SEGMENT:{
MATCH_STRUCT(segment_command, fileOffset)
address = segment_command->vmaddr + offset;
}break;
case LC_SEGMENT_64:{
MATCH_STRUCT(segment_command_64,fileOffset)
address = segment_command_64->vmaddr + offset;
}break;
default:break;
}
}
fileOffset += load_command->cmdsize;
}
} break;
case REBASE_OPCODE_ADD_ADDR_ULEB:{
uint64_t offset = read_uleb128(range, bytes);
address += offset;
} break;
case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:{
uint32_t scale = immediate;
address += scale * ptrSize;
} break;
case REBASE_OPCODE_DO_REBASE_IMM_TIMES:{
uint32_t count = immediate;
for (uint32_t index = 0; index < count; index++){
// is_64 ? rebases_64.push_back(address) : rebases.push_back(address);
doRebase(address, slide, is_64 ? sel_ref_64 : sel_ref);
address += ptrSize;
}
doRebaseLocation = NSMaxRange(range);
} break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:{
uint32_t startNextRebase = NSMaxRange(range);
uint64_t count = read_uleb128(range, bytes);
for (uint64_t index = 0; index < count; index++) {
// is_64 ? rebases_64.push_back(address) : rebases.push_back(address);
doRebase(address, slide, is_64 ? sel_ref_64 : sel_ref);
address += ptrSize;
}
doRebaseLocation = startNextRebase;
} break;
case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:{
uint32_t startNextRebase = NSMaxRange(range);
uint64_t offset = read_uleb128(range,bytes);
// is_64 ? rebases_64.push_back(address) : rebases.push_back(address);
doRebase(address, slide, is_64 ? sel_ref_64 : sel_ref);
address += ptrSize + offset;
doRebaseLocation = startNextRebase;
} break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: {
uint32_t startNextRebase = NSMaxRange(range);
uint64_t count = read_uleb128(range,bytes);
uint64_t skip = read_uleb128(range,bytes);
for (uint64_t index = 0; index < count; index++) {
// is_64 ? rebases_64.push_back(address) : rebases.push_back(address);
doRebase(address, slide, is_64 ? sel_ref_64 : sel_ref);
address += ptrSize + skip;
}
doRebaseLocation = startNextRebase;
} break;
default:
[NSException raise:@"Rebase info" format:@"Unknown opcode (%u %u)",
((uint32_t)-1 & opcode), ((uint32_t)-1 & immediate)];
}
}
}
if (dyld_info_command->bind_off * dyld_info_command->bind_size > 0){
createBinding(slide,dyld_info_command->bind_off + imageOffset, dyld_info_command->bind_size, base_addr, is_64, bytes, ncmds, imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64)),NodeTypeBind, bind_64, bind);
}
if (dyld_info_command->weak_bind_off * dyld_info_command->weak_bind_size > 0){
createBinding(slide,dyld_info_command->weak_bind_off + imageOffset, dyld_info_command->weak_bind_size, base_addr, is_64, bytes, ncmds, imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64)),NodeTypeWeakBind, bind_64, bind);
}
if (dyld_info_command->lazy_bind_off * dyld_info_command->lazy_bind_size > 0){
createBinding(slide,dyld_info_command->lazy_bind_off + imageOffset, dyld_info_command->lazy_bind_size, base_addr, is_64, bytes, ncmds, imageOffset + (!is_64 ? sizeof(struct mach_header) : sizeof(struct mach_header_64)),NodeTypeLazyBind, bind_64, bind);
}
if (dyld_info_command->export_off * dyld_info_command->export_size > 0){
printSymbols("",dyld_info_command->export_off + imageOffset, 0, base_addr, bytes);
}
if(is_64){
if(__class_list_64){
}
if(__category_list_64){
}
}
else{
if(__class_list){
}
if(__category_list){
}
}
}
零时
最新推荐文章于 2021-03-31 18:15:35 发布