tweaselORG / appstraction

An abstraction layer for common instrumentation functions (e.g. installing and starting apps, setting preferences, etc.) on Android and iOS.
MIT License
4 stars 1 forks source link

Support getting the gaid/IDFA in `getDeviceAttribute()` #6

Open baltpeter opened 1 year ago

baltpeter commented 1 year ago

Getting the Google Advertising ID through Frida is proving harder than I expected.

Copilot autocompleted this script which lines up with the documentation and various StackOverflow answers:

var app_ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
var ad_id = Java.use('com.google.android.gms.ads.identifier.AdvertisingIdClient').getAdvertisingIdInfo(app_ctx);
send({ name: "get_obj_from_frida_script", payload: ad_id.getId() });

But that produces the following error:

Error: java.lang.ClassNotFoundException: com.google.android.gms.ads.identifier.AdvertisingIdClient
    at <anonymous> (frida/node_modules/frida-java-bridge/lib/env.js:124)
    at <anonymous> (frida/node_modules/frida-java-bridge/lib/env.js:115)
    at apply (native)
    at <anonymous> (frida/node_modules/frida-java-bridge/lib/env.js:97)
    at <anonymous> (frida/node_modules/frida-java-bridge/lib/class-factory.js:434)
    at value (frida/node_modules/frida-java-bridge/lib/class-factory.js:818)
    at _make (frida/node_modules/frida-java-bridge/lib/class-factory.js:111)
    at use (frida/node_modules/frida-java-bridge/lib/class-factory.js:62)
    at use (frida/node_modules/frida-java-bridge/index.js:258)
    at <eval> (<input>:1)
    at eval (native)

I realize that the app we're injecting into needs to have the correct library for this to work. But I'm injecting into the Google Settings app which displays the gaid, so I would really expect this to work.

baltpeter commented 1 year ago

Just in case the Google Settings app has some special permissions or whatever and doesn't need GMS to get the gaid, I've now also tried My Device ID by AppsFlyer.

I've verified that this does actually include the class:

❯ dexdump 'com.appsflyer.android.deviceid.apk' | grep "Class descriptor" | grep "gms/ads"
  Class descriptor  : 'Lcom/google/android/gms/ads/identifier/AdvertisingIdClient$1;'
  Class descriptor  : 'Lcom/google/android/gms/ads/identifier/AdvertisingIdClient$Info;'
  Class descriptor  : 'Lcom/google/android/gms/ads/identifier/AdvertisingIdClient$zza;'
  Class descriptor  : 'Lcom/google/android/gms/ads/identifier/AdvertisingIdClient;'
  Class descriptor  : 'Lcom/google/android/gms/ads/identifier/zza;'

And yet, I'm still getting the same error.

baltpeter commented 1 year ago

This Gist alerted me to Java.enumerateLoadedClassesSync().

Let's try that:

var classes = Java.enumerateLoadedClassesSync();
classes.filter(c => c.includes('gms'));

That has a few results, no ads, though:

[
    "com.google.android.gms.common.a",
    "com.google.android.gms.common.e",
    "[Lcom.google.android.gms.common.v;",
    "com.google.android.gms.common.f",
    "com.google.android.gms.common.i",
    "com.google.android.gms.common.j",
    "com.google.android.gms.common.k",
    "com.google.android.gms.internal.measurement.m2",
    "com.google.android.gms.common.r",
    "com.google.android.gms.common.s",
    "com.google.android.gms.common.t",
    "com.google.android.gms.common.u",
    "com.google.android.gms.common.v",
    "com.google.android.gms.common.w",
    "com.google.android.gms.common.x",
    "com.google.android.gms.common.y",
    "com.google.android.gms.common.z",
    "com.google.android.gms.internal.measurement.h2",
    "com.google.android.gms.internal.measurement.y0",
    "com.google.android.gms.dynamite.DynamiteModule",
    "com.google.android.gms.internal.measurement.n2",
    "com.google.android.gms.dynamite.DynamiteModule$a",
    "com.google.android.gms.internal.measurement.t1",
    "com.google.android.gms.dynamite.DynamiteModule$b",
    "com.google.android.gms.internal.measurement.z0",
    "com.google.android.gms.internal.measurement.o0",
    "com.google.android.gms.internal.measurement.o1",
    "com.google.android.gms.internal.measurement.o2",
    "com.google.android.gms.internal.measurement.d1",
    "com.google.android.gms.internal.measurement.zzcl",
    "com.google.android.gms.internal.measurement.u2",
    "com.google.android.gms.internal.measurement.p0",
    "com.google.android.gms.dynamite.b",
    "com.google.android.gms.internal.measurement.e1",
    "com.google.android.gms.dynamite.c",
    "com.google.android.gms.internal.measurement.e2",
    "com.google.android.gms.dynamite.d",
    "com.google.android.gms.dynamite.e",
    "com.google.android.gms.dynamite.f",
    "com.google.android.gms.dynamite.g",
    "com.google.android.gms.dynamite.h",
    "com.google.android.gms.dynamite.i",
    "com.google.android.gms.dynamite.j",
    "com.google.android.gms.dynamite.k",
    "com.google.android.gms.internal.measurement.v2",
    "com.google.android.gms.dynamite.n",
    "com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable",
    "com.google.android.gms.internal.measurement.k1",
    "com.google.android.gms.common.api.internal.a",
    "com.google.android.gms.internal.measurement.k2",
    "com.google.android.gms.dynamite.descriptors.com.google.android.gms.measurement.dynamite.ModuleDescriptor",
    "com.google.android.gms.dynamite.DynamiteModule$b$a",
    "com.google.android.gms.dynamite.DynamiteModule$b$b",
    "com.google.android.gms.internal.measurement.q0",
    "com.google.android.gms.dynamite.DynamiteModule$DynamiteLoaderClassLoader",
    "com.google.android.gms.internal.measurement.f1",
    "com.google.android.gms.common.api.internal.a$a",
    "com.google.android.gms.internal.measurement.w0",
    "com.google.android.gms.internal.measurement.l1",
    "com.google.android.gms.internal.measurement.l2",
    "com.google.android.gms.chimera.container.DynamiteModuleApi",
    "com.google.android.gms.dynamic.ObjectWrapper",
    "com.google.android.gms.dynamiteloader.DynamiteLoaderV2",
    "com.google.android.gms.common.internal.safeparcel.SafeParcelable",
    "com.google.android.gms.dynamic.ObjectWrapper",
    "[Lcom.google.android.gms.common.api.Scope;",
    "com.google.android.gms.measurement.internal.AppMeasurementDynamiteService",
    "com.google.android.gms.common.internal.safeparcel.SafeParcelable",
    "com.google.android.gms.chimera.DynamiteModuleInitializer",
    "com.google.android.gms.common.api.Scope",
    "com.google.android.gms.common.internal.ReflectedParcelable"
]
baltpeter commented 1 year ago

