android hook之注入安卓进程,并hook java世界的方法

本文是对看雪上一篇文章的学习笔记。记录自己的一些实践和遇到的问题。
原文地址:注入安卓进程,并hook java世界的方法.

hook流程:

  • 通过系统ptrace调用可以控制被traced进程的寄存器和程序映象。
int inject_remote_process(pid_t target_pid, const char *library_path, const char *function_name, const char *param, size_t param_size)
{
        int ret = -1;
        void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr; // 存放目标进程相应函数的地址
        void *local_handle, *remote_handle, *dlhandle;
        uint8_t *map_base = 0; // 存放目标进程mmap获取的内存块的地址
        uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;

        struct pt_regs regs;
        struct pt_regs original_regs;
       
        uint32_t code_length;
        long parameters[10];

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

        if (ptrace_attach(target_pid) == -1) // 第一步: attach 到目标进程
                goto exit;

        if (ptrace_getregs(target_pid, &regs) == -1)
                goto exit;

        /* save original registers */
        memcpy(&original_regs, &regs, sizeof(regs)); // 第二步:保存目标进程被注入前的寄存器内容,方便注入完成后恢复

        mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap);
        DEBUG_PRINT("[+] Remote mmap address: %x\n", mmap_addr);

        /* call mmap */
        parameters[0] = 0;  // addr
        parameters[1] = 0x4000; // size
        parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot
        parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags
        parameters[4] = 0; //fd
        parameters[5] = 0; //offset

        if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, &regs) == -1)
                goto exit;

        map_base = ptrace_retval(&regs);  // 第三步,获取目标进程mmap调用的地址,并执行mmap调用,在目标进程分配一块地址,用于存放后面要注入的库路径和相关函数地址等

        dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen );
        dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym );
        dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose );
        dlerror_addr = get_remote_addr( target_pid, linker_path, (void *)dlerror );

        DEBUG_PRINT("[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x, dlerror: %x\n",
                        dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);

        printf("library path = %s\n", library_path);
        ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1);// 第四步,获取目标进程动态库的几个函数,并将要注入的so的路径写入刚刚申请的内存的初始地址

        parameters[0] = map_base;
        parameters[1] = RTLD_NOW| RTLD_GLOBAL;

        if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, &regs) == -1)
                goto exit;

        void * sohandle = ptrace_retval(&regs); // 第五步,在目标进程内调用 dlopen函数加载要注入的 so ,这一步成功后,so已经被注入目标进程的地址空间内了

#define FUNCTION_NAME_ADDR_OFFSET       0x100
        ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1);
        parameters[0] = sohandle;
        parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET;

        if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, &regs) == -1)
                goto exit;

        void * hook_entry_addr = ptrace_retval(&regs);
        DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr); // 第六步,在目标进程内调用 dlsym函数获取刚刚注入的so里的hook函数

#define FUNCTION_PARAM_ADDR_OFFSET      0x200
        ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1);
        parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;

        if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, &regs) == -1)
                goto exit;

       // printf("Press enter to dlclose and detach\n"); // 第七步,在目标进程内调用hook函数
      //  getchar();
        parameters[0] = sohandle;

        if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, &regs) == -1)
                goto exit;

        /* restore */
        ptrace_setregs(target_pid, &original_regs);
        ptrace_detach(target_pid); // 第八步,恢复目标进程的寄存器,detach 退出对目标进程的 ptrace
        ret = 0;

exit:
        return ret;
}
  • 在将so1注入到目标进程后,会执行so1中的一个方法,在这个方法中,我们加载一个新的so2库到进程。
  • 在so2库中封装了需要hook的函数的一些信息
  • 在so1中进行方法的替换,即修改了目标函数应该调用的函数指针。(具体替换还需要分析)

目前实现的功能:

  • 按照原作者的意图,实现了替换功能。

参考链接:

JNI介绍

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容