码迷,mamicode.com
首页 > 移动开发 > 详细

Android中的so挂钩(hook)之替换Got表

时间:2016-01-12 15:31:38      阅读:435      评论:0      收藏:0      [点我收藏+]

标签:

参考文章: http://blog.csdn.net/jinzhuojun/article/details/9900105

 

逻辑大概如下:

使用之前的注入代码注入自己的so并执行so中函数 -> so中函数解析ELF文件获取GOT表的位置和大小 -> 获取需要挂钩的原函数地址,以及自定义用于挂钩的函数地址 -> 遍历GOT表的每一项判断是否有与需要挂钩的原函数地址相同的项 -> 找到后把该项的地址替换为自定义用于挂钩的函数地址 -> 最后在自定义用于挂钩的函数中调用原函数

 

这种挂钩存在很多弊端: 如果只能挂钩函数的头部,无法达到对整个进程都有效等。

实现效果如下:

技术分享

代码写的很戳,只是为了了解实现原理,实际操作中还是要用一些比较成熟的HOOK库。

//Demo

#include <stdio.h>

int count = 0;
 
void sevenWeapons(int number)
{
    char* str = "Hello,LiBieGou!";
    printf("%s %d\n",str,number);
}

int main(int argc, char* argv[])
{
    while(1)
    {
        sevenWeapons(count);
        count++;
        sleep(1);
    }

    return 0;
}

 

//Inject代码

#include <jni.h>
#include <stdio.h>
#include <dlfcn.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <android/log.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/mman.h>

#define LOG_TAG "INJECT"
#define LOGD(fmt, args...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
#define DEBUG_PRINT(format, args...) LOGD(format, ##args)

#define LIBC_PATH   "/system/lib/libc.so"
#define LINKER_PATH "/system/bin/linker"

#define CPSR_T_MASK     ( 1u << 5 )

/*--------------------------------------------------
*   功能:   通过进程的名称获取对应的进程Pid
*
*   返回值: 未找到返回-1
*--------------------------------------------------*/
int FindProIdByProName(const char *lpszProName)
{
    DIR* lpDirp = NULL;
    struct dirent* lpDirentp = NULL;
    int nPid = 0;
    FILE *fp = NULL;
    char szLines[1024] = {0};
    char szCmdlinePath[256] = {0};
    int nFind = 0;

    lpDirp = opendir("/proc");
    if(lpDirp == NULL)
    {
        DEBUG_PRINT("[-]FindProIdByProName::opendir error\r\n");
        return -1;
    }

    while ((lpDirentp = readdir(lpDirp)) != NULL)
    {
        nPid = atoi(lpDirentp->d_name);
        memset(szCmdlinePath, sizeof(szCmdlinePath), 0);
        snprintf(szCmdlinePath, sizeof(szCmdlinePath), "/proc/%d/cmdline", nPid);
        fp = fopen(szCmdlinePath, "r");
        if (fp != NULL)
        {
            fgets(szLines, sizeof(szLines), fp);
            if (strcmp(szLines, lpszProName) == 0)
            {
                nFind = 1;
                DEBUG_PRINT("[+]Find ProId = %d\r\n", nPid);
                fclose(fp);
                fp = NULL;
                break;
            }

            fclose(fp);
            fp = NULL;
        }
    }

    if (nFind == 0)
    {
        DEBUG_PRINT("[-]No Find ProId\r\n");
        return -1;
    }

    return nPid;
}

/*--------------------------------------------------
*   功能:   附加进程
*
*   返回值: 失败返回-1
*--------------------------------------------------*/
int PtraceAttach(int nPid)
{
    //被跟踪进程将成为当前进程的子进程,并进入中止状态。
    if (ptrace(PTRACE_ATTACH, nPid, NULL, NULL) == -1)
    {
        return -1;
    }

    int nStatus = 0;

    //如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。
    //父进程退出时, 不影响子进程
    waitpid(nPid, &nStatus , WUNTRACED);

    return 0;
}

/*--------------------------------------------------
*   功能:   获取指定进程的寄存器信息
*
*   返回值: 失败返回-1
*--------------------------------------------------*/
int PtraceGetRegs(int nPid, struct pt_regs *lpRegs)
{
    if (ptrace(PTRACE_GETREGS, nPid, NULL, lpRegs) == -1)
    {
        return -1;
    }

    return 0;
}

/*--------------------------------------------------
*   功能:   取消附加
*
*   返回值: 失败返回-1
*--------------------------------------------------*/
int PtraceDetach(int nPid)
{
    if (ptrace(PTRACE_DETACH, nPid, NULL, NULL) == -1)
    {
        return -1;
    }

    return 0;
}

/*--------------------------------------------------
*   功能:   获取进程中指定模块的首地址
*
*   参数:
*           nPid            需要注入的进程Pid, 如果为0则获取自身进程
*           lpLibraryPath   需要获取模块路径
*
*   返回值: 失败返回NULL, 成功返回Addr
*--------------------------------------------------*/
void* GetModuleBase(int nPid, const char *lpLibraryPath)
{
    char szPath[256] = {0};
    char szLines[1024] = {0};
    char *lpCh = NULL;
    void *lpBaseAddr = NULL;

    if (nPid == 0)
    {
        snprintf(szPath, sizeof(szPath), "/proc/self/maps");
    }
    else
    {
        snprintf(szPath, sizeof(szPath), "/proc/%d/maps", nPid);
    }

    FILE *fp = fopen(szPath, "r");
    if (fp != NULL)
    {
        while (fgets(szLines, sizeof(szLines), fp))
        {
            if (strstr(szLines, lpLibraryPath))
            {
                lpCh = strtok(szLines, "-");
                lpBaseAddr = strtoul(lpCh, NULL, 16);
                fclose(fp);
                break;
            }
        }

        fclose(fp);
        fp = NULL;
    }

    return lpBaseAddr;
}

/*--------------------------------------------------
*   功能:   获取目标进程中函数指针
*
*   参数:
*           nPid            需要注入的进程Pid
*           lpLibraryPath   需要获取的函数所在的lib库路径
*           lpFunctionAddr  需要获取的函数所在当前进程内存中的地址
*
*           目标进程中函数指针 = 目标进程模块基址 - 自身进程模块基址 + 内存中的地址
*
*   返回值: 失败返回NULL, 成功返回Addr
*--------------------------------------------------*/
void* GetRemoteFunctionAddr(int nPid, const char *lpLibraryPath, void *lpFunctionAddr)
{
    //获取目标进程模块基址
    void *lpRemoteBaseAddr = GetModuleBase(nPid, lpLibraryPath);
    void *lpLocalBaseAddr = GetModuleBase(0, lpLibraryPath);
    void *lpRemoteFunctionAddr = NULL;

    if ((lpRemoteBaseAddr == NULL) || (lpLocalBaseAddr == NULL))
    {
        return lpRemoteFunctionAddr;
    }

    DEBUG_PRINT("[+] GetRemoteFunctionAddr: local[%p], remote[%p]\n", lpLocalBaseAddr, lpRemoteBaseAddr);

    lpRemoteFunctionAddr = (void *)((uint32_t)lpRemoteBaseAddr - (uint32_t)lpLocalBaseAddr + (uint32_t)lpFunctionAddr);

    return lpRemoteFunctionAddr;
}

/*--------------------------------------------------
*   功能:   向目标进程指定的地址中写入数据
*
*   参数:
*           nPid        需要注入的进程Pid
*           lpAddr      需要写入的目标进程地址
*           lpData      需要写入的数据缓冲区
*           nLength     需要写入的数据长度
*
*   返回值: -1
*--------------------------------------------------*/
int PtraceWriteProcessMemory(int nPid, void *lpAddr, const uint8_t *lpData, uint32_t nLength)
{
    uint32_t i, j, remain;
    uint8_t *lpDataBuff = NULL;

    union u {
        long val;
        char chars[sizeof(long)];
    } d;

    j = nLength / 4;
    remain = nLength % 4;

    lpDataBuff = lpData;

    //先4字节拷贝
    for (i = 0; i < j; i++)
    {
        memcpy(d.chars, lpDataBuff, 4);
        ptrace(PTRACE_POKETEXT, nPid, lpAddr, d.val);

        lpAddr  += 4;
        lpDataBuff += 4;
    }

    //最后不足4字节的,单字节拷贝
    if (remain > 0)
    {
        d.val = ptrace(PTRACE_PEEKTEXT, nPid, lpAddr, 0);
        for (i = 0; i < remain; i ++) {
            d.chars[i] = *lpDataBuff ++;
        }

        ptrace(PTRACE_POKETEXT, nPid, lpAddr, d.val);
    }

    return 0;
}

