上次讲过无root实现复制其它应用data内部数据,这次讲一下无root情况下直接访问目标应用进程,然后对其进行hook操作,这种跨进程hook的原理是通过dex注入和资源文件修改来实现的。
首先在android studio中创建一个模块,在模块中创建一个Activity,在Activity的onCreate方法中加入测试代码,比如:Toast当前包名:
Toast.makeText(appContext, this.getPackageName(), Toast.LENGTH_SHORT).show();
然后编译生成apk,用winRAR打开,拖出里面的classes.dex文件,再找一个宿主应用用来测试,比如微信.apk,用winRAR打开微信.apk,查看里面的dex文件,可能是多dex文件,看一下dex文件的最大号码,如果是12,就把自己的dex改名为classes13.dex,也就是最大值加1,然后把自己的dex文件拖进微信apk里去,使其成为微信的一部分。
第二步是建一个临时项目,在里面加入执行代码,首先导入arsclib库,然后用代码修改微信apk的资源配置文件AndroidManifest,在里面添加刚才模块中的Activity声明,exported设置为true:
<activity android:name="com.plugin.test.TestActivity"
android:exported="true" />
主要代码如下:
ApkModule module = ApkModule.loadApkFile(new File("/sdcard/微信.apk"));
AndroidManifestBlock manifestBlock = module.getAndroidManifestBlock();
ResXmlElement applicationElement = manifestBlock.getApplicationElement();
ResXmlElement activityElement = manifestBlock.getOrCreateActivity("com.plugin.test.TestActivity", false);
ResXmlAttribute exportedAttr = activityElement.getOrCreateAndroidAttribute("exported", android.R.attr.exported);
exportedAttr.setValueAsBoolean(true);
可以将launcherMode设置成singleInstance,避免只能启动一次,如果设置singleTask每次都会打开根Activity。
ResXmlAttribute launcherModeAttr = activityElement.getOrCreateAndroidAttribute("launcherMode", android.R.attr.launchMode);
launcherModeAttr.setTypeAndData(ValueType.DEC, 3); //singleInstance
最后在临时项目中添加启动该Activity的代码:
Intent intent = new Intent();
intent.setClassName("com.tencent.mm", "com.plugin.test.TestActivity");
startActivity(intent);
执行上述代码,就会启动我们自己的activity,实际上启动的是微信app,所以打印出的包名是微信的包名。在这个Activity里我们可以做一些自己的事,比如访问微信进程,监听它的行为,设置代理等。不过这种方式有个缺点,就是每次修改模块代码都要重新打包目标应用,再重新签名安装,解决这个问题的办法就是使用插件模式,目标应用只放一些加载代码,模块放外面,再由目标加载模块,WalxPlugin插件的原理也是这样。