Google 广告id流程分析

集成谷歌广告sdk

导包:

implementation("com.google.android.gms:play-services-ads-identifier:18.1.0")

获取广告id的代码

new Thread(() -> {
    try {
        Class.forName("com.google.android.gms.ads.identifier.AdvertisingIdClient");
        AdvertisingIdClient.Info advertisingIdClient$Info0 = AdvertisingIdClient.getAdvertisingIdInfo(this);
        if(advertisingIdClient$Info0 == null) {
            Log.e(Tag,"advertisingIdClient$Info0  == null");
        }
        else {
            String id = advertisingIdClient$Info0.getId();
            advertisingIdClient$Info0.isLimitAdTrackingEnabled();
            Log.e(Tag,"advertisingId = " + id);
        }
    }
    catch(Throwable throwable0) {
        Log.e(Tag,"Google Play Services is missing " + throwable0.getMessage());
    }


}).start();

跟踪代码流程

这个包也只是提供了一个获取的接口,实际生成不在这个包里面

 public static Info getAdvertisingIdInfo(Context context) throws IOException, IllegalStateException, GooglePlayServicesNotAvailableException, GooglePlayServicesRepairableException {
        Info advertisingIdClient$Info0;
        AdvertisingIdClient advertisingIdClient0 = new AdvertisingIdClient(context, -1L, true, false);
        try {
            long v = SystemClock.elapsedRealtime();
            advertisingIdClient0.zzb(false);
            advertisingIdClient$Info0 = advertisingIdClient0.zzd(-1);
            advertisingIdClient0.zzc(advertisingIdClient$Info0, true, 0.0f, SystemClock.elapsedRealtime() - v, "", null);
        }
        catch(Throwable throwable0) {
            try {
                advertisingIdClient0.zzc(null, true, 0.0f, -1L, "", throwable0);
                throw throwable0;
            }
            catch(Throwable throwable1) {
                advertisingIdClient0.zza();
                throw throwable1;
            }
        }


        advertisingIdClient0.zza();
        return advertisingIdClient$Info0;
    }

private final Info zzd(int v) throws IOException {
        Info advertisingIdClient$Info0;
        
        ……
        try {
            try {
                advertisingIdClient$Info0 = new Info(this.zzb.zzc(), this.zzb.zze(true)); //第一个参数是广告id ,第二个参数是isLimitAdTrackingEnabled
            }
            catch(RemoteException remoteException0) {
                Log.i("AdvertisingIdClient", "GMS remote exception ", remoteException0);
                throw new IOException("Remote exception");
            }


            __monitor_exit(this);
        }
        catch(Throwable throwable0) {
            __monitor_exit(this);
            throw throwable0;
        }


        this.zze();
        return advertisingIdClient$Info0;
    }

Info类,第一个参数是广告id ,第二个参数是isLimitAdTrackingEnabled
    public static final class Info {
        private final String zza;
        private final boolean zzb;


        @Deprecated
        public Info(String s, boolean z) {
            this.zza = s;
            this.zzb = z;
        }


        public String getId() {
            return this.zza;
        }


        public boolean isLimitAdTrackingEnabled() {
            return this.zzb;
        }


        @Override
        public String toString() {
            return "{" + this.zza + "}" + this.zzb;
        }
    }

zzd.zzc 返回值就是广告id,是通过binder接口跨进程获取的,后续代码就不在这个sdk里面了,相当于这个sdk就提供了获取的接口,实际值是怎么来的不在这里面。
    @Override  // com.google.android.gms.internal.ads_identifier.zzf
    public final String zzc() throws RemoteException {
        Parcel parcel0 = this.zzb(1, this.zza());
        String s = parcel0.readString();
        parcel0.recycle();
        return s;
    }


package com.google.android.gms.internal.ads_identifier;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

public class zza implements IInterface {
    private final IBinder zza;
    private final String zzb;


