(4.6.14)android 插桩基本概念plugging or Swap

前言:

1、本篇内容选自网络,仅介绍插桩的基本概念

2、要实现插桩需要一系列的反编译和打包工具,将在另一篇文章中介绍

插桩的概念是以静态的方式修改第三方的代码,也就是从编译阶段,对源代码(中间代码)进行编译,而后重新打包,是静态的篡改;

而hook则不需要再编译阶段修改第三方的源码或中间代码,是在运行时通过反射的方式修改调用,是一种动态的篡改

插桩的概念:

插桩就是在代码中插入一段我们自定义的代码。

插桩的目的:

将程序中插入我们自定义的代码编译到可执行文件中,

该程序的运行过程中就会执行我们自定义的代码,实现我们想要增加的功能需求。

安卓插桩简介:

在安卓方面,插桩通常是指在某手机的官方原厂ROM中通过反编译的方式获得中间代码,然后通过对中间代码的修改加入自定义的功能,达到为ROM添加功能的目的。

这样做的优势是:

  1. 厂商原厂ROM中的功能、特性或优化基本不会丧失。
  2. 适配工作很简单,因为官方的ROM本身就是能正常运行的,插桩者只要保证把自己的代码正确插入即可。

缺点是:

  1. 通过中间代码插桩实现功能比起源代码进行修改要费力太多。
  2. 维护起来也相对麻烦,各机型上难以复用,需要针对性的做一些修改。

什么时候用到插桩:

源码开发是自己拥有一套完整的源代码,想要实现新增的功能需求只需直接在源码上修改。

比如小米自己生产的手机的ROM,必然是在一套完整的源代码上不断修改完善的。

而小米用来适配到其它厂商手机的patchrom项目,则是通过插桩修改的方式。

中间代码.smali 和源代码.java

比如我们看小米Nexus 5 MIUIV6的框架包

这里的文件就是反编译Nexus 5官方原厂ROM后得到的中间代码并加入MIUI自己的功能的版本。

我们随便打开里面一个不太复杂的文件,如AsyncResult.smali,你看到的内容就是所谓中间代码了。

.class public Landroid/os/AsyncResult;
.super Ljava/lang/Object;
.source "AsyncResult.java"

# instance fields
.field public exception:Ljava/lang/Throwable;

.field public result:Ljava/lang/Object;

.field public userObj:Ljava/lang/Object;

# direct methods
.method public constructor <init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V
    .locals 0
    .param p1, "uo"    # Ljava/lang/Object;
    .param p2, "r"    # Ljava/lang/Object;
    .param p3, "ex"    # Ljava/lang/Throwable;

    .prologue
    .line 63
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    .line 64
    iput-object p1, p0, Landroid/os/AsyncResult;->userObj:Ljava/lang/Object;

    .line 65
    iput-object p2, p0, Landroid/os/AsyncResult;->result:Ljava/lang/Object;

    .line 66
    iput-object p3, p0, Landroid/os/AsyncResult;->exception:Ljava/lang/Throwable;

    .line 67
    return-void
.end method

.method public static forMessage(Landroid/os/Message;)Landroid/os/AsyncResult;
    .locals 3
    .param p0, "m"    # Landroid/os/Message;

    .prologue
    const/4 v2, 0x0

    .line 53
    new-instance v0, Landroid/os/AsyncResult;

    iget-object v1, p0, Landroid/os/Message;->obj:Ljava/lang/Object;

    invoke-direct {v0, v1, v2, v2}, Landroid/os/AsyncResult;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V

    .line 55
    .local v0, "ret":Landroid/os/AsyncResult;
    iput-object v0, p0, Landroid/os/Message;->obj:Ljava/lang/Object;

    .line 57
    return-object v0
.end method

.method public static forMessage(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)Landroid/os/AsyncResult;
    .locals 2
    .param p0, "m"    # Landroid/os/Message;
    .param p1, "r"    # Ljava/lang/Object;
    .param p2, "ex"    # Ljava/lang/Throwable;

    .prologue
    .line 40
    new-instance v0, Landroid/os/AsyncResult;

    iget-object v1, p0, Landroid/os/Message;->obj:Ljava/lang/Object;

    invoke-direct {v0, v1, p1, p2}, Landroid/os/AsyncResult;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V

    .line 42
    .local v0, "ret":Landroid/os/AsyncResult;
    iput-object v0, p0, Landroid/os/Message;->obj:Ljava/lang/Object;

    .line 44
    return-object v0
