阅读目录
Android平台进程模块信息获取
发布于:2016-4-29 15:06 | 192430次阅读 作者: 管理员 | 原作者: TP | 来自: 原创
一、概述 记得学习编程时的第一个helloworld程序: #include<stdio.h>
Int main(int argc, char **argv) { printf("Hello World"); return 0; } 打印” Hello World”,使用的是printf函数。但是,我们并没有去实现printf函数的功能,而是由C语言标准库去实现,我们直接加载该库就可以了。像这样的例子,还有很多。 在开发软件时,我们通常只实现软件的核心逻辑功能,而把基础的功能交给第三方完成,这样的好处是代码体积更小、占用更小的存储空间,而且更方便管理。如果我们想要知道软件加载了哪些库,就需要进行内存模块遍历。 二、Android内存模块遍历的原理 在Android系统上,要进行内存模块遍历,必须要了解proc文件系统。在linux系统上,把一切信息通过文件的形式输出。proc也是文件系统的一种,但是,它是伪文件系统,不占用磁盘空间,而是由内核挂载到内存中。proc文件系统提供了内核配置、进程状态输出等功能。 关于进程内存模块的信息,存放到proc文件系统下以pid为目录名称下的maps文件中,可以通过”cat /proc/21358/maps”命令打印(21358为假设的进程号)出,如下图: maps文件中每份模块信息的组织方式为: 第1列:模块内容在内存中的地址范围,以16进制显示。 第2列:模块内容在内存中的读取权限,r代表可读,w代表可写,x代表可执行,p代表私有,s代码共享。 第3列:模块内容对应模块文件中的偏移。 第4列:模块文件在文件系统中的主次设备号。 第5列:模块文件在文件系统中的节点号。 第6列:模块文件在文件系统中的路径。 即linux内核的mm.h里面的vm_area_struct数据结构内容。Linux内核中,关于虚存管理的最基本的管理单元应该是struct vm_area_struct了,它描述的是一段连续的、具有相同访问属性的虚存空间,该虚存空间的大小为物理内存页面的整数倍。vm_area_struct的详细解析可参考这篇文章(超链接至http://blog.csdn.net/ywf861029/article/details/6114794) 三、Android内存模块遍历的实现 下面将结合代码讲解获取模块信息的实现,GetModuleBase函数可进程中某一模块基地址,GetModuleFullName可获取某一模块的全路径名,实现如下: /***************************************************************************** Function: GetModuleBase Description: 获取进程中某一模块的基址 Input: pid,是进程ID;pszModName,是要查找的模块名称 Output: ulModBase,用来输出模块的基址。 Return:如果获取模块的基址成功,返回true;否则,返回false *****************************************************************************/ bool GetModuleBase(unsigned long &ulModBase, pid_t pid, const char *pszModName) { bool bRet = false; FILE *fp = NULL; char szMapFilePath[32] = {0}; char szMapFileLine[1024] = {0}; if (pszModName == NULL) { return bRet; }
if (pid < 0) // 获取自己进程的模块信息 { sprintf(szMapFilePath, "/proc/self/maps"); } else // 获取其它进程的模块信息,此时需要root权限 { sprintf(szMapFilePath, "/proc/%d/maps", pid); }
fp = fopen(szMapFilePath, "r"); if (fp != NULL) { while (fgets(szMapFileLine, 1023, fp) != NULL) { if (strstr(szMapFileLine, pszModName)) { char *pszModAddrStart = strtok(szMapFileLine, "-"); if (pszModAddrStart) { ulModBase = strtoul(pszModAddrStart, NULL, 16);
if (ulModBase == 0x8000) ulModBase = 0; bRet = true; break; } } }
fclose(fp); }
return bRet; }
/***************************************************************************** Function: GetModuleFullName Description: 获取进程中某一模块的绝对路径 Input: pid,是进程ID;pszModName,是要查找的模块名称;nBuffSize是pszFullModName的内存大小,防止溢出。 Output: pszFullModName,用来输出模块的绝对路径。 Return:如果获取模块的绝对路径成功,返回true;否则,返回false *****************************************************************************/ bool GetModuleFullName(pid_t pid, const char *pszModName, char *pszFullModName, int nBuffSize) { bool bRet = false; FILE *fp = NULL; char szMapFilePath[32] = {0}; char szMapFileLine[1024] = {0}; char *pszFullName = NULL;
if (pszModName == NULL || pszFullModName == NULL || nBuffSize <= 0 ) { return bRet; } if (pid < 0) // 获取自己进程的模块信息 { sprintf(szMapFilePath, "/proc/self/maps"); } else // 获取其它进程的模块信息,此时需要root权限 { sprintf(szMapFilePath, "/proc/%d/maps", pid); } fp = fopen(szMapFilePath, "r"); if (fp != NULL) { while (fgets(szMapFileLine, 1023, fp) != NULL) { if (strstr(szMapFileLine, pszModName)) { if (szMapFileLine[strlen(szMapFileLine) - 1] == '\n') // 去掉末尾的换行符 { szMapFileLine[strlen(szMapFileLine) - 1] = 0; } pszFullName = strchr(szMapFileLine, '/'); if (pszFullName == NULL) { continue; } strncpy(pszFullModName, pszFullName, nBuffSize - 1); bRet = true; } } fclose(fp); } return bRet; } 三、Android内存模块遍历的运用场景 模块遍历的运用场景非常广泛,如: l 获取自己进程的内存模块信息。 l 获取目标进程的内存模块信息。 l 检查注入模块的信息。 l 检查Hook模块的信息。 总之,通过内存模块遍历拿到模块的基础信息,结合文件操作,可以对模块的情况掌握得很清楚。 |
最新评论
bRet = true;
赋值之后应该 break; 出来吧,估计是大大手滑,陋写了。
查看全部评论(1)
发表评论