adbi的java hook实现代码ddi不在之前下载的文件中,下载地址:https://github.com/crmulliner/ddi,具体的编译看readme里面很详细的介绍了。注意ddi代码不能单独使用要跟之前的adbi相结合,因为adbi提供了注入so。本文不对代码进行详细的剖析(你可以看参考资料的文章),分析下2个问题:java如何hook;如何执行自己的java函数。

  java hook:

  其实在ddi的java hook和xposed的hook原理(不清楚的看我之前xposed的分析)是相同的,都是改变被hook函数的accessflag;将原本的java函数变成native函数,从而去执行自己定义的native函数;它实现的代码在dalvik_hook.c的dalvik_hook函数中。但不同于xposed是,它没有直接修改Mehtod结构的insns和nativeFunc而是调用了dvmUseJNIBridge函数来修改insns和nativeFunc。但在我看这个函数时发现其跟android源码中的dvmRegisterJNIMethod很相似:

static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
const char* signature, void* fnPtr)
{
  // 解释下参数:
  // clazz:类名"shy/luo/jni/ClassWithJni";
  // methodName:需要注册的jni方法名 nanosleep;
  // signature:方法的签名 实质是方法的参数和返回值,区别不同参数的函数
  // fnPtr: jni方法函数地址 即shy_luo_jni_ClassWithJni_nanosleep函数;dalvik执行的就是这个函数,很重要哎
Method* method;
......
method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
......
dvmUseJNIBridge(method, fnPtr);
......
}

  dvmRegisterJNIMethod(关于此函数的解析,看dalvik浅析二:jni、so)函数中用dvmFindDirectMethodByDescriptor找到函数在dalvik中的Method结构,然后再dvmUseJNIBridge为Method注册native函数(在正常情况下,该Method的accessflag就是native所以无需修改)。下面来看ddi中的dalvik_hook函数实现

void* dalvik_hook(struct dexstuff_t *dex, struct dalvik_hook_t *h)
{ //dalvik_hook_t结构体中已包含函数所属的class、name、signature
......
h->method = dex->dvmFindVirtualMethodHierByDescriptor_fnPtr(target_cls, h->method_name, h->method_sig);
if (h->method == 0) {
h->method = dex->dvmFindDirectMethodByDescriptor_fnPtr(target_cls, h->method_name, h->method_sig);
}
......
//保留method的属性带以后还原
h->iss = h->method->insSize;
h->rss = h->method->registersSize;
h->oss = h->method->outsSize;
  // 这里要处理
h->method->insSize = h->n_iss;
h->method->registersSize = h->n_rss;
h->method->outsSize = h->n_oss; h->method->jniArgInfo = 0x80000000; // <--- also important;这里很重要,下面要分析
......
h->access_flags = h->method->a; //保留原先函数的accessflag
h->method->a = h->method->a | h->af; // make method native
......
// bind function
dex->dvmUseJNIBridge_fnPtr(h->method, h->native_func);
......
}

  显而易见,dalvik_hook按dvmRegisterJNIMethod的逻辑来编写的,所以hook其实是自己为java函数注册了一个jni方法!(熟读源码理解实现机制,你会发现很多框架和工具都是基于源码的)ok,上面的知识点大部分都是熟悉,注意蓝色代码很重要的是函数使用的dalvik寄存器个数,xposed也对其进行修正但不同的是jniArgInfo属性,xposed没对它修改,看下对jniArgInfo的描述

