Android so注入-libinject2 简介、编译、运行

Android so注入-libinject2  如何实现so注入

Android so注入-Libinject 如何实现so注入

Android so注入挂钩-Adbi 框架简介、编译、运行

Android so注入挂钩-Adbi 框架如何实现so注入

Android so注入挂钩-Adbi 框架如何实现so函数挂钩

Android so注入挂钩-Adbi 框架如何实现dalvik函数挂钩

Android dalvik挂钩-Xposed框架如何实现注入

Android dalvik挂钩-Xposed框架如何实现挂钩

前面几篇分析已经能做到注入一个so到目标进程并用so里的函数挂钩目标进程的函数,如果对这个实现不了解,请返回去阅读  android hook 框架 ADBI 简介、编译、运行  、 android hook 框架 ADBI 如何实现so注入 、android hook 框架 ADBI 如何实现so函数挂钩, so函数的挂钩只能影响native世界,没有影响到java虚拟机内部,而android绝大部分逻辑都是跑在虚拟机内部的。所以这篇接着分析 adbi 剩下的部分代码,看它如何实现挂钩dalvik虚拟机内部函数,使得目标进程执行java函数时能执行到我们注入的 dex 文件里的函数,这部分代码在 adbi 项目的 ddi 目录下。

其中,dalvikhook目录存放具体的 dalvik 挂钩实现,examples 目录存放两个挂钩java函数的例子。我们使用第一个例子, smsdispatch 来分析这个过程。

一、 smsdispatch 例子主要是两个文件, smsdispatch.c 和  SMSDispatch.java , 前者编译成一个so,利用 android hook 框架 ADBI 如何实现so注入  的方法注入到目标进程,并执行挂钩操作。后者编译成一个dex 文件,smsdispatch.c 挂钩前会先加载这个Dex文件获取用来挂钩的函数。

void __attribute__ ((constructor)) my_init(void);

void my_init(void)
{
log("libsmsdispatch: started\n") debug = ;
// set log function for libbase (very important!)
set_logfunction(my_log2);
// set log function for libdalvikhook (very important!)
dalvikhook_set_logfunction(my_log2); hook(&eph, getpid(), "libc.", "epoll_wait", my_epoll_wait, );
}

同前面的分析,my_init函数由于带有 __attribute__ ((constructor)) 修饰,smsdispatch.so 被目标进程加载后自动执行my_init, 该函数执行hook操作,挂钩目标进程的 libc.so 的 epoll_wait 函数。其实这里可以直接执行 dalvik 的挂钩的。

static int my_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
{
int (*orig_epoll_wait)(int epfd, struct epoll_event *events, int maxevents, int timeout);
orig_epoll_wait = (void*)eph.orig;
// remove hook for epoll_wait
hook_precall(&eph); // resolve symbols from DVM
dexstuff_resolv_dvm(&d); // hook
dalvik_hook_setup(&dpdu, "Lcom/android/internal/telephony/SMSDispatcher;", "dispatchPdus", "([[B)V", , my_dispatch);
dalvik_hook(&d, &dpdu); // call original function
int res = orig_epoll_wait(epfd, events, maxevents, timeout);
return res;
}

目标进程epoll_wait被调用的时候,实际执行的是  my_epoll_wait , 这个函数与之前的例子相比,增加了 dexstuff_resolv_dvm、 dalvik_hook_setup、 dalvik_hook 三个函数,即执行了 dalvik的挂钩操作,被挂钩的是  com/android/internal/telephony/SMSDispatcher 类的  dispatchPdus 函数,挂成了 my_dispatch 函数。其实这几句可以直接放到  my_init 里,当so被注入时直接执行的。涉及到几个数据结构:

