首页
社区
课程
招聘
[原创]Xposed Hook技巧,代理abstract
2020-7-4 09:01 16839

[原创]Xposed Hook技巧,代理abstract

2020-7-4 09:01
16839

题意:代理抽象就是说,对于一个抽象类的实例化参数,我们需要进行hook他的结果的操作,这种匿名类或者对象往往有很多构造函数的参数是我们无法构造的,或者传入空可能需要和正常的处理方式相悖,增加复杂度。(说了这么多,还是上代码直接)

目录:

        1、代理接口

        2、代理抽象类

        3、其它

1、代理接口

    1.1(需要进行Xposed,需要拿到接口执行的对象的值。即onExecuted被调用的时候的TestModel的值

public class TestModel {
    public int code;
    public String msg;
}
public interface ITest {
    void onExecuted(TestModel paramT);
}
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ((Button)findViewById(R.id.btnTest2)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ITest testInter = new ITest() {
                    @Override
                    public void onExecuted(TestModel paramT) {
                        Toast.makeText(getBaseContext(), paramT.msg, Toast.LENGTH_LONG).show();
                    }
                };

                Test2(testInter);
            }
        });
    }

    public void Test2(ITest test){
        TestModel model = new TestModel();
        model.msg = "success";
        test.onExecuted(model);
    }
}

    1.2、 一般实现,我们回先拿到匿名类hook他的onExecuted,然后初始化匿名类对象,XposedHelper.callMethod(Test2, 匿名对象),得到结果。

    1.3、我们这里使用代理接口

findAndHookMethod("com.android.testabstract.MainActivity", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
    @Override
    protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);

        final Object pthis = param.thisObject; // 拿到对象用于下一步调用
        hookInterface(lpparam.classLoader, pthis);
    }
});

private void hookInterface(final ClassLoader classLoader, final Object pthis){
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Class<?> class_ITest = classLoader.loadClass("com.android.testabstract.ITest");
                Object obj_proxy = Proxy.newProxyInstance(classLoader, new Class<?>[]{class_ITest}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        // 这里接可以拿到,接口执行的方法和执行的参数了。
                        Log.i("testProxy", "method " + method.getName());
                        Log.i("testProxy", "objects.length " + (objects != null ? objects.length : "null"));

                        return null;
                    }
                });

                XposedHelpers.callMethod(pthis, "Test2", obj_proxy);
            }
            catch (NoClassDefFoundError fe){
                Log.i("testProxy", "fe " + fe.getMessage());
                fe.printStackTrace();
            }
            catch (Exception e){
                Log.i("testProxy", "e " + e.getMessage());
                e.printStackTrace();
            }
        }
    }).start();
}

    2、代理抽象类

    2.1、代码定义,类对象沿用上面的即可。

public abstract class TestAb<T> {
    public final void onExecuted(T paramT, Exception paramException) {
        onSuccess(paramT);
    }

    protected abstract void onSuccess(T paramT);
}
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        ((Button)findViewById(R.id.btnTest)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TestAb<TestModel> testAb = new TestAb<TestModel>() {
                    @Override
                    protected void onSuccess(TestModel paramT) {
                        Toast.makeText(getBaseContext(), paramT.msg, Toast.LENGTH_LONG).show();
                    }
                };

                Test(testAb);
            }
        });
    }
    public void Test(TestAb testAb){
        TestModel model = new TestModel();
        model.msg = "success";
        testAb.onExecuted(model, null);
    }
}

    2.2、一般处理方式,我们同样先拿到匿名的类(实例化抽象类的类),再hook他的onSuccess等待拿到结果,然后实例化匿名类,最后调用。

    2.3、代理的处理方式(由于我们没有可以继承的抽象类,所以需要自己定义一个类库,然后实例化他,但是定义的类库仅仅用于使用,不用于实现,使用 compileOnly引入。

private void hookFail(final Object pthis){
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                TestAb<TestModel> test = new TestAb<TestModel>() {
                    @Override
                    protected void onSuccess(TestModel paramT) {
                        Log.i("testAbProxy", "paramT " + paramT.msg);
                    }
                };

                XposedHelpers.callMethod(pthis, "Test", test);
            }
            catch (NoClassDefFoundError fe){
                Log.i("tt===tt", "fe " + fe.getMessage());
                fe.printStackTrace();
            }
            catch (Exception e){
                Log.i("tt===tt", "e " + e.getMessage());
                e.printStackTrace();
            }
        }
    }).start();
}

    虽然看上去很短,没毛病,实际调用才发现。有问题。NoClassDefineError,怎么回事呢,,,由于apk的包里面,确实找不到这个类,所以就有这样的错误。怎么解决。

    2.4、怎么办,解决。既然找不到,那么我们手动帮他找到,我们用自己的ClassLoader,载入自己的类,总没问题了吧。

 // 定义实现抽象的对象。下面用到
