rovo89 / XposedInstaller

3.85k stars 1.51k forks source link

Xposed module with BroadcastReceiver #409

Open voider1 opened 6 years ago

voider1 commented 6 years ago

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)
rovo89 commented 6 years ago

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.

voider1 commented 6 years ago

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?

rovo89 commented 6 years ago

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.

voider1 commented 6 years ago

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

rovo89 commented 6 years ago

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.

voider1 commented 6 years ago

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.

rovo89 commented 6 years ago

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?

voider1 commented 6 years ago

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?

rovo89 commented 6 years ago

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...

voider1 commented 6 years ago

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?

rovo89 commented 6 years ago

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.

voider1 commented 6 years ago

@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.