static struct dexstuff_t d;
static struct dalvik_hook_t dpdu;
struct dalvik_hook_t
{
char clname[];
char clnamep[];
char method_name[];
char method_sig[]; Method *method;
int sm; // static method // original values, saved before patching
int iss;
int rss;
int oss;
int access_flags;
void *insns; // dalvik code // native values
int n_iss; // == n_rss
int n_rss; // num argument (+ 1, if non-static method)
int n_oss; //
void *native_func; int af; // access flags modifier int resolvm; // for the call
jclass cls;
jmethodID mid; // debug stuff
int dump; // call dvmDumpClass() while patching
int debug_me; // print debug while operating on this method
};
struct dalvik_hook_t 结构描述了一次dalvik hook操作需要记录的信息,包括被挂钩的java函数和用于挂钩的java 函数的信息。其中, Method *method; 成员指向被挂钩java函数的Method结构体,通过动态替换这个指针指向的结构体内部成员的值,可以影响该java函数(一个java函数其实就是一个 Method 结构体,包括真实执行的native 函数地址及其他描述信息)。
struct dexstuff_t
{
void *dvm_hand; dvmCreateStringFromCstr_func dvmStringFromCStr_fnPtr;
dvmGetSystemClassLoader_func dvmGetSystemClassLoader_fnPtr;
dvmThreadSelf_func dvmThreadSelf_fnPtr; dvmIsClassInitialized_func dvmIsClassInitialized_fnPtr;
dvmInitClass_func dvmInitClass_fnPtr;
dvmFindVirtualMethodHierByDescriptor_func dvmFindVirtualMethodHierByDescriptor_fnPtr;
dvmFindDirectMethodByDescriptor_func dvmFindDirectMethodByDescriptor_fnPtr;
dvmIsStaticMethod_func dvmIsStaticMethod_fnPtr;
dvmAllocObject_func dvmAllocObject_fnPtr;
dvmCallMethodV_func dvmCallMethodV_fnPtr;
dvmCallMethodA_func dvmCallMethodA_fnPtr;
dvmAddToReferenceTable_func dvmAddToReferenceTable_fnPtr;
dvmDecodeIndirectRef_func dvmDecodeIndirectRef_fnPtr;
dvmUseJNIBridge_func dvmUseJNIBridge_fnPtr;
dvmFindInstanceField_func dvmFindInstanceField_fnPtr;
dvmFindLoadedClass_func dvmFindLoadedClass_fnPtr;
dvmDumpAllClasses_func dvmDumpAllClasses_fnPtr; dvmGetCurrentJNIMethod_func dvmGetCurrentJNIMethod_fnPtr;
dvmLinearSetReadWrite_func dvmLinearSetReadWrite_fnPtr; dvmSetNativeFunc_func dvmSetNativeFunc_fnPtr;
dvmCallJNIMethod_func dvmCallJNIMethod_fnPtr; dvmHashTableLock_func dvmHashTableLock_fnPtr;
dvmHashTableUnlock_func dvmHashTableUnlock_fnPtr;
dvmHashForeach_func dvmHashForeach_fnPtr; dvmDumpClass_func dvmDumpClass_fnPtr;
dvmInstanceof_func dvmInstanceof_fnPtr; DalvikNativeMethod *dvm_dalvik_system_DexFile;
DalvikNativeMethod *dvm_java_lang_Class; void *gDvm; // dvm globals ! int done;
};
struct dexstuff_t 结构体包含了dalvik 虚拟机的重要的函数指针,这些函数指针的值从libdvm.so动态库里获取,有了这些指针,就可以在 native 环境里操纵java世界(比如加载类,生成对象,调用java函数,设置java类或函数属性等等),dexstuff_resolv_dvm 函数干的事情就是加载 libdvm.so 动态库并填充 dexstuff_t 结构体。

