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

如何修改findLibrary获取/proc/self/maps中库的第二/第三映射段地址

问题背景

Android Native开发中读取/proc/self/maps获取so库内存地址时,同一个so会存在多个内存映射段,示例maps内容如下:

06200000-0620d000 r--p 00000000 08:06 1009                  /system/lib/arm/libbase.so -- not here
0620d000-0620e000 r--p 0000c000 08:06 1009                 /system/lib/arm/libbase.so  -- get here
0620e000-0620f000 rw-p 0000d000 08:06 1009                /system/lib/arm/libbase.so

原有findLibrary实现匹配到第一个带目标库名的行就直接返回,只能拿到第一个映射段的起始地址,无法获取后续段的地址。原有代码如下:

DWORD findLibrary(const char *library) {
    char filename[0xFF] = {0},
            buffer[1024] = {0};
    FILE *fp = NULL;
    DWORD address = 0;

    sprintf(filename, OBFUSCATE("/proc/self/maps"));

    fp = fopen(filename, OBFUSCATE("rt"));
    if (fp == NULL) {
        perror(OBFUSCATE("fopen"));
        goto done;
    }

    while (fgets(buffer, sizeof(buffer), fp)) {
        if (strstr(buffer, library)) {
            address = (DWORD) strtoul(buffer, NULL, 16);
            goto done;
        }
    }

    done:

    if (fp) {
        fclose(fp);
    }

    return address;
}
修改方案

核心改动点:

  • 给函数增加段序号入参,指定要获取第几个匹配到的映射段地址(序号从0开始,0对应第一个段,1对应第二个段,以此类推)
  • 匹配到目标库时先计数,计数和传入的目标序号一致时才读取地址返回,否则继续遍历后续行
  • 额外增加路径校验,避免匹配到库名是其他so子串的误判情况(比如找libbase.so时误匹配libbase_ext.so)

修改后的可直接使用的代码如下:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

// 入参seg_index: 要获取的映射段序号,从0开始计数
// 返回值:对应段的起始地址,找不到返回0
DWORD findLibraryBySegIndex(const char *library, int seg_index) {
    char filename[0xFF] = {0};
    char buffer[1024] = {0};
    FILE *fp = NULL;
    DWORD address = 0;
    int match_cnt = 0; // 记录匹配到的目标库段数量

    sprintf(filename, OBFUSCATE("/proc/self/maps"));
    fp = fopen(filename, OBFUSCATE("rt"));
    if (fp == NULL) {
        perror(OBFUSCATE("fopen"));
        goto done;
    }

    while (fgets(buffer, sizeof(buffer), fp)) {
        // 定位到行内文件路径起始位置,跳过非文件映射段
        char* path_start = strrchr(buffer, '/');
        if (path_start == NULL) {
            continue;
        }
        // 精确匹配库名,避免子串误判
        if (strstr(path_start, library) != NULL) {
            if (match_cnt == seg_index) {
                // 命中目标序号段,解析起始地址返回
                address = (DWORD)strtoul(buffer, NULL, 16);
                goto done;
            }
            match_cnt++;
        }
    }

done:
    if (fp) {
        fclose(fp);
    }
    return address;
}
使用示例

如果要获取示例里libbase.so标注-- get here的第二个映射段,直接传入序号1即可:

// 获取第二个映射段起始地址
DWORD second_seg_addr = findLibraryBySegIndex("libbase.so", 1);
// 获取第三个映射段起始地址传入序号2即可
DWORD third_seg_addr = findLibraryBySegIndex("libbase.so", 2);

注意:64位Android环境下地址长度为8字节,原代码用4字节的DWORD存储地址会溢出,建议将地址类型替换为uintptr_t同时适配32/64位环境。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 09:09:20