二、libbase

其实上面加载完SO库后,hook的功能我们完全可以自己在动态库中实现。而adbi作者为了方便我们使用,编写了一个通用的hook框架工具即libbase库。
libbase依然在解决两个问题:1.获取要hook的目标函数地址;2.给函数打二进制补丁即inline hook。

关于获取hook函数地址的方法这里不再赘述。直接看inline hook部分,这部分功能在base\hook.c的hook()函数中实现,先看hook_t结构体:

struct hook_t {
    unsigned int jump[3]; //跳转指令(ARM)
    unsigned int store[3]; //原指令(ARM)
    unsigned char jumpt[20]; //跳转指令(Thumb)
    unsigned char storet[20]; //原指令(Thumb)
    unsigned int orig; //被hook函数地址
    unsigned int patch; //补丁地址
    unsigned char thumb; //补丁代码指令集,1为Thumb,2为ARM
    unsigned char name[128]; //被hook函数名
    void *data;
};

hook_t是一个标准inline hook结构体,保存了跳转指令/跳转地址/指令集/hook函数名等信息。因为ARM使用了ARM和Thumb两种指令集,所以代码中需进行区分:

if (addr % 4 == 0) {
    /* ARM指令集 */
} else { 
    /* Thumb指令集 */
}

这样进行判断的依据,是编译器在使用Thumb指令集编译一个函数时,会自动将真正映射地址的最后一位置’1’赋给符号地址,这样可以实现无缝的Thumb指令集函数与Arm指令集代码混编。
接下来看一下ARM指令集分支的处理流程,这是该问题解决的核心部分:

if (addr % 4 == 0) {
    log("ARM using 0x%lx\n", (unsigned long)hook_arm)
    h->thumb = 0;
    h->patch = (unsigned int)hook_arm;
    h->orig = addr;
    h->jump[0] = 0xe59ff000; // LDR pc, [pc, #0]
    h->jump[1] = h->patch;
    h->jump[2] = h->patch;
    for (i = 0; i < 3; i++)                                  
                h->store[i] = ((int*)h->orig)[i];
    for (i = 0; i < 3; i++)                                  
                    ((int*)h->orig)[i] = h->jump[i];
}

首先填充hook_t结构体,第一个for循环保存原地址处3条指令共12字节。第二个for循环用新的跳转指令进行覆写,关键的三条指令分别保存在jump[0]-[2]中:

jump[0]赋值0xe59ff000,翻译成ARM汇编为ldr pc,[pc,#0],由于pc寄存器读出的值是当前指令地址加8,因此这条指令实际是将jump[2]的值加载到pc寄存器。
jump[2]保存的是hook函数地址。jump[1]仅用来4字节占位。Thumb分支原理与ARM分支一致,不再分析。

接下来我们注意到,函数最后调用了一处hook_cacheflush()函数:

hook_cacheflush((unsigned int)h->orig, (unsigned int)h->orig+sizeof(h->jumpt));

我们知道,现代处理器都有指令缓存,用来提高执行效率。前面我们修改的是内存中的指令,为防止缓存的存在,使我们修改的指令执行不到,需进行缓存的刷新:

void inline hook_cacheflush(unsigned int begin, unsigned int end)
{
    const int syscall = 0xf0002;
    __asm __volatile (
        "mov     r0, %0\n"
        "mov     r1, %1\n"
        "mov     r7, %2\n"
        "mov     r2, #0x0\n"
        "svc     0x00000000\n"
        :
        :   "r" (begin), "r" (end), "r" (syscall)
        :   "r0", "r1", "r7"
        );
}

参考资料

[1].adbi源码 https://github.com/crmulliner/adbi
[2].minghuasweblog,ARM Cache Flush on mmap’d Buffers with __clear_cache(),March 29, 2013

Android Hook框架adbi源码浅析(二)的更多相关文章

  1. Android Hook框架adbi源码浅析(一)

    adbi(The Android Dynamic Binary Instrumentation Toolkit)是一个Android平台通用hook框架,基于动态库注入与inline hook技术实现 ...

  2. Android Hook框架adbi的分析(2)--- inline Hook的实现

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/74452308 一. Android Hook框架adbi源码中inline Hoo ...

  3. Android Hook框架adbi的分析(3)---编译和inline Hook实践

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/75200800 一.序言 在前面的博客中,已经分析过了Android Hook框架a ...

  4. Android Hook框架adbi的分析(1)---注入工具hijack

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/74055505 一.Android Hook框架adbi的基本介绍 adbi是And ...

  5. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  6. android hook 框架 ADBI 如何实现dalvik函数挂钩

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  7. android hook 框架 ADBI 简介、编译、运行

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  8. ReentrantLock和condition源码浅析(二)

    转载请注明出处... 接着上一篇的ReentrantLock和condition源码浅析(一),这篇围绕着condition 一.condition的介绍 在这里为了作对比,引入Object类的两个方 ...

  9. android hook 框架 ADBI 如何实现so注入

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

随机推荐

  1. Linux下的Nginx的配置+Tomcat启动

    Linux下的Nginx的配置 首次如果你只仅主机模式,那么请你切换到桥接模式或者net模式. 1.安装编译工具及库文件 yum -y install make zlib zlib-devel gcc ...

  2. 《高性能SQL调优精要与案例解析》一书谈主流关系库SQL调优(SQL TUNING或SQL优化)核心机制之——索引(index)

    继<高性能SQL调优精要与案例解析>一书谈SQL调优(SQL TUNING或SQL优化),我们今天就谈谈各主流关系库中,占据SQL调优技术和工作半壁江山的.最重要的核心机制之一——索引(i ...

  3. Django之WSGI 和MVC/MTV

    一.什么是WSGI? WEB框架的本质是一个socket服务端接收用户请求,加工数据返回给客户端(Django),但是Django没有自带socket需要使用 别人的 socket配合Django才能 ...

  4. leetcode Kth Largest Element in a Stream——要熟悉heapq使用

    703. Kth Largest Element in a Stream Easy Design a class to find the kth largest element in a stream ...

  5. MINIUI应用

    MINIUI是一款优秀的JS前端web框架,提供丰富.强大控件库,能快速开发企业级Web应用软件. 属于付费插件. 如果有兴趣推荐去这个网址看看.MiniUI 在线示例  http://www.min ...

  6. 命令创建Vue

    创建vue+webpack vue init webpack projectName 基础 Vue+webpack+Vux 新建文件命令 # install vue-cli npm install - ...

  7. tp框架 php ajax 登陆

    html 文件 <form class="form-signin loginform" role="form"> <input type=&q ...

  8. C++解析三

    类的构造函数类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行.构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void.构造函数可用于为某些成员变量设置初始 ...

  9. application Initialization设置导致处理程序ExtensionlessUrlHandler-Integrated-4.0在其模块列表中有一个错误模块问题的解决

    HTTP 错误 500.21 - Internal Server Error 处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错误模块“Ma ...

  10. C/S与B/S架构对比

    概述 在这个信息急剧膨胀的社会,我们不得不说人类正进入一个崭新的时代,那就是信息时代.信息时代的一个主要而显著的特征就是计算机网络的应用.计算机网络从最初的集中式计算,经过了Client/Server ...