XPrivacy icon indicating copy to clipboard operation
XPrivacy copied to clipboard

Advertising ID not hooked for some applications

Open ifynk opened this issue 9 years ago • 29 comments

Applications can get Advertising ID bypassing standard methods (getId) if use this code http://stackoverflow.com/questions/20097506/using-the-new-android-advertiser-id-inside-an-sdk

ifynk avatar Apr 18 '15 18:04 ifynk

This can only be prevented by hooking in the service that provides the advertising ID. Unfortunately this is not possible, because this service is closed source. I could hook into the Binder, which I did before, but the big disadvantage is a system wide degraded performance.

M66B avatar Apr 18 '15 20:04 M66B

Hmm is there perhaps a way to change the Advertising ID itself, since this can be done by hand as well? There is no real use for it anyway, so I'm sure all users would be fine with Xprivacy's changing the ID every time a new application starts, or something like that.

Cerberus-tm avatar Apr 18 '15 20:04 Cerberus-tm

I don't think a random application can change the advertising ID.

M66B avatar Apr 18 '15 20:04 M66B

Not a random application, but Xprivacy? We can now reset it through some menu in the Google application. If Xprivacy were to change/reset the ID on a regular basis, that would protect users from being tracked that way fairly well?

Cerberus-tm avatar Apr 18 '15 21:04 Cerberus-tm

For Google Play services, XPrivacy is just a random application. The problem here it is closed source, so honking is not an option.

M66B avatar Apr 18 '15 21:04 M66B

Oh, in that way, I see. Too bad there isn't an intent to do that or something.

Cerberus-tm avatar Apr 18 '15 21:04 Cerberus-tm

I try to play with code and here is result:

        XposedHelpers.findAndHookMethod("android.os.BinderProxy", loadPackageParam.classLoader, "transact", int.class, Parcel.class, Parcel.class, int.class, new XC_MethodHook() {
            protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);

                IBinder binder = (IBinder) param.thisObject;

                String interfaceBinder = binder.getInterfaceDescriptor();

                if (interfaceBinder.equals("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService")) {
                     // change result for readString
                }
            }
        });

I think this code would work if change data in reply parcel.

ifynk avatar Apr 19 '15 05:04 ifynk

Yes, I know this will work, but check how many calls are done to transact to see what the performance impact is.

See also this source: https://github.com/M66B/XPrivacy/blob/master/src/biz/bokhorst/xprivacy/XBinder.java

M66B avatar Apr 19 '15 05:04 M66B

Nevertheless, make this work and do a pull request and I might merge it.

M66B avatar Apr 19 '15 05:04 M66B

I'd love to, but I can not deal with the substitution data Parcel. Can you show me the direction to solve this problem?

ifynk avatar Apr 19 '15 06:04 ifynk

Hook into android.os.Binder.execTransact (this is safer, because it is at the service side, which cannot be unhooked).

Then in "before" create a new parcel with the right layout and values, see here for how to create a new parcel: https://github.com/M66B/XPrivacy/blob/master/src/biz/bokhorst/xprivacy/XBinder.java#L311 and see here for how to write to the parcel: http://developer.android.com/reference/android/os/Parcel.html

One little concern: the parcel layout may be version dependent, but lets ignore that for now.

Nice challenge for a Sunday morning ;-)

If you use Hangouts/XMPP and want to chat, please contact me here to exchange addresses if you like: http://forum.faircode.eu/contact/

M66B avatar Apr 19 '15 06:04 M66B

This is the layout of the Parcel (taken from StackOverflow):

reply.readException();
id = reply.readString();

So, create the fake Parcel with:

writeNoException();
writeString(fakeValue);

M66B avatar Apr 19 '15 06:04 M66B

One other thing: you should test for the transaction code:

binder.transact(1, data, reply, 0);

So, like this:

int code = (Integer) param.args[0];
if (code == 1)
  ...

M66B avatar Apr 19 '15 06:04 M66B

Now i have this code

                    int code = (Integer) param.args[0];

                    if (code == 1) {

                        Method methodObtain = Parcel.class.getDeclaredMethod("obtain");
                        methodObtain.setAccessible(true);

                        Parcel reply = (Parcel) methodObtain.invoke(null, param.args[2]);

                        reply.writeNoException();

                        reply.writeString("a7bf815a-c37b-40db-be9d-3b395abbe888");
                    }

                    param.setResult(true);

but in this case i got error "java.lang.IllegalArgumentException: wrong number of arguments; expected 0, got 1" on line with code "Parcel reply = (Parcel) methodObtain.invoke(null, param.args[2]);"

