游戏安全实验室 首页 技术入门 查看内容

 阅读目录

Android平台进程模块信息获取

发布于:2016-4-29 15:06   |    181187次阅读 作者: 管理员    |   原作者: 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内存模块遍历的运用场景

模块遍历的运用场景非常广泛,如:

获取自己进程的内存模块信息。

获取目标进程的内存模块信息。

检查注入模块的信息。

检查Hook模块的信息。

总之,通过内存模块遍历拿到模块的基础信息,结合文件操作,可以对模块的情况掌握得很清楚。


 *转载请注明来自游戏安全实验室(GSLAB.QQ.COM)

分享到:
踩0 赞1

收藏

上一篇:IOS越狱环境注入实现

下一篇:IOS系统下进程模块的遍历

最新评论
引用 DeathMemory 2017-2-15 17:10
strncpy(pszFullModName, pszFullName, nBuffSize - 1);

bRet = true;

赋值之后应该 break; 出来吧,估计是大大手滑,陋写了。

查看全部评论(1)

B Color Image Link Quote Code Smilies

发表评论