int dalvik_hook_setup(struct dalvik_hook_t *h, char *cls, char *meth, char *sig, int ns, void *func)
{
if (!h)
return ; strcpy(h->clname, cls);
strncpy(h->clnamep, cls+, strlen(cls)-);
strcpy(h->method_name, meth);
strcpy(h->method_sig, sig);
h->n_iss = ns;
h->n_rss = ns;
h->n_oss = ;
h->native_func = func; h->sm = ; // set by hand if needed h->af = 0x0100; // native, modify by hand if needed h->resolvm = ; // don't resolve method on-the-fly, change by hand if needed h->debug_me = ; return ;
}
dalvik_hook_setup 做dalvik函数挂钩的准备工作,包括把目标类和目标函数的名字保存下来,把用于挂钩的native 函数的地址保存下来,设置 dalvik_hook_t 结构对象的初始值等。 

int dalvik_hook_setup(struct dalvik_hook_t *h, char *cls, char *meth, char *sig, int ns, void *func)
{ strcpy(h->method_name, meth);
strcpy(h->method_sig, sig);
h->n_iss = ns;
h->n_rss = ns;
h->n_oss = ;
h->native_func = func; h->sm = ; // set by hand if needed h->af = 0x0100; // native, modify by hand if needed h->resolvm = ; // don't resolve method on-the-fly, change by hand if needed h->debug_me = ; return ;
}
{
if (h->debug_me)
log("dalvik_hook: class %s\n", h->clname) void *target_cls = dex->dvmFindLoadedClass_fnPtr(h->clname);
if (h->debug_me)
log("class = 0x%x\n", target_cls) // print class in logcat
if (h->dump && dex && target_cls)
dex->dvmDumpClass_fnPtr(target_cls, (void*)); if (!target_cls) {
if (h->debug_me)
log("target_cls == 0\n")
return (void*);
} if (h->method == ) {
} // constrcutor workaround, see "dalvik_prepare" below
if (!h->resolvm) {
h->cls = target_cls;
h->mid = (void*)h->method;
} if (h->debug_me)
log("%s(%s) = 0x%x\n", h->method_name, h->method_sig, h->method) if (h->method) {
h->insns = h->method->insns; if (h->debug_me) {
log("nativeFunc %x\n", h->method->nativeFunc) } 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; if (h->debug_me) {
log("shorty %s\n", h->method->shorty)
log("name %s\n", h->method->name)
log("arginfo %x\n", h->method->jniArgInfo)
}
h->method->jniArgInfo = 0x80000000; // <--- also important
if (h->debug_me) {
log("noref %c\n", h->method->noRef)
log("access %x\n", h->method->a)
}
h->access_flags = h->method->a;
h->method->a = h->method->a | h->af; // make method native
if (h->debug_me)
log("access %x\n", h->method->a) dex->dvmUseJNIBridge_fnPtr(h->method, h->native_func); if (h->debug_me)
log("patched %s to: 0x%x\n", h->method_name, h->native_func) return (void*);
}
else {
if (h->debug_me)
log("could NOT patch %s\n", h->method_name)
} return (void*);
}

dalvik_hook 函数实现dalvik函数挂钩。分为几步:

step1, void *target_cls = dex->dvmFindLoadedClass_fnPtr(h->clname);  调用 dvmFindLoadedClass_fnPtr 函数获取目标类在虚拟机内部的指针,dvmFindLoadedClass_fnPtr这个函数是

dexstuff_resolv_dvm  获取的。
step2, h->method = dex->dvmFindVirtualMethodHierByDescriptor_fnPtr(target_cls, h->method_name, h->method_sig); 根据函数名获取目标dalvik函数对象指针
step3,
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;

保存目标Dalvik 函数寄存器环境,设置新的寄存器环境

step4,

                h->method->jniArgInfo = 0x80000000; // <--- also important
h->access_flags = h->method->a;
h->method->a = h->method->a | h->af; // make method native
dex->dvmUseJNIBridge_fnPtr(h->method, h->native_func);

设置目标函数对象类型 access_flags 为 native ,并通过  dvmUseJNIBridge_fnPtr 函数将挂钩函数 h->native_func 设置为目标dalvik 函数对象真正执行的函数。这一步之后,虚拟机内部执行到目标java函数时,就会调用到 native 函数  my_dispatch,挂钩已经完成。

