继续

于《两》通过专门出台ptrace实施注射的技术解决方案,在这一章,我就为大家介绍一Android在独特的喷射技术,我点了他的名字——Component Injection。顾名思义。这种方法是现在Android相关组件,具体见以下的说明。


Component Injection

原理

在android的开发人员文档里。对android:process的描写叙述是这种:

android:process


The name of a process where all components of the application should run. Each component can override this default by setting its own process attribute.
By default, Android creates a process for an application when the first of its components needs to run. All components then run in that process. The name of the default process matches the package name set by the <manifest> element.

By setting this attribute to a process name that's shared with another application, you can arrange for components of both applications to run in the same process — but only if the two applications also share a user ID and be signed
with the same certificate.

If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed. If the process name begins with a lowercase character, a global process of that name is created. A global process can be
shared with other applications, reducing resource usage.

从描写叙述上能够发现,当两个应用。它们签名同样且具备同样的shareduserID,它们之间仅仅有一个组件的android:process是同样的,那么这两个组件之间的互动能够发生在同一个进程里。这里所说的同一个进程。事实上就是进程注入的效果的了。

演示样例二

演示样例二相同包括两部分代码。各自是com.demo.host和com.demo.inject,它们的代码都很easy,例如以下所看到的:

com.demo.host

先看看host的manifest.xml的配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.demo.host"
android:sharedUserId="com.demo"
android:versionCode="1"
android:versionName="1.0" > <application
android:name=".DemoApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:process="com.demo"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="9" /> </manifest>

关键代码

package com.demo.host;

import android.app.Activity;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log; /**
*
* @author boyliang
*
*/
public final class MainActivity extends Activity {
private static int sA = 1; public static void setA(int a) {
sA = a;
} public static int getA() {
return sA;
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://demo_contentprovider");
resolver.query(uri, null, null, null, null); new Thread() { public void run() {
while (true) {
Log.i("TTT", "" + getA());
setA(getA() + 1); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}; }.start();
}
}

host一启动,就立即调用ContentResolver的query,这个正是Inject里的ContentProvider组件。


com.demo.inject

manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.demo.inject"
android:sharedUserId="com.demo"
android:versionCode="1"
android:versionName="1.0" > <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:process="com.demo"
android:theme="@style/AppTheme" > <provider
android:name=".DemoContentProvider"
android:authorities="demo_contentprovider"
android:exported="false" /> </application> <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="9" /> </manifest>

关键代码

<span style="white-space:pre">	</span>@Override
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) { final Timer timer = new Timer("demo");
timer.schedule(new TimerTask() { @Override
public void run() {
try {
Log.i("TTT", ">>>>>>>>>>>>>I am in, I am a bad boy!!!!<<<<<<<<<<<<<<\n");
//Class<?> MainActivity_class = Class.forName("com.demo.host.MainActivity");
Context context = ContexHunter.getContext();
ClassLoader classloader = context.getClass().getClassLoader();
Class<?> MainActivity_class = classloader.loadClass("com.demo.host.MainActivity");
Method setA_method = MainActivity_class.getDeclaredMethod("setA", int.class);
setA_method.invoke(null, 998);
} catch (Exception e) {
e.printStackTrace();
} timer.cancel();
} }, 5000); return null;
}

inject中,当query被调用后。会等待5s,然后通过反射调用host的MainActivity.setA方法,改动打印的数值。


绕过ClassLoader双亲托付

细心的朋友会发现,inject的代码中。获取MainActivity的Class。并非直接通过Class.forName("com.demo.host.MainActivity")获取到,而是先获取到全局Context(即Application对象)。然后再调用其ClassLoader来间接获取得的。为什么要这样呢?我我们知道,Java中每一个class都是通过双亲托付机制载入的,这方面的内容能够參考http://blog.csdn.net/xyang81/article/details/7292380,以下我画出示意图:


