rizin/libr/debug/p/native/maps/darwin.c

321 lines
8.6 KiB
C

#if __APPLE__
kern_return_t mach_vm_region_recurse (
vm_map_t target_task,
mach_vm_address_t *address,
mach_vm_size_t *size,
natural_t *nesting_depth,
vm_region_recurse_info_t info,
mach_msg_type_number_t *infoCnt
);
static const char * unparse_inheritance (vm_inherit_t i) {
switch (i) {
case VM_INHERIT_SHARE: return "share";
case VM_INHERIT_COPY: return "copy";
case VM_INHERIT_NONE: return "none";
default: return "???";
}
}
#if __LP64__
#define ADDR "%16lx"
#define HEADER_SIZE 0x1000
#define IMAGE_OFFSET 0x2000
#define KERNEL_LOWER 0xffffff8000000000
#else
#define ADDR "%8x"
#define HEADER_SIZE 0x1000
#define IMAGE_OFFSET 0x201000
#define KERNEL_LOWER 0x80000000
#endif
vm_address_t get_kernel_base(task_t ___task) {
kern_return_t ret;
task_t task;
vm_region_submap_info_data_64_t info;
ut64 size;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
unsigned int depth = 0;
ut64 addr = KERNEL_LOWER; // lowest possible kernel base address
int count;
ret = task_for_pid(mach_task_self(), 0, &task);
if (ret != KERN_SUCCESS)
return 0;
ut64 naddr;
eprintf ("%d vs %d\n", task, ___task);
for (count=128; count; count--) {
// get next memory region
naddr = addr;
ret = vm_region_recurse_64 (task, (vm_address_t*)&naddr, (vm_size_t*)&size,
&depth, (vm_region_info_t)&info, &info_count);
if (ret != KERN_SUCCESS)
break;
if (size<1) break;
if (addr == naddr) {
addr += size;
continue;
}
eprintf ("0x%08"PFMT64x" size 0x%08"PFMT64x" perm 0x%x\n", (ut64)addr, (ut64)size, info.max_protection);
// the kernel maps over a GB of RAM at the address where it maps
// itself so we use that fact to detect it's position
if (size > 1024*1024*1024) {
return addr + IMAGE_OFFSET;
}
addr += size;
}
return (vm_address_t)0;
}
extern int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize);
static RList *ios_dbg_maps(RDebug *dbg) {
boolt contiguous = R_FALSE;
ut32 oldprot = UT32_MAX;
char buf[1024];
mach_vm_address_t address = MACH_VM_MIN_ADDRESS;
mach_vm_size_t size = (mach_vm_size_t) 0;
mach_vm_size_t osize = (mach_vm_size_t) 0;
natural_t depth = 0;
task_t task = pid_to_task (dbg->tid);
RDebugMap *mr = NULL;
RList *list = NULL;
int i = 0;
#if __arm64__ || __aarch64__
size = osize = 16384; // acording to frida
#else
size = osize = 4096;
#endif
#if 0
if (dbg->pid == 0) {
vm_address_t base = get_kernel_base (task);
eprintf ("Kernel Base Address: 0x%"PFMT64x"\n", (ut64)base);
return NULL;
}
#endif
kern_return_t kr;
for (;;) {
struct vm_region_submap_info_64 info;
mach_msg_type_number_t info_count;
depth = VM_REGION_BASIC_INFO_64;
info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
memset (&info, 0, sizeof (info));
kr = mach_vm_region_recurse (task, &address, &size, &depth,
(vm_region_recurse_info_t) &info, &info_count);
if (kr != KERN_SUCCESS) {
//eprintf ("Cannot kern succ recurse\n");
break;
}
if (!list) {
list = r_list_new ();
//list->free = (RListFree*)r_debug_map_free;
}
if (mr) {
if (address == mr->addr + mr->size) {
if (oldprot != UT32_MAX && oldprot == info.protection) {
/* expand region */
mr->size += size;
contiguous = R_TRUE;
} else {
contiguous = R_FALSE;
}
} else {
contiguous = R_FALSE;
}
} else contiguous = R_FALSE;
oldprot = info.protection;
if (info.max_protection!=0 && !contiguous) {
char module_name[1024];
module_name[0] = 0;
int ret = proc_regionfilename (dbg->pid, address,
module_name, sizeof (module_name));
module_name[ret] = 0;
#define xwr2rwx(x) ((x&1)<<2) | (x&2) | ((x&4)>>2)
// XXX: if its shared, it cannot be read?
snprintf (buf, sizeof (buf), "%s %02x %s%s%s%s%s %s depth=%d",
r_str_rwx_i (xwr2rwx (info.max_protection)), i,
unparse_inheritance (info.inheritance),
info.user_tag? " user": "",
info.is_submap? " sub": "",
info.inheritance? " inherit": "",
info.is_submap ? " submap": "",
module_name, depth);
//info.shared ? "shar" : "priv",
//info.reserved ? "reserved" : "not-reserved",
//""); //module_name);
mr = r_debug_map_new (buf, address, address+size,
xwr2rwx (info.protection), 0);
if (mr == NULL) {
eprintf ("Cannot create r_debug_map_new\n");
break;
}
mr->file = strdup (module_name);
i++;
r_list_append (list, mr);
}
if (size<1) size = osize; // fuck
address += size;
size = 0;
}
return list;
}
#if 0
// TODO: this loop MUST be cleaned up
static RList *osx_dbg_maps (RDebug *dbg) {
RDebugMap *mr;
char buf[1024];
int i, print;
kern_return_t kret;
vm_region_basic_info_data_64_t info, prev_info;
mach_vm_address_t prev_address;
mach_vm_size_t size, prev_size;
mach_port_t object_name;
mach_msg_type_number_t count;
int nsubregions = 0;
int num_printed = 0;
size_t address = 0;
task_t task = pid_to_task (dbg->pid);
RList *list = r_list_new ();
// XXX: wrong for 64bits
/*
count = VM_REGION_BASIC_INFO_COUNT_64;
kret = mach_vm_region (pid_to_task (dbg->pid), &address, &size, VM_REGION_BASIC_INFO_64,
(vm_region_info_t) &info, &count, &object_name);
if (kret != KERN_SUCCESS) {
printf("No memory regions.\n");
return;
}
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
*/
#if __arm64__ || __aarch64__
size = 16384; // acording to frida
#else
size = 4096;
#endif
memset (&prev_info, 0, sizeof (prev_info));
prev_address = address;
prev_size = size;
nsubregions = 1;
for (i=0; ; i++) {
int done = 0;
address = prev_address + prev_size;
print = 0;
if (prev_size==0)
break;
/* Check to see if address space has wrapped around. */
if (address == 0)
done = 1;
if (!done) {
count = VM_REGION_BASIC_INFO_COUNT_64;
kret = mach_vm_region (task, (mach_vm_address_t *)&address,
&size, VM_REGION_BASIC_INFO_64,
(vm_region_info_t) &info, &count, &object_name);
if (kret != KERN_SUCCESS) {
size = 0;
print = done = 1;
}
}
if (address != prev_address + prev_size)
print = 1;
if ((info.protection != prev_info.protection)
|| (info.max_protection != prev_info.max_protection)
|| (info.inheritance != prev_info.inheritance)
|| (info.shared != prev_info.reserved)
|| (info.reserved != prev_info.reserved))
print = 1;
//#if __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0)
{
char module_name[1024];
module_name[0] = 0;
int ret = proc_regionfilename (dbg->pid, address, module_name, sizeof (module_name));
module_name[ret] = 0;
#define xwr2rwx(x) ((x&1)<<2) | (x&2) | ((x&4)>>2)
if (print && size>0 && prev_info.inheritance != VM_INHERIT_SHARE) {
snprintf (buf, sizeof (buf), "%s %02x %s/%s/%s %s",
r_str_rwx_i (xwr2rwx (prev_info.max_protection)), i,
unparse_inheritance (prev_info.inheritance),
prev_info.shared ? "shar" : "priv",
prev_info.reserved ? "reserved" : "not-reserved",
module_name);
// TODO: MAPS can have min and max protection rules
// :: prev_info.max_protection
mr = r_debug_map_new (buf, prev_address, prev_address+prev_size,
xwr2rwx (prev_info.protection), 0);
if (mr == NULL) {
eprintf ("Cannot create r_debug_map_new\n");
break;
}
mr->file = strdup (module_name);
r_list_append (list, mr);
}
}
#if 0
if (1==0 && rest) { /* XXX never pritn this info here */
addr = 0LL;
addr = (ut64) (ut32) prev_address;
if (num_printed == 0)
fprintf(stderr, "Region ");
else fprintf(stderr, " ... ");
fprintf(stderr, " 0x%08llx - 0x%08llx %s (%s) %s, %s, %s",
addr, addr + prev_size,
unparse_protection (prev_info.protection),
unparse_protection (prev_info.max_protection),
unparse_inheritance (prev_info.inheritance),
prev_info.shared ? "shared" : " private",
prev_info.reserved ? "reserved" : "not-reserved");
if (nsubregions > 1)
fprintf(stderr, " (%d sub-regions)", nsubregions);
fprintf(stderr, "\n");
prev_address = address;
prev_size = size;
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
nsubregions = 1;
num_printed++;
} else {
#endif
#if 0
prev_size += size;
nsubregions++;
#else
prev_address = address;
prev_size = size;
memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_64_t));
nsubregions = 1;
num_printed++;
#endif
// }
}
return list;
}
#endif
static RList *darwin_dbg_maps(RDebug *dbg) {
//return osx_dbg_maps (dbg);
return ios_dbg_maps (dbg);
#if 0
const char *osname = dbg->anal->syscall->os;
if (osname && !strcmp (osname, "ios")) {
return ios_dbg_maps (dbg);
}
return osx_dbg_maps (dbg);
#endif
}
#endif