static void my_dispatch(JNIEnv *env, jobject obj, jobjectArray pdu)
{
// load dex classes
int cookie = dexstuff_loaddex(&d, "/data/local/tmp/ddiclasses.dex");
log("libsmsdispatch: loaddex res = %x\n", cookie)
if (!cookie)
log("libsmsdispatch: make sure /data/dalvik-cache/ is world writable and delete data@local@tmp@ddiclasses.dex\n")
void *clazz = dexstuff_defineclass(&d, "org/mulliner/ddiexample/SMSDispatch", cookie);
log("libsmsdispatch: clazz = 0x%x\n", clazz) // call constructor and passin the pdu
jclass smsd = (*env)->FindClass(env, "org/mulliner/ddiexample/SMSDispatch");
jmethodID constructor = (*env)->GetMethodID(env, smsd, "<init>", "([[B)V");
if (constructor) {
jvalue args[];
args[].l = pdu; jobject obj = (*env)->NewObjectA(env, smsd, constructor, args);
log("libsmsdispatch: new obj = 0x%x\n", obj) if (!obj)
log("libsmsdispatch: failed to create smsdispatch class, FATAL!\n")
}
else {
log("libsmsdispatch: constructor not found!\n")
} // call original SMS dispatch method
jvalue args[];
args[].l = pdu;
dalvik_prepare(&d, &dpdu, env);
(*env)->CallVoidMethodA(env, obj, dpdu.mid, args);
log("success calling : %s\n", dpdu.method_name)
dalvik_postcall(&d, &dpdu);
}
my_dispatch 函数分几步,
step1, 加载我们自定义的 SMSDispatch dex 文件,dexstuff_defineclass 函数实现了这个过程
step2, 调用 JNIEnv 的 FindClass和GetMethodID函数,搜寻到step1加载的dex文件里的 SMSDispatch 类的构造函数, 再调用 NewObjectA 函数在目标 JNIEnv 环境里生成一个 SMSDispatch 实例
step3, 先调用 dalvik_prepare 函数将前面 hook 的函数回退,这样接下去自定义的 SMSDispatch 类可以执行真正的 com/android/internal/telephony/SMSDispatcher 类的 dispatchPdus 函数
step4, 调用 JNIEnv 的 CallVoidMethodA 函数,执行自定义的 SMSDispatch 类的函数
step5, 再调用 dalvik_postcall 函数恢复对 com/android/internal/telephony/SMSDispatcher 类的 dispatchPdus 函数的挂载
int dalvik_prepare(struct dexstuff_t *dex, struct dalvik_hook_t *h, JNIEnv *env)
{ // this seems to crash when hooking "constructors" if (h->resolvm) {
h->cls = (*env)->FindClass(env, h->clnamep);
if (h->debug_me)
log("cls = 0x%x\n", h->cls)
if (!h->cls)
return ;
if (h->sm)
h->mid = (*env)->GetStaticMethodID(env, h->cls, h->method_name, h->method_sig);
else
h->mid = (*env)->GetMethodID(env, h->cls, h->method_name, h->method_sig);
if (h->debug_me)
log("mid = 0x%x\n", h-> mid)
if (!h->mid)
return ;
} h->method->insSize = h->iss;
h->method->registersSize = h->rss;
h->method->outsSize = h->oss;
h->method->a = h->access_flags;
h->method->jniArgInfo = ;
h->method->insns = h->insns;
}
dalvik_prepare 函数比较简单,将 dalvik_hook_t  保存的寄存器值、Method access_flags 标记、 insns 函数指针重新赋值回去,即恢复到了挂钩之前的状态
void dalvik_postcall(struct dexstuff_t *dex, struct dalvik_hook_t *h)
{
h->method->insSize = h->n_iss;
h->method->registersSize = h->n_rss;
h->method->outsSize = h->n_oss; //log("shorty %s\n", h->method->shorty)
//log("name %s\n", h->method->name)
//log("arginfo %x\n", h->method->jniArgInfo)
h->method->jniArgInfo = 0x80000000;
//log("noref %c\n", h->method->noRef)
//log("access %x\n", h->method->a)
h->access_flags = h->method->a;
h->method->a = h->method->a | h->af;
//log("access %x\n", h->method->a) dex->dvmUseJNIBridge_fnPtr(h->method, h->native_func); if (h->debug_me)
log("patched BACK %s to: 0x%x\n", h->method_name, h->native_func)
}
dalvik_postcall 函数跟 dalvik_hook 函数后半部分一致,通过对目标 Method 对象的成员进行赋值实现挂钩
												