public class TestTestAb extends TestAb<TestModel> {

    public TestTestAb(){
    }

    @Override
    protected void onSuccess(TestModel paramT) {
        Log.i("tt===tt", "hooked msg " + paramT.msg);
    }
}
// 定义hook代码
private void hookTest2(final Object pthis){
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                // 这里针对art,直接这样使用,dalvik可能就不一样了
                String path = "/data/app/com.android.testxpabs-1/base.apk";
                if(!new File(path).exists()){
                    path = "/data/app/com.android.testxpabs-2/base.apk";
                }

                PathClassLoader pathClassLoader = new PathClassLoader(path, pthis.getClass().getClassLoader());
                Class<?> class_ = pathClassLoader.loadClass("com.android.testxpabs.TestTestAb");
                Object obj_ = class_.newInstance();
                Class<?> class_TestModel = pathClassLoader.loadClass("com.android.testabstract.TestModel");

                findAndHookMethod("com.android.testxpabs.TestTestAb", pathClassLoader,
                        "onSuccess", class_TestModel, new XC_MethodReplacement() {
                            @Override
                            protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                                Log.i("tt===tt", "hook replace " + param.args[0]);
                                return null;
                            }
                        });

                // 把当前APK加入
                XposedHelpers.callMethod(pthis, "Test", obj_);
            }
            catch (NoClassDefFoundError fe){
                Log.i("testAbProxy", "fe " + fe.getMessage());
                fe.printStackTrace();
            }
            catch (Exception e){
                Log.i("testAbProxy", "e " + e.getMessage());
                e.printStackTrace();
            }
        }
    }).start();
}

这样执行就没问题了,同时对于实现类我们也是可以hook的了。

    2.5 当然这不是唯一解决办法,我们通用可以把,当前hook的apk,加入到待hookAPP的dex的pathList集合中,这样就可以直接用pthis对象的ClassLoader,进行加载和hook了。

    对于这种实现方式,是不是眼熟呀。。。看看其他

    3、其他

        3.1、对Xposed的免重启更新也可以用他实现。

    

