rovo89 / XposedBridge

The Java part of the Xposed framework.
3.88k stars 1.1k forks source link

handleLoadPackage not called when wrapping a specific app (setprop wrap.com.package) #161

Open EquiFox opened 7 years ago

EquiFox commented 7 years ago

I'm running everything in a x86 emulator.

If I use setprop wrap.com.... to setup an LD_PRELOAD on a specific app, then handleLoadPackage will never be called for this specific app, only handleInitPackageResources will be called.

When I'm not using setprop, both are called.

EquiFox commented 7 years ago

Actually it seems to be related to the process wrapping and not LD_PRELOAD

I've tried setprop wrap.com.package.name "logwrapper" and the same behaviour occurs.

Is there any potential fix for this ?

EDIT: Same behaviour on my OnePlus 3 (ARM64)

rovo89 commented 7 years ago

What is setprop wrap.com.package.name ...? Never heard of this, is there any documenation how it works and how it should be used?

EquiFox commented 7 years ago

Thanks for your quick reply !

Actually it inserts a temporary entry in Build.prop (If I'm not wrong).

The only official doc that mention setprop wrap is there: https://source.android.com/devices/tech/debug/

EquiFox commented 7 years ago

Another piece of information I found that might help you get a better understanding (Than me)

We’re nearly there. We have a device which is all set up, and a debuggable Firefox on it. But we need to tell Zygote that we want to start Firefox with a wrapper, namely Valgrind. In the shell on the phone, do this:

   setprop wrap.org.mozilla.fennec_sewardj "logwrapper /data/local/start_valgrind_fennec"

This tells Zygote that any startup of “org.mozilla.fennec_sewardj” should be done via an exec() of /data/local/start_valgrind_fennec applied to Zygote-specified arguments. So, now we can put any old thing in a shell script, and Zygote will run it. Here’s what I have for /data/local/start_valgrind_fennec:

rovo89 commented 7 years ago

OK... it would still be necessary to understand what exactly happens in the background, how this is implemented. Usually, apps are started by forking from Zygote, which automatically inherits the Xposed setup (including the hook required for handleLoadPackage()). This somehow sounds like the app is started as an individual process, which might need its own setup to run. If you can find any related source code, that would be a big help.

EquiFox commented 7 years ago

That might be what we are looking for: https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/WrapperInit.java

The main function called when starting a runtime application through a wrapper process instead of by forking Zygote.

EquiFox commented 7 years ago

I understand you might be busy, so if you have an idea, you can point me and I'll try to implement a fix myself.

Thanks again:D

rovo89 commented 7 years ago

As far as I understood from the source code, Android actually launches a fresh new process in this case instead of forking from Zygote. That breaks quite a few assumptions in the code - not only in mine, but modules can usually assume that handleInitZygote() will run before handleLoadPackage() (and might do some common initialization there). Even if we were to fake a call to handleLoadPackage(), the behavior of modules is pretty much undefined as probably not even a single module developer has tested this case.

In my local codebase, I have actually disabled loading Xposed for such stand-alone processes for this and some other reasons a while ago. The fact that Xposed is loaded at all in this case is more or less by chance, as I was only aware of the Zygote case and tools like am. I had support for the latter in earlier versions, but hardly anyone used it and it was hard to maintain.

So in short, I think I'd rather consistently deactivate Xposed for this case than having to support an edge case with many possible traps. What's your use-case to set this property, by the way? Could there be alternatives?

liudongmiao commented 7 years ago

@rovo89

The fact that Xposed is loaded at all in this case is more or less by chance, as I was only aware of the Zygote case and tools like am

Yes, and IMO, you may offer a mode for Xposed not to hook apps, only hook system services. As any app, actually, can escape from the Xposed hook, or determine the existing of Xposed. It should be unsafe for Xposed module to hook normal apps.

rovo89 commented 7 years ago

I don't share your opinion. Just because apps could actively try to detect/circumvent Xposed hooks, why should I close that door? For me, it's quite useful to be able to customize apps' behavior, maybe even more than customing the way the system works.

Regarding the mode you mentioned: In the Zygote case, Xposed is just initialized once. Any apps and the system_server inherit that, it's not possible to un-initialize Xposed for some of them. And anyway, more variants increase the fragmentation and complexity, so I try to keep the number of settings as small as possible.

EquiFox commented 7 years ago

I see, thank you for the details.

However in my case, I'm using a wrapped process to allow me to use LD_PRELOAD to ultimately preload a custom native library before system libs are loaded (libc, etc), It's like doing a native code hook. My goal is to use both Xposed managed hooking power and this native hook technique. I can't use Frida along with Xposed and I find it mostly unstable. My only remaining solution would be to recompile a custom version of libc and overwrite it in my device but the effort to do that is less desirable considering the changes I would have to make.

If you could make a quick version that allow this for device >= 5.0 (If possible) I would really appreciate. No need to maintain if you don't want too, I'm not planning on changing my device soon. I could make a donation for your time as this is really important for me.

rovo89 commented 7 years ago

Two questions: Do you want to use any specific module, maybe one you developed yourself? And could the LD_PRELOAD be set for the whole system, so that it would apply to Zygote and all of its forks?

EquiFox commented 7 years ago

I will use one specific module that I created myself.

I tried a system wide preload like on usual Linux and it doesnt work even with SELinux off.

EquiFox commented 7 years ago

I also thought about editing init.zygote32.rc to add the LD_PRELOAD there, but it goes back to original after reboot and I'm unable to build a flashable zip to edit it on Genymotion.

rovo89 commented 7 years ago

I also thought about editing init.zygote32.rc to add the LD_PRELOAD there, but it goes back to original after reboot and I'm unable to build a flashable zip to edit it on Genymotion.

Yeah, that's part of the kernel. It's definitely possible to build a flashable zip that modifies the file and restarts Zygote afterwards, you'd have to flash it on every boot though.

I will use one specific module that I created myself.

Xposed creates an instance of your main class when it loads your module. If you put some code into the default constructor, it will be executed at that time. That's not part of the official APIs and I definitely don't recommend to rely on this, but if it's just for your own purposes and you could stick to an Xposed version where this works, you could give it a try.

EquiFox commented 7 years ago

@rovo89 Thanks for your time !

I managed to apply permanent modification to init.zygote32.rc so my LD_PRELOAD can work without actually wrapping the app process, this mean I can use Xposed :D

rovo89 commented 7 years ago

Great! Just in case someone comes across this issue later, could you quickly summarize how you did the modification? Did you build your own image?

EquiFox commented 7 years ago

Sure ! Although it is probably possible to make a flashable zip with a script to append a line to init.zygote32.rc, I wasn't able to make my attemps works on Genymotion.

Here's what I did:

Now, simply close your Ubuntu VM then restart the new Android VM we created. If everything worked, Zygote will use LD_PRELOAD to preload your native library before anything else (libc, etc) and since every Android app processes will fork Zygote they will inherit the same setup.

Hope it can help someone, I know it's an uncommon usage case, but hey if someone would have posted this on Github when I searched for it it would have saved alot of time :D

Thanks again @rovo89 for your time !

su-vikas commented 7 years ago

I have a similar use case and big thanks to @EquiFox for an alternative solution to the problem. Thanks to @rovo89 as well for discussing the details.

Google search didn't show me this page, but luckily landed when I wanted to file similar issue.