android hook 框架 ADBI 如何实现dalvik函数挂钩的更多相关文章

  1. android hook 框架 ADBI 如何实现so函数挂钩

    上一篇 android 5 HOOK 技术研究之 ADBI 项目 02 分析了hijack.c, 这个文件编译为一个可执行程序 hijack, 该程序实现了向目标进程注入一个动态库的功能.这一篇继续研 ...

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

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

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

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

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

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

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

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

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

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

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

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

  8. Android Hook框架adbi源码浅析(二)

    二.libbase 其实上面加载完SO库后,hook的功能我们完全可以自己在动态库中实现.而adbi作者为了方便我们使用,编写了一个通用的hook框架工具即libbase库.libbase依然在解决两 ...

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

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

随机推荐

  1. Nginx安装,目录结构与配置文件详解

    1.Nginx简介 Nginx(发音同 engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.由俄罗斯的程序设 ...

  2. P2183 巧克力(二分答案)

    P2183 巧克力 题目描述 佳佳邀请了M个同学到家里玩.为了招待客人,她需要将巧克力分给她的好朋友们.她有N(1<=N<=5000)块巧克力,但是大小各不一样,第i块巧克力大小为为1*X ...

  3. linux中如何解决克隆后的电脑的问题

    1.如何解决克隆后的电脑的网络问题 克隆出来的电脑,IP地址,网卡都是重复的,不能直接使用,需要修改 1)vim  /etc/udev/rules.d/70-persistent-net.rules ...

  4. 安装完最小化 RHEL/CentOS 7 后需要做的 30 件事情(一)

    本文导航 -1. 注册并启用红帽订阅 -2. 使用静态 IP 地址配置网络 -3. 设置服务器的主机名称 -4. 更新或升级最小化安装的 CentOS -5. 安装命令行 Web 浏览器 -6. 安装 ...

  5. centos使用--supervisor使用

    目录 1 下载程序并安装 2 编辑配置文件 3 supervisor的使用 4 配置文件详细解析 参考资料 supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变 ...

  6. 《Cracking the Coding Interview》——第17章:普通题——题目11

    2014-04-29 00:00 题目:给定一个rand5()函数,能够返回0~4间的随机整数.要求实现rand7(),返回0~6之间的随机整数.该函数产生随机数必须概率相等. 解法:自己想了半天没想 ...

  7. Pythontutor:可视化代码在内存的执行过程

    http://www.pythontutor.com/visualize.html今天去问开发一个Python浅拷贝的问题,开发给了一个神器,可以可视化代码在内存的执行过程,一看即懂,太NB了!~真是 ...

  8. NGUI-为Popuplist的下拉选项添加删除功能

    NGUI例子里的popuplist是这样的:,但有时我们希望下拉选项都有删除功能,也就是这样:,一种方法是改popuplist的源码,我想这个实现起来不难,但现在我想说的是用反射来实现此功能,以及其他 ...

  9. (原)Unreal渲染模块 管线 - 着色器(1)

    @author: 白袍小道 转载悄悄说明下 随缘查看,施主开心就好 说明: 本篇继续Unreal搬山部分的渲染模块的Shader部分, 主要牵扯模块RenderCore, ShaderCore, RH ...

  10. CodeForces-999D Equalize the Remainders

    题目链接 https://vjudge.net/problem/CodeForces-999D 题面 Description You are given an array consisting of ...