linux/android进程的模块信息获取

来源:互联网 发布:java overload 编辑:程序博客网 时间:2024/06/08 14:32

本文参考自腾讯游戏安全实验室,感谢腾讯游戏安全实验室的技术分享,如有侵权,请联系我@@

linux进程空间中有较多的模块信息,模块信息一般包括:动态加载的链接库和可执行文件的信息。通过遍历模块可获取的进程信息包括:模块基地址和模块路径等。
下面我们以HelloWord 程序来讲讲解linux上进程模块信息的获取。该程序用C语言完成,调用了C语言标准库中的printf函数,源码如下:

#include <stdio.h>**重点内容**int main(int argc,char ** argv){     printf("Hello World!\n");     getchar();     return 0;}

编译输出:

user1@user-virtual-machine:~/gamesafeTest$ gcc helloworld.c -o helloworlduser1@user-virtual-machine:~/gamesafeTest$ ./helloworldHello World!|

一、Linux内存模块遍历的原理

proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。
进程内存模块的信息存放在proc文件系统下以pid为目录名称的maps文件中,通过读取cat /proc/<pid>/maps来读取内存的相关信息
另开一个shell,查看helloword程序的进程信息:

user1@user-virtual-machine:~$ ps -aux | grep helloworlduser1      5059  0.0  0.0   4196   356 pts/0    S+   00:13   0:00 ./helloworlduser1      5082  0.0  0.0  15952   940 pts/4    S+   00:14   0:00 grep --color=auto helloworlduser1@user-virtual-machine:~$ cat /proc/5059/maps00400000-00401000 r-xp 00000000 08:05 149801                             /home/user1/gamesafeTest/helloworld00600000-00601000 r--p 00000000 08:05 149801                             /home/user1/gamesafeTest/helloworld00601000-00602000 rw-p 00001000 08:05 149801                             /home/user1/gamesafeTest/helloworld7f883df80000-7f883e13b000 r-xp 00000000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so7f883e13b000-7f883e33a000 ---p 001bb000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so7f883e33a000-7f883e33e000 r--p 001ba000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so7f883e33e000-7f883e340000 rw-p 001be000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so7f883e340000-7f883e345000 rw-p 00000000 00:00 0 7f883e345000-7f883e368000 r-xp 00000000 08:02 408793                     /lib/x86_64-linux-gnu/ld-2.19.so7f883e54c000-7f883e54f000 rw-p 00000000 00:00 0 7f883e563000-7f883e567000 rw-p 00000000 00:00 0 7f883e567000-7f883e568000 r--p 00022000 08:02 408793                     /lib/x86_64-linux-gnu/ld-2.19.so7f883e568000-7f883e569000 rw-p 00023000 08:02 408793                     /lib/x86_64-linux-gnu/ld-2.19.so7f883e569000-7f883e56a000 rw-p 00000000 00:00 0 7ffe737f7000-7ffe73818000 rw-p 00000000 00:00 0                          [stack]7ffe7391e000-7ffe73920000 r-xp 00000000 00:00 0                          [vdso]ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]user1@user-virtual-machine:~$ 

map文件中每份模块的每列信息含义如下:

  • 第1列:模块内容在内存中的地址范围,以16进制显示。
  • 第2列:模块内容在内存中的读取权限,r代表可读,w代表可写,x代表可执行,p代表私有,s代表共享。
  • 第3列:模块内容在对应模块文件中的偏移。
  • 第4列:模块文件在文件系统中的主次设备号。
  • 第5列:模块文件在文件系统中的节点号。
  • 第6列: 模块文件在文件系统中的路径。

每列信息对应Linux内核中mm.h(最新版本在 mm_types.h文件中定义该结构)文件的vm_area_struct数据结构内容。关于虚拟内存最基本的管理单元为 struct vm_area_struct信息,它描述的是一段连续的具有相同访问属性的虚存空间。该虚存空间的大小为物理内存页面的整数倍

