吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 46094|回复: 95
收起左侧

[Android 原创] Android逆向Hook学习——第一篇:Xposed

    [复制链接]
一夜梦惊人 发表于 2019-2-19 19:33
本帖最后由 一夜梦惊人 于 2019-5-6 17:19 编辑

一、前言
我于2019年2月19号写下本文,今天正好是元宵节,故在此祝各位元宵节快乐,新的一年里万事如意、步步高升和发大财!然后呢我来讲一下本文,我呢学习逆向方面没有多久但总归还是有点收获的,于是我就想把我学到的Android逆向Hook方面的知识和技巧分享给大家。我准备分为四篇:Xposed、Android inline hook和FrIDA。同时也请大家指出我的不正确的地方或者补充于你的技巧和知识(我将会说明于你的论坛ID)
Android逆向Hook学习系列:
第一篇:Xposed第一篇:Android inline Hook第三篇:Frida(待添加)

二、正文

2.1、Xposed原理介绍

Xposed是一款特殊的Android应用,通过替换system\bin\下面的的app_process等文件来控制zygote进程,进而实现控制手机上所有的app进程;缺点就是不能hook应用的so中的函数。

2.2、Xposed安装

Xposed的GitHub地址:https://github.com/rovo89/XposedInstaller

环境:OPPO R11、Android Studio3.3.1、Java1.8.0_201 注:可以使用模拟器、但是Android4.0-4.4和Android5.0以上的Android系统安装的版本是不同的

Xposedinstaller的apk下载页面:https://repo.xposed.info/module/de.robv.android.xposed.installer

下载完APK安装后,刷入Xposed框架,如果成功就会是我这样子。如果你已经成功了,那么你就推开了Xposed的大门,但是任重而道远,还需努力!

Screenshot_2019-02-19-16-17-34-03.png

2.3、Xposed代码的编写

新建一个项目,请注意如果你只是hook,那么可以选择add no activity,但是如果有和自身app交互,那么就选择empty activity。我为了给大家演示,是有展示的,所以我选择empty activity。

TIM截图20190219162141.png

创建成功后找到AndroidManifest,xml,在文件里面添加如下代码。

[Java] 纯文本查看 复制代码
        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <meta-data
            android:name="xposeddescription"
            android:value="XposedProject" />
        <meta-data
            android:name="xposedminversion"
            android:value="30" />

第一个xposedmodule的属性为ture,证明这是一个xposed的module;第二个xposeddescription,这是介绍项目的话语;第三个xposedminversion则是说明该xposedmodule所支持的最小版本,而最低版本就是30。

TIM截图20190219163131.png

接下来找到buile.gradle(module:app)文件,在里面添加如下代码。

[Asm] 纯文本查看 复制代码
    compileOnly 'de.robv.android.xposed:api:82'

    compileOnly 'de.robv.android.xposed:api:82:sources'

TIM截图20190219163851.png

我们新建一个Java类并且继承接口IXposedHookLoadPackage和重写handleLoadPackage方法。

[Java] 纯文本查看 复制代码
package com.yymjr.android.xposedproject;


import de.robv.android.xposed.IXposedHookLoadPackage;

import de.robv.android.xposed.callbacks.XC_LoadPackage;


public class HookMain implements IXposedHookLoadPackage {

    @Override

    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {


    }

}

在src/mian目录下添加一个assets目录,目录下添加一个xposed_init文件,里面的代码是你的Hook类的包名+类名。

而本项目就是:com.yymjr.android.xposedproject.HookMain。

编写MainActivity代码如下:

[Java] 纯文本查看 复制代码
package com.yymjr.android.xposedproject;


import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.widget.TextView;


public class MainActivity extends AppCompatActivity {

    private TextView textView;


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.HelloWorldTV);

        textView.setText(getInfmation());

    }


    private String getInfmation(){

        return "吾爱破解论坛——by 一夜梦惊人";

    }

}

Screenshot_2019-02-19-17-00-59-88.png

大家就可以看到结果就是这样子,而Hook代码我们现在写上。

[Java] 纯文本查看 复制代码
package com.yymjr.android.xposedproject;


