static RList *r_debug_native_map_get(RDebug *dbg) { RIOBdescbg *o = dbg->iob.io->desc->data; BfvmCPU *c = o->bfvm; RList *list = r_list_newf ((RListFree)r_debug_map_free); if (!list) return NULL; r_list_append (list, r_debug_map_new ( "code", 0, 4096, 6, 0)); r_list_append (list, r_debug_map_new ( "memory", c->base, c->base+c->size, 6, 0)); r_list_append (list, r_debug_map_new ( "screen", c->screen, c->screen+c->screen_size, 6, 0)); r_list_append (list, r_debug_map_new ( "input", c->input, c->input+c->input_size, 6, 0)); return list; }
static RList *__io_maps(RDebug *dbg) { RList *list = r_list_new (); dbg->iob.system (dbg->iob.io, "dm"); char *ostr, *str = strdup (r_cons_get_buffer ()); ut64 map_start, map_end; char perm[32]; char name[512]; ostr = str; while (true) { char *nl = strchr (str, '\n'); if (nl) { *nl = 0; *name = 0; *perm = 0; map_start = map_end = 0LL; if (!strncmp (str, "sys ", 4)) { char *sp = strchr (str + 4, ' '); if (sp) { str = sp + 1; } else { str += 4; } } char *_s_ = strstr (str, " s "); if (_s_) { memmove (_s_, _s_ + 2, strlen (_s_)); } _s_ = strstr (str, " ? "); if (_s_) { memmove (_s_, _s_ + 2, strlen (_s_)); } sscanf (str, "0x%"PFMT64x" - 0x%"PFMT64x" %s %s", &map_start, &map_end, perm, name); if (map_end != 0LL) { RDebugMap *map = r_debug_map_new (name, map_start, map_end, r_str_rwx (perm), 0); r_list_append (list, map); } str = nl + 1; } else { break; } } free (ostr); r_cons_reset(); return list; }
static RList *r_debug_native_sysctl_map (RDebug *dbg) { int mib[4]; size_t len; char *buf, *bp, *eb; struct kinfo_vmentry *kve; RList *list = NULL; RDebugMap *map; len = 0; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_VMMAP; mib[3] = dbg->pid; if (sysctl (mib, 4, NULL, &len, NULL, 0) != 0) return NULL; len = len * 4 / 3; buf = malloc(len); if (!buf) { return NULL; } if (sysctl (mib, 4, buf, &len, NULL, 0) != 0) { free (buf); return NULL; } bp = buf; eb = buf + len; list = r_debug_map_list_new(); if (!list) { free (buf); return NULL; } while (bp < eb) { kve = (struct kinfo_vmentry *)(uintptr_t)bp; map = r_debug_map_new (kve->kve_path, kve->kve_start, kve->kve_end, kve->kve_protection, 0); if (!map) break; r_list_append (list, map); bp += kve->kve_structsize; } free (buf); return list; }
static RList *r_debug_native_sysctl_map (RDebug *dbg) { int mib[3]; size_t len; struct kinfo_vmentry entry; u_long old_end = 0; RList *list = NULL; RDebugMap *map; len = sizeof(entry); mib[0] = CTL_KERN; mib[1] = KERN_PROC_VMMAP; mib[2] = dbg->pid; entry.kve_start = 0; if (sysctl (mib, 3, &entry, &len, NULL, 0) == -1) { eprintf ("Could not get memory map: %s\n", strerror(errno)); return NULL; } list = r_debug_map_list_new(); if (!list) return NULL; while (sysctl (mib, 3, &entry, &len, NULL, 0) != -1) { if (old_end == entry.kve_end) { /* No more entries */ break; } /* path to vm obj is not included in kinfo_vmentry. * see usr.sbin/procmap for namei-cache lookup. */ map = r_debug_map_new ("", entry.kve_start, entry.kve_end, entry.kve_protection, 0); if (!map) break; r_list_append (list, map); entry.kve_start = entry.kve_start + 1; old_end = entry.kve_end; } return list; }
static RList *r_debug_native_map_get (RDebug *dbg) { RList *list = NULL; #if __KFBSD__ int ign; char unkstr[128]; #endif #if __APPLE__ list = xnu_dbg_maps (dbg, 0); #elif __WINDOWS__ && !__CYGWIN__ list = w32_dbg_maps (dbg); // TODO: moar? #else #if __sun char path[1024]; /* TODO: On solaris parse /proc/%d/map */ snprintf (path, sizeof(path) - 1, "pmap %d > /dev/stderr", ps.tid); system (path); #else RDebugMap *map; int i, perm, unk = 0; char *pos_c; char path[1024], line[1024]; char region[100], region2[100], perms[5]; FILE *fd; if (dbg->pid == -1) { //eprintf ("r_debug_native_map_get: No selected pid (-1)\n"); return NULL; } #if __KFBSD__ list = r_debug_native_sysctl_map (dbg); if (list != NULL) return list; snprintf (path, sizeof (path), "/proc/%d/map", dbg->pid); #else snprintf (path, sizeof (path), "/proc/%d/maps", dbg->pid); #endif fd = fopen (path, "r"); if (!fd) { perror (sdb_fmt (0, "Cannot open '%s'", path)); return NULL; } list = r_list_new(); if (!list) { fclose (fd); return NULL; } list->free = (RListFree)_map_free; while (!feof (fd)) { line[0] = '\0'; fgets (line, sizeof(line) - 1, fd); if (line[0] == '\0') break; path[0] = '\0'; line[strlen (line) - 1] = '\0'; #if __KFBSD__ // 0x8070000 0x8072000 2 0 0xc1fde948 rw- 1 0 0x2180 COW NC vnode /usr/bin/gcc sscanf (line, "%s %s %d %d 0x%s %3s %d %d", ®ion[2], ®ion2[2], &ign, &ign, unkstr, perms, &ign, &ign); pos_c = strchr (line, '/'); if (pos_c) strncpy (path, pos_c, sizeof(path) - 1); else path[0] = '\0'; #else char null[64]; // XXX: this can overflow sscanf (line, "%s %s %s %s %s %s", ®ion[2], perms, null, null, null, path); pos_c = strchr (®ion[2], '-'); if (!pos_c) continue; pos_c[-1] = (char)'0'; // xxx. this is wrong pos_c[ 0] = (char)'x'; strncpy (region2, pos_c - 1, sizeof(region2) - 1); #endif // __KFBSD__ region[0] = region2[0] = '0'; region[1] = region2[1] = 'x'; if (!*path) snprintf (path, sizeof(path), "unk%d", unk++); perm = 0; for (i = 0; perms[i] && i < 4; i++) switch (perms[i]) { case 'r': perm |= R_IO_READ; break; case 'w': perm |= R_IO_WRITE; break; case 'x': perm |= R_IO_EXEC; break; } map = r_debug_map_new (path, r_num_get (NULL, region), r_num_get (NULL, region2), perm, 0); if (!map) break; map->file = strdup (path); r_list_append (list, map); } fclose (fd); #endif // __sun #endif // __WINDOWS return list; }
static RList *r_debug_native_map_get (RDebug *dbg) { RList *list = NULL; #if __KFBSD__ int ign; char unkstr[128]; #endif #if __APPLE__ list = xnu_dbg_maps (dbg, 0); #elif __WINDOWS__ && !__CYGWIN__ list = w32_dbg_maps (dbg); // TODO: moar? #else #if __sun char path[1024]; /* TODO: On solaris parse /proc/%d/map */ snprintf (path, sizeof(path) - 1, "pmap %d > /dev/stderr", ps.tid); system (path); #else RDebugMap *map; int i, perm, unk = 0; char *pos_c; char path[1024], line[1024], name[1024]; char region[100], region2[100], perms[5]; FILE *fd; if (dbg->pid == -1) { //eprintf ("r_debug_native_map_get: No selected pid (-1)\n"); return NULL; } /* prepend 0x prefix */ region[0] = region2[0] = '0'; region[1] = region2[1] = 'x'; #if __OpenBSD__ /* OpenBSD has no procfs, so no idea trying. */ return r_debug_native_sysctl_map (dbg); #endif #if __KFBSD__ list = r_debug_native_sysctl_map (dbg); if (list) { return list; } snprintf (path, sizeof (path), "/proc/%d/map", dbg->pid); #else snprintf (path, sizeof (path), "/proc/%d/maps", dbg->pid); #endif fd = fopen (path, "r"); if (!fd) { perror (sdb_fmt (0, "Cannot open '%s'", path)); return NULL; } list = r_list_new (); if (!list) { fclose (fd); return NULL; } list->free = (RListFree)_map_free; while (!feof (fd)) { size_t line_len; ut64 map_start, map_end; if (!fgets (line, sizeof (line), fd)) break; /* kill the newline if we got one */ line_len = strlen (line); if (line[line_len - 1] == '\n') { line[line_len - 1] = '\0'; line_len--; } /* maps files should not have empty lines */ if (line_len == 0) { break; } #if __KFBSD__ // 0x8070000 0x8072000 2 0 0xc1fde948 rw- 1 0 0x2180 COW NC vnode /usr/bin/gcc if (sscanf (line, "%s %s %d %d 0x%s %3s %d %d", ®ion[2], ®ion2[2], &ign, &ign, unkstr, perms, &ign, &ign) != 8) { eprintf ("%s: Unable to parse \"%s\"\n", __func__, path); r_list_free (list); return NULL; } /* snag the file name */ pos_c = strchr (line, '/'); if (pos_c) { strncpy (name, pos_c, sizeof (name) - 1); } else { name[0] = '\0'; } #else // 7fc8124c4000-7fc81278d000 r--p 00000000 fc:00 17043921 /usr/lib/locale/locale-archive i = sscanf (line, "%s %s %*s %*s %*s %[^\n]", ®ion[2], perms, name); if (i == 2) { name[0] = '\0'; } else if (i != 3) { eprintf ("%s: Unable to parse \"%s\"\n", __func__, path); eprintf ("%s: problematic line: %s\n", __func__, line); r_list_free (list); return NULL; } /* split the region in two */ pos_c = strchr (®ion[2], '-'); if (!pos_c) // should this be an error? continue; strncpy (®ion2[2], pos_c + 1, sizeof (region2) - 2 - 1); #endif // __KFBSD__ if (!*name) snprintf (name, sizeof (name), "unk%d", unk++); perm = 0; for (i = 0; perms[i] && i < 4; i++) { switch (perms[i]) { case 'r': perm |= R_IO_READ; break; case 'w': perm |= R_IO_WRITE; break; case 'x': perm |= R_IO_EXEC; break; } } map_start = r_num_get (NULL, region); map_end = r_num_get (NULL, region2); if (map_start == map_end || map_end == 0) { eprintf ("%s: ignoring invalid map size: %s - %s\n", __func__, region, region2); continue; } map = r_debug_map_new (name, map_start, map_end, perm, 0); if (!map) { break; } map->file = strdup (name); r_list_append (list, map); } fclose (fd); #endif // __sun #endif // __WINDOWS return list; }
static RList *ios_dbg_maps(RDebug *dbg, int only_modules) { boolt contiguous = R_FALSE; ut32 oldprot = UT32_MAX; ut32 oldmaxprot = UT32_MAX; char buf[1024]; char module_name[MAXPATHLEN]; 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; int tid = dbg->pid; task_t task = pid_to_task (tid); RDebugMap *mr = NULL; RList *list = NULL; int i = 0; if (only_modules) { return xnu_dbg_modules (dbg); } #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; 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 (info.is_submap) { depth++; continue; } if (!list) { list = r_list_new (); //list->free = (RListFree*)r_debug_map_free; } { module_name[0] = 0; int ret = proc_regionfilename (tid, address, module_name, sizeof (module_name)); module_name[ret] = 0; } #if 0 oldprot = info.protection; oldmaxprot = info.max_protection; // contiguous pages seems to hide some map names if (mr) { if (address == mr->addr + mr->size) { if (oldmaxprot == info.max_protection) { contiguous = R_FALSE; } else 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; //if (info.max_protection == oldprot && !contiguous) { #endif if (1) { #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) { eprintf ("EFUCK\n"); size = osize; // f**k } address += size; size = 0; } return list; }
static RList *xnu_dbg_modules(RDebug *dbg) { struct task_dyld_info info; mach_msg_type_number_t count; kern_return_t kr; int size, info_array_count, info_array_size, i; ut64 info_array_address; void *info_array = NULL; void *header_data = NULL; char file_path[MAXPATHLEN]; count = TASK_DYLD_INFO_COUNT; task_t task = pid_to_task (dbg->tid); ut64 addr, file_path_address; RDebugMap *mr = NULL; RList *list = NULL; kr = task_info (task, TASK_DYLD_INFO, (task_info_t) &info, &count); if (kr != KERN_SUCCESS) return NULL; if (info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_64) { DyldAllImageInfos64 all_infos; dbg->iob.read_at (dbg->iob.io, info.all_image_info_addr, (ut8*)&all_infos, sizeof (DyldAllImageInfos64)); info_array_count = all_infos.info_array_count; info_array_size = info_array_count * DYLD_IMAGE_INFO_64_SIZE; info_array_address = all_infos.info_array; } else { DyldAllImageInfos32 all_info; dbg->iob.read_at (dbg->iob.io, info.all_image_info_addr, (ut8*)&all_info, sizeof (DyldAllImageInfos32)); info_array_count = all_info.info_array_count; info_array_size = info_array_count * DYLD_IMAGE_INFO_32_SIZE; info_array_address = all_info.info_array; } if (info_array_address == 0) { return NULL; } info_array = malloc (info_array_size); if (!info_array) { eprintf ("Cannot allocate info_array_size %d\n", info_array_size); return NULL; } dbg->iob.read_at (dbg->iob.io, info_array_address, info_array, info_array_size); list = r_list_new (); for (i=0; i < info_array_count; i++) { if (info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_64) { DyldImageInfo64 * info = info_array + (i * DYLD_IMAGE_INFO_64_SIZE); addr = info->image_load_address; file_path_address = info->image_file_path; } else { DyldImageInfo32 * info = info_array + (i * DYLD_IMAGE_INFO_32_SIZE); addr = info->image_load_address; file_path_address = info->image_file_path; } dbg->iob.read_at (dbg->iob.io, file_path_address, (ut8*)file_path, MAXPATHLEN); //eprintf ("--> %d 0x%08"PFMT64x" %s\n", i, addr, file_path); size = mach0_size (dbg, addr); mr = r_debug_map_new (file_path, addr, addr+size, 7, 0); if (mr == NULL) { eprintf ("Cannot create r_debug_map_new\n"); break; } mr->file = strdup (file_path); r_list_append (list, mr); } free (info_array); return list; }
static RList *r_debug_gdb_map_get(RDebug* dbg) { //TODO check_connection (dbg); if (desc->pid <= 0) { return NULL; } RList *retlist = NULL; // Get file from GDB char path[128]; ut8 *buf; int ret; // TODO don't hardcode buffer size, get from remote target // (I think gdb doesn't do that, it just keeps reading till EOF) // fstat info can get file size, but it doesn't work for /proc/pid/maps ut64 buflen = 16384; // If /proc/%d/maps is not valid for gdbserver, we return NULL, as of now snprintf (path, sizeof (path) - 1, "/proc/%d/maps", desc->pid); if (gdbr_open_file (desc, path, O_RDONLY, S_IRUSR | S_IWUSR | S_IXUSR) < 0) { return NULL; } if (!(buf = malloc (buflen))) { gdbr_close_file (desc); return NULL; } if ((ret = gdbr_read_file (desc, buf, buflen - 1)) <= 0) { gdbr_close_file (desc); free (buf); return NULL; } buf[ret] = '\0'; // Get map list int unk = 0, perm, i; char *ptr, *pos_1; size_t line_len; char name[1024], region1[100], region2[100], perms[5]; RDebugMap *map = NULL; region1[0] = region2[0] = '0'; region1[1] = region2[1] = 'x'; if (!(ptr = strtok ((char*) buf, "\n"))) { gdbr_close_file (desc); free (buf); return NULL; } if (!(retlist = r_list_new ())) { gdbr_close_file (desc); free (buf); return NULL; } while (ptr) { ut64 map_start, map_end, offset; bool map_is_shared = false; line_len = strlen (ptr); // maps files should not have empty lines if (line_len == 0) { break; } // We assume Linux target, for now, so - // 7ffff7dda000-7ffff7dfd000 r-xp 00000000 08:05 265428 /usr/lib/ld-2.25.so ret = sscanf (ptr, "%s %s %"PFMT64x" %*s %*s %[^\n]", ®ion1[2], perms, &offset, name); if (ret == 3) { name[0] = '\0'; } else if (ret != 4) { eprintf ("%s: Unable to parse \"%s\"\nContent:\n%s\n", __func__, path, buf); gdbr_close_file (desc); free (buf); r_list_free (retlist); return NULL; } if (!(pos_1 = strchr (®ion1[2], '-'))) { ptr = strtok (NULL, "\n"); continue; } strncpy (®ion2[2], pos_1 + 1, sizeof (region2) - 2 - 1); if (!*name) { snprintf (name, sizeof (name), "unk%d", unk++); } perm = 0; for (i = 0; perms[i] && i < 5; i++) { switch (perms[i]) { case 'r': perm |= R_IO_READ; break; case 'w': perm |= R_IO_WRITE; break; case 'x': perm |= R_IO_EXEC; break; case 'p': map_is_shared = false; break; case 's': map_is_shared = true; break; } } map_start = r_num_get (NULL, region1); map_end = r_num_get (NULL, region2); if (map_start == map_end || map_end == 0) { eprintf ("%s: ignoring invalid map size: %s - %s\n", __func__, region1, region2); ptr = strtok (NULL, "\n"); continue; } if (!(map = r_debug_map_new (name, map_start, map_end, perm, 0))) { break; } map->offset = offset; map->shared = map_is_shared; map->file = strdup (name); r_list_append (retlist, map); ptr = strtok (NULL, "\n"); } gdbr_close_file (desc); free (buf); return retlist; }