.end method

而源代码可读性要比中间代码强多了,我们打开AOSP项目中相同文件的源码来看

https://github.com/android/platform_frameworks_base/blob/android-4.4_r1.2.0.1/core/java/android/os/AsyncResult.java

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import android.os.Message;

/** [url=home.php?mod=space&uid=398]@hide[/url] */
public class AsyncResult
{

    /*************************** Instance Variables **************************/

    // Expect either exception or result to be null
    public Object userObj;
    public Throwable exception;
    public Object result;

    /***************************** Class Methods *****************************/

    /** Saves and sets m.obj */
    public static AsyncResult
    forMessage(Message m, Object r, Throwable ex)
    {
        AsyncResult ret;

        ret = new AsyncResult (m.obj, r, ex);

        m.obj = ret; 

        return ret;
    }

    /** Saves and sets m.obj */
    public static AsyncResult
    forMessage(Message m)
    {
        AsyncResult ret;

        ret = new AsyncResult (m.obj, null, null);

        m.obj = ret; 

        return ret;
    }

    /** please note, this sets m.obj to be this */
    public
    AsyncResult (Object uo, Object r, Throwable ex)
    {
        userObj = uo;
        result = r;
        exception = ex;
    }
}

读到这里你应该会对插桩的中间代码和源代码的区别有一个基础的了解了。

patchrom开源根本不算开源代码,因为反编译中间代码的取得我们任何一个人通过反编译工具都能做到,这只是忽悠外行的东西

简单的插桩实例

接下来,我们用一个示例程序演示如果通过插桩和源代码修改的方式为一个程序增加功能。

这个示例程序很简单,打开之后只会在手机上显示一段话:

而我们要实现的就是用插桩和源码修改的两种方法实现另起一行再显示”以后多发科普,提升新手玩机水平,避免大家被这种人坑!”

如果是源代码的话,只需要很简单的在源码中加入一段”\n以后多发科普,提升新手玩机水平,避免大家被这种人坑!”

下面是修改后的源码:

package com.example.appdemo;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView mTextView = (TextView)findViewById(R.id.helloworld);
        mTextView.setText("moonlight-roms月亮打包大神就是个拿别人代码打包赚推广费,肆意胡编乱造各种没有常识的话欺骗新用户的骗子!\n以后多发科普,提升新手玩机水平,避免大家被这种人坑!");
    }
}

如果要插桩,则是要反编译这个程序,然后将

    .line 15
    .local v0, "mTextView":Landroid/widget/TextView;
    const-string v1, "moonlight-roms\u6708\u4eae\u6253\u5305\u5927\u795e\u5c31\u662f\u4e2a\u62ff\u522b\u4eba\u4ee3\u7801\u6253\u5305\u8d5a\u63a8\u5e7f\u8d39\uff0c\u8086\u610f\u80e1\u7f16\u4e71\u9020\u5404\u79cd\u6ca1\u6709\u5e38\u8bc6\u7684\u8bdd\u6b3a\u9a97\u65b0\u7528\u6237\u7684\u9a97\u5b50!"

修改为:

    .line 15
    .local v0, "mTextView":Landroid/widget/TextView;
    const-string v1, "moonlight-roms\u6708\u4eae\u6253\u5305\u5927\u795e\u5c31\u662f\u4e2a\u62ff\u522b\u4eba\u4ee3\u7801\u6253\u5305\u8d5a\u63a8\u5e7f\u8d39\uff0c\u8086\u610f\u80e1\u7f16\u4e71\u9020\u5404\u79cd\u6ca1\u6709\u5e38\u8bc6\u7684\u8bdd\u6b3a\u9a97\u65b0\u7528\u6237\u7684\u9a97\u5b50!\n\u4ee5\u540e\u591a\u53d1\u79d1\u666e\uff0c\u63d0\u5347\u65b0\u624b\u73a9\u673a\u6c34\u5e73\uff0c\u907f\u514d\u5927\u5bb6\u88ab\u8fd9\u79cd\u4eba\u5751\uff01"

时间: 2024-08-27 11:56:08

(4.6.14)android 插桩基本概念plugging or Swap的相关文章

Android基础入门教程——10.14 Android GPS初涉

