package com.czbix.xposed.wifipassword; import android.app.ActivityManager; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.res.Resources; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiManager; import android.os.Build; import android.os.Bundle; import android.os.UserHandle; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import java.util.List; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; public class Patch implements IXposedHookLoadPackage { private static final String PKG_NAME = "com.android.settings"; private static final String PKG_NAME_LGE = "com.lge.wifisettings"; private static final boolean IS_ABOVE_N = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; private static final boolean IS_ABOVE_M = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; private static final boolean IS_SAMSUNG = Build.BRAND.equals("samsung"); private static final boolean IS_HTC = Build.BRAND.equals("htc"); private static final boolean IS_LG = Build.BRAND.equals("lge"); public void handleLoadPackage(LoadPackageParam param) throws Throwable { if (param.packageName.equals("android")) { ServerPatch.hookWifiStore(param.classLoader); } else if (IS_LG && param.packageName.equals(PKG_NAME_LGE)) { hookWifiController(param.classLoader); } else if (param.packageName.equals(PKG_NAME)) { hookWifiController(param.classLoader); } } private void hookWifiController(ClassLoader loader) { final String controllerClassName = IS_LG ? "com.lge.wifisettings.WifiConfigController" : "com.android.settings.wifi.WifiConfigController"; final Class<?> controller = XposedHelpers.findClass(controllerClassName, loader); do { if (IS_ABOVE_N) { if (tryHookConstructor(controller, "Hook N constructor", "com.android.settings.wifi.WifiConfigUiBase", View.class, "com.android.settingslib.wifi.AccessPoint", int.class, methodHook)) { break; } if (IS_LG && tryHookConstructor(controller, "Hook LG N constructor", "com.lge.wifisettings.WifiConfigUiBase", View.class, "com.lge.wifisettings.AccessPoint", int.class, methodHook)) { break; } if (IS_SAMSUNG && tryHookConstructor(controller, "Hook Samsung N constructor", "com.android.settings.wifi.WifiConfigUiBase", View.class, "com.android.settingslib.wifi.AccessPoint", int.class, Bundle.class, methodHook)) { break; } } if (IS_ABOVE_M && tryHookConstructor(controller, "Hook M constructor", "com.android.settings.wifi.WifiConfigUiBase", View.class, "com.android.settingslib.wifi.AccessPoint", boolean.class, boolean.class, methodHook)) { break; } if (tryHookConstructor(controller, "Hook L constructor", "com.android.settings.wifi.WifiConfigUiBase", View.class, "com.android.settings.wifi.AccessPoint", boolean.class, methodHook)) { break; } if (IS_SAMSUNG && tryHookConstructor(controller, "Hook Samsung constructor", "com.android.settings.wifi.WifiConfigUiBase", View.class, "com.android.settings.wifi.AccessPoint", boolean.class, boolean.class, methodHook)) { break; } if (IS_HTC && tryHookConstructor(controller, "Hook HTC constructor", "com.android.settings.wifi.WifiConfigUiBase", View.class, "com.android.settings.wifi.AccessPoint", int.class, methodHook)) { break; } XposedBridge.log("All constructor hook failed!"); } while (false); } private static boolean tryHookConstructor(Class<?> clazz, String msg, Object... parameterTypesAndCallback) { try { XposedHelpers.findAndHookConstructor(clazz, parameterTypesAndCallback); } catch (Error e) { return false; } XposedBridge.log(msg + " success"); return true; } private final XC_MethodHook methodHook = new XC_MethodHook() { private Context mContext; @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { if (!isOwner()) { // only show password for owner return; } final Object mAccessPoint = XposedHelpers.getObjectField(param.thisObject, "mAccessPoint"); if (mAccessPoint == null) { return; } final int networkId = XposedHelpers.getIntField(mAccessPoint, "networkId"); if (networkId == -1) { return; } if (IS_ABOVE_N) { final int mMode = XposedHelpers.getIntField(param.thisObject, "mMode"); // WifiConfigUiBase.MODE_VIEW if (mMode != 0) { return; } } else if (IS_HTC) { final int mEdit = XposedHelpers.getIntField(param.thisObject, "mEdit"); if (mEdit != 0) { return; } } else { final boolean mEdit = XposedHelpers.getBooleanField(param.thisObject, "mEdit"); if (mEdit) { return; } } final View mView = (View) XposedHelpers.getObjectField(param.thisObject, "mView"); final Context context = mView.getContext(); mContext = context.createPackageContext(BuildConfig.APPLICATION_ID, Context.CONTEXT_RESTRICTED); final Resources resources = context.getResources(); final int idInfo = resources.getIdentifier("info", "id", PKG_NAME); final int idPwd = resources.getIdentifier("wifi_password", "string", PKG_NAME); final ViewGroup group = (ViewGroup) mView.findViewById(idInfo); final int mSecurity = XposedHelpers.getIntField(param.thisObject, "mAccessPointSecurity"); final String emptyPassword = mContext.getString(R.string.empty_password); String pwd; if (mSecurity != 1 && mSecurity != 2) { // not WEP/PSK pwd = emptyPassword; } else { pwd = getWiFiPassword(context, networkId); // more check, more safe if (pwd == null) { pwd = emptyPassword; } } final String ssid = (String) XposedHelpers.getObjectField(mAccessPoint, "ssid"); addRow(param, idPwd, group, ssid, pwd); } private void addRow(MethodHookParam param, int idPwd, ViewGroup group, final String ssid, final String pwd) { String defaultPwd = mContext.getString(R.string.empty_password); if (!pwd.equals(defaultPwd)) { defaultPwd = new String(new char[pwd.length()]).replace("\0", "ยท"); } XposedHelpers.callMethod(param.thisObject, "addRow", group, idPwd, defaultPwd); final View view = group.getChildAt(group.getChildCount() - 1); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final Context context = v.getContext(); final int idValue = context.getResources().getIdentifier("value", "id", PKG_NAME); final TextView textView = (TextView) view.findViewById(idValue); if (textView == null) { if (IS_HTC) { // I hate HTC final int idItem = context.getResources().getIdentifier("item", "id", PKG_NAME); XposedHelpers.callMethod(view.findViewById(idItem), "setSecondaryText", pwd); } else { // show password in toast as alternative Toast.makeText(context, pwd, Toast.LENGTH_LONG).show(); } } else { textView.setText(pwd); } } }); view.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { final Context context = v.getContext(); final ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); clipboardManager.setPrimaryClip(ClipData.newPlainText(null, mContext.getString(R.string.clip_info_format, ssid, pwd))); Toast.makeText(context, mContext.getString(R.string.toast_wifi_info_copied), Toast.LENGTH_SHORT).show(); return false; } }); } private String getWiFiPassword(Context context, int networkId) { final WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); @SuppressWarnings("unchecked") final List<WifiConfiguration> list = (List<WifiConfiguration>) XposedHelpers.callMethod(wifiManager, "getPrivilegedConfiguredNetworks"); String pwd; for (WifiConfiguration config : list) { if (config.networkId == networkId) { if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { pwd = config.preSharedKey; } else { pwd = config.wepKeys[config.wepTxKeyIndex]; } if (pwd != null) { return pwd.replaceAll("^\"|\"$", ""); } } } return null; } }; private static boolean isOwner() { final int currentUser = (int) XposedHelpers.callStaticMethod(ActivityManager.class, "getCurrentUser"); return currentUser == XposedHelpers.getStaticIntField(UserHandle.class, "USER_OWNER"); } }