java hook 框架_Android平台dalvik模式下java Hook框架ddi的分析(1)

一、前 言

在前面的博客中已经学习了作者crmulliner编写的,针对Android系统的跨进程 inline Hook的实现即Android native Hook框架adbi的实现。Android Hook框架adbi主要是针对的Android的native函数进行inline Hook操作,那么如果需要对Android系统中Java编写的函数进行Hook,又该怎么操作呢?作者crmulliner后面又实现了针对Android的java函数进行Hook的框架ddi。adbi Hook框架和ddi java Hook框架的实现流程都差不多,首先实现root权限下Android跨进程的so注入,在so库文件被加载注入到目标进程中时,调用该so库文件的构造函数有一次代码执行的机会,利用这一次代码执行的机会既可以进行针对Android系统底层native函数的inline Hook或者.got Hook等,也可以进行针对Android系统的java函数进行dalvik Hook或者art Hook。Android平台的所有跨进程Hook都是基于Android系统root权限下的so注入和一次代码执行机会来实现的,只要能实现Android的跨进程注入(这个注入既可以是shellcode代码片段的注入也可以是so库文件的注入)就可以在目标进程中做很多的事情。

这里简要说下Android平台针对java函数的dalvik Hook(暂时不讨论基于art模式下的java函数的Hook,后面有时间再讨论)。dalvik虚拟机模式下java函数的Hook主要是修改存储java函数的信息结构体Method。在dalvik虚拟机中,java函数的形式是以Method结构体来表现的,每一个java编写的类成员函数最终在dalvik虚拟机中以Method结构体的形式存在。基于dalvik虚拟机的java Hook通过修改java函数的Method结构体中的函数属性值access_flags将一个java层函数修改为native属性的函数,这样一个java层实现的函数被修改为native层实现的函数,我们就可以将自定义编写的native函数替换掉原来的java层函数实现,从而实现基于dalvik虚拟机的java Hook。

二、Android平台java Hook框架ddi实现dalvik 模式下Hook的步骤

1)在so库文件被加载注入到目标进程中时,调用该so库文件.init段的构造函数获取dalvik模式下执行Hook java函数代码的机会;

2) dalvik虚拟机模式下,动态加载”libdvm.so”库文件并获取该动态加载的”libdvm.so”库文件中java Hook实现需要的导出函数的指针和导出全局变量,例如获取导出函数dvmFindLoadedClass、dvmFindVirtualMethodHierByDescriptor、dvmFindDirectMethodByDescriptor、dvmUseJNIBridge等的函数指针;

3)调用上面步骤中提到的”libdvm.so”库文件中的导出函数 dvmFindLoadedClass 获取被java Hook的java目标函数所在的目标类,然后再调用导出函数 dvmFindVirtualMethodHierByDescriptor、dvmFindDirectMethodByDescriptor 在查找到的目标类中获取被java Hook的目标函数(java层实现的函数)的信息结构体Method;

4)查找到被java Hook的目标函数(java层实现的函数)的信息结构体Method以后,先保存该目标函数的信息结构体Method的原始值,用以后面对目标函数进行java Hook操作后的恢复还原,如果没有保存目标函数的原始Method信息结构体值的话,想在java Hook操作之后再调用原来的java层实现的目标函数的话就不可能了;

5)对将被java Hook的目标函数的信息结构体Method进行修改即修改目标函数信息结构体Method的成员变量 access_flags 的值,实现将一个java层实现的方法改为 native 层实现的本地方法,这样一个java函数就变成了可以被我们自定义替换的native函数;

6)java层实现的目标函数被修改为native属性的本地方法以后,还需要对该被java Hook的目标函数信息结构体Method的成员变量 insSize(函数传参寄存器的数量)、outsSize(局部变量使用寄存器数量)、registersSize(函数调用使用的寄存器的总数)、jniArgInfo、native_func(改为jni桥接函数,例如 dvmResolveNativeMethod)的值进行修正;

7)为被java Hook的目标函数设置新的函数实现,按照被java Hook的目标函数的原始java函数声明实现对应函数声明的native层的jni函数(java Hook的替换函数),然后修改该目标函数的信息结构体Method的成员变量 insns 的值为该native层实现的jni函数,到这里java层实现的目标函数就替换为我们自定义实现的native层的jni函数,从而实现dalvik虚拟机模式下的java Hook。

提示:ddi 框架的 java Hook 实现原理和前面的博客《Android进程so注入Hook java方法》中提到的 java Hook 实现原理是一样的,只是在细节处理上稍有不同,ddi 框架处理的更好,不需要再次进行jni函数的注册。

三、Android平台java Hook框架ddi实现dalvik 模式下Hook的代码分析

1. 在dalvik虚拟机中每一个方法都由一个称作Method的结构体来表示(包括JNI方法),ddi框架实现java Hook就是通过修改目标函数的信息结构体Method来实现的。下面来了解一下Method结构体构成:

