An overview,

This article describes how to implement root-free hook via FastHook + VirtualApp. Since VirtualApp is no longer up to date, this article is intended as a tutorial and does not address compatibility and stability issues.

Project address: VirtualFastHook: github.com/turing-tech…

Two, the implementation principle

To implement hook application, it can be simply divided into the following three steps: 1. Identify hook plug-in 2. Save Hook plug-in information. 3. Obtain Hook plug-in information and Hook

2.1 Identify Hook plug-ins

Androidmanifest.xml: androidmanifest.xml: androidmanifest.xml: androidmanifest.xml: androidmanifest.xml: androidmanifest.xml

<meta-data
        android:name="fasthook.hook.plugin"
        android:value="true"/>
        
<meta-data
        android:name="fasthook.hook.process"
        android:value="XXX"/>
        
<meta-data
        android:name="fasthook.hook.info"
        android:value="XXX"/>
Copy the code

1. Fasthook.hook. Plugin: indicates that this is a hook plug-in

Fasthook. hook. Process: indicates the process to hook

3. Fasthook. hook. Info: indicates the name of the hook information class

You can add code to determine whether Apk is a Hook plug-in when VirtualApp parses it, for example in apPrepository.java

private List<AppInfo> convertPackageInfoToAppData(Context context, List<PackageInfo> pkgList, boolean fastOpen) {
        PackageManager pm = context.getPackageManager();
        List<AppInfo> list = new ArrayList<>(pkgList.size());
        String hostPkg = VirtualCore.get().getHostPkg();
        for (PackageInfo pkg : pkgList) {
            // ignore the host package
            if (hostPkg.equals(pkg.packageName)) {
                continue;
            }
            // ignore the System package
            if (isSystemApplication(pkg)) {
                continue;
            }
            boolean isHookPlugin = false; //start check whether it is a Hook plugin ApplicationInfo ai = null; try { ai = context.getPackageManager().getApplicationInfo(pkg.packageName,PackageManager.GET_META_DATA);if(ai.metaData ! = null) { booleanenable = ai.metaData.getBoolean("fasthook.hook.plugin".false);
                    if(enable) {
                        String hookProcess = ai.metaData.getString("fasthook.hook.process"."");
                        String hookInfo = ai.metaData.getString("fasthook.hook.info"."");
                        if(! hookProcess.isEmpty() || ! hookInfo.isEmpty()) { isHookPlugin =true; } } } }catch (Exception e) { e.printStackTrace(); } //end check whether it is Hook plugin String path = ai.publicsourcedir! = null ? ai.publicSourceDir : ai.sourceDir;if (path == null) {
                continue;
            }
            AppInfo info = new AppInfo();
            info.packageName = pkg.packageName;
            info.fastOpen = fastOpen;
            info.path = path;
            info.icon = ai.loadIcon(pm);
            info.name = ai.loadLabel(pm);
            info.isHook = isHookPlugin;
            InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(pkg.packageName, 0);
            if(installedAppInfo ! = null) { info.cloneCount = installedAppInfo.getInstalledUsers().length; } list.add(info); }return list;
    }
Copy the code

2.2 How to Obtain the Hook plug-in

The Hook plug-in can be saved during apK installation, for example in vappManagerService.java.

public synchronized InstallResult installPackage(String path, int flags, Boolean notify {// null code Boolean isHook = (flags & installStrategy.is_hook)! = 0; // Irrelevant codeif (res.isUpdate) {
            FileUtils.deleteDir(libDir);
            VEnvironment.getOdexFile(pkg.packageName).delete();
            if(isHook) {
                VActivityManagerService.get().killAllApps();
            }
            else{ VActivityManagerService.get().killAppByPkg(pkg.packageName, VUserHandle.USER_ALL); }} // params;if(existSetting ! = null) { ps = existSetting; }else {
            ps = new PackageSetting();
        }
        ps.isHook = isHook;
        ps.dependSystem = dependSystem;
        ps.apkPath = packageFile.getPath();
        ps.libPath = libDir.getPath();
        ps.packageName = pkg.packageName;
        ps.appId = VUserHandle.getAppId(mUidSystem.getOrCreateUid(pkg));
        if (res.isUpdate) {
            ps.lastUpdateTime = installTime;
        } else {
            ps.firstInstallTime = installTime;
            ps.lastUpdateTime = installTime;
            for (int userId : VUserManagerService.get().getUserIds()) {
                boolean installed = userId == 0;
                ps.setUserState(userId, false/*launched*/, false/*hidden*/, installed); }} // irrelevant code // save Hook plugin informationif(isHook) { HookCacheManager.HookCacheInfo info = new HookCacheManager.HookCacheInfo(ps.packageName,(String)(pkg.mAppMetaData.get(HookCacheManager.HOOK_PROCESS)),(String)(pkg .mAppMetaData.get(HookCacheManager.HOOK_INFO))); HookCacheManager.put((String)(pkg.mAppMetaData.get(HookCacheManager.HOOK_PROCESS)),info); }else if (notify) {
            notifyAppInstalled(ps, -1);
        }
        res.isSuccess = true;
        return res;
    }
Copy the code

2.3 how to Hook

