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
- FastHook — An efficient, stable, simple and easy to use Android Hook framework
- FastHook — Smart use of dynamic proxies for non-invasive AOP
- FastHook — Superior stability over YAHFA
- FastHook – implements.dynsym and.symtab symbol queries