linux/android進程的模塊信息獲取

本文參考自騰訊遊戲安全實驗室,感謝騰訊遊戲安全實驗室的技術分享,如有侵權,請聯繫我@@

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 helloworld
user1@user-virtual-machine:~/gamesafeTest$ ./helloworld
Hello World!
|

一、Linux內存模塊遍歷的原理

proc文件系統是一個僞文件系統,它只存在內存當中,而不佔用外存空間。它以文件系統的方式爲訪問系統內核數據的操作提供接口。用戶和應用程序可以通過proc得到系統的信息,並可以改變內核的某些參數。
進程內存模塊的信息存放在proc文件系統下以pid爲目錄名稱的maps文件中,通過讀取cat /proc/<pid>/maps來讀取內存的相關信息
另開一個shell,查看helloword程序的進程信息:

user1@user-virtual-machine:~$ ps -aux | grep helloworld
user1      5059  0.0  0.0   4196   356 pts/0    S+   00:13   0:00 ./helloworld
user1      5082  0.0  0.0  15952   940 pts/4    S+   00:14   0:00 grep --color=auto helloworld

user1@user-virtual-machine:~$ cat /proc/5059/maps
00400000-00401000 r-xp 00000000 08:05 149801                             /home/user1/gamesafeTest/helloworld
00600000-00601000 r--p 00000000 08:05 149801                             /home/user1/gamesafeTest/helloworld
00601000-00602000 rw-p 00001000 08:05 149801                             /home/user1/gamesafeTest/helloworld
7f883df80000-7f883e13b000 r-xp 00000000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so
7f883e13b000-7f883e33a000 ---p 001bb000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so
7f883e33a000-7f883e33e000 r--p 001ba000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so
7f883e33e000-7f883e340000 rw-p 001be000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so
7f883e340000-7f883e345000 rw-p 00000000 00:00 0 
7f883e345000-7f883e368000 r-xp 00000000 08:02 408793                     /lib/x86_64-linux-gnu/ld-2.19.so
7f883e54c000-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.so
7f883e568000-7f883e569000 rw-p 00023000 08:02 408793                     /lib/x86_64-linux-gnu/ld-2.19.so
7f883e569000-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 these
296  * per VM-area/task.  A VM area is any part of the process virtual memory
297  * space that has a special rule for the page-fault handlers (ie a shared
298  * 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 address
305                                            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 the
315          * VMAs below us in the VMA rbtree and its ->vm_prev. This helps
316          * 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_vma
337          * list, after a COW of one of the file pages.  A MAP_SHARED vma
338          * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack
339          * 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_SIZE
350                                            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_MMU
355         struct vm_region *vm_region;    /* NOMMU mapping region */
356 #endif
357 #ifdef CONFIG_NUMA
358         struct mempolicy *vm_policy;    /* NUMA policy for the VMA */
359 #endif
360         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 mapcheck
user1@user-virtual-machine:~/gamesafeTest$ ./mapcheck
c mod base:0x7f28c6471000
c mod full path:/lib/x86_64-linux-gnu/libc-2.19.so
finish 
發佈了45 篇原創文章 · 獲贊 31 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章