/*--------------------------------------------------
*   功能:   修改目标进程寄存器的值
*
*   参数:
*           nPid        需要注入的进程Pid
*           lpRegs      需要修改的新寄存器信息
*
*   返回值: -1
*--------------------------------------------------*/
int PtraceSetRegs(int nPid, struct pt_regs *lpRegs)
{
    if (ptrace(PTRACE_SETREGS, nPid, NULL, lpRegs) == -1)
    {
        return -1;
    }

    return 0;
}

/*--------------------------------------------------
*   功能:   恢复程序运行
*
*   参数:
*           nPid        需要注入的进程Pid
*
*   返回值: -1
*--------------------------------------------------*/
int PtraceContinue(int nPid)
{
    if (ptrace(PTRACE_CONT, nPid, NULL, NULL) == -1)
    {
        return -1;
    }

    return 0;
}

/*--------------------------------------------------
*   功能:   调用远程函数指针
*
*   参数:
*           nPid            需要注入的进程Pid
*           pfnFunctionAddr 调用的函数指针地址
*           lpParamArg      调用的参数
*           nParamCount     调用的参数个数
*           lpRegs          远程进程寄存器信息(ARM前4个参数由r0 ~ r3传递)
*
*   返回值: 失败返回-1
*--------------------------------------------------*/
int PtraceCallRemoteFunction(int nPid, void *pfnFunctionAddr, long *lpParamArg, int nParamCount, struct pt_regs *lpRegs)
{
    uint32_t i = 0;
    int nStatus = 0;

    //首先将前4个参数赋值给r0~r3
    for (; (i < nParamCount) && (i < 4); i++)
    {
        lpRegs->uregs[i] = lpParamArg[i];
    }

    //如果有超过4个的参数, 则将剩余参数拷贝到目标栈上
    if (i < nParamCount)
    {
        //抬高栈顶sub esp, xxx
        lpRegs->ARM_sp -= (nParamCount - i) * sizeof(long);
        if (PtraceWriteProcessMemory(nPid, (void *)lpRegs->ARM_sp, (const uint8_t *)&lpParamArg[i], (uint32_t)((nParamCount - i) * sizeof(long))) == -1)
        {
            DEBUG_PRINT("[-]PtraceCallRemoteFunction::PtraceWriteProcessMemory Error\r\n");
            return -1;
        }
    }

    //将PC的值设置为函数地址
    lpRegs->ARM_pc = pfnFunctionAddr;

    //设置ARM_cpsr寄存器的值
    if (lpRegs->ARM_pc & 1)
    {
        /* thumb */
        lpRegs->ARM_pc &= (~1u);
        lpRegs->ARM_cpsr |= CPSR_T_MASK;
    }
    else
    {
        /* arm */
        lpRegs->ARM_cpsr &= ~CPSR_T_MASK;
    }

    //设置返回地址为0的原因见下面注释
    lpRegs->ARM_lr = 0;

    //修改目标进程寄存器的值
    if (PtraceSetRegs(nPid, lpRegs) == -1)
    {
        DEBUG_PRINT("[-]PtraceCallRemoteFunction::PtraceSetRegs Error\r\n");
        return -1;
    }

    /*
        WUNTRACED告诉waitpid,如果子进程进入暂停状态,那么就立即返回。
        如果是被ptrace的子进程,那么即使不提供WUNTRACED参数,也会在子进程进入暂停状态的时候立即返回。
        对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:
        ①下一次系统调用;
        ②子进程退出;
        ③子进程的执行发生错误。
        这里的0xb7f就表示子进程进入了暂停状态,且发送的错误信号为11(SIGSEGV),它表示试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据。
        那么什么时候会发生这种错误呢?
        显然,当子进程执行完注入的函数后,由于我们在前面设置了regs->ARM_lr = 0,它就会返回到0地址处继续执行,这样就会产生SIGSEGV了!
    */
    do
    {
        //恢复程序运行, 由于之前Attach被挂起了
        if (PtraceContinue(nPid) == -1)
        {
            DEBUG_PRINT("[-]PtraceCallRemoteFunction::PtraceContinue Error\r\n");
            return -1;
        }

        waitpid(nPid, &nStatus, WUNTRACED);

    } while(nStatus != 0xb7f);

    return 0;
}

