国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

android中如何實(shí)現got表HOOK

發(fā)布時(shí)間:2021-09-04 11:55 來(lái)源:億速云 閱讀:0 作者:小新 欄目: 開(kāi)發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)android中如何實(shí)現got表HOOK的內容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

概述

對于android的so文件的hook根據ELF文件特性分為:Got表hook、Sym表hook和inline hook等。
全局符號表(GOT表)hook,它是通過(guò)解析SO文件,將待hook函數在got表的地址替換為自己函數的入口地址,這樣目標進(jìn)程每次調用待hook函數時(shí),實(shí)際上是執行了我們自己的函數。

Androd so注入和函數Hook(基于got表)的步驟:

1.ptrace附加目標pid進(jìn)程;
2.在目標pid進(jìn)程中,查找內存空間(用于存放被注入的so文件的路徑和so中被調用的函數的名稱(chēng)或者shellcode);
3.調用目標pid進(jìn)程中的dlopen、dlsym等函數,用于加載so文件實(shí)現Android so的注入和函數的Hook;
4.釋放附加的目標pid進(jìn)程和卸載注入的so文件。

具體代碼實(shí)現

以下以fopen函數進(jìn)行g(shù)ot hook為例。

//獲取模塊地址功能實(shí)現
void* getModuleBase(pid_t pid, const char* module_name){
    FILE* fp;
    long address = 0;
    char* pch;
    char filename[32];
    char line[1024];

    // 格式化字符串得到 "/proc/pid/maps"
    if(pid < 0){
        snprintf(filename, sizeof(filename), "/proc/self/maps");
    }else{
        snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
    }

    // 打開(kāi)文件/proc/pid/maps,獲取指定pid進(jìn)程加載的內存模塊信息
    fp = fopen(filename, "r");
    if(fp != NULL){
        // 每次一行,讀取文件 /proc/pid/maps中內容
        while(fgets(line, sizeof(line), fp)){
            // 查找指定的so模塊
            if(strstr(line, module_name)){
                // 分割字符串
                pch = strtok(line, "-");
                // 字符串轉長(cháng)整形
                address = strtoul(pch, NULL, 16);
               
                }
                break;
            }
        }
    }
    fclose(fp);
    return (void*)address;
}
//hook fopen進(jìn)行實(shí)現
//(libxxxx.so文件是ELF32文件)
#define LIBPATH "/data/app-lib/com.xxxx/libxxxx.so"

int hookFopen(){

    // 獲取目標pid中"/data/app-lib/com.xxxx/libxxxx.so"模塊的加載地址
    void* base_addr = getModuleBase(getpid(), LIBPATH );
    // 保存Hook目標函數的原始調用地址
    old_fopen = fopen;
    int fd;
    // 用open打開(kāi)內存模塊文件"/data/app-lib/com.xxxx/libxxxx.so"
    fd = open(LIB_PATH, O_RDONLY);
    if(-1 == fd){
        return -1;
    }

     // elf32文件的文件頭結構體Elf32_Ehdr
    Elf32_Ehdr ehdr;
    // 讀取elf32格式的文件"/data/app-lib/com.xxxx/libxxxx.so"的文件頭信息
    read(fd, &ehdr, sizeof(Elf32_Ehdr));

    // elf32文件中節區表信息結構的文件偏移
    unsigned long shdr_addr = ehdr.e_shoff;
    // elf32文件中節區表信息結構的數量
    int shnum = ehdr.e_shnum;
    // elf32文件中每個(gè)節區表信息結構中的單個(gè)信息結構的大?。枋雒總€(gè)節區的信息的結構體的大?。?
    int shent_size = ehdr.e_shentsize;

    // elf32文件節區表中每個(gè)節區的名稱(chēng)存放的節區名稱(chēng)字符串表,在節區表中的序號index
    unsigned long stridx = ehdr.e_shstrndx;

    Elf32_Shdr shdr;
    lseek(fd, shdr_addr + stridx * shent_size, SEEK_SET);
    // 讀取elf32文件中的描述每個(gè)節區的信息的結構體(這里是保存elf32文件的每個(gè)節區的名稱(chēng)字符串的)
    read(fd, &shdr, shent_size);

    // 為保存elf32文件的所有的節區的名稱(chēng)字符串申請內存空間
    char * string_table = (char *)malloc(shdr.sh_size);
    // 定位到具體存放elf32文件的所有的節區的名稱(chēng)字符串的文件偏移處
    lseek(fd, shdr.sh_offset, SEEK_SET);
    read(fd, string_table, shdr.sh_size);
    lseek(fd, shdr_addr, SEEK_SET);

    int i;
    uint32_t out_addr = 0;
    uint32_t out_size = 0;
    uint32_t got_item = 0;
    int32_t got_found = 0;

    // 循環(huán)遍歷elf32文件的節區表(描述每個(gè)節區的信息的結構體)
    for(i = 0; i<shnum; i++){
        // 依次讀取節區表中每個(gè)描述節區的信息的結構體
        read(fd, &shdr, shent_size);
        // 判斷當前節區描述結構體描述的節區是否是SHT_PROGBITS類(lèi)型
        //類(lèi)型為SHT_PROGBITS的.got節區包含全局偏移表
        if(shdr.sh_type == SHT_PROGBITS){
            // 獲取節區的名稱(chēng)字符串在保存所有節區的名稱(chēng)字符串段.shstrtab中的序號
            int name_idx = shdr.sh_name;

            // 判斷節區的名稱(chēng)是否為".got.plt"或者".got"
            if(strcmp(&(string_table[name_idx]), ".got.plt") == 0
                || strcmp(&(string_table[name_idx]), ".got") == 0){
                // 獲取節區".got"或者".got.plt"在內存中實(shí)際數據存放地址
                out_addr = base_addr + shdr.sh_addr;
                // 獲取節區".got"或者".got.plt"的大小
                out_size = shdr.sh_size;

                int j = 0;
                // 遍歷節區".got"或者".got.plt"獲取保存的全局的函數調用地址
                for(j = 0; j<out_size; j += 4){
                    // 獲取節區".got"或者".got.plt"中的單個(gè)函數的調用地址
                    got_item = *(uint32_t*)(out_addr + j);
                    // 判斷節區".got"或者".got.plt"中函數調用地址是否是將要被Hook的目標函數地址
                    if(got_item == old_fopen){
                        got_found = 1;
                        // 獲取當前內存分頁(yè)的大小
                        uint32_t page_size = getpagesize();
                        // 獲取內存分頁(yè)的起始地址(需要內存對齊)
                        uint32_t entry_page_start = (out_addr + j) & (~(page_size - 1));
                 
                        // 修改內存屬性為可讀可寫(xiě)可執行
                        if(mprotect((uint32_t*)entry_page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) == -1){
                          
                            return -1;
                        }
                 
                        // Hook的函數,是我們自己定義的函數
                        got_item = new_fopen;
                    
                        // 進(jìn)行恢復內存屬性為可讀可執行
                        if(mprotect((uint32_t*)entry_page_start, page_size, PROT_READ | PROT_EXEC) == -1){
                         
                            return -1;
                        }
                        break;
                    // 目標函數的調用地址已經(jīng)被Hook了
                    }else if(got_item == new_fopen){
                        break;
                    }
                }
                // 對目標函數HOOk成功,跳出循環(huán)
                if(got_found)
                    break;
            }
        }
    }
    free(string_table);
    close(fd);
}

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

欧美日韩国产精品自在自线| 无码人妻黑人中文字幕| 天天摸天天透天天添| 久久精品国产亚洲av麻豆小说| 欧洲性开放大片| 一本久道视频无线视频|