装X指南之通过 VirtualApp 实现免 Root 权限 Hook

《装X指南之通过 VirtualApp 实现免 Root 权限 Hook》 装X指南之通过 VirtualApp 实现免 Root 权限 Hook

一、前言

之前写的 「装X指南之Xposed安装与配置」,有人反馈手机 root 风险较大,而且操作成本高,有没有什么方法是不需要 root 就能够实现 hook 的或者不需要 Xposed 也能玩起插件的?于是就有了这篇文章,离开 Xposed ,带你免 root 实现 hook!

二、VirtualApp

1、关于 VirtualApp 的介绍

VA目前被广泛应用于插件化开发、无感知热更新、自动化、多开等技术领域,但它决不仅限于此,Android本身就是一个极其开放的平台,免安装运行APK这一Feature打开了无限可能—–这都取决于您的想象力。

感谢 asLody 开源,据说他写这个项目才高二,佩服佩服~

  • VirtualApp 项目地址:
  1. https://github.com/asLody/VirtualApp

2、VirtualApp 的原理

VirtualApp 伪造了一套 framework 代码,实现所有在其进程启动的应用,都运行在一个虚拟空间(注:个人理解,如有错误,还请指出)。

  • VirtualApp 源码学习与原理分析
  1. https://blog.csdn.net/leif_/article/details/72420934
  2. https://blog.csdn.net/ganyao939543405/article/details/76146760

3、VirtualApp 使用问题

Github 上的代码,作者已经没有继续开源更新了,可以看到后续的所有修改,都在作者的商业版上操作,所以有可能在使用上会出现一些 bug

其实可以看到「商业版」,不管稳定性与兼容性,都做了很大的修复和改动,最重要的是,支持 Dalvik 和 Art 的 Java Hook( API 同 Xposed ),可惜在作者没有公开源码的情况下,我们个人不可能为了学习去购买「商业版」~

特别说明:作者明确指出,如果项目需要投入商业使用,请购买「商业版」。我们这里仅做技术学习使用

《装X指南之通过 VirtualApp 实现免 Root 权限 Hook》 商业版特性

4、VirtualHook 介绍

上文说到我们无法使用「商业版」的 VirtualApp ,来进行 Hook ,准确来说是作者没把 Hook 的 Api 公开。

下面我要介绍另一个基于 VirtualApp 改造的项目 —— VirtualHook(区分:VirtualAppVirtualHook 的区别,不要搞混了,后文使用 VirtualHook 来实践),感谢 rk700 开源 VirtualHook 与 YAHFA

1)VirtualHook 项目地址:
  1. https://github.com/rk700/VirtualHook
2)VirtualHook 构成:

VirtualHook is a tool for hooking application without root permission. It is based on two projects:

  • VirtualApp. It’s a plugin framework which allows running applications in its virtual space.
  • YAHFA . It’s a hook framework for ART which allows hooking Java method of the application.
3)VirtualHook 注入
  • 关键的地方,VirtualHook 修改 VirtualApp 的核心代码,提供 Hook 注入代码的窗口
  • 以下是在 VirtualApp 里面 VClienImpl 类注入的关键代码
    DexClassLoader dexClassLoader = new DexClassLoader(apkPath,
            VEnvironment.getDalvikCacheDirectory().getAbsolutePath(),
            libPath,
            appClassLoader);
    // YAHFA do hook 
    HookMain.doHookDefault(dexClassLoader, appClassLoader);
public void findAndBackupAndHook(Class targetClass, String methodName,
String methodSig, Method hook, Method backup);

三、YAHFA

1、YAHFA 介绍

YAHFA(Yet Another Hook Framework for ART) 是基于 ART 的 Hook 框架,支持 Android 5.0 ~ 9.0 版本的 Java 方法的 Hook 与替代 。而 VirtualHook 则是靠 YAHFA 实现的免 Root Hook。

  • 来自看雪论坛:
  1. https://bbs.pediy.com/thread-216786.htm
  • YAHFA 项目地址:
  1. https://github.com/rk700/YAHFA

2、YAHFA 原理

我是看不太懂里面的原理,但是还是把别人的分析过程,贴出来给大家,希望看懂的朋友,不吝分享:

  • 写文的时候,好像作者的博客挂了,不过还是写上吧

http://rk700.github.io/2017/03/30/YAHFA-introduction/

  • csdn 一位博主分享的原理分析

https://blog.csdn.net/zhu929033262/article/details/74457324

3、YAHFA Hook

解释一下相关变量与方法:

  • className:指定要 hook 的类名
  • methodName:指定要 hook 的方法
  • methodSig:指定要 hook 的方法签名
  • hook():该方法是你 hook 方法需要处理的逻辑,这里执行 hook 相关操作
  • backup():是原方法的调用,一般不需要重写什么
1)普通方法

Log.e() 方法。代码如下:

public class Hook_Log_e {
    public static String className = "android.util.Log";
    public static String methodName = "e";
    public static String methodSig = "(Ljava/lang/String;Ljava/lang/String;)I";
    public static int hook(String tag, String msg) {
        Log.w("YAHFA", "in Log.e(): "+tag+", "+msg);
        return backup(tag, msg);
    }

    public static int backup(String tag, String msg) {
        Log.w("YAHFA", "Log.e() should not be here");
        return 1;
    }
}
2)静态方法

静态方法和静态差不多,区别就是,静态的方法在hook和origin的参数中,少一个 Object 的参数。如 URI.create() 方法。代码如下:

