美文网首页
针对加“壳”so的Gothook

针对加“壳”so的Gothook

作者: 处于蒙比阶段的小白 | 来源:发表于2018-04-02 09:53 被阅读0次

    起因

    在测试某加固过程中,由于so进行了加壳(upx变种),导致常规的gothook,无法hook got表函数。
    常规的gothook 方法如下

    /**
     * \brief 注意使用gothook so必须在maps中能找到内存地址
     * \param path 
     */
    GotHook::GotHook(const char * path)
    {
        //获取so内存加载地址
        pBase = get_module_base(path);
        LOGI("%s base:%p", path, pBase);
        get_elf_info((Elf32_Addr)pBase, &einfo);
    }
    
    void GotHook::hookGotFun(const char * name,void* fun_ptr)
    {
        long tmpaddr = find_sym_in_rel(&einfo, name);
        int pagesize = getpagesize();
        long startAddress = tmpaddr & ~(pagesize - 1);
        if (mprotect((void*)startAddress, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
        {
            LOGE("mprotect failed");
        }
        *(int *)tmpaddr = (int)fun_ptr;
    }
    
    void* GotHook::get_module_base(const char* module_name)
    {
        FILE *fp;
        long addr = 0;
        char *pch;
        char filename[32];
        char line[1024];
        int pid = getpid();
        if (pid < 0)
        {
            /* self process */
            snprintf(filename, sizeof(filename), "/proc/self/maps");
        }
        else
        {
            snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
        }
        //打开maps文件
        fp = fopen(filename, "r");
        //获取其内存地址
        if (fp != NULL)
        {
            while (fgets(line, sizeof(line), fp))
            {
                if (strstr(line, module_name))
                {
                    pch = strtok(line, "-");
                    addr = strtoul(pch, NULL, 16);
    
                    //if ( addr == 0x8000 )  
                    //  addr = 0;  
    
                    break;
                }
            }
    
            fclose(fp);
        }
    
        return (void *)addr;
    }
    
    unsigned long GotHook::find_sym_in_rel(elf_info* einfo, const char* sym_name)
    {
        Elf32_Rel rel;
        Elf32_Sym sym;
        unsigned int i;
        char *str = NULL;
        unsigned long ret;
        struct dyn_info dinfo;
        LOGI("find sym in rel %p %s \n", (void*)einfo->base, sym_name);
    
        get_dyn_info(einfo, &dinfo);
        for (i = 0; i < dinfo.nrels; i++) {
            memcpy(&rel, (void*)((unsigned long)(dinfo.jmprel + i * sizeof(Elf32_Rel))), sizeof(Elf32_Rel));
            if (DEBUG)
            {
                LOGI("rel addr %p\n", &rel);
            }
            if (ELF32_R_SYM(rel.r_info)) {
                memcpy(&sym, (void*)(dinfo.symtab + ELF32_R_SYM(rel.r_info) * sizeof(Elf32_Sym)), sizeof(Elf32_Sym));
                str = (char*)(dinfo.strtab + sym.st_name);
                if (DEBUG)
                {
                    LOGI("   str-> %s\n", str);
                }
                if (strcmp(str, sym_name) == 0) {
                    break;
                }
                // free(str);  
            }
        }
    
        if (i == dinfo.nrels)
            ret = 0;
        else {
            ret = (unsigned long)((IS_DYN(einfo) ? (char*)einfo->base : 0) + rel.r_offset);
        }
        return ret;
    }
    
    void GotHook::get_elf_info(Elf32_Addr base, elf_info * einfo)
    {
    
        int i = 0;
        //获取pid
        einfo->pid = getpid();
        //内存地址
        einfo->base = (void*)base;
        memcpy(&einfo->ehdr, einfo->base, sizeof(Elf32_Ehdr));
        einfo->phdr_addr = (Elf32_Addr)((char*)einfo->base + einfo->ehdr.e_phoff);
    
        memcpy(&einfo->phdr, (void*)einfo->phdr_addr, sizeof(Elf32_Phdr));
        if (DEBUG)
        {
            LOGI("dump %s %d phdr\n", einfo->ehdr, einfo->ehdr.e_phnum);
        }
        for (i = 0; i < einfo->ehdr.e_phnum; i++) {
            Elf32_Phdr phdr;
            memcpy(&phdr, (void*)(einfo->phdr_addr + i * sizeof(Elf32_Phdr)), sizeof(Elf32_Phdr));
        }
        while (einfo->phdr.p_type != PT_DYNAMIC) {
            memcpy(&einfo->phdr, (void*)(einfo->phdr_addr += sizeof(Elf32_Phdr)), sizeof(Elf32_Phdr));
        }
        einfo->dynaddr = (Elf32_Word)(IS_DYN(einfo) ? einfo->base : 0) + einfo->phdr.p_vaddr;
        memcpy(&einfo->dyn, (void*)(einfo->dynaddr), sizeof(Elf32_Dyn));
        while (einfo->dyn.d_tag != DT_PLTGOT) {
            memcpy(&einfo->dyn, (void*)(einfo->dynaddr + i * sizeof(Elf32_Dyn)), sizeof(Elf32_Dyn));
            i++;
        }
        einfo->got =(Elf32_Word)((IS_DYN(einfo) ? (char*)einfo->base : 0) + (Elf32_Word)einfo->dyn.d_un.d_ptr);
        memcpy(&einfo->map_addr, (void*)(einfo->got + 4), 4);
     
    }
    
    void GotHook::get_dyn_info(elf_info* einfo, dyn_info* dinfo)
    {
        Elf32_Dyn dyn;
        int i = 0;
        if (DEBUG)
        {
            LOGI("get_dyn_info 0x%08x...\n", einfo->dynaddr);
        }
        memcpy(&dyn, (void*)(einfo->dynaddr + i * sizeof(Elf32_Dyn)), sizeof(Elf32_Dyn));
        i++;
        while (dyn.d_tag) {
            switch (dyn.d_tag) {
            case DT_SYMTAB:
                LOGI("DT_SYMTAB");
                dinfo->symtab = (Elf32_Addr)(IS_DYN(einfo) ? einfo->base : 0) + dyn.d_un.d_ptr;
                break;
            case DT_STRTAB:
                dinfo->strtab = (Elf32_Addr)(IS_DYN(einfo) ? einfo->base : 0) + dyn.d_un.d_ptr;
                LOGI("DT_STRTAB");
                break;
            case DT_JMPREL:
                dinfo->jmprel = (Elf32_Addr)(IS_DYN(einfo) ? einfo->base : 0) + dyn.d_un.d_ptr;
                LOGI("DT_JMPREL");
                LOGI("jmprel\t %08x\n", dinfo->jmprel);
                break;
            case DT_PLTRELSZ:
                LOGI("DT_PLTRELSZ");
                dinfo->totalrelsize = dyn.d_un.d_val;
                LOGI("totalrelsize %d\n", dinfo->totalrelsize);
                break;
            case DT_RELAENT:
                LOGI("DT_RELAENT");
                dinfo->relsize = dyn.d_un.d_val;
                LOGI("relsize %d\n", dinfo->relsize);
                break;
            case DT_RELENT:
                LOGI("DT_RELENT");
                dinfo->relsize = dyn.d_un.d_val;
                LOGI("relsize2 %d\n", dinfo->relsize);
                break;
            }
            memcpy(&dyn, (void*)(einfo->dynaddr + i * sizeof(Elf32_Dyn)), sizeof(Elf32_Dyn));
            i++;
        }
        if (dinfo->relsize == 0) {
            dinfo->relsize = 8;
        }
        dinfo->nrels = dinfo->totalrelsize / dinfo->relsize;
    
    }
    

    在maps中查找son内存地址,然后进行hook,这种方法对加了“壳”,不起作用,具体原因不太了解。

    修改

    查看dlopen 函数,根据dlopen返回值,发现其返回值是一个叫“soinfo”的结构体指针。
    结构体经过简单精简如下

    struct soinfo
        {
        public:
            char name[128];
            const Elf32_Phdr* phdr; //Elf32_Phdr 实际内存地址
            size_t phnum;
            Elf32_Addr entry;
            Elf32_Addr base; //SO起始
            unsigned size; //内存对齐后占用大小
    
            uint32_t unused1; // DO NOT USE, maintained for compatibility.
    
            Elf32_Dyn* dynamic;; //.dynamic实际内存地址 That's the point.
        };
    

    其中比较重要的是“dynamic”,我对elf 加载过程不太熟悉,具体的可以参考下面的文章
    ELF Linker学习篇(三)关于链接过程
    通过.dynamic段可以拿到重定位好的函数
    如下:

    bool GotHook::hookAPI19(const char* name, void* funptr)
    {
        struct soinfo
        {
        public:
            char name[128];
            const Elf32_Phdr* phdr; //Elf32_Phdr 实际内存地址
            size_t phnum;
            Elf32_Addr entry;
            Elf32_Addr base; //SO起始
            unsigned size; //内存对齐后占用大小
    
            uint32_t unused1; // DO NOT USE, maintained for compatibility.
    
            Elf32_Dyn* dynamic;; //.dynamic实际内存地址 That's the point.
        };
        //start hook 
        struct dyn_info dinfo;
        soinfo* si = (soinfo*)handle;
        for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d)
        {
            switch (d->d_tag)
            {
            case DT_SYMTAB:
                LOGI("DT_SYMTAB");
                dinfo.symtab = (Elf32_Addr)(si->base + d->d_un.d_ptr);
                break;
            case DT_STRTAB:
                dinfo.strtab = (Elf32_Addr)(si->base + d->d_un.d_ptr);
                LOGI("DT_STRTAB");
                break;
            case DT_JMPREL:
                dinfo.jmprel = (Elf32_Addr)(si->base + d->d_un.d_ptr);
                LOGI("DT_JMPREL");
                LOGI("jmprel\t %08x\n", dinfo.jmprel);
                break;
            case DT_PLTRELSZ:
                LOGI("DT_PLTRELSZ");
                dinfo.totalrelsize = d->d_un.d_val;
                LOGI("totalrelsize %d\n", dinfo.totalrelsize);
                break;
            case DT_RELAENT:
                LOGI("DT_RELAENT");
                dinfo.relsize = d->d_un.d_val;
                LOGI("relsize %d\n", dinfo.relsize);
                break;
            case DT_RELENT:
                LOGI("DT_RELENT");
                dinfo.relsize = d->d_un.d_val;
                LOGI("relsize2 %d\n", dinfo.relsize);
                break;
            }
        }
        if (dinfo.relsize == 0)
        {
            dinfo.relsize = 8;
        }
        dinfo.nrels = dinfo.totalrelsize / dinfo.relsize;
        Elf32_Rel rel;
        Elf32_Sym sym;
        int i;
        for (i = 0; i < dinfo.nrels; i++)
        {
            memcpy(&rel, (void*)((unsigned long)(dinfo.jmprel + i * sizeof(Elf32_Rel))), sizeof(Elf32_Rel));
    
            //LOGE("rel addr %p\n", &rel);
    
            if (ELF32_R_SYM(rel.r_info))
            {
                memcpy(&sym, (void*)(dinfo.symtab + ELF32_R_SYM(rel.r_info) * sizeof(Elf32_Sym)), sizeof(Elf32_Sym));
                char* str = (char*)(dinfo.strtab + sym.st_name);
                //LOGE("   str-> %s\n", str);
                // free(str);  
                if (strcmp(str, name) == 0)
                {
                    LOGE("[+] found address success");
                    break;
                }
            }
        }
        unsigned long ret;
        if (i == dinfo.nrels)
            ret = 0;
        else
        {
            ret = (unsigned long)((si->base) + rel.r_offset);
        }
        if (ret == 0)
        {
            LOGE("[-] get offset fail");
            return false;
        }
        int pagesize = getpagesize();
        long startAddress = ret & ~(pagesize - 1);
        //modify memory address to be writable
        if (mprotect((void*)startAddress, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
        {
            LOGE("mprotect failed");
            return false;
        }
        *(int *)ret = (int)funptr;
        LOGE("[+] hook success");
        return true;
    }
    

    做的比较着急,也没具体了解原理,中间可能有不少错误。经过发现是没问题的。其他的慢慢补充

    相关文章

      网友评论

          本文标题:针对加“壳”so的Gothook

          本文链接:https://www.haomeiwen.com/subject/vtdthftx.html