You can Hook it anywhere, but for better Hook, Hook it after the apK application is loaded and before the attachBaseContext method is called, so you can Hook all the methods of the application. For example, in vclientimpl.java.

private void bindApplicationNoCheck (String packageName, String processName, ConditionVariable lock) {/ / independent code NativeEngine launchEngine ();  Object mainThread = VirtualCore.mainThread(); NativeEngine.startDexOverride(); Context context = createPackageContext(data.appInfo.packageName); System.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath()); Object boundApp = fixBoundApp(mBoundApplication); mBoundApplication.info = ContextImpl.mPackageInfo.get(context); mirror.android.app.ActivityThread.AppBindData.info.set(boundApp, data.info); VMRuntime.setTargetSdkVersion.call(VMRuntime.getRuntime.call(), data.appInfo.targetSdkVersion); / / Hook try {tryHook (processName, context getClassLoader ()); }catch (Exception e) { e.printStackTrace(); } // Irrelevant code virtualCore.get ().getComponentDelegate().beforeApplicationCreate(mInitialApplication); try { mInstrumentation.callApplicationOnCreate(mInitialApplication); InvocationStubManager.getInstance().checkEnv(HCallbackStub.class);if (conflict) {
                InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class);
            }
            Application createdApp = ActivityThread.mInitialApplication.get(mainThread);
            if(createdApp ! = null) { mInitialApplication = createdApp; } } catch (Exception e) {if(! mInstrumentation.onException(mInitialApplication, e)) { throw new RuntimeException("Unable to create application " + mInitialApplication.getClass().getName()
                                + ":"+ e.toString(), e); } } VActivityManager.get().appDoneExecuting(); VirtualCore.get().getComponentDelegate().afterApplicationCreate(mInitialApplication); } // Hook private void tryHook(String process, ClassLoader apkClassLoader) { String[] infos = VPackageManager.get().getInstalledHookPlugins(process);if(infos ! = null) {for(String info : infos) {
                int size = info.charAt(0);
                String pluginName = info.substring(1,1 + size);
                String hookInfoName = info.substring(1 + size);

		DexClassLoader hookClassLoader = new DexClassLoader(VEnvironment.getPackageResourcePath(pluginName).getAbsolutePath(),
                        VEnvironment.getDalvikCacheDirectory().getAbsolutePath(),
                        VEnvironment.getPackageLibPath(pluginName).getAbsolutePath(),
                        apkClassLoader);

		FastHookManager.doHook(hookInfoName,hookClassLoader,apkClassLoader,hookClassLoader,hookClassLoader,false); }}}Copy the code

Hook wechat

3.1 Preparing a Hook plug-in

According to the FastHook framework, the following information is provided:

1. HookMethodInfo. Java (Hook method, Forward method concrete implementation)

public class HookMethodInfo {
    public static void hook(Object thiz, Context context) {
        Log.d("FastHookManager"."hook attachBaseContext2");
        forward(thiz,context);
        Toast toast = Toast.makeText(context,"hook attachBaseContext2",Toast.LENGTH_LONG);
        toast.show();
    }
    
    public native static void forward(Object thiz, Context context);
}
Copy the code

You can see that the logic of the Hook method is very simple, just pop up a Toast with the content of Hook attachBaseContext2.

2. Hookinfo.java (provides HOOK_ITEMS information according to the FastHook framework)

public class HookInfo {
    public static String[][] HOOK_ITEMS = {
            {"1"."com.tencent.tinker.loader.app.TinkerApplication"."attachBaseContext"."Landroid/content/Context;"."com.example.fasthookplugin.HookMethodInfo"."hook"."Ljava/lang/Object; Landroid/content/Context;"."com.example.fasthookplugin.HookMethodInfo"."forward"."Ljava/lang/Object; Landroid/content/Context;"}}; }Copy the code

Inline mode is used and the Hook is the attachBaseContext method, which is the first method to be invoked by the system.

3. Configure androidmanifest.xml (configure Hook plugin information)

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="fasthook.hook.plugin"
            android:value="true"/>

	<meta-data
            android:name="fasthook.hook.process"
            android:value="com.tencent.mm"/>
	
	<meta-data
            android:name="fasthook.hook.info"
            android:value="com.example.fasthookplugin.HookInfo"/>
	<activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

		<category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
Copy the code

Apk is configured as Hook plug-in, the target process of Hook is com.tencent. Mm, namely the main process of wechat, and the specific Hook information is located in HookInfo class HOOK_ITEMS array.

Three, the actual effect

Install VirtualFastHook and Hook plugins and run them to see what happens

All Hook plugins have a small red icon in the upper left corner, indicating that the application is a Hook plug-in

Four, conclusion

The above is just a basic Hook operation, in fact, it can also make more useful functions, the following is my handy 7.0.3 version of wechat message withdrawal.

reference

FastHook — An efficient, stable, simple and easy to use Android Hook framework

FastHook:github.com/turing-tech…

VirtualApp:github.com/asLody/Virt…

FastHook series

  1. FastHook — An efficient, stable, simple and easy to use Android Hook framework
  2. FastHook — Smart use of dynamic proxies for non-invasive AOP
  3. FastHook — Superior stability over YAHFA
  4. FastHook – implements.dynsym and.symtab symbol queries