源码
Github: https://github.com/skyun1314/haha
前几天突然看到一个牛逼的工具Xpatch。由于Android 9.0以上手机不好root,不能装xposed 。虽然有一个太极可以免root加载xposed模块,但是里面的模块是有限制的,必须的上传到太极官网,审核通过才能使用 xposed模块。所以 平时 调试app在高版本手机上 兼容性的时候很麻烦。虽然可以重打包测试。但是遇到几百兆的app的时候就特别无力了。Xpatch确实是一个不错的选择,但是他不是app,为了使用方便我把它改成了app,并针对手机特性 结合Xposed代码做了一些优化。
效果图:
优化点:
1、需要加载Xposed模块的app可以选择开启那些模块,而不需要自身开启读取sd卡权限,因为咱们使用了 ContentProvider!
2、为了加快速度不反编译smali代码,使用dexlib2库查找manifest中定义的 application 最终父类 所在的dex。 并查看当前application中有没有静态代码块,
同时使用 baksmali d 参数 只反编译一个smali文件从而插入入口代码。最后使用 DexMerger 库 合并dex。速度大大提升
3、使用AXmlConverter 库修改manifest 二进制文件
关键代码
使用ContentProvider 保存模块开启状态
public synchronized void updateModulesList(Context showToast) {
try {
String[] strings = {MODULES_LIST_FILE, ENABLED_MODULES_LIST_FILE};
for (int i = 0; i < strings.length; i++) {
File file = new File(strings[i]);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
}
Cursor query = showToast.getContentResolver().query(StudentsProvider.CONTENT_URIstudents, null, null, null, null);
if (query != null && query.getCount() > 0) {
showToast.getContentResolver().delete(StudentsProvider.CONTENT_URIstudents, "_id>0", null);
}
PrintWriter modulesList = new PrintWriter(MODULES_LIST_FILE);
PrintWriter enabledModulesList = new PrintWriter(ENABLED_MODULES_LIST_FILE);
List<InstalledModule> enabledModules = getEnabledModules();
for (InstalledModule module : enabledModules) {
modulesList.println(module.app.sourceDir);
try {
String installer = mPm.getInstallerPackageName(module.app.packageName);
if (!PLAY_STORE_PACKAGE.equals(installer)) {
enabledModulesList.println(module.app.packageName);
ContentValues values = new ContentValues();
values.put(StudentsProvider.NAME,
module.app.packageName);
values.put(StudentsProvider.GRADE,
module.app.sourceDir);
Uri uri = showToast.getContentResolver().insert(
StudentsProvider.CONTENT_URIstudents, values);
}
} catch (IllegalArgumentException ignored) {
// In rare cases, the package might not be installed anymore at this point,
// so the PackageManager can't return its installer package name.
}
}
modulesList.close();
enabledModulesList.close();
FileUtils.setPermissions(MODULES_LIST_FILE, 00664, -1, -1);
FileUtils.setPermissions(ENABLED_MODULES_LIST_FILE, 00664, -1, -1);
} catch (IOException e) {
hahahaha.Log.e(e.toString());
}
}
使用dexlib2 解析 class和method
public static List<String> getClass(String input) {
List<String>strings=new ArrayList<>();
try {
File file = new File(input);
MultiDexContainer<? extends DexBackedDexFile> container = DexFileFactory.loadDexContainer(file, null);
MultiDexContainer.DexEntry<? extends DexBackedDexFile> dexEntry = container.getEntry(container.getDexEntryNames().get(0));
assert dexEntry != null;
DexBackedDexFile dexFile = dexEntry.getDexFile();
for (ClassDef classDef : dexFile.getClasses()) {
strings.add(classDef.getType());
// System.out.println(classDef.getType());
}
} catch (Exception e) {
e.printStackTrace();
}
return strings;
}
public static List<String> getMethods(String input) {
List<String>strings=new ArrayList<>();
try {
File file = new File(input);
MultiDexContainer<? extends DexBackedDexFile> container = DexFileFactory.loadDexContainer(file, null);
MultiDexContainer.DexEntry<? extends DexBackedDexFile> dexEntry = container.getEntry(container.getDexEntryNames().get(0));
assert dexEntry != null;
DexBackedDexFile dexFile = dexEntry.getDexFile();
for (Reference reference: dexFile.getReferences( ReferenceType.METHOD)) {
// System.out.println(ReferenceUtil.getReferenceString(reference));
strings.add(ReferenceUtil.getReferenceString(reference));
}
} catch (Exception e) {
e.printStackTrace();
}
return strings;
}
使用axml 修改 manifest
// 修改app名称
@Override
public NodeVisitor visitChild(String ns, String name) {// manifest 下面的说有大标签
if ("application".equals(name)) {
return new NodeVisitor(super.visitChild(ns, name)) {
@Override
public void visitEnd() {
NodeVisitor meta = super.visitChild("http://schemas.android.com/apk/res/android", "meta-data");
meta.visitContentAttr("http://schemas.android.com/apk/res/android", "name", 16842755, 3, meta_data_key);
meta.visitContentAttr("http://schemas.android.com/apk/res/android", "value", 16842788, 3, meta_data_value);
if (!has_Application) {
super.visitContentAttr("http://schemas.android.com/apk/res/android", "name", 16842755, 3, Application_name);
}
super.visitEnd();
}
@Override
public void visitContentAttr(String ns, String name, int resourceId, int type,//application 这一行
Object obj) {
if ("name".equals(name)) {
yuan_Application=obj.toString();
if(obj.toString().startsWith(".")){
yuan_Application=yuan_packageName+yuan_Application;
}
has_Application = true;
hahahaha.Log.e("visitContentAttr:" + name + " " + obj + " " + ns + " " + resourceId + " " + type);
}
super.visitContentAttr(ns, name, resourceId, type, obj);
}
@Override
public NodeVisitor visitChild(String ns, String name) {//application 下面所有大标签
return new NodeVisitor(super.visitChild(ns, name)) {
@Override
public void visitContentAttr(String ns, String name, int resourceId, int type, Object obj) {
// System.out.println("aaaa_visitChild:"+ns+" "+name+" "+resourceId+" "+type+" "+obj);
super.visitContentAttr(ns, name, resourceId, type, obj);
}
@Override
public NodeVisitor visitChild(String ns, String name) {
// System.out.println("xxxx_visitChild:"+ns+" "+name);
return super.visitChild(ns, name);
}
};
}
};
}
return super.visitChild(ns, name);
}
};
}
});
[课程]FART 脱壳王!加量不加价!FART作者讲授!
最后于 2019-12-6 12:39
被skyun编辑
,原因: