首先简单介绍一下进程注入的概念:
进程注入就是将一段代码拷贝到目标进程,然后让目标进程执行这段代码的技术。由于这样的代码构造起来比较复杂,所以实际情况下,只将很少的代码注入到目标进程,而将真正做事的代码放到一个共享库中,即.so文件。被注入的那段代码只负责加载这个.so,并执行里面的函数。
由于.so中的函数是在目标进程中执行的,所以在.so中的函数可以修改目标进程空间的任何内存,当然也可以加钩子,从而达到改变目标进程工作机制的目的。
当然不是任何进程都有权限执行注入操作的。Android平台上的进程注入是基于ptrace()的,要调用ptrace()需要有root权限。目前市面上的主流安全软件也都是基于进程注入来管理和控制其他应用进程的。这也就是为什么这些安全软件需要获得root权限的原因。
关于如何.so注入的实现,有兴趣的朋友可以参考看雪论坛的上的一个注入库 LibInject http://bbs.pediy.com/showthread.php?t=141355
和洗大师的一个开源项目 Android Injector Library。 http://code.google.com/p/libandroidinjector/downloads/list
.so注入以后已经可以干很多事情了,但毕竟是在native层。想要在native层直接修改Java层的变量和逻辑还是很不方便的。况且Android平台的绝大多数应用都是用Java代码写的。因此自然而然就会想到,有没有什么方式可以将dex文件注入目标进程,然后执行dex文件中的Java代码?

经过一段时间的研究,笔者找到了一个切实可行的方法。这里分享给大家:首先,所有的Java类都是由类加载器(ClassLoader)加载的,我们要从特定的路径下加载一个我们自己的dex文件,就必须要有一个自己类加载器才行。有了这个类加载器我们就可以加载我们自己的类,并用反射调用这个类里面的方法。其次,要构造生成这样一个类加载器必须要获得现有的类加载器,因为类加载器是双亲委派模式的。现有的类加载器可以通过反射获得。只是这些都需要用native代码实现。
下面简述一下dex注入的过程:
1. 将.so注入目标进程,执行.so文件中的某个函数。
2. 在这个函数里先获得一个JNIEnv指针,通过这个指针就可以调JNI函数了。
3. 反射得到当前应用进程的PathClassLoader,用这个ClassLoader来构造一个DexClassLoader对象。Dex文件路径作为一个参数传入DexClassLoader的构造函数,另一个重要的参数是,一个具有可写权限的文件夹路径。因为在做dex优化时,需要生成优化过的dex文件,这跟生成/data/dalvik-cache/下的dex文件是一个道理。
4. 通过这个DexClassLoader对象,来加载目标类,然后反射目标类中的目标函数。最终调用之。

参考代码:

