Android so注入(inject)和Hook技術學習(二)——G

Jack2k發表於2021-09-09

全域性符號表(GOT表)hook實際是透過解析SO檔案,將待hook函式在got表的地址替換為自己函式的入口地址,這樣目標程式每次呼叫待hook函式時,實際上是執行了我們自己的函式。
  GOT表其實包含了匯入表和匯出表,匯出表指將當前動態庫的一些函式符號保留,供外部呼叫,匯入表中的函式實際是在該動態庫中呼叫外部的匯出函式。
  這裡有幾個關鍵點要說明一下:
  (1) so檔案的絕對路徑和載入到記憶體中的基址是可以透過 /proc/[pid]/maps 獲取到的。
  (2) 修改匯入表的函式地址的時候需要修改頁的許可權,增加寫許可權即可。
  (3) 一般的匯入表Hook是基於注入操作的,即把自己的程式碼注入到目標程式,本次例項重點講述Hook的實現,注入程式碼採用上節所有程式碼inject.c。
  匯入表的hook有兩種方法,以hook fopen函式為例。

  方法一:

  透過解析elf格式,找出靜態的.got表的位置,並在記憶體中找到相應的.got表位置,這個時候記憶體中.got表儲存著匯入函式的地址,讀取目標函式地址,與.got表每一項函式入口地址進行匹配,找到的話就直接替換新的函式地址,這樣就完成了一次匯入表的Hook操作了。
  hook流程如下圖所示:

  圖片描述

 圖1 匯入表Hook流程圖 

 

  具體程式碼實現如下:

  entry.c:

圖片描述

  1 #include   2 #include   3 #include   4 #include   5 #include   6 #include   7 #include   8 #include   9 #include  10  11 #define LOG_TAG "INJECT" 12 #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) 13  14 //FILE *fopen(const char *filename, const char *modes) 15 FILE* (*old_fopen)(const char *filename, const char *modes); 16 FILE* new_fopen(const char *filename, const char *modes){ 17     LOGD("[+] New call fopen.n"); 18     if(old_fopen == -1){ 19         LOGD("error.n"); 20     } 21     return old_fopen(filename, modes); 22 } 23  24 void* get_module_base(pid_t pid, const char* module_name){ 25     FILE* fp; 26     long addr = 0; 27     char* pch; 28     char filename[32]; 29     char line[1024]; 30      31     // 格式化字串得到 "/proc/pid/maps" 32     if(pid 

圖片描述

執行ndk-build編譯,得到libentry.so,push到/data/local/tmp目錄下,執行上節所得到的inject程式,得到如下結果,表明hook成功:

圖片描述

圖2.

 

方法二

  透過分析program header table查詢got表。匯入表對應在動態連結段.got.plt(DT_PLTGOT)指向處,但是每項的資訊是和GOT表中的表項對應的,因此,在解析動態連結段時,需要解析DT_JMPREL、DT_SYMTAB,前者指向了每一個匯入表表項的偏移地址和相關資訊,包括在GOT表中偏移,後者為GOT表。

  具體程式碼如下:

圖片描述

  1 #include   2 #include   3 #include   4 #include   5 #include   6 #include   7 #include   8 #include   9 #include  10  11 #define LOG_TAG "INJECT" 12 #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) 13  14  15 //FILE *fopen(const char *filename, const char *modes) 16 FILE* (*old_fopen)(const char *filename, const char *modes); 17 FILE* new_fopen(const char *filename, const char *modes){ 18     LOGD("[+] New call fopen.n"); 19     if(old_fopen == -1){ 20         LOGD("error.n"); 21     } 22     return old_fopen(filename, modes); 23 } 24  25 void* get_module_base(pid_t pid, const char* module_name){ 26     FILE* fp; 27     long addr = 0; 28     char* pch; 29     char filename[32]; 30     char line[1024]; 31      32     // 格式化字串得到 "/proc/pid/maps" 33     if(pid e_ident, "177ELF", 4) != 0) { 77         return 0; 78     } 79  80     Elf32_Phdr* phdr_table = (Elf32_Phdr*)(base_addr + header->e_phoff); 81     if (phdr_table == 0) 82     { 83         LOGD("[+] phdr_table address : 0"); 84         return 0; 85     } 86     size_t phdr_count = header->e_phnum; 87     LOGD("[+] phdr_count : %d", phdr_count); 88  89  90     //遍歷program header table,ptype等於PT_DYNAMIC即為dynameic,獲取到p_offset 91     unsigned long dynamicAddr = 0; 92     unsigned int dynamicSize = 0; 93     int j = 0; 94     for (j = 0; j > 8) & 0xffffff;150         Elf32_Sym* symTableIndex = (Elf32_Sym*)(number*16 + symTabOff + base_addr);151         char* funcName = (char*)(symTableIndex->st_name + strTabOff + base_addr);152         //LOGD("[+] Func Name : %s",funcName);153         if(memcmp(funcName, "fopen", 5) == 0)154         {155             // 獲取當前記憶體分頁的大小156             uint32_t page_size = getpagesize();157             // 獲取記憶體分頁的起始地址(需要記憶體對齊)158             uint32_t mem_page_start = (uint32_t)(((Elf32_Addr)rel_table[i].r_offset + base_addr)) & (~(page_size - 1));159             LOGD("[+] mem_page_start = %lx, page size = %lxn", mem_page_start, page_size);160             //void* pstart = (void*)MEM_PAGE_START(((Elf32_Addr)rel_table[i].r_offset + base_addr));161             mprotect((uint32_t)mem_page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);162             LOGD("[+] r_off : %x",rel_table[i].r_offset + base_addr);163             LOGD("[+] new_fopen : %x",new_fopen);164             *(unsigned int*)(rel_table[i].r_offset + base_addr) = new_fopen;165         }166     }167 168     return 0;169 }170 171 int hook_entry(char* a){172     LOGD("[+] Start hooking.n");173     hook_fopen();174     return 0;175 }

圖片描述

執行後的結果為:

圖片描述

 圖3

參考文章:

http://gslab.qq.com/portal.php?mod=view&aid=169

https://blog.csdn.net/u011247544/article/details/78668791

https://blog.csdn.net/qq1084283172/article/details/53942648

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/36/viewspace-2804522/,如需轉載,請註明出處,否則將追究法律責任。

相關文章