經過 VirtualApp 實現免 Root 權限 Hook

1、前言

以前寫的 「裝X指南之Xposed安裝與配置」,有人反饋手機 root 風險較大,並且操做成本高,有沒有什麼方法是不須要 root 就可以實現 hook 的或者不須要 Xposed 也能玩起插件的?因而就有了這篇文章,離開 Xposed ,帶你免 root 實現 hook!java

2、VirtualApp

1.關於 VirtualApp 的介紹

VA目前被普遍應用於插件化開發、無感知熱更新、自動化、多開等技術領域,但它決不只限於此,Android自己就是一個極其開放的平臺,免安裝運行APK這一Feature打開了無限可能-----這都取決於您的想象力。android

感謝 asLody 開源,聽說他寫這個項目才高二,佩服佩服~git

  • VirtualApp 項目地址:
  1. github.com/asLody/Virt…

2.VirtualApp 的原理

VirtualApp 僞造了一套 framework 代碼,實現全部在其進程啓動的應用,都運行在一個虛擬空間(注:我的理解,若有錯誤,還請指出)。github

  • VirtualApp 源碼學習與原理分析
  1. blog.csdn.net/leif_/artic…
  2. blog.csdn.net/ganyao93954…

3.VirtualApp 使用問題

Github 上的代碼,做者已經沒有繼續開源更新了,能夠看到後續的全部修改,都在做者的商業版上操做,因此有可能在使用上會出現一些 bugapi

其實能夠看到「商業版」,無論穩定性與兼容性,都作了很大的修復和改動,最重要的是,支持 Dalvik 和 Art 的 Java Hook( API 同 Xposed ),惋惜在做者沒有公開源碼的狀況下,咱們我的不可能爲了學習去購買「商業版」~數組

特別說明:做者明確指出,若是項目須要投入商業使用,請購買「商業版」。咱們這裏僅作技術學習使用bash

商業版特性

4.VirtualHook 介紹

上文說到咱們沒法使用「商業版」的 VirtualApp ,來進行 Hook ,準確來講是做者沒把 Hook 的 Api 公開。微信

下面我要介紹另外一個基於 VirtualApp 改造的項目 —— VirtualHook(區分:VirtualAppVirtualHook 的區別,不要搞混了,後文使用 VirtualHook 來實踐),感謝 rk700 開源 VirtualHook 與 YAHFAapp

1)VirtualHook 項目地址:
  1. github.com/rk700/Virtu…
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);
複製代碼

3、YAHFA

1.YAHFA 介紹

YAHFA(Yet Another Hook Framework for ART) 是基於 ART 的 Hook 框架,支持 Android 5.0 ~ 9.0 版本的 Java 方法的 Hook 與替代 。而 VirtualHook 則是靠 YAHFA 實現的免 Root Hook。

  • 來自看雪論壇:
  1. bbs.pediy.com/thread-2167…
  • YAHFA 項目地址:
  1. github.com/rk700/YAHFA

2.YAHFA 原理

我是看不太懂裏面的原理,可是仍是把別人的分析過程,貼出來給你們,但願看懂的朋友,不吝分享:

  • 寫文的時候,好像做者的博客掛了,不過仍是寫上吧

rk700.github.io/2017/03/30/…

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

blog.csdn.net/zhu92903326…

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 Desciptor Java Language Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double
V void
[ 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
複製代碼

4、VirtualHook 搭配 YAHFA 使用教程

咱們這裏是使用 VirtualHook 來實踐 。整體步驟以下:

  1. git clone VirtualHook 工程或者下載源碼
  2. 新建 module 並配置爲插件
  3. module 打包成 apk,並放到手機裏面
  4. VirtualHook 裏面,克隆目標 App 和加載插件 apk

項目目錄結構以下:

項目目錄結構

  • 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 裏面

插件
安裝

  • hook 成功打印出 log
    Hook_Wx_Launcher

更多技術分享,請加微信公衆號——碼農茅草屋:

碼農茅草屋
相關文章
相關標籤/搜索