继续

于《两》通过专门出台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. 用JavaScript实现网页动态水印

    1.基本原理 页面加载后,通过javascript创建页面元素div,并在div元素中创建文本节点,展示水印内容 设置div元素样式,将其zIndex设置一个较高的值,并设置透明度,实现浮在页面的水印 ...

  2. hdu3873 有约束条件的最短路

    题目大意:美国佬打算入侵火星,火星上有n个城市,有些城市可能受其他城市保护, 如果i城市受j城市保护,那么你必须先攻占j城市才能再攻占i城市,问你攻占城市n的最短时间是多少. 数据解释: 给定t, 表 ...

  3. 轻量级分布式RPC框架

    随笔- 139  文章- 0  评论- 387  一个轻量级分布式RPC框架--NettyRpc   1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 ...

  4. Jetty安装学习并展示

    Jetty 的基本架构 Jetty 眼下的是一个比較被看好的 Servlet 引擎,它的架构比較简单,也是一个可扩展性和很灵活的应用server,它有一个基本数据模型,这个数据模型就是 Handler ...

  5. iOS开展-Xcode技巧总结(持续更新)

    1. <LLDB调试命令初探> 2. <Xcode LLDB Debug教程> 3. <iOS开发准备篇-(5)Xcode调试技巧_1> 4. <iOS开发准 ...

  6. 【UFLDL】多层神经网络

    请参见原始英文教程地址:http://ufldl.stanford.edu/tutorial/supervised/MultiLayerNeuralNetworks 本文是在学习该教程时记得笔记,供參 ...

  7. 很久没来这里,今天的评测java怪东西,左右Date类和时间戳转换

    在发展过程中,经常会遇到利用上课时间.说话的Date类就不得不提时间戳,左右fr=aladdin" target="_blank">的定义大家能够看看网上对时间戳的 ...

  8. 一个简单的java僵局演示示例

    在实际编程,为了避免死锁情况,但是,让你写一个有用的程序死锁似几乎不要太简单(种面试题),下面是一个简单的死锁样例. 线程的同步化可能会造成死锁,死锁发生在两个线程相互持有对方正在等待的东西(实际是两 ...

  9. lock订单号

    常见误用场景:在订单支付环节中,为了防止用户不小心多次点击支付按钮而导致的订单重复支付问题,我们用 lock(订单号) 来保证对该订单的操作同时只允许一个线程执行. 这样的想法很好,至少比 lock( ...

  10. Android 高仿微信即时聊天 百度云为基础的推

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天最终有幸利用百 ...