I feel like I'm missing something here. I can't even load any of the *gms* classes returned by Java.enumerateLoadedClassesSync():

var classes = Java.enumerateLoadedClassesSync();
for (const c of classes) {
    if (c.includes('.gms.')) {
        try {
            Java.use(c);
            console.log(1, c)
        } catch {}
    }
}

That has no output. Every Java.use() fails with java.lang.ClassNotFoundException.

baltpeter commented 1 year ago

Just for reference, here's what the Google Settings app (shows up in Frida as Google Play services) outputs for classes.filter(c => c.includes('gms.ads')):

[
    "com.google.android.gms.ads.admanager.a",
    "com.google.android.gms.ads.admanager.b",
    "com.google.android.gms.adsidentity.settings.AdsIdentityCollapseSettingsChimeraActivity",
    "com.google.android.gms.ads.internal.util.aa",
    "com.google.android.gms.adsidentity.settings.ui.NewAdIdCustomPreference",
    "com.google.android.gms.ads.internal.util.ah",
    "com.google.android.gms.ads.internal.util.ai",
    "com.google.android.gms.ads.internal.util.d",
    "com.google.android.gms.ads.internal.util.e",
    "com.google.android.gms.ads.internal.util.h",
    "com.google.android.gms.ads.internal.util.m",
    "com.google.android.gms.ads.internal.util.n",
    "com.google.android.gms.ads.internal.scionintegration.j",
    "com.google.android.gms.ads.internal.appcontent.c",
    "com.google.android.gms.ads.internal.util.client.f",
    "com.google.android.gms.ads.internal.util.client.k",
    "com.google.android.gms.ads.internal.util.client.n",
    "com.google.android.gms.ads.internal.webview.p",
    "com.google.android.gms.ads.internal.js.function.c",
    "com.google.android.gms.ads.internal.mediation.c",
    "com.google.android.gms.ads.internal.cache.a",
    "com.google.android.gms.ads.internal.client.d",
    "com.google.android.gms.ads.internal.client.f",
    "com.google.android.gms.ads.internal.client.s",
    "com.google.android.gms.ads.internal.client.u",
    "com.google.android.gms.ads.internal.csi.c",
    "com.google.android.gms.ads.interstitial.b",
    "com.google.android.gms.adsidentity.settings.ui.ImageViewPreference",
    "com.google.android.gms.ads.internal.overlay.a",
    "com.google.android.gms.ads.internal.c",
    "com.google.android.gms.ads.search.a",
    "com.google.android.gms.ads.internal.overlay.c",
    "com.google.android.gms.ads.internal.request.service.g",
    "com.google.android.gms.ads.internal.util.client.VersionInfoParcel",
    "com.google.android.gms.ads.internal.util.net.a",
    "com.google.android.gms.ads.internal.state.a",
    "com.google.android.gms.ads.internal.state.e",
    "com.google.android.gms.ads.internal.state.f",
    "com.google.android.gms.ads.internal.state.g",
    "com.google.android.gms.adsidentity.settings.AdsIdentityGoogleSettingsIntentOperation",
    "com.google.android.gms.ads.internal.video.gmsg.b",
    "com.google.android.gms.adsidentity.settings.AdsIdentityCollapseSettingsActivity",
    "com.google.android.gms.ads.internal.util.weaklisteners.a"
]

But trying to load any of those fails with java.lang.ClassNotFoundException. shrug

baltpeter commented 1 year ago

Getting the IDFA is a lot easier on iOS (thanks, Copilot):

ObjC.classes.ASIdentifierManager.sharedManager().advertisingIdentifier().toString();

Only problem: You need an app that has the kTCCServiceUserTracking permission, otherwise you just get 00000000-0000-0000-0000-000000000000 (even in system apps like SpringBoard :/).