import de.robv.android.xposed.IXposedHookLoadPackage;

import de.robv.android.xposed.XC_MethodHook;

import de.robv.android.xposed.XposedHelpers;

import de.robv.android.xposed.callbacks.XC_LoadPackage;


public class HookMain implements IXposedHookLoadPackage {

    @Override

    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        if(!lpparam.packageName.equals("com.yymjr.android.xposedproject")) return;

        XposedHelpers.findAndHookMethod("com.yymjr.android.xposedproject.MainActivity", lpparam.classLoader, "getInfmation", new XC_MethodHook() {

            @Override

            protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                super.afterHookedMethod(param);

                param.setResult("破解成功——by 一夜梦惊人");

            }

        });

    }

}

重新编译,而且在XposedInstaller里面把该APP选上并且重启。

Screenshot_2019-02-19-17-10-35-72.png

成功破解!

2.4、Xposed技巧

注:paramTypes是指函数传参的类---来自一位不愿暴露的网友的提醒
1.通过Class.getName获取clazz。  <Xposed Hook Apk不在classes.dex中定义的类>
[Java] 纯文本查看 复制代码
XposedHelpers.findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {

            @Override

            protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                super.afterHookedMethod(param);

                if (param.hasThrowable()) return;

                Class<?> clazz = (Class<?>) param.getResult();

                if (clazz.getName().equals("")){ //判断类名

                    XposedHelpers.findAndHookMethod(clazz, "methodName", paramTypes, new XC_MethodHook() {

                        @Override

                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                            super.afterHookedMethod(param);

                        }

                    });

                }

            }

        });

2.通过Hook Application的attachBaseContext/onCreate/attach来获取DexClassLoader @lemniscate 来源:据说是非虫大佬提出的思路,无从查证。如若错误请指正。 参考:支付宝订单监控

[Java] 纯文本查看 复制代码
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {

                @Override

                protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                    super.afterHookedMethod(param);

                    if (param.hasThrowable()) return;

                    ClassLoader classLoader = ((Context) param.args[0]).getClassLoader();

                    XposedHelpers.findAndHookMethod("className", classLoader, "methodName", paramTypes, new XC_MethodHook() {

                        @Override

                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                            super.afterHookedMethod(param);

                        }

                    });

                }

            });

3.打印方法堆栈。 参考:破解支付宝防Xposed

[Java] 纯文本查看 复制代码
XposedHelpers.findAndHookMethod("className", lpparam.classLoader, "methodName", paramTypes, new XC_MethodHook() {

            @Override

            protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                super.afterHookedMethod(param);

                try {

                    throw new NullPointerException();

                }catch (NullPointerException e) {

                    Log.getStackTraceString(e);

                }

            }

        });

4.构造函数。 注:Jadx反编译apk后,看不出来是构造函数,直接hook将会导致classnotfound,使用apktool反编译打开smali文件。

TIM截图20190219191653.png

看见constructor就可以知道这是一个构造函数,而构造函数则是不需要输入methodName的。

[Java] 纯文本查看 复制代码
XposedHelpers.findAndHookConstructor("className", lpparam.classLoader, new XC_MethodHook() {

            @Override

            protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                super.afterHookedMethod(param);

            }

        });

5.免重启。 来源:修改支付宝资产

Xposed每次更新或者安装module都需要重启,本技巧就是免于重启。<该代码未经任何修改>

[Java] 纯文本查看 复制代码
/**
 * @author DX
 *         这种方案建议只在开发调试的时候使用,因为这将损耗一些性能(需要额外加载apk文件),调试没问题后,直接修改xposed_init文件为正确的类即可
 *         可以实现免重启,由于存在缓存,需要杀死宿主程序以后才能生效
 *         这种免重启的方式针对某些特殊情况的hook无效
 *         例如我们需要implements IXposedHookZygoteInit,并将自己的一个服务注册为系统服务,这种就必须重启了
 *         Created by DX on 2017/10/4.
 */