ifynk avatar Apr 19 '15 06:04 ifynk

Change to:

Method methodObtain = Parcel.class.getDeclaredMethod("obtain", int.class);

Note that this has been changed on Lollipop:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/os/Parcel.java#Parcel.obtain%28int%29

Also, you need this to rewrite the Parcel:

reply.setDataPosition(0);

M66B avatar Apr 19 '15 06:04 M66B

Ok. This code should work, but not worked. I am confused (

        XposedHelpers.findAndHookMethod("android.os.Binder", loadPackageParam.classLoader, "execTransact", int.class, long.class, long.class, int.class, new XC_MethodHook() {
            protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);

                IBinder binder = (IBinder) param.thisObject;

                String interfaceBinder = binder.getInterfaceDescriptor();

                if (interfaceBinder.equals("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService")) {

                    int code = (Integer) param.args[0];

                    if (code == 1) {

                        Method methodObtain = Parcel.class.getDeclaredMethod("obtain", int.class);
                        methodObtain.setAccessible(true);

                        Parcel reply = (Parcel) methodObtain.invoke(null, param.args[2]);

                        reply.setDataPosition(0);
                        reply.writeNoException();

                        reply.writeString("a7bf815a-c37b-40db-be9d-3b395abbe888");
                    }

                    param.setResult(true);
                }
            }
        });

I got error java.lang.NoSuchMethodError: android.os.Binder#execTransact(int,long,long,int)#exact

ifynk avatar Apr 19 '15 06:04 ifynk

Which Android version are you using?

Android 5.x: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/os/Binder.java#435

Earlier versions: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/os/Binder.java#393

M66B avatar Apr 19 '15 06:04 M66B

I have corrected the links in my previous comment

M66B avatar Apr 19 '15 06:04 M66B

param.setResult(true);

Should be for code 1 only.

M66B avatar Apr 19 '15 06:04 M66B

I use 4.0.3 at now. And i have 4.4 device, but not tested on them.

ifynk avatar Apr 19 '15 06:04 ifynk

Then change to:

XposedHelpers.findAndHookMethod("android.os.Binder", loadPackageParam.classLoader, "execTransact", int.class, int.class, int.class, int.class, new XC_MethodHook() {

M66B avatar Apr 19 '15 06:04 M66B

You are amazing ). I was not able to solve this problem for 3 days. Thank you very much. Sorry, but i don't know how to create pull request. Worked code.

        XposedHelpers.findAndHookMethod("android.os.Binder", loadPackageParam.classLoader, "execTransact", int.class, int.class, int.class, int.class, new XC_MethodHook() {
            protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);

                IBinder binder = (IBinder) param.thisObject;

                String interfaceBinder = binder.getInterfaceDescriptor();

                if (interfaceBinder.equals("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService")) {

                    int code = (Integer) param.args[0];

                    if (code == 1) {

                        Method methodObtain = Parcel.class.getDeclaredMethod("obtain", int.class);
                        methodObtain.setAccessible(true);

                        Parcel reply = (Parcel) methodObtain.invoke(null, param.args[2]);

                        reply.setDataPosition(0);
                        reply.writeNoException();

                        reply.writeString("a7bf815a-c37b-40db-be9d-3b395abbe888");

                        param.setResult(true);
                    }
                }
            }
        });

Best regards from Ukraine.

ifynk avatar Apr 19 '15 07:04 ifynk

You will first have to integrate this code into XPrivacy. Take a look at the XBinder class (or any other X-class) about how to do this and write a similar class, which you should reference from XPrivacy. You'll see it is simple.

XPrivacy uses an abstraction layer around Xposed, so it can easily be replaced by another framework.

M66B avatar Apr 19 '15 07:04 M66B

Ok, i will try.

ifynk avatar Apr 19 '15 07:04 ifynk

I can do this easily, but I think it is good if others learn how to do this as well.

M66B avatar Apr 19 '15 07:04 M66B

Me = M66B Why are you asking?

M66B avatar Apr 19 '15 07:04 M66B

I have to add that Parcel.obtain takes long as argument, not int. I tried this code and have exception. Android 5.1.1

kupalinka avatar Dec 03 '15 20:12 kupalinka

The argument (integer or long) depends on the Android version.

M66B avatar Dec 03 '15 21:12 M66B

Thnx! and if it is part of universal module, what is the best way to solve it?

kupalinka avatar Dec 04 '15 09:12 kupalinka