//功能:调用dexPath文件中的className类的methodName方法。
//dexPath: dex/jar/apk 文件路径
//dexOptDir: 优化目录, 这个目录的owner必须是要被注入进程的user,否则dex优化会失败
//className: 目标类名,如“com.hook.Test”
//methodName: 目标方法名,如"main", 在Java代码里必须定义为public static void main(String[] args);
//argc,传给目标方法的参数个数
//argv,传给目标方法的参数
int invoke_dex_method(const char* dexPath, const char* dexOptDir, const char* className, const char* methodName, int argc, char *argv[]) {
ALOGD("Invoke dex E");
JNIEnv* env = android::AndroidRuntime::getJNIEnv();
jclass stringClass, classLoaderClass, dexClassLoaderClass, targetClass;
jmethodID getSystemClassLoaderMethod, dexClassLoaderContructor, loadClassMethod, targetMethod;
jobject systemClassLoaderObject, dexClassLoaderObject;
jstring dexPathString, dexOptDirString, classNameString, tmpString;
jobjectArray stringArray;
/* Get SystemClasLoader */
stringClass = env->FindClass("java/lang/String");
classLoaderClass = env->FindClass("java/lang/ClassLoader");
dexClassLoaderClass = env->FindClass("dalvik/system/DexClassLoader");
getSystemClassLoaderMethod = env->GetStaticMethodID(classLoaderClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
systemClassLoaderObject = env->CallStaticObjectMethod(classLoaderClass, getSystemClassLoaderMethod);
/* Create DexClassLoader */
dexClassLoaderContructor = env->GetMethodID(dexClassLoaderClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
dexPathString = env->NewStringUTF(dexPath);
dexOptDirString = env->NewStringUTF(dexOptDir);
dexClassLoaderObject = env->NewObject(dexClassLoaderClass, dexClassLoaderContructor, dexPathString, dexOptDirString, NULL, systemClassLoaderObject);
/* Use DexClassLoader to load target class */
loadClassMethod = env->GetMethodID(dexClassLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
classNameString = env->NewStringUTF(className);
targetClass = (jclass)env->CallObjectMethod(dexClassLoaderObject, loadClassMethod, classNameString);
if (!targetClass) {
ALOGE("Failed to load target class %s", className);
return -1;
}
/* Invoke target method */
targetMethod = env->GetStaticMethodID(targetClass, methodName, "([Ljava/lang/String;)V");
if (!targetMethod) {
ALOGE("Failed to load target method %s", methodName);
return -1;
}
stringArray = env->NewObjectArray(argc, stringClass, NULL);
for (int i = 0; i < argc; i++) {
tmpString = env->NewStringUTF(argv[i]);
env->SetObjectArrayElement(stringArray, i, tmpString);
}
env->CallStaticVoidMethod(targetClass, targetMethod, stringArray);
ALOGD("Invoke dex X");
return 0;
}

java代码(dex)注入相关推荐

  1. java 代码执行el,专属于java的漏洞——EL表达式注入

    前言"FSRC经验分享"系列文章,旨在分享焦点科技信息安全部工作过程中的经验总结,包括但不限于漏洞分析.运营技巧.sdl推行.等保合规.自研工具等等. 欢迎各位安全从业者持续关注~ ...

  2. java代码防止sql注入_动态Java代码注入

    java代码防止sql注入 在本文中,我们将研究如何将Java代码动态加载到正在运行的jvm中. 该代码可能是全新的,或者我们可能想更改程序中某些现有代码的功能. (在开始之前,您可能想知道为什么到底 ...

  3. 动态Java代码注入

    在本文中,我们将研究如何将Java代码动态加载到正在运行的jvm中. 该代码可能是全新的,或者我们可能想更改程序中某些现有代码的功能. (在开始之前,您可能想知道为什么到底有人会这样做.显而易见的示例 ...

  4. JDK9,像Unix脚本一样执行Java代码

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 现在你多少听说一些JDK9 JShell相关的内容,这篇文章中将介 ...

  5. 如何避免JSP文件中的Java代码?

    本文翻译自:How to avoid Java code in JSP files? I'm new to Java EE and I know that something like the fol ...

  6. java代码编译之后是如何运行的?不知道这些,面试官问你jvm问题,你只能懵圈

    目录 从机器语言->汇编语言->高级语言 JVM的整体结构 java代码执行流程 java虚拟机种类(常用的就是HotSpot) 从机器语言->汇编语言->高级语言 计算机系统 ...

  7. springMVC纯java代码配置(一)- 数据源与事务管理(转载的哦)

    原文地址:http://my.oschina.net/devleon/blog/530803?fromerr=9Z8ZFdbf 摘要 自Spring3.0开 始,Spring正式将JavaConfig ...

  8. 通过Java代码装配bean

    向着某一天终于要达到的那个终极目标迈步还不够,还要把每一步骤看成目标,使它作为步骤而起作用. --歌德 很多场景下我们都可以通过Spring组件扫描和自动装配的方式来装配bean,但是在部分情况下,如 ...

  9. 怎么才能学好Java编程写好Java代码?

    动力节点Java培训最新上线Java实验班,等你来测试自己适不适合学习Java编程哦! 刚刚接触Java编程的朋友总会遇到一些情况,比如:跟着Java基础教程看过一遍后,自己写代码的时候却无从下手:写 ...

最新文章

  1. linux内核 semaphore,2.4内核里semaphore源码的一个疑问
  2. 为什么css一开始需要设定margin和padding为 0px?
  3. 你不知道的Javascript之原型
  4. 如何通过Graph+AI的方法打造高精度风控模型?
  5. 浏览器中的JavaFX
  6. 怎么在html中加入pjax,pjax加载多说的三种方法
  7. 数据爆发式增长下,CIO不可不知的“数据经济学”
  8. idea的英文是什么意思_德芙和多芬的英文都是Dove!“Dove”究竟是什么意思?
  9. Python开发——安装requests第三方库
  10. 运行 lighttrack 遇到错误和解决方法
  11. python:python对象属性及属性函数property()
  12. 【转】GBK编码表和GBK编码规范
  13. Aboutface3交互设计精髓笔记0001
  14. win10系统崩溃(UNEXPECTED_STORE_EXCEPTION)解决方法
  15. 一个心理医生和一个心理不正常的小孩的冷笑话
  16. onion spring_英语里的葱不都是Onion
  17. java数据爬取_java爬虫,爬取当当网数据
  18. 微信小程序-模板与配置
  19. MQTT Web Toolkit - MQTT 在线测试工具正式发布
  20. adb shell获取root权限

热门文章

  1. 在线项目管理软件推荐
  2. 谷歌某程序员抱怨“招人难”:招了小半年,8个岗位才招到1个,现在又空出6个岗位!...
  3. 字节跳动终于宣布取消大小周,字节员工却一片哀嚎!
  4. 图解 | 搞定分布式,程序员进阶之路
  5. 太尴尬!百度某程序员向领导请假去面试,却在面试一楼大厅和领导相遇,网友:缘分啊!回去一起对对面试题!...
  6. Java并发必知必会第三弹:用积木讲解ABA原理
  7. 2次转管理失败后,我对项目、团队、敏捷转型的新认知
  8. 滴滴ElasticSearch平台跨版本升级以及平台重构之路
  9. 【基础巩固篇】Java 8中对CAS的优化
  10. 详解分布式系统与消息投递