本文介绍如何通过FastHook + VirtualApp实现免root hook。由于VirtualApp已经不更新了,所以本文只作为一个教程,并不主要解决一些兼容和稳定性问题。
二、实现原理
本文介绍如何通过FastHook + VirtualApp实现免root hook。由于VirtualApp已经不更新了,所以本文只作为一个教程,并不主要解决一些兼容和稳定性问题。
要实现应用hook,可以简单的分为下面三个步骤:
- 识别Hook插件
- 保存Hook插件信息
- 获取Hook插件信息进行Hook
规定Hook插件须在
AndroidManifest.xml里定义三个
<meta-data>:
<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"/>
-
fasthook.hook.plugin:表示这是一个Hook插件
-
fasthook.hook.process:表示要Hook的进程
-
fasthook.hook.info:Hook信息类名
可以在VirtualApp解析Apk时加上判断是否为Hook插件的代码,例如在
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;
//判断是否是Hook插件
ApplicationInfo ai = null;
try {
ai = context.getPackageManager().getApplicationInfo(pkg.packageName,PackageManager.GET_META_DATA);
if(ai.metaData != null) {
boolean enable = 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();
}
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;
android.util.Log.d("FastHookManager","isHookPlugin:"+isHookPlugin+" package:"+pkg.packageName);
InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(pkg.packageName, 0);
if (installedAppInfo != null) {
info.cloneCount = installedAppInfo.getInstalledUsers().length;
}
list.add(info);
}
return list;
}
在apk安装时,可以把Hook插件保存起来,例如在
VAppManagerService.java
public synchronized InstallResult installPackage(String path, int flags, boolean notify) {
long installTime = System.currentTimeMillis();
if (path == null) {
return InstallResult.makeFailure("path = NULL");
}
boolean isHook = (flags & InstallStrategy.IS_HOOK) != 0;
File packageFile = new File(path);
if (!packageFile.exists() || !packageFile.isFile()) {
return InstallResult.makeFailure("Package File is not exist.");
}
VPackage pkg = null;
try {
pkg = PackageParserEx.parsePackage(packageFile);
} catch (Throwable e) {
e.printStackTrace();
}
if (pkg == null || pkg.packageName == null) {
return InstallResult.makeFailure("Unable to parse the package.");
}
InstallResult res = new InstallResult();
res.packageName = pkg.packageName;
// PackageCache holds all packages, try to check if we need to update.
VPackage existOne = PackageCacheManager.get(pkg.packageName);
PackageSetting existSetting = existOne != null ? (PackageSetting) existOne.mExtras : null;
if (existOne != null) {
if ((flags & InstallStrategy.IGNORE_NEW_VERSION) != 0) {
res.isUpdate = true;
return res;
}
if (!canUpdate(existOne, pkg, flags)) {
return InstallResult.makeFailure("Not allowed to update the package.");
}
res.isUpdate = true;
}
File appDir = VEnvironment.getDataAppPackageDirectory(pkg.packageName);
File libDir = new File(appDir, "lib");
if (res.isUpdate) {
FileUtils.deleteDir(libDir);
VEnvironment.getOdexFile(pkg.packageName).delete();
if(isHook) {
VActivityManagerService.get().killAllApps();
}
else {
VActivityManagerService.get().killAppByPkg(pkg.packageName, VUserHandle.USER_ALL);
}
}
if (!libDir.exists() && !libDir.mkdirs()) {
return InstallResult.makeFailure("Unable to create lib dir.");
}
boolean dependSystem = (flags & InstallStrategy.DEPEND_SYSTEM_IF_EXIST) != 0
&& VirtualCore.get().isOutsideInstalled(pkg.packageName);
if (existSetting != null && existSetting.dependSystem) {
dependSystem = false;
}
NativeLibraryHelperCompat.copyNativeBinaries(new File(path), libDir);
try {
// copy libva-native.so so that the symbol MSHookFunction() can be accessed in patch plugin after Android N
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
File vaNativeSo = new File(libDir, "libva++.so");
if (!vaNativeSo.exists()) {
FileUtils.createSymlink(
new File(VEnvironment.getRoot().getParent(), "lib/libva++.so").getAbsolutePath(),
vaNativeSo.getAbsolutePath());
}
}
}
catch (Exception e) {
e.printStackTrace();
}
if (!dependSystem) {
File privatePackageFile = new File(appDir, "base.apk");
File parentFolder = privatePackageFile.getParentFile();
if (!parentFolder.exists() && !parentFolder.mkdirs()) {
VLog.w(TAG, "Warning: unable to create folder : " + privatePackageFile.getPath());
} else if (privatePackageFile.exists() && !privatePackageFile.delete()) {
VLog.w(TAG, "Warning: unable to delete file : " + privatePackageFile.getPath());
}
try {
FileUtils.copyFile(packageFile, privatePackageFile);
} catch (IOException e) {
privatePackageFile.delete();
return InstallResult.makeFailure("Unable to copy the package file.");
}
packageFile = privatePackageFile;
chmodPackageDictionary(packageFile);
}
if (existOne != null) {
PackageCacheManager.remove(pkg.packageName);
}
PackageSetting ps;
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);
}
}
PackageParserEx.savePackageCache(pkg);
PackageCacheManager.put(pkg, ps);
mPersistenceLayer.save();
if (!dependSystem) {
boolean runDexOpt = false;
if (VirtualRuntime.isArt()) {
try {
ArtDexOptimizer.interpretDex2Oat(ps.apkPath, VEnvironment.getOdexFile(ps.packageName).getPath());
} catch (IOException e) {
e.printStackTrace();
runDexOpt = true;
}
} else {
runDexOpt = true;
}
if (runDexOpt) {
try {
DexFile.loadDex(ps.apkPath, VEnvironment.getOdexFile(ps.packageName).getPath(), 0).close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BroadcastSystem.get().startApp(pkg);
//保存Hook插件信息
if(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;
}
实际可以在任意地方Hook,但为了更好的Hook,这里在应用apk加载之后,attachBaseContext方法调用之前进行Hook,这样便可以Hook所有应用的方法了。例如在
VClientImpl.java
private void bindApplicationNoCheck(String packageName, String processName, ConditionVariable lock) {
VDeviceInfo deviceInfo = getDeviceInfo();
if (processName == null) {
processName = packageName;
}
mTempLock = lock;
try {
setupUncaughtHandler();
} catch (Throwable e) {
e.printStackTrace();
}
try {
fixInstalledProviders();
} catch (Throwable e) {
e.printStackTrace();
}
mirror.android.os.Build.SERIAL.set(deviceInfo.serial);
mirror.android.os.Build.DEVICE.set(Build.DEVICE.replace(" ", "_"));
ActivityThread.mInitialApplication.set(
VirtualCore.mainThread(),
null
);
AppBindData data = new AppBindData();
InstalledAppInfo info = VirtualCore.get().getInstalledAppInfo(packageName, 0);
if (info == null) {
new Exception("App not exist!").printStackTrace();
Process.killProcess(0);
System.exit(0);
}
data.appInfo = VPackageManager.get().getApplicationInfo(packageName, 0, getUserId(vuid));
data.processName = processName;
data.providers = VPackageManager.get().queryContentProviders(processName, getVUid(), PackageManager.GET_META_DATA);
Log.i(TAG, "Binding application " + data.appInfo.packageName + " (" + data.processName + ")");
mBoundApplication = data;
VirtualRuntime.setupRuntime(data.processName, data.appInfo);
int targetSdkVersion = data.appInfo.targetSdkVersion;
if (targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {
StrictMode.ThreadPolicy newPolicy = new StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();
StrictMode.setThreadPolicy(newPolicy);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
mirror.android.os.Message.updateCheckRecycle.call(targetSdkVersion);
}
if (VASettings.ENABLE_IO_REDIRECT) {
startIOUniformer();
}
NativeEngine.launchEngine();
Object mainThread = VirtualCore.mainThread();
NativeEngine.startDexOverride();
Context context = createPackageContext(data.appInfo.packageName);
System.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath());
File codeCacheDir;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
codeCacheDir = context.getCodeCacheDir();
} else {
codeCacheDir = context.getCacheDir();
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
if (HardwareRenderer.setupDiskCache != null) {
HardwareRenderer.setupDiskCache.call(codeCacheDir);
}
} else {
if (ThreadedRenderer.setupDiskCache != null) {
ThreadedRenderer.setupDiskCache.call(codeCacheDir);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (RenderScriptCacheDir.setupDiskCache != null) {
RenderScriptCacheDir.setupDiskCache.call(codeCacheDir);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (RenderScript.setupDiskCache != null) {
RenderScript.setupDiskCache.call(codeCacheDir);
}
}
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();
}
Configuration configuration = context.getResources().getConfiguration();
Object compatInfo = CompatibilityInfo.ctor.newInstance(data.appInfo, configuration.screenLayout, configuration.smallestScreenWidthDp, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
DisplayAdjustments.setCompatibilityInfo.call(ContextImplKitkat.mDisplayAdjustments.get(context), compatInfo);
}
DisplayAdjustments.setCompatibilityInfo.call(LoadedApkKitkat.mDisplayAdjustments.get(mBoundApplication.info), compatInfo);
} else {
CompatibilityInfoHolder.set.call(LoadedApkICS.mCompatibilityInfo.get(mBoundApplication.info), compatInfo);
}
boolean conflict = SpecialComponentList.isConflictingInstrumentation(packageName);
if (!conflict) {
InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class);
}
mInitialApplication = LoadedApk.makeApplication.call(data.info, false, null);
mirror.android.app.ActivityThread.mInitialApplication.set(mainThread, mInitialApplication);
ContextFixer.fixContext(mInitialApplication);
if (Build.VERSION.SDK_INT >= 24 && "com.tencent.mm:recovery".equals(processName)) {
fixWeChatRecovery(mInitialApplication);
}
if (data.providers != null) {
installContentProviders(mInitialApplication, data.providers);
}
if (lock != null) {
lock.open();
mTempLock = null;
}
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插件并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);
}
}
}
三、Hook微信
要实现应用hook,可以简单的分为下面三个步骤:
- 识别Hook插件
- 保存Hook插件信息
- 获取Hook插件信息进行Hook
规定Hook插件须在
AndroidManifest.xml里定义三个
<meta-data>:
<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"/>
-
fasthook.hook.plugin:表示这是一个Hook插件
-
fasthook.hook.process:表示要Hook的进程
-
fasthook.hook.info:Hook信息类名
可以在VirtualApp解析Apk时加上判断是否为Hook插件的代码,例如在
AppRepository.java
<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"/>
-
fasthook.hook.plugin:表示这是一个Hook插件
-
fasthook.hook.process:表示要Hook的进程
-
fasthook.hook.info:Hook信息类名
可以在VirtualApp解析Apk时加上判断是否为Hook插件的代码,例如在
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;
//判断是否是Hook插件
ApplicationInfo ai = null;
try {
ai = context.getPackageManager().getApplicationInfo(pkg.packageName,PackageManager.GET_META_DATA);
if(ai.metaData != null) {
boolean enable = 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();
}
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;
android.util.Log.d("FastHookManager","isHookPlugin:"+isHookPlugin+" package:"+pkg.packageName);
InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(pkg.packageName, 0);
if (installedAppInfo != null) {
info.cloneCount = installedAppInfo.getInstalledUsers().length;
}
list.add(info);
}
return list;
}
在apk安装时,可以把Hook插件保存起来,例如在
VAppManagerService.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;
//判断是否是Hook插件
ApplicationInfo ai = null;
try {
ai = context.getPackageManager().getApplicationInfo(pkg.packageName,PackageManager.GET_META_DATA);
if(ai.metaData != null) {
boolean enable = 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();
}
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;
android.util.Log.d("FastHookManager","isHookPlugin:"+isHookPlugin+" package:"+pkg.packageName);
InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(pkg.packageName, 0);
if (installedAppInfo != null) {
info.cloneCount = installedAppInfo.getInstalledUsers().length;
}
list.add(info);
}
return list;
}
在apk安装时,可以把Hook插件保存起来,例如在
VAppManagerService.java
public synchronized InstallResult installPackage(String path, int flags, boolean notify) {
long installTime = System.currentTimeMillis();
if (path == null) {
return InstallResult.makeFailure("path = NULL");
}
boolean isHook = (flags & InstallStrategy.IS_HOOK) != 0;
File packageFile = new File(path);
if (!packageFile.exists() || !packageFile.isFile()) {
return InstallResult.makeFailure("Package File is not exist.");
}
VPackage pkg = null;
try {
pkg = PackageParserEx.parsePackage(packageFile);
} catch (Throwable e) {
e.printStackTrace();
}
if (pkg == null || pkg.packageName == null) {
return InstallResult.makeFailure("Unable to parse the package.");
}
InstallResult res = new InstallResult();
res.packageName = pkg.packageName;
// PackageCache holds all packages, try to check if we need to update.
VPackage existOne = PackageCacheManager.get(pkg.packageName);
PackageSetting existSetting = existOne != null ? (PackageSetting) existOne.mExtras : null;
if (existOne != null) {
if ((flags & InstallStrategy.IGNORE_NEW_VERSION) != 0) {
res.isUpdate = true;
return res;
}
if (!canUpdate(existOne, pkg, flags)) {
return InstallResult.makeFailure("Not allowed to update the package.");
}
res.isUpdate = true;
}
File appDir = VEnvironment.getDataAppPackageDirectory(pkg.packageName);
File libDir = new File(appDir, "lib");
if (res.isUpdate) {
FileUtils.deleteDir(libDir);
VEnvironment.getOdexFile(pkg.packageName).delete();
if(isHook) {
VActivityManagerService.get().killAllApps();
}
else {
VActivityManagerService.get().killAppByPkg(pkg.packageName, VUserHandle.USER_ALL);
}
}
if (!libDir.exists() && !libDir.mkdirs()) {
return InstallResult.makeFailure("Unable to create lib dir.");
}
boolean dependSystem = (flags & InstallStrategy.DEPEND_SYSTEM_IF_EXIST) != 0
&& VirtualCore.get().isOutsideInstalled(pkg.packageName);
if (existSetting != null && existSetting.dependSystem) {
dependSystem = false;
}
NativeLibraryHelperCompat.copyNativeBinaries(new File(path), libDir);
try {
// copy libva-native.so so that the symbol MSHookFunction() can be accessed in patch plugin after Android N
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
File vaNativeSo = new File(libDir, "libva++.so");
if (!vaNativeSo.exists()) {
FileUtils.createSymlink(
new File(VEnvironment.getRoot().getParent(), "lib/libva++.so").getAbsolutePath(),
vaNativeSo.getAbsolutePath());
}
}
}
catch (Exception e) {
e.printStackTrace();
}
if (!dependSystem) {
File privatePackageFile = new File(appDir, "base.apk");
File parentFolder = privatePackageFile.getParentFile();
if (!parentFolder.exists() && !parentFolder.mkdirs()) {
VLog.w(TAG, "Warning: unable to create folder : " + privatePackageFile.getPath());
} else if (privatePackageFile.exists() && !privatePackageFile.delete()) {
VLog.w(TAG, "Warning: unable to delete file : " + privatePackageFile.getPath());
}
try {
FileUtils.copyFile(packageFile, privatePackageFile);
} catch (IOException e) {
privatePackageFile.delete();
return InstallResult.makeFailure("Unable to copy the package file.");
}
packageFile = privatePackageFile;
chmodPackageDictionary(packageFile);
}
if (existOne != null) {
PackageCacheManager.remove(pkg.packageName);
}
PackageSetting ps;
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);
}
}
PackageParserEx.savePackageCache(pkg);
PackageCacheManager.put(pkg, ps);
mPersistenceLayer.save();
if (!dependSystem) {
boolean runDexOpt = false;
if (VirtualRuntime.isArt()) {
try {
ArtDexOptimizer.interpretDex2Oat(ps.apkPath, VEnvironment.getOdexFile(ps.packageName).getPath());
} catch (IOException e) {
e.printStackTrace();
runDexOpt = true;
}
} else {
runDexOpt = true;
}
if (runDexOpt) {
try {
DexFile.loadDex(ps.apkPath, VEnvironment.getOdexFile(ps.packageName).getPath(), 0).close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BroadcastSystem.get().startApp(pkg);
//保存Hook插件信息
if(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;
}
实际可以在任意地方Hook,但为了更好的Hook,这里在应用apk加载之后,attachBaseContext方法调用之前进行Hook,这样便可以Hook所有应用的方法了。例如在
VClientImpl.java
public synchronized InstallResult installPackage(String path, int flags, boolean notify) {
long installTime = System.currentTimeMillis();
if (path == null) {
return InstallResult.makeFailure("path = NULL");
}
boolean isHook = (flags & InstallStrategy.IS_HOOK) != 0;
File packageFile = new File(path);
if (!packageFile.exists() || !packageFile.isFile()) {
return InstallResult.makeFailure("Package File is not exist.");
}
VPackage pkg = null;
try {
pkg = PackageParserEx.parsePackage(packageFile);
} catch (Throwable e) {
e.printStackTrace();
}
if (pkg == null || pkg.packageName == null) {
return InstallResult.makeFailure("Unable to parse the package.");
}
InstallResult res = new InstallResult();
res.packageName = pkg.packageName;
// PackageCache holds all packages, try to check if we need to update.
VPackage existOne = PackageCacheManager.get(pkg.packageName);
PackageSetting existSetting = existOne != null ? (PackageSetting) existOne.mExtras : null;
if (existOne != null) {
if ((flags & InstallStrategy.IGNORE_NEW_VERSION) != 0) {
res.isUpdate = true;
return res;
}
if (!canUpdate(existOne, pkg, flags)) {
return InstallResult.makeFailure("Not allowed to update the package.");
}
res.isUpdate = true;
}
File appDir = VEnvironment.getDataAppPackageDirectory(pkg.packageName);
File libDir = new File(appDir, "lib");
if (res.isUpdate) {
FileUtils.deleteDir(libDir);
VEnvironment.getOdexFile(pkg.packageName).delete();
if(isHook) {
VActivityManagerService.get().killAllApps();
}
else {
VActivityManagerService.get().killAppByPkg(pkg.packageName, VUserHandle.USER_ALL);
}
}
if (!libDir.exists() && !libDir.mkdirs()) {
return InstallResult.makeFailure("Unable to create lib dir.");
}
boolean dependSystem = (flags & InstallStrategy.DEPEND_SYSTEM_IF_EXIST) != 0
&& VirtualCore.get().isOutsideInstalled(pkg.packageName);
if (existSetting != null && existSetting.dependSystem) {
dependSystem = false;
}
NativeLibraryHelperCompat.copyNativeBinaries(new File(path), libDir);
try {
// copy libva-native.so so that the symbol MSHookFunction() can be accessed in patch plugin after Android N
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
File vaNativeSo = new File(libDir, "libva++.so");
if (!vaNativeSo.exists()) {
FileUtils.createSymlink(
new File(VEnvironment.getRoot().getParent(), "lib/libva++.so").getAbsolutePath(),
vaNativeSo.getAbsolutePath());
}
}
}
catch (Exception e) {
e.printStackTrace();
}
if (!dependSystem) {
File privatePackageFile = new File(appDir, "base.apk");
File parentFolder = privatePackageFile.getParentFile();
if (!parentFolder.exists() && !parentFolder.mkdirs()) {
VLog.w(TAG, "Warning: unable to create folder : " + privatePackageFile.getPath());
} else if (privatePackageFile.exists() && !privatePackageFile.delete()) {
VLog.w(TAG, "Warning: unable to delete file : " + privatePackageFile.getPath());
}
try {
FileUtils.copyFile(packageFile, privatePackageFile);
} catch (IOException e) {
privatePackageFile.delete();
return InstallResult.makeFailure("Unable to copy the package file.");
}
packageFile = privatePackageFile;
chmodPackageDictionary(packageFile);
}
if (existOne != null) {
PackageCacheManager.remove(pkg.packageName);
}
PackageSetting ps;
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);
}
}
PackageParserEx.savePackageCache(pkg);
PackageCacheManager.put(pkg, ps);
mPersistenceLayer.save();
if (!dependSystem) {
boolean runDexOpt = false;
if (VirtualRuntime.isArt()) {
try {
ArtDexOptimizer.interpretDex2Oat(ps.apkPath, VEnvironment.getOdexFile(ps.packageName).getPath());
} catch (IOException e) {
e.printStackTrace();
runDexOpt = true;
}
} else {
runDexOpt = true;
}
if (runDexOpt) {
try {
DexFile.loadDex(ps.apkPath, VEnvironment.getOdexFile(ps.packageName).getPath(), 0).close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BroadcastSystem.get().startApp(pkg);
//保存Hook插件信息
if(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;
}
实际可以在任意地方Hook,但为了更好的Hook,这里在应用apk加载之后,attachBaseContext方法调用之前进行Hook,这样便可以Hook所有应用的方法了。例如在
VClientImpl.java
private void bindApplicationNoCheck(String packageName, String processName, ConditionVariable lock) {
VDeviceInfo deviceInfo = getDeviceInfo();
if (processName == null) {
processName = packageName;
}
mTempLock = lock;
try {
setupUncaughtHandler();
} catch (Throwable e) {
e.printStackTrace();
}
try {
fixInstalledProviders();
} catch (Throwable e) {
e.printStackTrace();
}
mirror.android.os.Build.SERIAL.set(deviceInfo.serial);
mirror.android.os.Build.DEVICE.set(Build.DEVICE.replace(" ", "_"));
ActivityThread.mInitialApplication.set(
VirtualCore.mainThread(),
null
);
AppBindData data = new AppBindData();
InstalledAppInfo info = VirtualCore.get().getInstalledAppInfo(packageName, 0);
if (info == null) {
new Exception("App not exist!").printStackTrace();
Process.killProcess(0);
System.exit(0);
}
data.appInfo = VPackageManager.get().getApplicationInfo(packageName, 0, getUserId(vuid));
data.processName = processName;
data.providers = VPackageManager.get().queryContentProviders(processName, getVUid(), PackageManager.GET_META_DATA);
Log.i(TAG, "Binding application " + data.appInfo.packageName + " (" + data.processName + ")");
mBoundApplication = data;
VirtualRuntime.setupRuntime(data.processName, data.appInfo);
int targetSdkVersion = data.appInfo.targetSdkVersion;
if (targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {
StrictMode.ThreadPolicy newPolicy = new StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();
StrictMode.setThreadPolicy(newPolicy);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
mirror.android.os.Message.updateCheckRecycle.call(targetSdkVersion);
}
if (VASettings.ENABLE_IO_REDIRECT) {
startIOUniformer();
}
NativeEngine.launchEngine();
Object mainThread = VirtualCore.mainThread();
NativeEngine.startDexOverride();
Context context = createPackageContext(data.appInfo.packageName);
System.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath());
File codeCacheDir;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
codeCacheDir = context.getCodeCacheDir();
} else {
codeCacheDir = context.getCacheDir();
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
if (HardwareRenderer.setupDiskCache != null) {
HardwareRenderer.setupDiskCache.call(codeCacheDir);
}
} else {
if (ThreadedRenderer.setupDiskCache != null) {
ThreadedRenderer.setupDiskCache.call(codeCacheDir);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (RenderScriptCacheDir.setupDiskCache != null) {
RenderScriptCacheDir.setupDiskCache.call(codeCacheDir);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (RenderScript.setupDiskCache != null) {
RenderScript.setupDiskCache.call(codeCacheDir);
}
}
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();
}
Configuration configuration = context.getResources().getConfiguration();
Object compatInfo = CompatibilityInfo.ctor.newInstance(data.appInfo, configuration.screenLayout, configuration.smallestScreenWidthDp, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
DisplayAdjustments.setCompatibilityInfo.call(ContextImplKitkat.mDisplayAdjustments.get(context), compatInfo);
}
DisplayAdjustments.setCompatibilityInfo.call(LoadedApkKitkat.mDisplayAdjustments.get(mBoundApplication.info), compatInfo);
} else {
CompatibilityInfoHolder.set.call(LoadedApkICS.mCompatibilityInfo.get(mBoundApplication.info), compatInfo);
}
boolean conflict = SpecialComponentList.isConflictingInstrumentation(packageName);
if (!conflict) {
InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class);
}
mInitialApplication = LoadedApk.makeApplication.call(data.info, false, null);
mirror.android.app.ActivityThread.mInitialApplication.set(mainThread, mInitialApplication);
ContextFixer.fixContext(mInitialApplication);
if (Build.VERSION.SDK_INT >= 24 && "com.tencent.mm:recovery".equals(processName)) {
fixWeChatRecovery(mInitialApplication);
}
if (data.providers != null) {
installContentProviders(mInitialApplication, data.providers);
}
if (lock != null) {
lock.open();
mTempLock = null;
}
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插件并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);
}
}
}
private void bindApplicationNoCheck(String packageName, String processName, ConditionVariable lock) {
VDeviceInfo deviceInfo = getDeviceInfo();
if (processName == null) {
processName = packageName;
}
mTempLock = lock;
try {
setupUncaughtHandler();
} catch (Throwable e) {
e.printStackTrace();
}
try {
fixInstalledProviders();
} catch (Throwable e) {
e.printStackTrace();
}
mirror.android.os.Build.SERIAL.set(deviceInfo.serial);
mirror.android.os.Build.DEVICE.set(Build.DEVICE.replace(" ", "_"));
ActivityThread.mInitialApplication.set(
VirtualCore.mainThread(),
null
);
AppBindData data = new AppBindData();
InstalledAppInfo info = VirtualCore.get().getInstalledAppInfo(packageName, 0);
if (info == null) {
new Exception("App not exist!").printStackTrace();
Process.killProcess(0);
System.exit(0);
}
data.appInfo = VPackageManager.get().getApplicationInfo(packageName, 0, getUserId(vuid));
data.processName = processName;
data.providers = VPackageManager.get().queryContentProviders(processName, getVUid(), PackageManager.GET_META_DATA);
Log.i(TAG, "Binding application " + data.appInfo.packageName + " (" + data.processName + ")");
mBoundApplication = data;
VirtualRuntime.setupRuntime(data.processName, data.appInfo);
int targetSdkVersion = data.appInfo.targetSdkVersion;
if (targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {
StrictMode.ThreadPolicy newPolicy = new StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();
StrictMode.setThreadPolicy(newPolicy);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
mirror.android.os.Message.updateCheckRecycle.call(targetSdkVersion);
}
if (VASettings.ENABLE_IO_REDIRECT) {
startIOUniformer();
}
NativeEngine.launchEngine();
Object mainThread = VirtualCore.mainThread();
NativeEngine.startDexOverride();
Context context = createPackageContext(data.appInfo.packageName);
System.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath());
File codeCacheDir;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
codeCacheDir = context.getCodeCacheDir();
} else {
codeCacheDir = context.getCacheDir();
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
if (HardwareRenderer.setupDiskCache != null) {
HardwareRenderer.setupDiskCache.call(codeCacheDir);
}
} else {
if (ThreadedRenderer.setupDiskCache != null) {
ThreadedRenderer.setupDiskCache.call(codeCacheDir);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (RenderScriptCacheDir.setupDiskCache != null) {
RenderScriptCacheDir.setupDiskCache.call(codeCacheDir);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (RenderScript.setupDiskCache != null) {
RenderScript.setupDiskCache.call(codeCacheDir);
}
}
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();
}
Configuration configuration = context.getResources().getConfiguration();
Object compatInfo = CompatibilityInfo.ctor.newInstance(data.appInfo, configuration.screenLayout, configuration.smallestScreenWidthDp, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
DisplayAdjustments.setCompatibilityInfo.call(ContextImplKitkat.mDisplayAdjustments.get(context), compatInfo);
}
DisplayAdjustments.setCompatibilityInfo.call(LoadedApkKitkat.mDisplayAdjustments.get(mBoundApplication.info), compatInfo);
} else {
CompatibilityInfoHolder.set.call(LoadedApkICS.mCompatibilityInfo.get(mBoundApplication.info), compatInfo);
}
boolean conflict = SpecialComponentList.isConflictingInstrumentation(packageName);
if (!conflict) {
InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class);
}
mInitialApplication = LoadedApk.makeApplication.call(data.info, false, null);
mirror.android.app.ActivityThread.mInitialApplication.set(mainThread, mInitialApplication);
ContextFixer.fixContext(mInitialApplication);
if (Build.VERSION.SDK_INT >= 24 && "com.tencent.mm:recovery".equals(processName)) {
fixWeChatRecovery(mInitialApplication);
}
if (data.providers != null) {
installContentProviders(mInitialApplication, data.providers);
}
if (lock != null) {
lock.open();
mTempLock = null;
}
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插件并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);
}
}
}
HookMethodInfo.java
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);
}
当启动微信时会弹出一个Toast
HookInfo.java
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;"}
};
}
AndroidManifest.xml
<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>
注:左上角有红色图标即为Hook插件
四、结语
上述是一个简单的例子,也可以做一些有用的功能,下面是我随手做的一个7.0.3版本的微信消息防撤回
参考
HookMethodInfo.java
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);
}
当启动微信时会弹出一个Toast
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);
}
当启动微信时会弹出一个Toast
HookInfo.java
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;"}
};
}
AndroidManifest.xml
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;"}
};
}
AndroidManifest.xml
<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>
<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>
注:左上角有红色图标即为Hook插件
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)