zoukankan      html  css  js  c++  java
  • Android Hotpatch系列之-给release包打Patch

    在默认debug包里面,是不对class做混淆的,所以Patch编写相对简单,但是应用在发布的时候都是release包,会对代码做混淆,此时class name ,field name,method name都会被混淆,这个时候改如何编写Patch?

         在打release包时,在build/outputs/mapping/release/下面有mapping.txt,这个里面记录了混淆以前的类和混淆以后的类的一一对应关系(所以叫mapping.txt),所以每次发版以后要保留好mapping.txt文件,以便以后编写Patch。

         在https://github.com/fengcunhan/Hotpatch-Sample项目中的dexposedexamples,下面新定义了一个Test类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.taobao.model;
    public class Test {
     
        public String getHello(int a){
            if(a==0){
                return "PatchSuccess";
            }
            return "hello";
        }
     
    }

       这个类在TestFragment中使用到,发了版本以后,发现需要将业务的逻辑改成a<=0都返回PatchSuccess,然后就坑爹了,只能发布一个Patch来做这个事情,有两种Patch编写方式都可以达到上述目的。

         1.XC_MethodHook 中重写beforeHookedMethod方法,在这个里面修改传入方法的参数,如果a<0,那就设置a==0,不用改变原先方法的逻辑,就可以达成目的。

         2.替换原先方法。XC_MethodReplacement,重写 replaceHookedMethod 方法,在这个方法中实现你想要的逻辑。

         下面以第二种方式来编写例子。编写Patch,要替换Test类中的getHello()方法,首先要找到release包下面Test类,然后替换掉getHello方法。在mapping.txt文件中找到了Test类以及对应混淆后的新类名和方法名:

    1
    2
    com.taobao.model.Test -> com.taobao.a.a://类混淆了
        java.lang.String getHello(int) -> a //方法名也混淆了

    TestPatch编写如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    import android.util.Log;
     
    import com.taobao.android.dexposed.DexposedBridge;
    import com.taobao.android.dexposed.XC_MethodReplacement;
     
    /**
     * Created by renxuan on 15/9/8.
     */
    public class TestPatch implements IPatch {
        private static final String TAG="TestPatch";
        @Override
        public void handlePatch(final PatchParam patchParam) throws Throwable {
            {
                Class<?> cls = null;
                try {
                //根据混淆以后的类来找到想要Patch的class
                    cls= patchParam.context.getClass().getClassLoader().loadClass("com.taobao.a.a");
                catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
                Log.e(TAG, "cls:" + cls);
                /**
                 * 修改逻辑,原先是==0的时候返回Patch success,现在改成<=0都是返回Patch Success
                 *注意添加的int.class,因为getHello是有参数的,如果没有传int.class,是找不到对应方法的。不知道为什么的人,可以去看看反射先
                 * */
                DexposedBridge.findAndHookMethod(cls, "a",int.class,new XC_MethodReplacement() {
                    @Override
                    protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
                        Log.e(TAG, "methodHookParam:" + methodHookParam.method.getName());
                        int methodArgsLength=methodHookParam.args.length;
                        if(methodArgsLength>0){
                            int a=(int)methodHookParam.args[0];
                            if(a<=0){
                                return "PatchSuccess";
                            }
                        }
                        return "hello";
                    }
                });
     
            }
        }
    }

      注意:

          1.如果是在debug下测试,因为Test class没有混淆,Patch包这边的类名就应该是com.taobao.model.Test,方法名也应该还是getHello。

          2.release包的签名一定要和patch的签名一样(线上情况),如果没有这个检测,那你的应用就很不安全,恶意攻击者可以随意load一个Patch进去,后果不可想象。

          3.有问题可以加入Hotpatch QQ群:254384686

  • 相关阅读:
    【dp】P1982 小朋友的数字
    NOIp2017囤题计划
    Java语言编写计算器(简单的计算器)
    关于建立Android工程R文件丢失的问题
    读《黑客与画家》
    格式化输出%、基本运算符
    常量、变量;基本数据类型;input()、if、while、break、continue
    初遇Linux
    MVC5+EF6 入门完整教程10 数据查询更新
    Razor语法和Razor引擎大全
  • 原文地址:https://www.cnblogs.com/clarence/p/5066640.html
Copyright © 2011-2022 走看看