Android基础入门教程--10.14 Android GPS初涉 标签(空格分隔): Android基础入门教程 本节引言: 说到GPS这个名词,相信大家都不陌生,GPS全球定位技术嘛,嗯,Android中定位的方式 一般有这四种:GPS定位,WIFI定准,基站定位,AGPS定位(基站+GPS): 本系列教程只讲解GPS定位的基本使用!GPS是通过与卫星交互来获取设备当前的经纬度,准确 度较高,但也有一些缺点,最大的缺点就是:室内几乎无法使用-需要收到4颗卫星或以上 信号才能保证GPS的准确

14.Android之Layout布局学习

Android布局主要有5种,接下来学习总结下. 1) 最常见的线性布局 LinearLayout 线性布局是Android布局中最简单的布局,也是最常用,最实用的布局. android:orientation线形布局的对齐方式 : vertical(垂直) 和 horizontal(水平) LayoutParams中的特殊参数: layout_weight 权值 layout_gravity 相对于父元素的重力值(默认top|left): (top|bottom|left|right|cent

Android开发涉及有点概念&amp;相关知识点(待写)

前言,承接之前的 IOS开发涉及有点概念&相关知识点,这次归纳的是Android开发相关,好废话不说了.. 先声明下,Android开发涉及概念比IOS杂很多,可能有很多都题不到的.. 首先由于Android是基于Linux,而Linux又是用c山寨Unix的,但是为什么Android不用开发App,其实我也不懂,我想可能是java比较简单. 同样的,IOS为啥没用java,这个我也想可能是因为IOS是封闭的吧..晕,又废话了..好,开始吧,不过这次很多要查资料了,很多名词.单词不会啊! 首先还

《Android笔记3.5》 在 Android 中 Intent 的概念及应用

课程背景:Intent 是 Android 开发中的非常重要的基础概念,想要成为一个 Android 开发者,Intent 是必学的内容. 核心内容:1.隐式 Intent 2.显式 Intent 可以通过隐式Intent,从外部启动某个APP的Activity: 在AndroidManifest.xml中设置action,或设置禁止导出Activity不允许其他APP启动. Intent 过滤器相关选项 当同一个APP或不同APP中的Activity里的action相同的时候,启动时会提示选择

Android数据库之基本概念(上)

1.Android数据库简介 Android通过结合使用SQLite数据库和Content Provider,提供了结构化数据的持久功能. SQLite数据库可以通过一种结构化的.易于管理的方法来存储应用程序数据.Android提供了一个完整的SQLite关系数据库的库文件.每个应用程序都可以创建自己的数据库,并对这个数据库拥有完全的控制权. Android数据库存储在设备上的/data/data/<package name>/database文件夹中,所有的数据库都是私有的,只能被创建他们的

Android View, Window,Activity概念区分(2)

(1)View:最基本的UI组件,表示屏幕上的一个矩形区域. (2)Window: 表示一个窗口,不一定有屏幕那么大,可以很大也可以很小:它包含一个View tree和窗口的layout 参数.View tree的root View可以通过getDecorView得到.还可以设置Window的Content View. (3)Activity:Activity包含一个Window,该Window在Activity的attach方法中通过调用PolicyManager.makeNewWindo创建

介绍自己的一个Android插桩热修复框架项目QuickPatch

QuickPatch项目地址:https://gitee.com/egg90/QuickPatch 和 https://github.com/eggfly/QuickPatch 同步更新 类似于美团的Robust插桩热修复,但是代码可读性比较强,还在继续完善,todo list在项目README里 特性:基于函数插桩,兼容性好(Android版本升级不需要做修改),支持热更新无需重启app,参考了美团的Robust插桩热修复框架,精简了很多实现细节,代码可读性高 一句话原理 简单地讲,就是通过编

在Android中Intent的概念及应用(一)——显示Intent和隐式Intent

Intent寻找目标组件的两种方式: 显式Intent:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的. 隐式Intent:通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间. 一.显示Intent: 创建一个Activity的完整过程: 1.手动创建一个类,让其继承自Activity: public class MyAty extends Activity 2.让其绑定一个

在 Android 中 Intent 的概念及应用

一.显式Intent: startActivity(new Intent(MainActivity.this, 类名.class));   二.隐式Intent: 1.在AndroidManiFest.xml 文件的<application>标签中注册 <activity>标签,形如 .类名: <activity android:name=".Another" android:exported="false" > <inte