public class Hook_url {
    public static String className = "java.net.URI";
    public static String methodName = "create";
    public static String methodSig = "(Ljava/lang/String;)Ljava/net/URI;";
    public static Object hook(String url)
    {
        // 改变 url 的值
        url = "http://www.baidu.com";
        return origin(url);
    }
 
    public static Object origin(String url)
    {
        Log.w("YAHFA", "String.startsWith() should not be here");
        return url;
    }
}
3)匿名内部类

内部类只是编译时的概念,一旦编译成功,就会出现两个不同的类,例如,类outClass中有个intClass,那么编译后就出现一个名为outClass.class和一个outClass$intClass.class的类。所以className中就要指定类路径为a.b.c.outClass$intClass

4、获取方法的签名描述符

1)方法签名描述符组成,括号内是参数的签名,括号外是返回值的签名:
如 Log.e() 里面的方法:
    public static int e(String tag, String msg)
对应
    (Ljava/lang/String;Ljava/lang/String;)I
2)各类型参照表
  • 除了 boolean 和 long 类型分别是 Z 和 J 外,其他的描述符对应的都是 Java 类型名的大写首字母。另外,void 的描述符为 V
File DesciptorJava Language Type
Zboolean
Bbyte
Cchar
Sshort
Iint
Jlong
Ffloat
Ddouble
Vvoid
[array
L + 类型描符 + ;引用类型
  • 说明:
  1. 数组用 [ 表示,二维数组 [[ 表示。如: [Ljava/lang/String; 对应 String[],
    [[Ljava/lang/Object; 对应 Object[][]
  2. 引用类型注意前面的 L , “/” 分割和 “;” ,不要遗漏了。如:Lcom/tencent/wcdb/Cursor;
  3. String 是对象,所以是:Ljava/lang/String;
  4. 还是不知道怎么写的话,可以通过以下 adb 命令找到方法签名描述符:
1. 查看 Java 类的方式  javap -s java.awt.Label
2. 查看 Android 类的方式  javap -s -bootclasspath "D:\Program Files\Android\android-sdk\platforms\android-25\android.jar" -classpath bin/classes android.app.Activity
3. 查看第三方 Jar 的类的方式 javap -s  -classpath "D:\AMap_Location.jar" com.amap.api.location.AMapLocation

四、VirtualHook 搭配 YAHFA 使用教程

我们这里是使用 VirtualHook 来实践 。总体步骤如下:

  1. git clone VirtualHook 工程或者下载源码
  2. 新建 module 并配置为插件
  3. module 打包成 apk,并放到手机里面
  4. VirtualHook 里面,克隆目标 App 和加载插件 apk

项目目录结构如下:

《装X指南之通过 VirtualApp 实现免 Root 权限 Hook》 项目目录结构

  • applibVirtualApp 相关代码
  • YAHFAHook 框架代码
  • demoHookPlugin 是插件 module

1、配置插件 module

配置插件 moduleAndroidManifest.xmlmeta-data 的值,设置 valuetrue

<application
    android:label="@string/app_name">
    <meta-data
        android:name="yahfa.hook.plugin"
        android:value="true"
    />
</application>

2、配置 Hook 类

假如我们需要 Hook 处理 Log.e() 方法,新建一个 Hook_Log_e 类,并在 lab.galaxy.yahfa.HookInfo 配置(不配置的话,hook 不生效),代码如下:

public class HookInfo {
    public static String[] hookItemNames = {
           "lab.galaxy.yahfa.demoPlugin.Hook_Log_e",
    };
}

注意:HookInfo 类的包名,如果需要改的话,要同时改 HookMain.doHookDefault() 方法里面的包名。

public static void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader) {
    try {
        Class<?> hookInfoClass = Class.forName("lab.galaxy.yahfa.HookInfo", true, patchClassLoader);
        String[] hookItemNames = (String[])hookInfoClass.getField("hookItemNames").get(null);
        for(String hookItemName : hookItemNames) {
            doHookItemDefault(patchClassLoader, hookItemName, originClassLoader);
        }
        hookInfoClasses.add(hookInfoClass);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

3、验证结果

  • 这里我写了个 hook 微信启动页的 onCreate() 方法。
public class Hook_Wx_Launcher {
    public static String className = "com.tencent.mm.ui.LauncherUI";
    public static String methodName = "onCreate";
    public static String methodSig = "(Landroid/os/Bundle;)V";

    public static Activity LauncherUi;

    public static void hook(Object thiz, Bundle b) {
        Log.w("czc", "LauncherUI oncreate");
        return "";
    }

    public static void backup(Object thiz, Bundle b) {
        Log.w("YAHFA", "LauncherUI backup");
        return;
    }
}
  • 安装打包好的插件apk,插件左上有个小图标,以作区别,同时克隆 微信 到 VirtualHook 里面

《装X指南之通过 VirtualApp 实现免 Root 权限 Hook》 插件

《装X指南之通过 VirtualApp 实现免 Root 权限 Hook》 安装

  • hook 成功打印出 log

    《装X指南之通过 VirtualApp 实现免 Root 权限 Hook》 Hook_Wx_Launcher

更多技术分享,请关注微信公众号——码农茅草屋:

《装X指南之通过 VirtualApp 实现免 Root 权限 Hook》 码农茅草屋

    原文作者:幕后眼光
    原文地址: https://www.jianshu.com/p/865300d4d6f9
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