/*

* A method. We create one of these for every method in every class

* we load, so try to keep the size to a minimum.

*

* Much of this comes from and could be accessed in the data held in shared

* memory. We hold it all together here for speed. Everything but the

* pointers could be held in a shared table generated by the optimizer;

* if we're willing to convert them to offsets and take the performance

* hit (e.g. "meth->insns" becomes "baseAddr + meth->insnsOffset") we

* could move everything but "nativeFunc".

*/

// Android 4.4.4r1源码文件路径 /dalvik/vm/oo/Object.h

struct Method {

/* the class we are a part of */

ClassObject* clazz;

/* access flags; low 16 bits are defined by spec (could be u2?) */

u4 accessFlags;

/*

* For concrete virtual methods, this is the offset of the method

* in "vtable".

*

* For abstract methods in an interface class, this is the offset

* of the method in "iftable[n]->methodIndexArray".

*/

u2 methodIndex;

/*

* Method bounds; not needed for an abstract method.

*

* For a native method, we compute the size of the argument list, and

* set "insSize" and "registerSize" equal to it.

*/

u2 registersSize; /* ins + locals */

u2 outsSize;

u2 insSize;

/* method name, e.g. "" or "eatLunch" */

const char* name;

/*

* Method prototype descriptor string (return and argument types).

*

* TODO: This currently must specify the DexFile as well as the proto_ids

* index, because generated Proxy classes don't have a DexFile. We can

* remove the DexFile* and reduce the size of this struct if we generate

* a DEX for proxies.

*/

DexProto prototype;

/* short-form method descriptor string */

const char* shorty;

/*

* The remaining items are not used for abstract or native methods.

* (JNI is currently hijacking "insns" as a function pointer, set

* after the first call. For internal-native this stays null.)

*/

/* the actual code */

const u2* insns; /* instructions, in memory-mapped .dex */

/* JNI: cached argument and return-type hints */

int jniArgInfo;

/*

* JNI: native method ptr; could be actual function or a JNI bridge. We

* don't currently discriminate between DalvikBridgeFunc and

* DalvikNativeFunc; the former takes an argument superset (i.e. two

* extra args) which will be ignored. If necessary we can use

* insns==NULL to detect JNI bridge vs. internal native.

*/

DalvikBridgeFunc nativeFunc;

/*

* JNI: true if this static non-synchronized native method (that has no

* reference arguments) needs a JNIEnv* and jclass/jobject. Libcore

* uses this.

*/

bool fastJni;

/*

* JNI: true if this method has no reference arguments. This lets the JNI

* bridge avoid scanning the shorty for direct pointers that need to be

* converted to local references.

*

* TODO: replace this with a list of indexes of the reference arguments.

*/

bool noRef;

/*

* JNI: true if we should log entry and exit. This is the only way

* developers can log the local references that are passed into their code.

* Used for debugging JNI problems in third-party code.

*/

bool shouldTrace;

/*

* Register map data, if available. This will point into the DEX file

* if the data was computed during pre-verification, or into the

* linear alloc area if not.

*/

const RegisterMap* registerMap;

/* set if method was called during method profiling */

bool inProfile;

};

(1)clazz:当前方法所在的类;

(2)accessFlags:当前方法所具有的属性,例如:类访问属性、是否静态函数等,accessFlags属性值 的定义如下:

/*

* access flags and masks; the "standard" ones are all <= 0x4000

*

* Note: There are related declarations in vm/oo/Object.h in the ClassFlags

* enum.

*/

// Android 4.4.4r1 源码路径 /dalvik/libdex/DexFile.h

enum {

ACC_PUBLIC = 0x00000001, // class, field, method, ic

ACC_PRIVATE = 0x00000002, // field, method, ic

ACC_PROTECTED = 0x00000004, // field, method, ic

ACC_STATIC = 0x00000008, // field, method, ic

ACC_FINAL = 0x00000010, // class, field, method, ic

ACC_SYNCHRONIZED = 0x00000020, // method (only allowed on natives)

ACC_SUPER = 0x00000020, // class (not used in Dalvik)

ACC_VOLATILE = 0x00000040, // field

ACC_BRIDGE = 0x00000040, // method (1.5)

ACC_TRANSIENT = 0x00000080, // field

ACC_VARARGS = 0x00000080, // method (1.5)

ACC_NATIVE = 0x00000100, // method

ACC_INTERFACE = 0x00000200, // class, ic

ACC_ABSTRACT = 0x00000400, // class, method, ic

ACC_STRICT = 0x00000800, // method

ACC_SYNTHETIC = 0x00001000, // field, method, ic

ACC_ANNOTATION = 0x00002000, // class, ic (1.5)

ACC_ENUM = 0x00004000, // class, field, ic (1.5)

ACC_CONSTRUCTOR = 0x00010000, // method (Dalvik only)

ACC_DECLARED_SYNCHRONIZED =

0x00020000, // method (Dalvik only)

ACC_CLASS_MASK =

(ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT

| ACC_SYNTHETIC | ACC_ANNOTATION

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值