本篇文章讲解如果真正修改手机硬件参数。
app 会通过判断当前手机的imei、mac、imsi等参数来判断此手机多次注册过app。一般情况下的权重是 imei > imsi > mac > android_id 。
Android 获取 imei 等信息的源码主要在TelephonyManager.java中,app 能获取这些参数只有这一种途径,通过adb 和shell是获取不到。所以比较简单。
获取imei

telephonyManager.getImei(){ //获取默认卡的imei ,就是当前正在联网的
if(true){
    从sd卡或者数据库读取动态imei
[size=3]}[/size]
 return getImei(getSlotIndex());
}[/size]
public String getImei(int slotIndex) { //如果是多卡,就获取指定的imei。不知道模拟器或者双开注意要支持
        ITelephony telephony = getITelephony(); 
        if (telephony == null) return null;


        try {
            return telephony.getImeiForSlot(slotIndex, getOpPackageName());[/size]
        } catch (RemoteException ex) {
            return null;
        } catch (NullPointerException ex) {
            return null;
        }
    }

剩下 手机号 、 simnum 、iccid 的大概都是此方法,我已经通过下面代码验证,修改的参数完全起作用

private void imei() {
        try {
            TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            String ANDROID_ID = Settings.System.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
            Log.e(TAG,"def ANDROID_ID ->" + ANDROID_ID);
           String imei0 = telephonyManager.getDeviceId();
            Log.e(TAG,"def myimei ->" + imei0);
            String imei1 = telephonyManager.getDeviceId(1);
            Log.e(TAG,"myimei1 ->" + imei1);
            if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1){
            String imei2 = telephonyManager.getImei(0);
            Log.e(TAG,"26+ imei0 ->" + imei2);}


            String imsi = telephonyManager.getSubscriberId();
            Log.e(TAG, "imsi ->" + imsi);

            String phoneNumber = telephonyManager.getLine1Number();
            Log.e(TAG, "SIM卡中存储本机号码 phoneNumber ->" + phoneNumber);

            String voiceMail = telephonyManager.getVoiceMailNumber();
            Log.e(TAG, "语音邮件号码 voiceMail ->" + voiceMail);

            String simSerial = telephonyManager.getSimSerialNumber();
            Log.e(TAG, "SIM卡序列号 simSerial ->" + simSerial);

            String countryIso = telephonyManager.getNetworkCountryIso();
            Log.e(TAG, "SIM卡提供商的国家代码 countryIso ->" + countryIso);

            String carrier = telephonyManager.getNetworkOperatorName();
            Log.e(TAG, "当前移动网络运营商 mynetname ->" + carrier);
            String netid = telephonyManager.getNetworkOperator();
            Log.e(TAG, "当前移动网络运营商 netid ->" + netid);

            int count = telephonyManager.getPhoneCount();
            Log.e(TAG, "移动卡数量 count ->" + count);
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
                String Meid = telephonyManager.getMeid();
                Log.e(TAG, "移动卡数量 Meid ->" + Meid);
            }
            if (Build.VERSION.SDK_INT > 28) {
                String nai = telephonyManager.getNai();
                Log.e(TAG, "移动卡数量 Nai ->" + nai);
            }


            String simOperator = telephonyManager.getSimOperator();
            Log.e(TAG, "SIM的移动运营商的名称 mysmo ->" + simOperator);

            int phoneType = telephonyManager.getPhoneType();
            Log.e(TAG, "移动终端的类型 phoneType ->" + phoneType);

            int radioType = telephonyManager.getNetworkType();
            Log.e(TAG, "当前使用的网络制式 radioType ->" + radioType);

            String softVersion = telephonyManager.getDeviceSoftwareVersion();
            Log.e(TAG, "软件版本 softVersion ->" + softVersion);
            boolean Roam = telephonyManager.isNetworkRoaming();
            Log.e(TAG, "漫游 Roam ->" + Roam);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Android 修改Android_id的方法:
Android 获取的方法是
String ANDROID_ID = Settings.System.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
此参数read-only。如果使用 Settings.System.putString(this.getContentResolver(),“自定义id”);
会报错误,只需要把

public static boolean putStringForUser(@NonNull ContentResolver resolver,
                @NonNull String name, [url=home.php?mod=space&uid=1043391]@nullable[/url] String value, @Nullable String tag,
                boolean makeDefault, @UserIdInt int userHandle) {
            if (LOCAL_LOGV) {
                Log.v(TAG, "Global.putString(name=" + name + ", value=" + value
                        + " for " + userHandle);
            }
            // Global and Secure have the same access policy so we can forward writes
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Global"
                        + " to android.provider.Settings.Secure, value is unchanged.");
                return Secure.putStringForUser(resolver, name, value, tag,
                        makeDefault, userHandle);
            }
            return sNameValueCache.putStringForUser(resolver, name, value, tag,
                    makeDefault, userHandle);
        }

只需要 if (MOVED_TO_SECURE.contains(name)) {}内容注释掉即可。
Android 动态修改mac 比较麻烦
Android 获取 mac 方式有以下几种
第一种执行 shell 命令:ifconfig
第二种是

private static String getMacFromHardware() {
    try {
        List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
        Log.d("Utils", "all:" + all.size());
        for (NetworkInterface nif : all) {
            if (!nif.getName().equalsIgnoreCase("wlan0")) {
                continue;
            }

            byte[] macBytes = nif.getHardwareAddress();
            if (macBytes == null) {
                return null;
            }
            Log.d("Utils", "macBytes:" + macBytes.length + "," + nif.getName());

            StringBuilder res1 = new StringBuilder();
            for (byte b : macBytes) {
                res1.append(String.format("%02X:", b));
            }

            if (res1.length() > 0) {
                res1.deleteCharAt(res1.length() - 1);
            }
            return res1.toString();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

第三种 cat /sys/class/net/wlan0/address
对于第一种 和第三种比较麻烦。如果通过修改getInetAddresses 返回动态的的 mac,无法绕过ifconfig 和 cat /sys/class/net/wlan0/address 所有我这边是直接修改mac地址,通过执行命名 ifconfig wlan0 hw ether $Mac ,修改后三种方法都起作用,不知道可有第四种通过反射的方式获取mac。但是此方法必须由root权限才行。如果手机userdebug 或者eng 就可以随便修改。如果想在代码中就可以动态修改,需要修改开机脚本。具体细节不列出了。修改 SN

public static String getSerial() {
            boolean flag =SystemProperties.getBoolean("persist.sys.keep.mprop",false);
                if(flag){
                返回我的sn
             }
                }else{
                IDeviceIdentifiersPolicyService service = IDeviceIdentifiersPolicyService.Stub
                        .asInterface(ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE));
                try {
                    return service.getSerial();
                } catch (RemoteException e) {
                    e.rethrowFromSystemServer();
                }
                }
        return UNKNOWN;
    }

以上修改都通过我测试app 验证过。完全可以支持动态修改, 对于动态修改屏幕分辨率和密度 、sensor类型及名字 和 apk 列表都已经完成。只是个人感觉没啥作用我的这些 很方便的移植到Lineage OS 上,可以支持多款手机 。