当我们尝试在DemoContentProvider通过Class.forNmae寻找MainActivity时,必定会抛ClassNotFoundException。唯一可行的方案是找到host的PathClassLoader,然后通过这个ClassLoader寻找MainActivity。我们须要寻找的变量须要满足例如以下条件:

  • 这个变量必须由host产生的;
  • 这个变量必须是全局的,并且其引用会保存在BootClassLoader(也就是Android SDK中的某个引用)。
  • 能够通过反射机制读取到;
非常自然的,想到了host的Application对象。

通过阅读源代码。发现能够通过以下的方式读取到Application对象:

  • 假设是System_Process。能够通过例如以下方式获取
Context context = ActivityThread.mSystemContext
  • 假设是非System_Process(即普通的Android进程)。能够通过例如以下方式获取
Context context = ((ApplicationThread)RuntimeInit.getApplicationObject()).app_obj.this$0

输出

理解了上述的原理之后,我们再看看演示样例的输出:
I/TTT     (  633): com.demo.inject starts.
I/TTT ( 633): com.demo.host starts
I/TTT ( 633): 1
I/TTT ( 633): 2
I/TTT ( 633): 3
I/TTT ( 633): 4
I/TTT ( 633): 5
I/TTT ( 633): >>>>>>>>>>>>>I am in, I am a bad boy!!!!<<<<<<<<<<<<<<
I/TTT ( 633): 998
I/TTT ( 633): 999
I/TTT ( 633): 1000
I/TTT ( 633): 1001
I/TTT ( 633): 1002
I/TTT ( 633): 1003

从前二行就能够看出,这两个组件都是执行在同一个进程的。从第5秒開始。打印的数据開始发生变化,证明我们的注入逻辑生效了。

文中的演示样例代码。大家能够到https://github.com/boyliang/Component_Injection下载

最后

ComponentInjection的优点是不须要ROOT权限,但其使用限制或许多。但假设跟MaskterKey漏洞结合起来用,那效果还是相当惊艳的。我们知道。Zygote进程会接收来自system_process的命令,当中比較关键的信息有uid, gid, gids, classpath, runtime-init等等。这些信息是决定了Zygote子进程的载入容器以及所从属的uid。

通过MasterKey漏洞我们能够伪造系统的Setting包。Setting与system_process的配置正好符合我所说的ComponentInjection条件,因此利用这样的方式。能够注入到system_process进程,进而控制传递给Zygote的參数。当中classpath和runtime-init是载入容器的配置,classpath是指向一个dex文件的路径,runtime-init是其main函数所在的类名,通过指定每一个App的载入容器。就能够非常巧妙的控制了全部普通用户的进程的环境。


LBE 以前就是利用这样的技术实现主动防御的。更具体的介绍可訪问http://safe.baidu.com/2013-10/lbe-root.html。只是这个文章分析得并不到位。最关键的环节即ComponentInjection并没有提及,结合的我分享。算是做一个完美的补充吧。

这一章节里。介绍了一种Android特有的注入技术,通过一些小技巧绕过了Java的双父托付机制。并且找到了能够轻松找到Application对象的方法,这个对象在Android开发中能够是至关重要的。在接下来的《四》里,我会具体介绍怎样利用JNI获取JNIEnv指针,再通过JNI找到DexCloassLoader载入中DEX档。

版权声明:本文博主原创文章,博客,未经同意不得转载。