/*--------------------------------------------------
*   功能:   调用远程函数指针
*
*   参数:
*           nPid            需要注入的进程Pid
*           lpFunctionName  调用的函数名称, 此参数仅作Debug输出用
*           pfnFunctionAddr 调用的函数指针地址
*           lpParamArg      调用的参数
*           nParamCount     调用的参数个数
*           lpRegs          远程进程寄存器信息(ARM前4个参数由r0 ~ r3传递)
*
*   返回值: 失败返回-1
*--------------------------------------------------*/
int CallRemoteFunction(int nPid, const char *lpFunctionName, void *pfnFunctionAddr, long *lpParamArg, int nParamCount, struct pt_regs *lpRegs)
{
    DEBUG_PRINT("[+] Calling %s in target process.\n", lpFunctionName);

    //call
    if (PtraceCallRemoteFunction(nPid, pfnFunctionAddr, lpParamArg, nParamCount, lpRegs) == -1)
    {
        return -1;
    }

    //获取返回值
    if (PtraceGetRegs(nPid, lpRegs) == -1)
    {
        DEBUG_PRINT("[-]CallRemoteFunction::PtraceGetRegs Error\r\n");
        return -1;
    }

    DEBUG_PRINT("[+] Target process returned from %s, return value=%p, pc=%p\r\n",
                lpFunctionName, lpRegs->ARM_r0, lpRegs->ARM_pc);
    return 0;
}

/*--------------------------------------------------
*   功能:   远程注入
*
*   参数:
*           nPid            需要注入的进程Pid
*           lpLibraryPath   需要注入的.so路径
*           lpFunctionName  .so中导出的函数名
*           lpFunctionParam 函数的参数
*
*   返回值: 注入失败返回-1
*--------------------------------------------------*/
int InjectRemoteProcess(int nPid, const char *lpLibraryPath, const char *lpFunctionName, const char *lpFunctionParam)
{
    int nRet = 0;
    void *pfnmmap = NULL;
    void *pfndlopen = NULL;
    void *pfndlsym = NULL;
    void *pfndlclose = NULL;
    void *lpMmapBase = NULL;
    struct pt_regs Regs = {0};
    struct pt_regs OldRegs = {0};
    long ParamArg[10] = {0};
    void *hSo = NULL;
    void *pfnRemoteFunction = NULL;
    void *pfnsleep = NULL;

    DEBUG_PRINT("[+] Injecting process: %d\n", nPid);

    //附加目标进程
    if (PtraceAttach(nPid) == -1)
    {
        DEBUG_PRINT("[-]PtraceAttach Error\r\n");
        return -1;
    }

    //获取保存寄存器信息, 恢复时用
    if (PtraceGetRegs(nPid, &Regs) == -1)
    {
        DEBUG_PRINT("[-]PtraceGetRegs Error\r\n");
        nRet = -1;
        goto SAFE_END;
    }

    //保存
    memcpy(&OldRegs, &Regs, sizeof(Regs));

    pfnmmap = GetRemoteFunctionAddr(nPid, LIBC_PATH, (void *)mmap);
    if (pfnmmap == NULL)
    {
        DEBUG_PRINT("[-]pfnmmap == NULL\r\n");
        nRet = -1;
        goto SAFE_END;
    }

    DEBUG_PRINT("[+] pfnmmap Addr: %p\r\n", pfnmmap);

    //申请远程空间
    //构造参数void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
    ParamArg[0] = 0;
    ParamArg[1] = 0x4000;
    ParamArg[2] = PROT_READ | PROT_WRITE | PROT_EXEC;
    ParamArg[3] = MAP_ANONYMOUS | MAP_PRIVATE;
    ParamArg[4] = 0;
    ParamArg[5] = 0;

    //调用远程函数指针
    if (CallRemoteFunction(nPid, "mmap", pfnmmap, ParamArg, 6, &Regs) == -1)
    {
        nRet = -1;
        goto SAFE_END;
    }

    //远程申请的Buffer首地址
    lpMmapBase = Regs.ARM_r0;

    pfndlopen = GetRemoteFunctionAddr(nPid, LINKER_PATH, (void *)dlopen);
    pfndlsym = GetRemoteFunctionAddr(nPid, LINKER_PATH, (void *)dlsym);
    pfndlclose = GetRemoteFunctionAddr(nPid, LINKER_PATH, (void *)dlclose);
    pfnsleep = GetRemoteFunctionAddr(nPid, LIBC_PATH, (void *)sleep);
    if ((pfndlopen == NULL) || (pfndlsym == NULL) || (pfndlclose == NULL) || (pfnsleep == NULL))
    {
        DEBUG_PRINT("[-]pfndlopen | pfndlsym | pfndlclose | pfnsleep == NULL\r\n");
        nRet = -1;
        goto SAFE_END;
    }

    DEBUG_PRINT("[+] Get imports: dlopen: %p, dlsym: %p, dlclose: %p\r\n",
                pfndlopen, pfndlsym, pfndlclose);

    printf("lpLibraryPath Length: %d\r\n", strlen(lpLibraryPath) + 1);

    //远程申请的Buffer首地址写入需要注入的so路径
    if (PtraceWriteProcessMemory(nPid, lpMmapBase, lpLibraryPath, strlen(lpLibraryPath) + 1) == -1)
    {
        DEBUG_PRINT("[-]InjectRemoteProcess::PtraceWriteProcessMemory Error\r\n");
        nRet = -1;
        goto SAFE_END;
    }

    //传递参数, 准备调用dlopen  void * dlopen(const char * pathname, int mode);
    ParamArg[0] = lpMmapBase;
    ParamArg[1] = RTLD_NOW| RTLD_GLOBAL;

    if (CallRemoteFunction(nPid, "dlopen", pfndlopen, ParamArg, 2, &Regs) == -1)
    {
        nRet = -1;
        goto SAFE_END;
    }

    hSo = Regs.ARM_r0;

    //传递参数, 准备调用pfndlsym  void* dlsym( void* handle, const char* name );
    ParamArg[0] = hSo;

#define FUNCTION_NAME_OFFSET    0x100
    //lpFunctionName需要写入远程的buffer中才能使用
    if (PtraceWriteProcessMemory(nPid, lpMmapBase + FUNCTION_NAME_OFFSET, lpFunctionName, strlen(lpFunctionName) + 1) == -1)
    {
        DEBUG_PRINT("[-]InjectRemoteProcess::PtraceWriteProcessMemory Error\r\n");
        nRet = -1;
        goto SAFE_END;
    }

    ParamArg[1] = lpMmapBase + FUNCTION_NAME_OFFSET;

    if (CallRemoteFunction(nPid, "dlsym", pfndlsym, ParamArg, 2, &Regs) == -1)
    {
        nRet = -1;
        goto SAFE_END;
    }

    pfnRemoteFunction = Regs.ARM_r0;
    DEBUG_PRINT("hook_entry_addr = %p\r\n", pfnRemoteFunction);

    //传递参数, 准备调用注入模块中的函数  void MyHook(void)
    if (CallRemoteFunction(nPid, lpFunctionName, pfnRemoteFunction, ParamArg, 0, &Regs) == -1)
    {
        nRet = -1;
        goto SAFE_END;
    }

    /*
    printf("Press enter to dlclose and detach\r\n");
    getchar();

    //传递参数, 准备调用dlclose
    ParamArg[0] = hSo;

    if (CallRemoteFunction(nPid, "dlclose", pfndlclose, ParamArg, 1, &Regs) == -1)
    {
        nRet = -1;
    }
    */

SAFE_END:
    //恢复原始寄存器信息
    if (PtraceSetRegs(nPid, &OldRegs) == -1)
    {
        DEBUG_PRINT("[-]PtraceSetRegs Error\r\n");
    }

    //取消附加
    if (PtraceDetach(nPid) == -1)
    {
        DEBUG_PRINT("[-]PtraceDetach Error\r\n");
    }

    return nRet;
}