    protected zza(IBinder iBinder0, String s) {
        this.zza = iBinder0;
        this.zzb = "com.google.android.gms.ads.identifier.internal.IAdvertisingIdService";
    }
    @Override  // android.os.IInterface
    public final IBinder asBinder() {
        return this.zza;
    }
    protected final Parcel zza() {
        Parcel parcel0 = Parcel.obtain();
        parcel0.writeInterfaceToken(this.zzb);
        return parcel0;
    }
    protected final Parcel zzb(int v, Parcel parcel0) throws RemoteException {
        Parcel parcel1 = Parcel.obtain();
        try {
            this.zza.transact(v, parcel0, parcel1, 0);
            parcel1.readException();
        }
        catch(RuntimeException runtimeException0) {
            try {
                parcel1.recycle();
                throw runtimeException0;
            }
            catch(Throwable throwable0) {
                parcel0.recycle();
                throw throwable0;
            }
        }
        catch(Throwable throwable0) {
            parcel0.recycle();
            throw throwable0;
        }
        parcel0.recycle();
        return parcel1;
    }
}

继续跟踪分析gms包

adb shell pm path com.google.android.gms 搜索安装包路径,然后包apk pull出来分析。
搜索上面的接口 “com.google.android.gms.ads.identifier.internal.IAdvertisingIdListener”
追踪流程

public abstract class bpub implements ServiceConnection {
     public final void onServiceConnected(ComponentName componentName0, IBinder iBinder0) {
        eows eows0 = this.a.j(componentName0, "onServiceConnected");
        try {
            this.a(componentName0, iBinder0);
        }
        catch(Throwable throwable0) {
            if(eows0 != null) {
                try {
                    eows0.close();
                }
                catch(Throwable throwable1) {
                    throwable0.addSuppressed(throwable1);
                }
            }


            throw throwable0;
        }


        if(eows0 != null) {
            eows0.close();
        }
    }

public final class rhp extends bpub {
    @Override  // bpub
    public final void a(ComponentName componentName0, IBinder iBinder0) {
        npz npz0;
        if(iBinder0 == null) {
            npz0 = null;
        }
        else {
            IInterface iInterface0 = iBinder0.queryLocalInterface("com.google.android.gms.ads.identifier.internal.IAdvertisingIdListener");
            npz0 = (iInterface0 instanceof a) ? ((a)iInterface0) : new a(iBinder0);
        }


        try {
            int v = amza.b(this.c).d(this.a, 0).uid;
            Bundle bundle0 = new Bundle();
            bundle0.putString("ad_id", this.e.f(v));
            bundle0.putBoolean("lat_enabled", this.e.o(v));
            Parcel parcel0 = npz0.fs();
            nqb.d(parcel0, bundle0);
            npz0.ft(1, parcel0);
        }
        catch(Throwable throwable0) {
            ((ertf)AdvertisingIdNotificationChimeraService.a.j()).B("Failed to notify listener service of %s.", this.a);
            Log.w("AdvertisingIdNS", throwable0);
        }


        try {
            ampa.a().b(this.c, this);
        }
        catch(IllegalArgumentException unused_ex) {
        }


        this.d.release();
    }

接上面bundle0.putString("ad_id", this.e.f(v));
    public final String f(int v) {
        boolean z;
        if(((long)Build.VERSION.SDK_INT) >= furq.c() && (this.o(v))) {
            if(furq.g()) {
                this.j();  // this.b().edit().remove("adid_key").remove("fake_adid_key").apply();
            }

            if(furq.a.e().J()) {
                return b.a; //b.a = new UUID(0L, 0L).toString();
            }
        }


        String[] arr_s = amza.b(this.f).k(Binder.getCallingUid());
        if(arr_s != null && arr_s.length == 1) {
            String s = arr_s[0];
            if(!com.google.android.gms.ads.identifier.util.d.a(s) && !com.google.android.gms.ads.identifier.util.d.b(s)) {
                if(!com.google.android.gms.ads.identifier.util.d.c(s) || !fush.f()) {
                    goto label_13;
                }


                z = this.q(s, "android.permission.ACCESS_PRIVILEGED_AD_ID_COMPAT");
            }
            else {
                z = this.q(s, "android.permission.ACCESS_PRIVILEGED_AD_ID");
            }


            if(z) {
                goto label_27;
            }
        }


    label_13:
        if(v != -100) {
            String[] arr_s1 = amza.b(this.f).k(v);
            if(arr_s1 == null) {
                Log.w("AdvertisingIdSettings", "Invalid caller uid. Permission check failed");
                goto label_23;
            }


            for(int v1 = 0; v1 < arr_s1.length; ++v1) {
                if(34L >= furq.b() && boik.c(this.f, "com.google.android.gms.permission.AD_ID", -1, v, arr_s1[v1], null) == -1) {
                    if(furq.a.e().u()) {
                        Log.w("AdvertisingIdSettings", "Package " + arr_s1[v1] + " failed Ad Id permission check. Apps that target Android SDK " + furq.b() + " or higher should declare com.google.android.gms.permission.AD_ID in the app manifest to access Ad Id.");
                    }


                label_23:
                    if(((long)Build.VERSION.SDK_INT) < furq.a.e().a() || !furq.a.e().t()) {
                        break;
                    }


                    return b.a;
                }
            }
        }


    label_27:
        amue.p(this.f);
        String s1 = this.n() ? this.g() : this.h(); //没开开发者选项获取adid_key,开了开发者选项要看enable_debug_logging的值,true就是获取fake_adid_key,false是获取adid_key
        return s1.isEmpty() ? this.e() : s1;      //如果为空重新生成adid
    }

// 判断开发者选项有没有打开,打开"development_settings_enabled"值是1 ,默认没打开是0;若==0 直接返回false, 否则返回enable_debug_logging 的值。
adb shell settings get global development_settings_enabled 可以看这个值。
public final boolean n() {
        if(fuok.c()) {
            try {
                return Settings.Global.getInt(this.f.getContentResolver(), "development_settings_enabled", 0) == 0 ? false : this.b().getBoolean("enable_debug_logging", false);
            }
            catch(Exception exception0) {
                Log.w("AdvertisingIdSettings", "Fail to determine debug setting.", exception0);
                return false;
            }
        }


        return false;
    }
    public final String g() {
        return this.b().getString("fake_adid_key", "");
    }