//Linux/include/linux/mm_types.h /*295  * This struct defines a memory VMM memory area. There is one of these296  * per VM-area/task.  A VM area is any part of the process virtual memory297  * space that has a special rule for the page-fault handlers (ie a shared298  * library, the executable area etc).299  */300 struct vm_area_struct {301         /* The first cache line has the info for VMA tree walking. */302 303         unsigned long vm_start;         /* Our start address within vm_mm. */304         unsigned long vm_end;           /* The first byte after our end address305                                            within vm_mm. */306 307         /* linked list of VM areas per task, sorted by address */308         struct vm_area_struct *vm_next, *vm_prev;309 310         struct rb_node vm_rb;311 312         /*313          * Largest free memory gap in bytes to the left of this VMA.314          * Either between this VMA and vma->vm_prev, or between one of the315          * VMAs below us in the VMA rbtree and its ->vm_prev. This helps316          * get_unmapped_area find a free area of the right size.317          */318         unsigned long rb_subtree_gap;319 320         /* Second cache line starts here. */321 322         struct mm_struct *vm_mm;        /* The address space we belong to. */323         pgprot_t vm_page_prot;          /* Access permissions of this VMA. */324         unsigned long vm_flags;         /* Flags, see mm.h. */325 326         /*327          * For areas with an address space and backing store,328          * linkage into the address_space->i_mmap interval tree.329          */330         struct {331                 struct rb_node rb;332                 unsigned long rb_subtree_last;333         } shared;334 335         /*336          * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma337          * list, after a COW of one of the file pages.  A MAP_SHARED vma338          * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack339          * or brk vma (with NULL file) can only be in an anon_vma list.340          */341         struct list_head anon_vma_chain; /* Serialized by mmap_sem &342                                           * page_table_lock */343         struct anon_vma *anon_vma;      /* Serialized by page_table_lock */344 345         /* Function pointers to deal with this struct. */346         const struct vm_operations_struct *vm_ops;347 348         /* Information about our backing store: */349         unsigned long vm_pgoff;         /* Offset (within vm_file) in PAGE_SIZE350                                            units */351         struct file * vm_file;          /* File we map to (can be NULL). */352         void * vm_private_data;         /* was vm_pte (shared mem) */353 354 #ifndef CONFIG_MMU355         struct vm_region *vm_region;    /* NOMMU mapping region */356 #endif357 #ifdef CONFIG_NUMA358         struct mempolicy *vm_policy;    /* NUMA policy for the VMA */359 #endif360         struct vm_userfaultfd_ctx vm_userfaultfd_ctx;361 };362 

二、Linux内存模块遍历实现

乌班图64系统下获取”libc.so“模块内存加载基址和路径名.

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>bool GetModuleBase(long 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{            sprintf(szMapFilePath,"/proc/%d/maps",pid);        }        fp = fopen(szMapFilePath,"r");        if(fp != NULL)        {              while(fgets(szMapFileLine,sizeof(szMapFileLine),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;}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        {          sprintf(szMapFilePath,"/proc/%d/maps",pid);        }        fp = fopen(szMapFilePath,"r");        if(fp!=NULL)        {           while(fgets(szMapFileLine,sizeof(szMapFileLine),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;}int main(int argc,char ** argv){     long long ulCModBase  = 0;     char szCModPath[256] = {0};     if(GetModuleBase(ulCModBase,getpid(),"libc-2.19.so"))     {        printf("c mod base:0x%llx\n", ulCModBase);     }     if (GetModuleFullName(getpid(), "libc-2.19.so", szCModPath, 256))     {        printf("c mod full path:%s\n", szCModPath);     }     printf("finish \n");     return 0;}

编译输出:

user1@user-virtual-machine:~/gamesafeTest$ g++ MapCheck.cpp -o mapcheckuser1@user-virtual-machine:~/gamesafeTest$ ./mapcheckc mod base:0x7f28c6471000c mod full path:/lib/x86_64-linux-gnu/libc-2.19.sofinish 
0 0
原创粉丝点击