如何修改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
相关产品推荐
相关产品推荐