int main(int argc, char* argv[])
{
    int nProId = FindProIdByProName("./hello");
    if (nProId == -1)
    {
        return -1;
    }

    if (InjectRemoteProcess(nProId, "/data/local/tmp/MyTest.so", "MyHook", NULL) == -1)
    {
        DEBUG_PRINT("[+]InjectRemoteProcess Failed\r\n");
    }
    else
    {
        DEBUG_PRINT("[+]InjectRemoteProcess Success\r\n");
    }

    return 0;
}
//Hook代码

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>


typedef unsigned int (*PFNSLEEP)(unsigned int);

typedef unsigned short Elf32_Half;
typedef unsigned long Elf32_Word;
typedef unsigned long Elf32_Addr;
typedef unsigned long Elf32_Off;

#define EI_NIDENT (16)
#define SHT_PROGBITS 1

typedef struct
{
  unsigned char    e_ident[EI_NIDENT];    /* Magic number and other info */
  Elf32_Half    e_type;            /* Object file type */
  Elf32_Half    e_machine;        /* Architecture */
  Elf32_Word    e_version;        /* Object file version */
  Elf32_Addr    e_entry;        /* Entry point virtual address */
  Elf32_Off    e_phoff;        /* Program header table file offset */
  Elf32_Off    e_shoff;        /* Section header table file offset */
  Elf32_Word    e_flags;        /* Processor-specific flags */
  Elf32_Half    e_ehsize;        /* ELF header size in bytes */
  Elf32_Half    e_phentsize;        /* Program header table entry size */
  Elf32_Half    e_phnum;        /* Program header table entry count */
  Elf32_Half    e_shentsize;        /* Section header table entry size */
  Elf32_Half    e_shnum;        /* Section header table entry count */
  Elf32_Half    e_shstrndx;        /* Section header string table index */
} Elf32_Ehdr;

