diff options
Diffstat (limited to 'vpndialogxposed/src/main/java')
3 files changed, 354 insertions, 0 deletions
diff --git a/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/AllowedVPNsChooser.java b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/AllowedVPNsChooser.java new file mode 100644 index 00000000..199f23fb --- /dev/null +++ b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/AllowedVPNsChooser.java @@ -0,0 +1,150 @@ +package de.blinkt.vpndialogxposed; + +import android.Manifest; +import android.app.ListActivity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.*; +import android.os.Bundle; +import android.widget.AbsListView; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + + +/** + * Created by arne on 06.10.13. + */ +public class AllowedVPNsChooser extends ListActivity { + + public static final String ALLOWED_APPS = "allowedApps"; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Collection<VpnApp> vpnApps = getVpnAppList(); + ListAdapter la = new ArrayAdapter<VpnApp>(this, android.R.layout.simple_list_item_multiple_choice, vpnApps.toArray(new VpnApp[vpnApps.size()])); + setListAdapter(la); + setContentView(R.layout.vpnapplayout); + getListView().setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE); + + + Collection<String> allowedapps = getAllowedApps(); + for(int i=0; i < vpnApps.size(); i++) { + VpnApp va= (VpnApp) getListView().getItemAtPosition(i); + boolean allowed = allowedapps.contains(va.mPkg); + getListView().setItemChecked(i,allowed); + } + + } + + + + private Collection<String> getAllowedApps(){ + SharedPreferences prefs = getPreferences(MODE_WORLD_READABLE); + HashSet<String> defaultapps = new HashSet<String>(); + defaultapps.add("de.blinkt.openvpn"); + return prefs.getStringSet(ALLOWED_APPS,defaultapps ); + } + + private void saveAllowedApps(Set<String> allowedApps) + { + SharedPreferences prefs = getPreferences(MODE_WORLD_READABLE); + prefs.edit().putStringSet(ALLOWED_APPS,allowedApps) + .putInt("random",new Random().nextInt()).apply(); + } + + + @Override + protected void onStop() { + super.onStop(); + + HashSet<String> allowedPkgs= new HashSet<String>(); + for(int i=0;i < getListView().getChildCount();i++) { + if(getListView().getCheckedItemPositions().get(i)) { + allowedPkgs.add(((VpnApp)getListView().getItemAtPosition(i)).mPkg); + } + } + saveAllowedApps(allowedPkgs); + } + + private Collection<VpnApp> getVpnAppList() { + PackageManager pm = getPackageManager(); + Intent vpnOpen = new Intent(); + vpnOpen.setAction("android.net.VpnService"); + Vector<VpnApp> vpnApps = new Vector<VpnApp>(); + + // Hack but should work + for(PackageInfo pkg : pm.getInstalledPackages(PackageManager.GET_SERVICES)) { + if (pkg.services != null) { + for(ServiceInfo serviceInfo:pkg.services) { + if(Manifest.permission.BIND_VPN_SERVICE.equals(serviceInfo.permission)) + vpnApps.add(new VpnApp(pkg.applicationInfo.loadLabel(pm), pkg.packageName)); + } + } + } + + + /* public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent, + int flags, int userId); + */ + + /* This does not work ... */ + /* + Class<?>[] queryIntentServicesAsUserSignature = {Intent.class, int.class, int.class}; + try { + Method queryIntentServicesAsUser = pm.getClass().getMethod("queryIntentServicesAsUser", queryIntentServicesAsUserSignature); + + List<ApplicationInfo> installedApps = pm.getInstalledApplications(0); + + + + for (ApplicationInfo app : installedApps) { + + List<ResolveInfo> apps; + if (app.packageName.equals(getPackageName())) { + apps = pm.queryIntentServices(vpnOpen, 0); + } else { + apps = (List<ResolveInfo>) queryIntentServicesAsUser.invoke(pm, vpnOpen, 0, app.uid); + } + + + + for (ResolveInfo ri : apps) { + vpnApps.add(new VpnApp(ri.toString())); + } + } + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + */ + + return vpnApps; + } + + static class VpnApp { + + private final String mPkg; + private CharSequence mName; + + public VpnApp(CharSequence name, String pkg) { + mName = name; + mPkg = pkg; + } + + @Override + public String toString() { + return mName.toString(); + } + } +} diff --git a/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/IConnectivityManager.java b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/IConnectivityManager.java new file mode 100644 index 00000000..9b26283e --- /dev/null +++ b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/IConnectivityManager.java @@ -0,0 +1,105 @@ +/* + * This file is auto-generated. DO NOT MODIFY. + * Original file: /Users/arne/software/icsopenvpn/vpndialogxposed/src/main/aidl/android/net/IConnectivityManager.aidl + */ +package de.blinkt.vpndialogxposed; +/** + * Interface that answers queries about, and allows changing, the + * state of network connectivity. + */ + +/** + * {@hide} + */ +public interface IConnectivityManager extends android.os.IInterface { + public boolean prepareVpn(java.lang.String oldPackage, java.lang.String newPackage) throws android.os.RemoteException; + + /** Local-side IPC implementation stub class. */ + public static abstract class Stub extends android.os.Binder implements IConnectivityManager { + static final int TRANSACTION_prepareVpn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); + private static final java.lang.String DESCRIPTOR = "android.net.IConnectivityManager"; + + /** Construct the stub at attach it to the interface. */ + public Stub() { + this.attachInterface(this, DESCRIPTOR); + } + + /** + * Cast an IBinder object into an android.net.IConnectivityManager interface, + * generating a proxy if needed. + */ + public static IConnectivityManager asInterface(android.os.IBinder obj) { + if ((obj == null)) { + return null; + } + android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (((iin != null) && (iin instanceof IConnectivityManager))) { + return ((IConnectivityManager) iin); + } + return new IConnectivityManager.Stub.Proxy(obj); + } + + @Override + public android.os.IBinder asBinder() { + return this; + } + + @Override + public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { + switch (code) { + case INTERFACE_TRANSACTION: { + reply.writeString(DESCRIPTOR); + return true; + } + case TRANSACTION_prepareVpn: { + data.enforceInterface(DESCRIPTOR); + java.lang.String _arg0; + _arg0 = data.readString(); + java.lang.String _arg1; + _arg1 = data.readString(); + boolean _result = this.prepareVpn(_arg0, _arg1); + reply.writeNoException(); + reply.writeInt(((_result) ? (1) : (0))); + return true; + } + } + return super.onTransact(code, data, reply, flags); + } + + private static class Proxy implements IConnectivityManager { + private android.os.IBinder mRemote; + + Proxy(android.os.IBinder remote) { + mRemote = remote; + } + + @Override + public android.os.IBinder asBinder() { + return mRemote; + } + + public java.lang.String getInterfaceDescriptor() { + return DESCRIPTOR; + } + + @Override + public boolean prepareVpn(java.lang.String oldPackage, java.lang.String newPackage) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + boolean _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(oldPackage); + _data.writeString(newPackage); + mRemote.transact(Stub.TRANSACTION_prepareVpn, _data, _reply, 0); + _reply.readException(); + _result = (0 != _reply.readInt()); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + } + } +} diff --git a/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java new file mode 100644 index 00000000..9cf22d0c --- /dev/null +++ b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java @@ -0,0 +1,99 @@ +package de.blinkt.vpndialogxposed; + +import android.app.Activity; +import android.content.Context; +import android.os.IBinder; +import android.widget.Toast; +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.XSharedPreferences; +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; +import de.robv.android.xposed.IXposedHookZygoteInit; + + +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; + +public class VpnDialogPatcher implements IXposedHookLoadPackage, IXposedHookZygoteInit { + public static final String MY_PACKAGE_NAME = AllowedVPNsChooser.class.getPackage().getName(); + private static XSharedPreferences pref; + + + @Override + public void initZygote(StartupParam startupParam) throws Throwable { + pref = new XSharedPreferences(MY_PACKAGE_NAME, "AllowedVPNsChooser"); + + } + + @Override + public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable { + if (!lpparam.packageName.equals("com.android.vpndialogs")) + return; + + + XposedBridge.log("Got VPN Dialog"); + + XposedHelpers.findAndHookMethod("com.android.vpndialogs.ConfirmDialog", lpparam.classLoader, + "onResume", new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + + // IConnectivityManager mService = IConnectivityManager.Stub.asInterface( + // ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); + + try { + + /*Class servicemanager = Class.forName("android.os.ServiceManager"); + Method getService = servicemanager.getMethod("getService",String.class); + + IConnectivityManager mService = IConnectivityManager.Stub.asInterface( + (IBinder) getService.invoke(servicemanager, Context.CONNECTIVITY_SERVICE)); + + */ + Object mService = XposedHelpers.getObjectField(param.thisObject, "mService"); + + String mPackage = ((Activity) param.thisObject).getCallingPackage(); + + // App is already allowed do nothing + /*if (mService.prepareVpn(mPackage, null)) { + return; + }*/ + + + Class<?>[] prepareVPNsignature = {String.class, String.class}; + if((Boolean) XposedHelpers.callMethod(mService,"prepareVpn",prepareVPNsignature, mPackage,(String)null)) + return; + + + HashSet<String> blinktapp = new HashSet<String>(); + blinktapp.add("de.blinkt.openvpn"); + // blinktapp.add("de.blinkt.nothingset"); + + pref.reload(); + Set<String> allowedApps = pref.getStringSet("allowedApps",blinktapp); + + //Toast.makeText((Context)param.thisObject, "Allowed apps: " + allowedApps, Toast.LENGTH_LONG).show(); + + if (allowedApps.contains(mPackage)) { + //mService.prepareVpn(null, mPackage); + XposedHelpers.callMethod(mService,"prepareVpn",prepareVPNsignature, (String)null,mPackage); + ((Activity) param.thisObject).setResult(Activity.RESULT_OK); + Toast.makeText((Context)param.thisObject,"Allowed VpnService app: " + mPackage,Toast.LENGTH_LONG).show(); + ((Activity) param.thisObject).finish(); + } + + } catch (Exception e) { + e.printStackTrace(); + + } + + } + + + }); + + } +} |