You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MacOS下用程序获取vmmap级别的进程内存区域问题

获取与vmmap一致的完整进程内存区域信息

要还原vmmap展示的所有细分内存区域(包括Submap下的Mach-O段/节),需要结合多层Submap遍历和Mach-O文件结构解析,以下是具体实现步骤:

1. 递归遍历多层Submap

vmmap展示的细分区域大多来自嵌套的Submap,仅设置depth>0不够,需要递归遍历所有层级的Submap:

  • 使用mach_vm_region_recurse时,将初始depth设为足够大的值(如32,覆盖绝大多数嵌套场景)
  • 检查返回的vm_region_recurse_info_data_64中的is_submap标志,若为真,则递归遍历该Submap的地址范围

示例C代码片段:

#include <mach/mach.h>
#include <mach/mach_vm.h>

void traverse_submap(mach_port_t target_task, mach_vm_address_t base_addr, mach_vm_size_t size, natural_t max_depth) {
    mach_vm_address_t addr = base_addr;
    mach_vm_size_t sub_size;
    vm_region_recurse_info_data_64_t sub_info;
    mach_msg_type_number_t info_count = VM_REGION_RECURSE_INFO_COUNT_64;
    natural_t depth = max_depth;

    while (addr < base_addr + size) {
        kern_return_t kr = mach_vm_region_recurse(target_task, &addr, &sub_size, &depth, (vm_region_info_t)&sub_info, &info_count);
        if (kr != KERN_SUCCESS) break;

        // 处理当前Submap内的内存区域(打印地址、大小、保护属性等)
        printf("Submap Region: 0x%lx - 0x%lx, Size: 0x%lx\n", addr, addr + sub_size, sub_size);

        if (sub_info.is_submap && depth > 0) {
            // 递归遍历更深层级的Submap
            traverse_submap(target_task, addr, sub_size, depth - 1);
        }

        addr += sub_size;
        depth = max_depth; // 重置depth,处理下一个同级区域
    }
}

void traverse_all_regions(mach_port_t target_task) {
    mach_vm_address_t addr = 0;
    mach_vm_size_t size;
    vm_region_recurse_info_data_64_t info;
    mach_msg_type_number_t info_count = VM_REGION_RECURSE_INFO_COUNT_64;
    natural_t depth = 32;

    while (addr < MACH_VM_MAX_ADDRESS) {
        kern_return_t kr = mach_vm_region_recurse(target_task, &addr, &size, &depth, (vm_region_info_t)&info, &info_count);
        if (kr != KERN_SUCCESS) break;

        if (info.is_submap) {
            // 进入Submap遍历
            traverse_submap(target_task, addr, size, depth - 1);
        } else {
            // 处理普通内存区域
            printf("Normal Region: 0x%lx - 0x%lx, Size: 0x%lx\n", addr, addr + size, size);
        }

        addr += size;
        depth = 32; // 重置depth
    }
}

2. 解析Mach-O文件的段/节信息

对于映射了Mach-O文件的区域(如系统共享库、可执行文件),需要读取文件并解析其segment_command_64和section_64结构体,以获取__TEXT、__DATA等细分段:

  • 通过vm_region_recurse_info_data_64中的object_name字段获取映射的文件路径
  • 打开文件并映射到内存,解析Mach-O头部和加载命令,提取段和节的虚拟地址、大小等信息
  • 注意:Mach-O文件中的vmaddr是相对偏移,需要加上进程中的实际映射基址(即mach_vm_region返回的addr)得到实际地址

示例C代码片段:

#include <mach-o/loader.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>

void parse_macho_sections(const char *file_path, mach_vm_address_t map_base) {
    int fd = open(file_path, O_RDONLY);
    if (fd == -1) return;

    struct stat st;
    if (fstat(fd, &st) == -1) { close(fd); return; }

    void *map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (map == MAP_FAILED) { close(fd); return; }

    mach_header_64_t *hdr = (mach_header_64_t *)map;
    uintptr_t cmd_ptr = (uintptr_t)map + sizeof(mach_header_64_t);

    for (uint32_t i = 0; i < hdr->ncmds; i++) {
        load_command_t *cmd = (load_command_t *)cmd_ptr;
        if (cmd->cmd == LC_SEGMENT_64) {
            segment_command_64_t *seg_cmd = (segment_command_64_t *)cmd;
            // 计算段在进程中的实际起始地址
            mach_vm_address_t seg_addr = map_base + seg_cmd->vmaddr;
            printf("Segment: %s, Address: 0x%lx, Size: 0x%lx\n", seg_cmd->segname, seg_addr, seg_cmd->vmsize);

            // 遍历段内的节
            section_64_t *sect = (section_64_t *)(seg_cmd + 1);
            for (uint32_t j = 0; j < seg_cmd->nsects; j++) {
                mach_vm_address_t sect_addr = map_base + sect[j].addr;
                printf("  Section: %s, Address: 0x%lx, Size: 0x%lx\n", sect[j].sectname, sect_addr, sect[j].size);
            }
        }
        cmd_ptr += cmd->cmdsize;
    }

    munmap(map, st.st_size);
    close(fd);
}

3. 整合逻辑

在遍历内存区域时,对每个非Submap区域,判断是否为Mach-O文件映射:

  • 若info.object_name不为空且是合法文件路径,调用parse_macho_sections解析段/节信息
  • 结合Submap遍历和Mach-O解析,即可得到与vmmap一致的完整内存区域详情

内容的提问来源于stack exchange,提问作者Aayush

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 09:55:23