typedef struct
{
  Elf32_Word    sh_name;        /* Section name (string tbl index) */
  Elf32_Word    sh_type;        /* Section type */
  Elf32_Word    sh_flags;        /* Section flags */
  Elf32_Addr    sh_addr;        /* Section virtual addr at execution */
  Elf32_Off    sh_offset;        /* Section file offset */
  Elf32_Word    sh_size;        /* Section size in bytes */
  Elf32_Word    sh_link;        /* Link to another section */
  Elf32_Word    sh_info;        /* Additional section information */
  Elf32_Word    sh_addralign;        /* Section alignment */
  Elf32_Word    sh_entsize;        /* Entry size if section holds table */
} Elf32_Shdr;

//新函数
unsigned int NewSleep(unsigned int seconds)
{
    printf("Hello NewSleep\r\n");

    //调用原始函数,也可以定义一个函数指针来调
    //return (*pfnSleep)(seconds);
    return sleep(seconds);
}

//解析Got表的内存偏移和表的大小
int GetGotTableInfo(int *lpnVirtualAddr, int *lpnSize)
{
    int nRet = -1;
    FILE *fp = fopen("/data/local/tmp/hello", "r");
    if (fp == NULL)
    {
        return -1;
    }

    Elf32_Ehdr Elf32Header;
    Elf32_Shdr Elf32SectionHeader;

    //不做返回值检查了
    fread(&Elf32Header, sizeof(Elf32_Ehdr), 1, fp);

    fseek(fp, Elf32Header.e_shstrndx * Elf32Header.e_shentsize + Elf32Header.e_shoff, SEEK_SET);
    fread(&Elf32SectionHeader, Elf32Header.e_shentsize, 1, fp);

    char *lpStringTable = (char *)malloc(Elf32SectionHeader.sh_size);
    if (lpStringTable == NULL)
    {
        goto SAFE_END;
    }

    fseek(fp, Elf32SectionHeader.sh_offset, SEEK_SET);
    fread(lpStringTable, Elf32SectionHeader.sh_size, 1, fp);
    fseek(fp, Elf32Header.e_shoff, SEEK_SET);

    int nNameIndex = 0;
    int i = 0;

    for (i = 0; i < Elf32Header.e_shnum; i++)
    {
        fread(&Elf32SectionHeader, Elf32Header.e_shentsize, 1, fp);
        if (Elf32SectionHeader.sh_type == SHT_PROGBITS)
        {
            nNameIndex = Elf32SectionHeader.sh_name;
            if ((strcmp(&(lpStringTable[nNameIndex]), ".got.plt") == 0) ||
                (strcmp(&(lpStringTable[nNameIndex]), ".got") == 0))
            {
                //不是.so就不用修正地址了, so的话需要加上模块基地址修正
                *lpnVirtualAddr = Elf32SectionHeader.sh_addr;      
                *lpnSize = Elf32SectionHeader.sh_size;
                nRet = 0;
                break;
            }
        }
    }

SAFE_END:
    if (fp != NULL)
    {
        fclose(fp);
    }

    if (lpStringTable != NULL)
    {
        free(lpStringTable);
    }

    return nRet;
}

void MyHook()
{
    int nVirtualAddr = 0;
    int nSize = 0;
    int i = 0;

    //获取GotTable的VirtualAddr, Size
    if (GetGotTableInfo(&nVirtualAddr, &nSize) == -1)
    {
        return;
    }

    //遍历Got表中的每一项
    for (i = 0; i < nSize; i += 4)
    {
        if ((int)sleep == (*(int *)(nVirtualAddr + i)))
        {
            //修改内存保护属性为可写
            mprotect((void *)0x9000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC);
            *(int *)(nVirtualAddr + i) = (int)NewSleep;
            break;
        }
    }
}

 

Android中的so挂钩(hook)之替换Got表

标签:

原文地址:http://www.cnblogs.com/dacainiao/p/5124107.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!