Enhance enhance!

This commit is contained in:
NekoInverter 2020-04-05 19:05:39 +08:00
parent c460571a3e
commit b235892098
No known key found for this signature in database
GPG Key ID: 280D6CCCF95715F9
7 changed files with 311 additions and 11 deletions

View File

@ -0,0 +1 @@
org.meowcat.edxposed.manager.xposed.Enhancement

View File

@ -26,6 +26,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.takisoft.preferencex.PreferenceFragmentCompat;
import com.topjohnwu.superuser.Shell;
import org.meowcat.edxposed.manager.adapters.AppHelper;
import org.meowcat.edxposed.manager.adapters.BlackListAdapter;
import org.meowcat.edxposed.manager.databinding.ActivitySettingsBinding;
import org.meowcat.edxposed.manager.util.RepoLoader;
import org.meowcat.edxposed.manager.widget.IntegerListPreference;
@ -34,6 +36,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Objects;
public class SettingsActivity extends BaseActivity {
private static final String KEY_PREFIX = SettingsActivity.class.getName() + '.';
@ -111,6 +114,8 @@ public class SettingsActivity extends BaseActivity {
@SuppressWarnings({"ResultOfMethodCallIgnored", "deprecation"})
public static class SettingsFragment extends PreferenceFragmentCompat {
private static final File pretendXposedInstallerFlag = new File(XposedApp.BASE_DIR + "conf/pretend_xposed_installer");
private static final File hideEdXposedManagerFlag = new File(XposedApp.BASE_DIR + "conf/hide_edxposed_manager");
static final File disableResourcesFlag = new File(XposedApp.BASE_DIR + "conf/disable_resources");
static final File dynamicModulesFlag = new File(XposedApp.BASE_DIR + "conf/dynamicmodules");
static final File deoptBootFlag = new File(XposedApp.BASE_DIR + "conf/deoptbootimage");
@ -486,6 +491,74 @@ public class SettingsActivity extends BaseActivity {
return true;
});
updatePreference(!md2.isChecked());
Preference enhancement_status = findPreference("enhancement_status");
Objects.requireNonNull(enhancement_status).setSummary(StatusInstallerFragment.isEnhancementEnabled() ? R.string.settings_summary_enhancement_enabled : R.string.settings_summary_enhancement);
SwitchPreferenceCompat prefPretendXposedInstaller = findPreference("pretend_xposed_installer");
Objects.requireNonNull(prefPretendXposedInstaller).setChecked(pretendXposedInstallerFlag.exists());
prefPretendXposedInstaller.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
new BlackListAdapter(getContext(), AppHelper.isWhiteListMode(), null).generateCheckedList();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(pretendXposedInstallerFlag.getPath());
setFilePermissionsFromMode(pretendXposedInstallerFlag.getPath());
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
pretendXposedInstallerFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
pretendXposedInstallerFlag.delete();
}
return (enabled == pretendXposedInstallerFlag.exists());
});
SwitchPreferenceCompat prefHideEdXposedManager = findPreference("hide_edxposed_manager");
Objects.requireNonNull(prefHideEdXposedManager).setChecked(hideEdXposedManagerFlag.exists());
prefHideEdXposedManager.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
new BlackListAdapter(getContext(), AppHelper.isWhiteListMode(), null).generateCheckedList();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(hideEdXposedManagerFlag.getPath());
setFilePermissionsFromMode(hideEdXposedManagerFlag.getPath());
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
hideEdXposedManagerFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
hideEdXposedManagerFlag.delete();
}
return (enabled == hideEdXposedManagerFlag.exists());
});
}
}

View File

