XposedInstaller icon indicating copy to clipboard operation
XposedInstaller copied to clipboard

Xposed module with BroadcastReceiver

Open voider1 opened this issue 7 years ago • 12 comments

Can I make an Xposed module which stores it's XC_LoadPackage.LoadPackageParam and then uses this when the BroadcastReceiver receives an Intent? I've tried to do this, but for some reason the BroadcastReceiver never fires...

Xposed BroadcastReceiver:

class CallReceiver: BroadcastReceiver() {

    private val tag = CallReceiver::class.java.name

    override fun onReceive(context: Context?, intent: Intent?) {
        logI(tag, "Received an intent +!!!!!!!!!!!!!!!!!!!!!!!!!!!++!!!!!!!!")
        intent?.action?.let { logI(tag, "Received $it") }
        intent?.getStringExtra("data")?.let { logI(tag, it) }
    }
}

Xposed Manifest:

    <application
        android:allowBackup="true"
        android:fullBackupContent="@xml/backup_descriptor"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <meta-data
            android:name="xposeddescription"
            android:value="Dynamically call methods" />
        <meta-data
            android:name="xposedminversion"
            android:value="53" />

        <receiver android:name=".CallReceiver">
            <intent-filter>
                <action android:name="Intent.android.intent.action.CALL"/>
            </intent-filter>
        </receiver>
    </application>

App which sends the broadcast:

val intent = Intent()
intent.action = "Intent.android.intent.action.CALL"
intent.addCategory(Intent.CATEGORY_ALTERNATIVE)
intent.putExtra("data", "Test")
context.sendBroadcast(intent)

voider1 avatar Nov 13 '17 14:11 voider1

Can I make an Xposed module which stores it's XC_LoadPackage.LoadPackageParam and then uses this when the BroadcastReceiver receives an Intent?

Not in the way you want to do it. You have to differentiate between the module part of your app and the UI part. The module code gets executed in various contexts, basically in every app. The UI part gets executed in your own app's context. And you can't (easily) share data between those contexts.

rovo89 avatar Nov 13 '17 15:11 rovo89

Well, that's the thing. I want them to share data. I want so send data to my Xposed hook from the BroadcastReceiver and then get back data. How can I do this?

voider1 avatar Nov 13 '17 15:11 voider1

No idea. Your receiver runs in your app's process. Unless you hook your own app, the module code will be in another process, so you need some sort of IPC. Maybe you can register a receiver or a service in the other app programmatically and use that, but I haven't tried it myself.

rovo89 avatar Nov 13 '17 16:11 rovo89

Could you please expand on this? I think I understand the hooking of my app itself, but what about the receiver or service?

voider1 avatar Nov 13 '17 18:11 voider1

Everything you declare in your manifest always refers to your own app's process. If you hook other apps, Android won't know about your own manifest, it will just let you use the receivers, services, activities, ... from the app you hooked. However, there are things like https://developer.android.com/reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver,%20android.content.IntentFilter) which let you register a receiver from code, as long as you have access to a Context. An easy way to get one (although maybe not the best) would be hooking Application.onCreate(), then you have have the application context in param.thisObject. When you try to send data to this receiver, you might have to explicitely specify the package name in the intent, especially if you hook multiple apps and register a receiver in each one. Not sure if the same would also work for services and whether you can use this for two-way communication.

rovo89 avatar Nov 14 '17 07:11 rovo89

I tried to register it in my module, but it seems that it doesn't work:

    override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
        Main.lpparam = lpparam!!
        Main.tag = "[Dynamic Method Call] ${lpparam.packageName}"
        logI(tag, "hooked")

        findAndHookMethod(application, lpparam.classLoader, onCreate, object: XC_MethodHook() {
            override fun beforeHookedMethod(param: MethodHookParam?) {
                val app = param?.thisObject as Application
                context = app.applicationContext
                logI(tag , "retrieved the Context")
            }
        })

        makeBroadcastReceiver()
        return
    }

    private fun makeBroadcastReceiver() {
        val filter = IntentFilter()
        filter.addAction("test")

        val receiver = object: BroadcastReceiver() {
            override fun onReceive(p0: Context?, p1: Intent?) {
                logI(tag, "Got intent!!!!!!!!!!!!!!")
                Log.i(tag, "GOT INTENT +!!!!!!!!!1")
            }
        }
        context?.registerReceiver(receiver, filter)
        logI(tag, "Registered the broadcastreceiver")
    }

I don't see any logs from the receiver in logcat.

voider1 avatar Nov 14 '17 12:11 voider1

You might have to do that if your intent filters aren't unique. Again, if you hook multiple apps, you might end up registering the same receiver in all of those apps. How should Android know to which one of those it should send the intent?

rovo89 avatar Nov 14 '17 13:11 rovo89

I got it working, I wanted to send it to all of them in the first place, so that's a good thing. It does exactly that now. I have another question, is there a way I can start all apps on the phone and keep them from closing?

voider1 avatar Nov 14 '17 14:11 voider1

I got it working

Could you please post the relevant code here? Others (including myself) might want to do similar things.

is there a way I can start all apps on the phone and keep them from closing?

You could probably use the PackageManager to get a list of all apps/activities/whatever and send intents to all of them. The term "keep them from closing" is pretty vague - there can only be one active app at a time, and unactive apps will be unloaded by Android due to limited memory. I don't see any sense in this anyway...

rovo89 avatar Nov 14 '17 14:11 rovo89

The code above is still relevant, I did something wrong with sending my intent, it works implicit and explicit. What I mean by keep them from closing... So when you start Xposed you can print out all the packages. So now you know when the package gets loaded. Some packages don't get loaded for some reason, or they get "unloaded". How can I load an app and make sure it doesn't get unloaded? And why do some packages not get loaded?

voider1 avatar Nov 14 '17 14:11 voider1

How can I load an app and make sure it doesn't get unloaded?

Apps get loaded when they're used (e.g. when you start them from the launcher or the system wants to deliver an intent to them), so you could just send an intent to the app you want to start, as mentioned above. I don't think you can prevent unloading unless you hook something deep in the system (out-of-memory killer) and then you'll probably run out of memory very fast.

And why do some packages not get loaded?

Because they're not needed (yet). Why should the system start something that isn't needed?

Again, I don't understand why you would want to start all apps. It's like searching *.exe on your PC and putting all of them into Autostart.

rovo89 avatar Nov 14 '17 15:11 rovo89

@rovo89 Alright, so is it possible to send an Intent to the app and then prevent that single app from closing? I actually want to prevent one app from closing, not all of them. Doing it with all the apps was actually kind of besides the point and unnecessary.

voider1 avatar Nov 28 '17 11:11 voider1