jniArgInfo:这个变量记录了一些预先计算好的信息,从而不需要在调用的时候再通过方法的参数和返回值实时计算了,方便了JNI的调用,提高了调用的速度。如果第一位为1(即0x80000000),则Dalvik虚拟机会忽略后面的所有信息,强制在调用时实时计算;

  可以这么理解jniArgInfo相当于jni方法的cache标识符,若jniArgInfo不为0x80000000则dalvik会按之前调用过的jni方法去执行。回到xposed和ddi的区别:

   xposed:在loadPackage时hook函数,而在此时绝对没有执行过函数的jni方法;

   ddi:在app运行时hook函数,我们可不敢肯定此时没有执行过jni方法啊

 执行自己的java函数:

  在so中执行了上面的java hook后,app在调用被hook函数时就会执行我们的自定义的native函数。那我们又怎样去执行我们自己的java函数呢(难道不可以直接在native函数中实现逻辑?当然可以啊,但java开发android简单啊)?很简单,1.加载自己的dex(包含自定义java函数的文件);2.找到自定义java函数地址3.执java函数。下面对以上三步用到的知识点剖析。

const DalvikNativeMethod dvm_dalvik_system_DexFile[] = {  //  /dalvik/vm/native/dalvik_system_DexFile.cpp基于源码4.4
520 { "openDexFileNative", "(Ljava/lang/String;Ljava/lang/String;I)I",
521 Dalvik_dalvik_system_DexFile_openDexFileNative },
522 { "openDexFile", "([B)I",
523 Dalvik_dalvik_system_DexFile_openDexFile_bytearray },
524 { "closeDexFile", "(I)V",
525 Dalvik_dalvik_system_DexFile_closeDexFile },
526 { "defineClassNative", "(Ljava/lang/String;Ljava/lang/ClassLoader;I)Ljava/lang/Class;",
527 Dalvik_dalvik_system_DexFile_defineClassNative },
528 { "getClassNameList", "(I)[Ljava/lang/String;",
529 Dalvik_dalvik_system_DexFile_getClassNameList },
530 { "isDexOptNeeded", "(Ljava/lang/String;)Z",
531 Dalvik_dalvik_system_DexFile_isDexOptNeeded },
532 { NULL, NULL, NULL },
533};

  第一、二步的知识点都在上面的代码里。加载dex的知识我们在app加壳的文章中有所提及,ddi利用Dalvik_dalvik_system_DexFile_openDexFileNative直接加载目录里的dex文件。关于第二步找函数是利用Dalvik_dalvik_system_DexFile_defineClassNative来实现,具体可以看dalvik浅析三:类加载。 这里我有一点不明白的是为什么调用了Dalvik_dalvik_system_DexFile_defineClassNative还要再去调用(*env)->FindClass去得到ClassObject,明明2者都是调用dvmFindClassNoInit去实现的啊,有谁知道告诉我!第三步更简单了,得到函数的ClassObject后直接找到methodID,再调用CallVoidMethodA就可以在native执行java函数啦。

  最后添幅图来理解下ddi的整个执行过程吧

  

  当然你也可以在my_init中hook到自定义native函数2中,省去native函数1的执行。

  ok,adbi的分析就到此为止啦。总结下adbi在hijack中利用ptrace在目标进程注入代码,该代码会加载so;而在so里面可以进行so和java hook:

  so hook:找到native函数的指令利用Inline hook去修改它,就可以在执行native函数时去执行自定义的函数;

  java hook:改变函数的accessflag去执行自己的native函数,而在native中去执行自定义的java函数

参考资料:

  1 Android平台下Dalvik层hook框架ddi的研究

adbi学习:java hook实现机制的更多相关文章

  1. Java 类反射机制分析

    Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...

  2. Java学习系列(一)Java的运行机制、JDK的安装配置及常用命令详解

    俗话说:“十五的月亮十六圆”.那学习是不是也是如此呢?如果把月亮看成是我们的愿望,那十五便是我们所处的“高原期”,坚持迈过这个坎,我相信你的愿望终究会现实的.记得马云曾说:今天很残酷,明天更残酷,后天 ...

  3. JAVA的反射机制学习笔记(二)

    上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了.自己的步伐全然被打乱了~不能继续被动下去.得又一次找到自己的节奏. 4.获取类的Constructor 通过反射机制得到 ...

  4. java学习笔记09--反射机制

    java学习笔记09--反射机制 什么是反射: 反射是java语言的一个特性,它允许程序在运行时来进行自我检查并且对内部的成员进行操作.例如它允许一个java的类获取他所有的成员变量和方法并且显示出来 ...

  5. 深入浅出学习hibernate框架(三):java的反射机制

    上篇博客写到了JDBC的基本操作,今天准备写一篇关于JAVA反射机制的文章,因为java的反射机制和上一篇JDBC都是Hibernate框架的基本要素.在Hibernate的运行机制中,这两块的内容正 ...

  6. java学习笔记13--反射机制与动态代理

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note13.html,转载请注明源地址. Java的反射机制 在Java运行时环境中,对于任意 ...

  7. Java反射学习:深入学习Java反射机制

    一.Java反射的理解(反射是研究框架的基础之一) Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的 ...

  8. java垃圾回收机制学习总结

    最近学习了一下java垃圾回收机制,将其主要内容大致总结一下: 1.什么是垃圾回收机制 java GC机制(garbage collection,垃圾收集,垃圾回收),是java特有的机制,作为jav ...

  9. 学习AOP之JAVA的代理机制

    从一个输出日志的实例分析JAVA的代理机制 一.通用的日志输出方法  :需要在每个类里都增加对输出日志信息的代码 二.通过面向接口编程实现日志的输出(JAVA的静态代理):虽然实现了业务逻辑与输出日志 ...

随机推荐

  1. 180. 连续出现的数字 + MySql + 连续出现数字 + 多表联合查询

    180. 连续出现的数字 LeetCode_MySql_180 题目描述 代码实现 # Write your MySQL query statement below select distinct t ...

  2. WIFI6 基本知识(二)

    WI-FI6核心技术 WI-FI6除了继承了WI-FI5的所有MIMO特性之外,还增加了许多针对高密部署场景的特性.以下是WI-FI6的核心新特性: OFDMA频分复用技术 DL/UL MU-MIMO ...

  3. Linux速通03 目录文件的浏览、管理和维护

    Linux文件系统的层次结构 # 树状结构:在Linux或Unix操作系统中,所有的文件和目录都被组织成一个以根节点开始的倒置的树状结构. # 目录的定义:目录相当于Windows中的文件夹,目录中存 ...

  4. 大数据实战-Spark实战技巧

    1.连接mysql --driver-class-path mysql-connector-java-5.1.21.jar 在数据库中,SET GLOBAL binlog_format=mixed; ...

  5. Linux下基础命令

      (1)ls(查看列表) (2)ls  -l(查看列出文件详细信息) (3)ls  -al (查看全部列出文件详细信息) (4)ls  -dl(查看目录信息) (5)pwd(查看当前工作的目录)   ...

  6. P3388 【模板】割点(割顶) 题解 (Tarjan)

    题目链接 P3388 [模板]割点(割顶) 解题思路 最近学的东西太杂了,多写点博客免得自己糊里糊涂的过去了. 这个题求割点,感觉这篇文章写得挺好. 割点是啥?如果去掉这个点之后连通图变成多个不连通图 ...

  7. Windows包管理器——Scoop 包管理器

    Scoop 包管理器 目录 Scoop 包管理器 参考 官方 博客 声明 目录 scoop 安装&&卸载 安装( 使用 powershell) 卸载(软件的使用权归自己所有,一言不合即 ...

  8. c语言跨文件调用函数中声明的变量

    转载:weixin_33885253 变量的作用域 变量根据其作用域有全局变量和局部变量之分.全局变量作用域是整个文件,并且可以使用关键字extern达到跨文件调用的目的.但是局部变量值作用于它当前所 ...

  9. html Ajax连接.NET Ashx

    Html代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <m ...

  10. Java并发编程之多线程

    线程 进程/线程/协程/管程 进程:操作系统会以进程为单位,分配系统资源(CPU时间片.内存等资源),是资源分配的最小单位 进程间通信(IPC): 管道(Pipe) 命名管道(FIFO) 消息队列(M ...