本篇文章讲解如果真正修改手机硬件参数。
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 上,可以支持多款手机
。 有兴趣的可以联系我一起研究,如果还有其他修改可以留言