先锋军Android注射技术《三》的更多相关文章

  1. Android动画 三种动画

    Android可以使用三种动画 Frame Animation-帧动画 ,就像GIF图片,通过一系列Drawable依次显示来模拟动画的效果 Tween Animation-补间动画,给出两个关键帧, ...

  2. 【转】Android LCD(三):Samsung LCD接口篇

    关键词:android LCD控制器 Framebuffer PWM  平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:samsung exynos ...

  3. 【转】android camera(三):camera V4L2 FIMC

    关键词:android  camera CMM 模组 camera参数  CAMIF   V4L2  平台信息:内核:linux系统:android 平台:S5PV310(samsung exynos ...

  4. Android LCD(三):Samsung LCD接口篇

    关键词:android LCD控制器 Framebuffer PWM  平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0  平台:samsung exy ...

  5. Android中三种超实用的滑屏方式汇总(转载)

    Android中三种超实用的滑屏方式汇总   现如今主流的Android应用中,都少不了左右滑动滚屏这项功能,(貌似现在好多人使用智能机都习惯性的有事没事的左右滑屏,也不知道在干什么...嘿嘿),由于 ...

  6. Android Studio(三):设置Android Studio编码

    Android Studio相关博客: Android Studio(一):介绍.安装.配置 Android Studio(二):快捷键设置.插件安装 Android Studio(三):设置Andr ...

  7. 我的Android第三章

    先看效果图. 点击之后出变成 按钮内容改变了,并且弹出一个小提示 下面我们就来看看如何实现这个小案例 1)先打开string.xml文件,把要定义的字符串资源放置在里面 2)然后我们要画页面,基本An ...

  8. Android入门(三)Activity-生命周期与启动模式

    原文链接:http://www.orlion.ga/432/ 一.活动的生命周期 1.返回栈 Android中的活动是可以重叠的,我们每启动一个新的活动,就会覆盖在原活动之上,然后点击Back键会销毁 ...

  9. 修正 XE5 Android 键盘三个问题

    说明:XE5 在 Android 平台上存在这一些键盘操作的问题,目前发现有下列几种: 按键盘上的隐藏键后,无法按上一页(需要修改 XE5 源码「FMX.VirtualKeyboard.Android ...

随机推荐

  1. NET MVC异常处理模块

    一个简单的ASP.NET MVC异常处理模块   一.前言 异常处理是每个系统必不可少的一个重要部分,它可以让我们的程序在发生错误时友好地提示.记录错误信息,更重要的是不破坏正常的数据和影响系统运行. ...

  2. Left Menu抽屉效果ScrollView姿态共存冲突

    我们有一个小项目,需要做主页ScrollView嵌套TableView. 再就是Left与Right抽屉效果. 课前有眼似的,然后完成忘. 非常糟糕的记忆.真应了那句话:好记性不如烂博客. 由于我首页 ...

  3. Java调用Lua(转)

    Java 调用 Lua app发版成本高,覆盖速度慢,覆盖率页低.一些策略上的东西如果能够从服务端控制会方便一些.所以考虑使用Lua这种嵌入式语言作为策略实现,Java则是宿主语言. 总体上看是一个模 ...

  4. 【NO.3】 c program to caculate and display sum of two matrix

    source code: #include "stdafx.h" /* display sum of two matrix*/ int _tmain(int argc, _TCHA ...

  5. Visual Studio 2010 将网站直接发布到远程站点

    原文:Visual Studio 2010 将网站直接发布到远程站点 这次说下如何将web应用程序直接发布到IIS服务器站点!!! 问题的由来 本人每天要发布更新的程序,所以每次更新的时候要做的工作: ...

  6. atitit.设计模式(2) -----查询方式/ command 总结

    atitit.设计模式(2) -----查询方式/ command 总结 1. 应用场景: 1 1. 代替一瓦if else 1 2. 建设api rpc风格的时候儿. 1 3. 菜单是Command ...

  7. 辛星和你解读PHP递归

    事实上递归成其他的编程语言可以是初学者练习功能,但由于PHP特殊性,我们把它拿出来具体解释什么.关于什么是递归先说说.我是第一个承认正在寻求一些递归阶乘,例如,我们写一个函数,然后问多少的阶乘. 看以 ...

  8. 解决Nginx的connect() to 127.0.0.1:8080 failed (13: Permission denied) while connect

    在进行Nginx+Tomcat 负载均衡的时候遇到了这个权限问题,在error.log日志中.我们能够看到例如以下: connect() to 127.0.0.1:8080 failed (13: P ...

  9. Android 深入解析光传感器(二)

    光线传感器演示1        讲了一大堆的理论,那么以下的样例就来展示一下光线感应器的使用.为什么充分展现光感的用法,我这个样例写的很easy,仅仅写了使用光感必须的代码,然后用了几个textVie ...

  10. [LeetCode217]Contains Duplicate

    题目:Given an array of integers, find if the array contains any duplicates. Your function should retur ...