源码 https://github.com/supperlitt/testabstract


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-7-4 11:25 被supperlitt编辑 ,原因:
收藏
点赞10
打赏
分享
最新回复 (17)
雪    币: 634
活跃值: (1503)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Monkeylord 2020-7-6 10:21
2
0
赞楼主,动态代理和反射能解决好多问题。
不过从难易程度来讲,最简单的办法是hook抓一个对象存着,使用的时候改改属性直接复用。
雪    币: 1694
活跃值: (4002)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小黄鸭爱学习 2020-7-6 10:40
3
0
Monkeylord 赞楼主,动态代理和反射能解决好多问题。 不过从难易程度来讲,最简单的办法是hook抓一个对象存着,使用的时候改改属性直接复用。
hook抓一个对象这种操作起来也很麻烦 有些抽象类的实现类非常难触发。
还是代理好用
雪    币: 1694
活跃值: (4002)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小黄鸭爱学习 2020-7-6 10:42
4
0
Monkeylord 赞楼主,动态代理和反射能解决好多问题。 不过从难易程度来讲,最简单的办法是hook抓一个对象存着,使用的时候改改属性直接复用。
第二种那里 可以直接写java代码编译成jar转成dex文件合上去。道理是一样的
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_xjxu 2020-12-11 18:33
5
0
可是TestAb抽象类是在目标程序中 ,我们只能拿到他的class 无法在xposed的模块中得到他的引用 ,所以无法写一个类来继承他
雪    币: 1366
活跃值: (5584)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
supperlitt 2020-12-12 10:09
6
0
wx_xjxu 可是TestAb抽象类是在目标程序中 ,我们只能拿到他的class 无法在xposed的模块中得到他的引用 ,所以无法写一个类来继承他
定义一个jar,只有那个抽象类相关的(包名,类名一致),然后使用。compileOnly files你就可以在你要用的app里面用了噻。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_xjxu 2020-12-24 15:43
7
0
supperlitt 定义一个jar,只有那个抽象类相关的(包名,类名一致),然后使用。compileOnly files你就可以在你要用的app里面用了噻。
compileOnly 指的是我们写的模块的build文件里面的引入方式吗
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_xjxu 2020-12-24 15:47
8
0
wx_xjxu compileOnly 指的是我们写的模块的build文件里面的引入方式吗
在工程中看到了 这就试试集成目标程序中的抽象类
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_xjxu 2020-12-25 11:24
9
0
已经成功了  这样就算在自己的代码中继承了 目标程序的抽象类吧 楼主真厉害
雪    币: 62
活跃值: (566)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
万里星河 2020-12-26 21:47
10
0
感觉好晦涩  得慢慢研究
雪    币: 1355
活跃值: (1162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
litianp 2022-3-31 20:45
11
0
这种方式怎么兼容LSPatch XPatch这些内置的情况?
雪    币: 342
活跃值: (759)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
学着学逆向 2022-4-1 11:06
12
0

我也是这么搞的。说白了就是双亲委托机制罢了。
Xposed的得到的param中的classLaoder是宿主的。加载插件的classLoader的父Loader不是宿主。


其实你可以直接在加载的DEX/Apk中直接 new 宿主的类了(插件化思想)。

最后于 2022-4-1 11:12 被学着学逆向编辑 ,原因:
雪    币: 40
活跃值: (58)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
留352183717 2022-4-1 19:43
13
0
都是大神
雪    币: 228
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
nullpointer1 2024-1-12 16:37
14
0
我理一下看对不对,第一天很迷,因为apk和模块放在一起,包名太像了,简单来说就是在本地定义一遍包名类名实现和宿主app中一样的接口,并且自己写一个实现,然后在hook之前,把自己写的接口实现加载到宿主的app的环境中,然后newinstance去hook构造接口参数了,并且抽象方法还是自己实现的,可以随便写
雪    币: 1481
活跃值: (1877)
能力值: ( LV5,RANK:61 )
在线值:
发帖
回帖
粉丝
陈可牛 1 2024-1-13 00:41
15
0
其实作者的最后一点就挺好的了:    2.5 当然这不是唯一解决办法,我们通用可以把,当前hook的apk,加入到待hookAPP的dex的pathList集合中,这样就可以直接用pthis对象的ClassLoader,进行加载和hook了。
这样子就可以使用apk的原始类了,直接new他的子类了,不过还有一种简单的方法就是hook:Object pthis中的app原始的实现类,这样子就不需要手动调用它的原本方法了
雪    币: 1481
活跃值: (1877)
能力值: ( LV5,RANK:61 )
在线值:
发帖
回帖
粉丝
陈可牛 1 2024-1-13 00:43
16
0
典型的类加载的问题,这个是其中的一个知识点,xposed插件继承app的方法。还有一个就是xposed注入so回调插件的类进行callback(hook数据回调上报)。其实这两个都是classloader的修正问题。。。很多的事情都是其一或者两者兼并。
雪    币: 228
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
nullpointer1 2024-1-16 11:37
17
0
完全听不太懂,大佬可以发帖细说吗。。。刚好遇到这么个场景,抽象类的抽象方法当做回调,有我想获取的一个数据,2.5这个原理不太懂诶(新手,大佬勿怪
雪    币: 19485
活跃值: (29158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2024-1-16 14:31
18
1
感谢分享
游客
登录 | 注册 方可回帖
返回