@ -51,6 +51,7 @@ public class PackageChangeReceiver extends BroadcastReceiver {
moduleUtil = getModuleUtilInstance();
moduleUtil.updateModulesList(false);
InstalledModule module = ModuleUtil.getInstance().reloadSingleModule(packageName);
if (module == null
|| intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
@ -58,13 +59,11 @@ public class PackageChangeReceiver extends BroadcastReceiver {
// Xposed mod
if (moduleUtil.isModuleEnabled(packageName)) {
moduleUtil.setModuleEnabled(packageName, false);
moduleUtil.updateModulesList(false);
}
return;
}
if (moduleUtil.isModuleEnabled(packageName)) {
moduleUtil.updateModulesList(false);
NotificationUtil.showModulesUpdatedNotification();
} else {
NotificationUtil.showNotActivatedNotification(packageName, module.getAppName());

View File

@ -1,6 +1,19 @@
package org.meowcat.edxposed.manager.xposed;
package org.meowcat.edxposed.manager.xposed;import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.os.Binder;
import android.os.Build;
import androidx.annotation.Keep;
import org.meowcat.edxposed.manager.StatusInstallerFragment;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
@ -8,12 +21,45 @@ import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import static org.meowcat.edxposed.manager.BuildConfig.APPLICATION_ID;
@Keep
public class Enhancement implements IXposedHookLoadPackage {
private static final String mPretendXposedInstallerFlag = "pretend_xposed_installer";
private static final String mHideEdXposedManagerFlag = "hide_edxposed_manager";
private static final String LEGACY_INSTALLER = "de.robv.android.xposed.installer";
private static List modulesList = null;
private static boolean getFlagState(int user, String flag) {
return new File(String.format("/data/user_de/%s/%s/conf/%s", user, APPLICATION_ID, flag)).exists();
}
private static List getModulesList(int user) {
if (modulesList != null) {
return modulesList;
}
final File listFile = new File(String.format("/data/user_de/%s/%s/conf/enabled_modules.list", user, APPLICATION_ID));
List<String> list = new ArrayList<>();
try {
FileReader fileReader = new FileReader(listFile);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String str;
while ((str = bufferedReader.readLine()) != null) {
list.add(str);
}
bufferedReader.close();
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
modulesList = list;
return list;
}
private static void hookAllMethods(String className, ClassLoader classLoader, String methodName, XC_MethodHook callback) {
try {
Class<?> hookClass = XposedHelpers.findClassIfExists(className, classLoader);
@ -27,24 +73,165 @@ public class Enhancement implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
if (lpparam.packageName.equals("android")) {
// Hook PM to pretend to have legacy Xposed Installer installed
// android.app.ApplicationPackageManager.getInstalledApplicationsAsUser(int flag, int userId)
findAndHookMethod("android.app.ApplicationPackageManager", lpparam.classLoader, "getInstalledApplicationsAsUser", int.class, int.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
if (param.args != null && param.args[0] != null) {
final int userId = (int) param.args[1];
boolean isXposedModule = false;
final String[] packages =
(String[]) XposedHelpers.callMethod(param.thisObject, "getPackagesForUid", Binder.getCallingUid());
for (String packageName : packages) {
if (packageName.equals(APPLICATION_ID)) {
return;
}
if (getModulesList(userId).contains(packageName)) {
isXposedModule = true;
break;
}
}
@SuppressWarnings("unchecked") List<ApplicationInfo> applicationInfoList = (List<ApplicationInfo>) param.getResult();
if (isXposedModule) {
if (getFlagState(userId, mPretendXposedInstallerFlag)) {
for (ApplicationInfo applicationInfo : applicationInfoList) {
if (applicationInfo.packageName.equals(APPLICATION_ID)) {
applicationInfo.packageName = LEGACY_INSTALLER;
applicationInfoList.add(applicationInfo);
break;
}
}
}
} else {
if (getFlagState(userId, mHideEdXposedManagerFlag)) {
for (ApplicationInfo applicationInfo : applicationInfoList) {
if (applicationInfo.packageName.equals(APPLICATION_ID)) {
applicationInfoList.remove(applicationInfo);
break;
}
}
}
}
param.setResult(applicationInfoList);
}
}
});
// android.app.ApplicationPackageManager.getInstalledPackagesAsUser(int flag, int userId)
findAndHookMethod("android.app.ApplicationPackageManager", lpparam.classLoader, "getInstalledPackagesAsUser", int.class, int.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
if (param.args != null && param.args[0] != null) {
final int userId = (int) param.args[1];
boolean isXposedModule = false;
final String[] packages =
(String[]) XposedHelpers.callMethod(param.thisObject, "getPackagesForUid", Binder.getCallingUid());
for (String packageName : packages) {
if (packageName.equals(APPLICATION_ID)) {
return;
}
if (getModulesList(userId).contains(packageName)) {
isXposedModule = true;
break;
}
}
@SuppressWarnings("unchecked") List<PackageInfo> packageInfoList = (List<PackageInfo>) param.getResult();
if (isXposedModule) {
if (getFlagState(userId, mPretendXposedInstallerFlag)) {
for (PackageInfo packageInfo : packageInfoList) {
if (packageInfo.packageName.equals(APPLICATION_ID)) {
packageInfo.packageName = LEGACY_INSTALLER;
packageInfoList.add(packageInfo);
break;
}
}
}
} else {
if (getFlagState(userId, mHideEdXposedManagerFlag)) {
for (PackageInfo packageInfo : packageInfoList) {
if (packageInfo.packageName.equals(APPLICATION_ID)) {
packageInfoList.remove(packageInfo);
break;
}
}
}
}
param.setResult(packageInfoList);
}
}
});
// com.android.server.pm.PackageManagerService.getApplicationInfo(String packageName, int flag, int userId)
hookAllMethods("com.android.server.pm.PackageManagerService", lpparam.classLoader, "getApplicationInfo", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
if (param.args != null && param.args[0] != null) {
if (param.args[0].equals(LEGACY_INSTALLER)) {
param.args[0] = APPLICATION_ID;
final int userId = (int) param.args[2];
boolean isXposedModule = false;
final String[] packages =
(String[]) XposedHelpers.callMethod(param.thisObject, "getPackagesForUid", Binder.getCallingUid());
for (String packageName : packages) {
if (packageName.equals(APPLICATION_ID)) {
return;
}
if (getModulesList(userId).contains(packageName)) {
isXposedModule = true;
break;
}
}
if (isXposedModule) {
if (getFlagState(userId, mPretendXposedInstallerFlag)) {
if (param.args[0].equals(LEGACY_INSTALLER)) {
param.args[0] = APPLICATION_ID;
}
}
} else {
if (getFlagState(userId, mHideEdXposedManagerFlag)) {
if (param.args[0].equals(APPLICATION_ID)) {
param.setResult(null);
}
}
}
}
}
});
// com.android.server.pm.PackageManagerService.getPackageInfo(String packageName, int flag, int userId)
hookAllMethods("com.android.server.pm.PackageManagerService", lpparam.classLoader, "getPackageInfo", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
if (param.args != null && param.args[0] != null) {
if (param.args[0].equals(LEGACY_INSTALLER)) {
param.args[0] = APPLICATION_ID;
final int userId = (int) param.args[2];
boolean isXposedModule = false;
final String[] packages =
(String[]) XposedHelpers.callMethod(param.thisObject, "getPackagesForUid", Binder.getCallingUid());
for (String packageName : packages) {
if (packageName.equals(APPLICATION_ID)) {
return;
}
if (getModulesList(userId).contains(packageName)) {
isXposedModule = true;
break;
}
}
if (isXposedModule) {
if (getFlagState(userId, mPretendXposedInstallerFlag)) {
if (param.args[0].equals(LEGACY_INSTALLER)) {
param.args[0] = APPLICATION_ID;
}
}
} else {
if (getFlagState(userId, mHideEdXposedManagerFlag)) {
if (param.args[0].equals(APPLICATION_ID)) {
param.setResult(null);
}
}
}
}
}
@ -84,7 +271,8 @@ public class Enhancement implements IXposedHookLoadPackage {
}
} else if (lpparam.packageName.equals(APPLICATION_ID)) {
// Make sure Xposed work
XposedHelpers.findAndHookMethod("org.meowcat.edxposed.manager.StatusInstallerFragment", lpparam.classLoader, "isEnhancementEnabled", XC_MethodReplacement.returnConstant(true));
XposedHelpers.findAndHookMethod(StatusInstallerFragment.class.getName(), lpparam.classLoader, "isEnhancementEnabled", XC_MethodReplacement.returnConstant(true));
// XposedHelpers.findAndHookMethod(StatusInstallerFragment.class.getName(), lpparam.classLoader, "isSELinuxEnforced", XC_MethodReplacement.returnConstant(SELinuxHelper.isSELinuxEnforced()));
}
}

View File

@ -302,6 +302,14 @@
<string name="colorized_action_bar">着色应用栏</string>
<string name="settings_group_theme">主题</string>
<string name="material_design_2">惨白设计</string>
<string name="xposed_description">启用 EdXposed 的增强功能:\n判断 Xposed 是否正常工作\n移除针对 EdXposed 的后台限制\n假装安装了 Xposed Installer</string>
<string name="xposed_description">启用 EdXposed 的增强功能:\n - 判断 Xposed 是否正常工作\n - 移除针对 EdXposed 的后台限制\n - 假装安装了 Xposed Installer\n - 隐藏 EdXposed Manager</string>
<string name="status_enhancement">增强模式已激活</string>
<string name="settings_group_enhancement">增强模式</string>
<string name="settings_title_enhancement">增强模式状态</string>
<string name="settings_summary_enhancement">未激活\n你可以在「模块」中启用增强模块</string>
<string name="settings_summary_enhancement_enabled">已激活</string>
<string name="settings_title_pretend_xposed_installer">Xposed Installer 伪装</string>
<string name="settings_summary_pretend_xposed_installer">假装已安装 Xposed Installer 来使一些过时但有用的模块正常工作\n注开启此功能可能会被某些软件如 RootBeer检测到 EdXposed</string>
<string name="settings_title_hide_edxposed_manager">隐藏 EdXposed Manager</string>
<string name="settings_summary_hide_edxposed_manager">防止软件检测到 EdXposed Manager\n注模块可能无法正常打开 Manager 界面</string>
</resources>

View File

@ -333,7 +333,15 @@
<string name="colorized_action_bar">Colorized action bar</string>
<string name="settings_group_theme">Theme</string>
<string name="material_design_2">Material Design 2</string>
<string name="xposed_description">Enable EdXposed enhancements:\nRemove background restrictions on EdXposed\nDetermine if Xposed is working properly\nPretend to have Xposed Installer installed</string>
<string name="xposed_description">Enable EdXposed enhancements:\nRemove background restrictions on EdXposed\nDetermine if Xposed is working properly\nPretend to have Xposed Installer installed\nHide EdXposed Manager</string>
<string name="status_enhancement">Enhancement mode</string>
<string name="settings_group_enhancement">Enhancement mode</string>
<string name="settings_title_enhancement">Enhancement mode status</string>
<string name="settings_summary_enhancement">Disabled\nYou can enable enhancement mode in the module</string>
<string name="settings_summary_enhancement_enabled">Enabled</string>
<string name="settings_title_pretend_xposed_installer">Pretend to have Xposed Installer installed</string>
<string name="settings_summary_pretend_xposed_installer">Pretend that Xposed Installer is installed to make some outdated but useful modules work\nWARNING: Some software (eg. RootBeer) may detect that EdXposed when this function is turned on</string>
<string name="settings_title_hide_edxposed_manager">Hide EdXposed Manager</string>
<string name="settings_summary_hide_edxposed_manager">Prevent the software from detecting EdXposed Manager\nWARNING: Modules may not be able to start the Manager UI properly</string>
<string name="version_x">Version %d</string>
</resources>

View File

@ -189,4 +189,27 @@
app:iconSpaceReserved="false" />
</PreferenceCategory>
<PreferenceCategory
android:key="group_enhancement"
android:title="@string/settings_group_enhancement">
<Preference
android:key="enhancement_status"
android:title="@string/settings_title_enhancement"
android:summary="@string/settings_summary_enhancement" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="pretend_xposed_installer"
android:summary="@string/settings_summary_pretend_xposed_installer"
android:title="@string/settings_title_pretend_xposed_installer" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="hide_edxposed_manager"
android:summary="@string/settings_summary_hide_edxposed_manager"
android:title="@string/settings_title_hide_edxposed_manager" />
</PreferenceCategory>
</PreferenceScreen>