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. 如何在netcore下,愉快的使用IServiceProvider

    之前一直做dotnet framework开发,依赖注入使用Autofac,Autofac的一般用法是服务启动时,将用到的接口.实现类名注入进去, 然后在服务其他地方如果使用该类时,直接在Contai ...

  2. 【HTB系列】Beep

    出品|MS08067实验室(www.ms08067.com) 这次挑战的是 HTB 的第5台靶机:Beep,评分很高,难度中等 靶机描述 Beep 运行了大量的服务,这对正确发掘入口点有一定的挑战,由 ...

  3. crudapi零代码开发平台应用场景和成功案例

    应用场景 在前面文章中,已经介绍了crudapi主要功能和使用方式,本文主要介绍crudapi应用场景以及具体的使用方式. 概要 crudapi属于产品级的零代码平台,无需编程,通过配置自动生成cru ...

  4. Graylog日志管理单机部署、日志节点的Sidecar配置以及简单的警告事件邮件发送

    应该是上个星期的上个星期,下了个任务,要做Graylog的部署以及文档,emmm....带log,肯定是和日志有关系了呗,不过也没听过啊,去搜了一下,确实,也不少帖子博客相关的都有安装部署,还是yum ...

  5. Windows下用户手册

      (1)net user(查看系统用户) (2)net user 用户名(查看具体某个系统用户详细信息) (3)net user 用户名 密码 /add(在本地组成员创建新用户,此时为Users组) ...

  6. css整理之-----------基本知识

    盒子模型 所有HTML元素可以看作盒子,它包括:边距,边框,填充,和实际内容. CSS中组成一个块级盒子需要: Content box: 这个区域是用来显示内容,大小可以通过设置 width 和 he ...

  7. 使用nodejs进行了简单的文件分卷工具

    关键词:node fs readline generator (在这之前需要声明的是这篇博客的应用范围应该算是相当狭隘,写出来主要也就是给自己记录一下临时兴起写的一个小工具,仅从功能需求上来说我相信是 ...

  8. 在SSM框架中如何将图片上传到数据库中

    今天我们来看看SSM中如何将图片转换成二进制,最后传入到自己的数据库中,好了,废话不多说,我们开始今天的学习,我这里用的编辑器是IDEA 1.导入图片上传需要的jar依赖包 1 <depende ...

  9. Announcing cnblogs-hardening 1.0 Preview 1

    Release Notes Write about coding Note About coding Share about coding Talk about coding Comment abou ...

  10. 「HTML+CSS」--自定义按钮样式【002】

    前言 Hello!小伙伴! 首先非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出- 哈哈 自我介绍一下 昵称:海轰 标签:程序猿一只|C++选手|学生 简介:因C语言结识编程,随后转入计算机 ...