    public final String h() {
        return this.b().getString("adid_key", "");
    }

//重新生成adid 保存到sp里面
    public final String e() {
        String s1;
        String s;
        boolean z;
        Object object0 = this.b;
        __monitor_enter(object0);
        try {
            z = this.n();
            s = z ? b.d() : ""; 
            this.j();
            s1 = "";
            if(!furq.j()) {
                goto label_15;
            }


            boolean z1 = furq.a.e().Q();
        }
        catch(Throwable throwable0) {
            goto label_26;
        }


        if(!z1) {
            goto label_15;
        }


        try {
            s1 = ddvs.b(this.g.e()).toString();
            if(!TextUtils.isEmpty(s1)) {
                goto label_15;
            }


            throw new IOException("Generated Id is null");
        }
        catch(IOException | GeneralSecurityException exception0) {
        }
        catch(Throwable throwable0) {
            goto label_26;
        }


        try {
            d.c(this.f, "generateNewIdError", exception0);
            s1 = "";
        label_15:
            int v = TextUtils.isEmpty(s1);
            if(v != 0) {
                s1 = UUID.randomUUID().toString();
            }


            if(furq.a.e().A()) {
                q.a(this.f).b();
                q.a(this.f).c();
            }


            int v1 = this.b().getInt("adid_reset_count", 0) + 1;
            this.b().edit().putInt("adid_reset_count", v1).apply();
            __monitor_exit(object0);
            return this.i(z, ((boolean)(v ^ 1)), s1, s);
        label_26:
            __monitor_exit(object0);
        }
        catch(Throwable throwable0) {
            goto label_26;
        }


        throw throwable0;
    }

    public final String i(boolean z, boolean z1, String s, String s1) {
        if(z) {
            amdo.b(((boolean)(s1.isEmpty() ^ 1)));
        }
        else {
            amdo.b(s1.isEmpty());
        }


        this.b().edit().putBoolean("enable_debug_logging", z).putBoolean("using_cert", z1).putString("adid_key", s).putString("fake_adid_key", s1).apply();
        this.k();
        return z ? s1 : s;
    }

//fake_adid_key
    public static String d() {
        String s = UUID.randomUUID().toString();
        return s.substring(0, s.length() - 12) + "10ca1ad1abe1";
    }

//sp配置文件    
final SharedPreferences b() {
        return this.f.getSharedPreferences("adid_settings", 4);
    }

sp配置文件的路径和内容:

sargo:/data/data/com.google.android.gms/shared_prefs # cat adid_settings.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <boolean name="enable_debug_logging" value="false" />
    <boolean name="using_cert" value="false" />
    <string name="adid_key">a8e3cc65-3fa2-4d07-9688-24ad61ac110d</string>
    <string name="fake_adid_key"></string>
    <int name="adid_reset_count" value="1" />
    <boolean name="enable_limit_ad_tracking" value="false" />
</map>

你可能感兴趣的:(安卓逆向,android,逆向分析)