public class HookLoader2 implements IXposedHookLoadPackage {
    //按照实际使用情况修改下面几项的值
    /**
     * 当前Xposed模块的包名,方便寻找apk文件
     */
    private final String modulePackage = "com.xxx.plugin";
    /**
     * 宿主程序的包名(允许多个),过滤无意义的包名,防止无意义的apk文件加载
     */
    private static List<String> hostAppPackages = new ArrayList<>();

    static {
        // TODO: Add the package name of application your want to hook!
        hostAppPackages.add("com.eg.android.AlipayGphone");
        hostAppPackages.add("com.xxx.plugin");
    }

    /**
     * 实际hook逻辑处理类
     */
    private final String handleHookClass = TargetHook.class.getName();
    /**
     * 实际hook逻辑处理类的入口方法
     */
    private final String handleHookMethod = "handleLoadPackage";

    @Override
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (hostAppPackages.contains(loadPackageParam.packageName)) {
            //将loadPackageParam的classloader替换为宿主程序Application的classloader,解决宿主程序存在多个.dex文件时,有时候ClassNotFound的问题
            XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Context context=(Context) param.args[0];
                    loadPackageParam.classLoader = context.getClassLoader();
                    invokeHandleHookMethod(context,modulePackage, handleHookClass, handleHookMethod, loadPackageParam);
                }
            });
        }
    }

    /**
     * 安装app以后,系统会在/data/app/下备份了一份.apk文件,通过动态加载这个apk文件,调用相应的方法
     * 这样就可以实现,只需要第一次重启,以后修改hook代码就不用重启了
     * @param context context参数
     * @param modulePackageName 当前模块的packageName
     * @param handleHookClass   指定由哪一个类处理相关的hook逻辑
     * @param loadPackageParam  传入XC_LoadPackage.LoadPackageParam参数
     * @throws Throwable 抛出各种异常,包括具体hook逻辑的异常,寻找apk文件异常,反射加载Class异常等
     */
    private void invokeHandleHookMethod(Context context, String modulePackageName, String handleHookClass, String handleHookMethod, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        File apkFile=findApkFile(context,modulePackageName);
        if (apkFile==null){
            throw new RuntimeException("寻找模块apk失败");
        }
        //加载指定的hook逻辑处理类,并调用它的handleHook方法
        PathClassLoader pathClassLoader = new PathClassLoader(apkFile.getAbsolutePath(), ClassLoader.getSystemClassLoader());
        Class<?> cls = Class.forName(handleHookClass, true, pathClassLoader);
        Object instance = cls.newInstance();
        Method method = cls.getDeclaredMethod(handleHookMethod, XC_LoadPackage.LoadPackageParam.class);
        method.invoke(instance, loadPackageParam);
    }

    /**
     * 根据包名构建目标Context,并调用getPackageCodePath()来定位apk
     * @param context context参数
     * @param modulePackageName 当前模块包名
     * @return return apk file
     */
    private File findApkFile(Context context, String modulePackageName){
        if (context==null){
            return null;
        }
        try {
            Context moudleContext = context.createPackageContext(modulePackageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
            String apkPath=moudleContext.getPackageCodePath();
            return new File(apkPath);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

6.主动调用函数。 提醒:@$喂人民服雾  参考:Xposed模块编写那些事--https://www.freebuf.com/articles/terminal/114910.html
[Java] 纯文本查看 复制代码
        Class<?> clazz = XposedHelpers.findClass("className",lpparam.classLoader);
        XposedHelpers.callMethod(clazz.newInstance(),"methodName",paramTypes, paramValue);
注:第一个参数是hook类的对象,在本代码获取了类,但是没有实例化,所以调用newInstance;paramValue是传入参数的值。

7.内部类(inner_class)hook 参考:<支付宝订单监控>
TIM截图.png
首先获取class,而内部类则是用$连接。
[Java] 纯文本查看 复制代码
        XposedHelpers.findAndHookMethod("className$inner_class", lpparam.classLoader, "methodName", paramTypes, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
            }
        });

8.调用静态函数
[Java] 纯文本查看 复制代码
                            [/size][/font][font=黑体][size=3]Class[] clazz = new Class[1];[/size][/font][/align][align=left][font=黑体][size=3]                            clazz[0] = Clazz;
                            XposedHelpers.callStaticMethod(XposedHelpers.findClass("[/size][/font][font=黑体][size=3]className[/size][/font][font=黑体][size=3]", classLoader),"[/size][/font][font=黑体][size=3]methodName[/size][/font][font=黑体][size=3]",[/size][/font][font=黑体][size=3]clazz,[/size][/font][font=黑体][size=3]paramValue[/size][/font][font=黑体][size=3]);[/size][/font][/align][align=left][font=黑体][size=3]
捕获.PNG
请注意这里如果要传入参数的Clazz,请传为数组类,而参数的值则是可变,否则将会出错!

以上部分不分排名,切莫乱想。


三、后言

本帖就到此为至,但是呢“本帖将会持续更新,建议加入收藏!

最后希望大家多多评分给我一些鼓励!!!放上上面的代码 XposedProject.7z (120.14 KB, 下载次数: 452)

免费评分

参与人数 28威望 +1 吾爱币 +33 热心值 +28 收起 理由
98km6 + 1 + 1 学习受用了!
hangez + 1 + 1 好强好强!学习到了
h1ck + 1 + 1 用心讨论,共获提升!
netxwind + 1 + 1 谢谢@Thanks!
菜鸟也想飞 + 1 + 1 谢谢@Thanks!
sharkyc + 1 + 1 我很赞同!
123321.tk + 1 + 1 谢谢@Thanks!
fqr2009 + 1 + 1 谢谢@Thanks!
谷寒 + 1 + 1 真心感谢大神带我入门
hope11111 + 1 我很赞同!
永恒陌 + 1 大佬啊!请问avd或者说没有root的模拟器 怎么root还有怎么装xposed
安然初冬112 + 1 + 1 谢谢@Thanks!
whjack + 1 + 1 我很赞同!
Payphone7 + 1 + 1 谢谢@Thanks!新手学习中
朱仔里 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
tflyr + 1 + 1 持续关注
zxc19914 + 1 谢谢@Thanks!
$喂人民服雾 + 1 + 1 我很赞同!
独行风云 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
stars-one + 1 + 1 我很赞同!
C_actus + 1 + 1 谢谢@Thanks!
H_hacker + 1 + 1 谢谢@Thanks!
qtfreet00 + 1 + 9 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
qaz003 + 1 + 1 谢谢分享,期待续集系列
a48602 + 1 + 1 谢谢@Thanks!
zysanjing1 + 1 + 1 已收藏,期待有更多教程~~
home_pig + 1 + 1 谢谢@Thanks!
lbwb2 + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 一夜梦惊人 发表于 2019-8-18 10:38
lianziheqing 发表于 2019-7-2 23:15
hook某个控件,比如button,view之类的直接点击,hook该类的字段值并打印之类的这些应该也挺常用吧,期待楼 ...

Hook这种的话,基本都是继承这种OnClickListener类并且重写方法,你可以用apktool进行反编译就可以发现会形成一个内部类了,直接hook这个内部类就可以。
 楼主| 一夜梦惊人 发表于 2019-2-19 20:04
zyx1211 发表于 2019-2-19 19:50
希望你坚持更新啊

会的,本来就是更新技巧,让大家不用到处找。
zyx1211 发表于 2019-2-19 19:50
多幸运遇见baby 发表于 2019-2-19 20:21
热心回复!
hui00000 发表于 2019-2-19 20:28 来自手机
感谢分享
syrmb 发表于 2019-2-19 21:20
入门的其实很多教程,大多都类似

但像HOOK加壳APP或者NativeMethod这类就少了
shyjlo 发表于 2019-2-19 21:28
非常感谢!
PyScrapy 发表于 2019-2-19 21:53
感谢分享~~ 学习了
番茄炒西红柿1 发表于 2019-2-19 22:37
小白前来学习
a48602 发表于 2019-2-19 23:02
小白對 Xposed 仍是不太懂,大大此篇教學正好可以多看幾遍學習一下,謝謝樓主的分享。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-28 10:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表