Sunday 19 March 2017

Creating a new Xposed module in Android

How Xposed works

Before we start lets see how Xposed works -

There is a process that is called "Zygote". This is the heart of the Android runtime. Every application is started as a copy ("fork") of it. This process is started by an /init.rc script when the phone is booted. The process start is done with /system/bin/app_process, which loads the needed classes and invokes the initialization methods.

This is where Xposed comes into play. When you install the framework, an extended app_process executable is copied to /system/bin. This extended startup process adds an additional jar to the classpath and calls methods from there at certain places. For instance, just after the VM has been created, even before the main method of Zygote has been called. And inside that method, we are part of Zygote and can act in its context.

The jar is located at /data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar and its source code can be found here. Looking at the class XposedBridge, you can see the main method. This is what I wrote about above, this gets called in the very beginning of the process. Some initializations are done there and also the modules are loaded.

Creating a new Xposed module in Android

I have couple of app on playstore . I am going to use FlashLight to demonstrate Xposed module.

  • Create a normal Android app. Add following extra meta data in the apps manifest file. This is how xposed installer app knows your apk is a xposed module.

        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <meta-data
            android:name="xposeddescription"
            android:value="Demo example that renders Flashlight app (com.osfg.flashlight) useless" />
        <meta-data
            android:name="xposedminversion"
            android:value="53" />

  • Next create a class that implements IXposedHookLoadPackage like below -

public class XPFlashLightKiller implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {

        if (!loadPackageParam.packageName.equals("com.osfg.flashlight"))
            return;

        XposedBridge.log("Loaded app: " + loadPackageParam.packageName);

        XposedHelpers.findAndHookMethod("com.osfg.flashlight.FlashLightActivity", loadPackageParam.classLoader, "isFlashSupported", new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called before the clock was updated by the original method
            }
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called after the clock was updated by the original method
                XposedBridge.log("Hooken method isFlashSupported of class com.osfg.flashlight.FlashLightActivity");
                param.setResult(false);
            }
        });
    }
}

NOTE :  Here we have used XC_MethodHook as callback so that we can execute methods before and after original method is executed. Other alternative is to replace the original method entirely - original hooked method will never get executed.

When you call XposedHelpers.findAndHookMethod the callback can either be
  • XC_MethodHook : Callback class for method hooks. Usually, anonymous subclasses of this class are created which override beforeHookedMethod(XC_MethodHook.MethodHookParam) and/or afterHookedMethod(XC_MethodHook.MethodHookParam).
  • XC_MethodReplacement : A special case of XC_MethodHook which completely replaces the original method.

1st one just provides you the hooks to execute methods before and after original method where as 2nd one replaces it completely.

  • Next create a file called xposed_init in your assets folder and add your fully qualified class name to it. This file tells xposed installer where to look for the module class. For eg in our case it will be -
com.osfg.flashlightxpmodule.XPFlashLightKiller


  • Finally download XposedbridgeApi.jar from here and add it in your app folder. Make sure the version of this jar should be same as xposedminversion set in the meta data tags in step 1.
Now build your app and deploy on your device. Once done Xposed installed should detect it. Just enable the module and reboot the device -



Testing out the module


Just to give you some background on the original Flashlight app. It's code is something like below -

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
    {
        switch (requestCode)
        {
            case CAMERA_PERMISSION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "Received Camera permission");
                    if(!isFlashSupported()) {
                        Toast.makeText(getApplicationContext(), "LED Flash is not supported on your device",Toast.LENGTH_LONG).show();
                        finish();
                    }

                }
                else {
                    Log.d(TAG, "Camera permission denied");
                    Toast.makeText(this, "Please provide camera permission", Toast.LENGTH_SHORT).show();
                    finish();
                }
                return;
        }
    }



It first asks for permission. If you give it then it will check if flash is supported on the device. So if you have already given Flashlight app camera permission then remove it from settings and open the app again. Now when it prompts for permissions again give it. But now you can see that the app shuts down with toast message - "Flash not supported on this device". This is because we hooked into isFlashSupported() method and made it always return false. So that the app never works :)

NOTE : From next time it will work fine. Since permission is already given next time it will not prompt and never execute  isFlashSupported() method. To retest remove the permissions from settings again.





You can also see following line in logcat -

03-20 02:36:37.864 8002-8002/? I/Xposed: Loaded app: com.osfg.flashlight

03-20 02:36:44.123 8002-8002/? I/Xposed: Hooken method isFlashSupported of class com.osfg.flashlight.FlashLightActivity


Complete code is added in my github repo -

Related Links


No comments:

Post a Comment

t> UA-39527780-1 back to top