利用Frida修改Android设备的唯一标识符

Android设备的唯一标识符

1.IMEI (手机的身份证号码)

IMEI(International Mobile Equipment Identity)是国际移动设备身份码的缩写,国际移动装备辨识码,是由15位数字组成的”电子串号”,它与每台移动电话机一一对应,而且该码是全世界唯一的。每一只移动电话机在组装完成后都将被赋予一个全球唯一的一组号码,这个号码从生产到交付使用都将被制造生产的厂商所记录。

有些设备的IMEI有两个,可以在拨号键盘输入“*#06#”查看。普通APP获取需要申请权限():

1
2
3
4
//权限 <uses-permissionandroid:name="android.permission.READ_PHONE_STATE" />
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
//获取IMEI号
String imei = telephonyManager.getDeviceId();

2.IMSI (SIM卡的身份证号码)

IMSI是区别移动用户的标志,储存在SIM卡中,可用于区别移动用户的有效信息。其总长度不超过15位,同样使用0~9的数字,例如460010280100023。其中MCC是移动用户所属国家代号,占3位数字,中国的MCC规定为460;MNC是移动网号码,最多由两位数字组成,用于识别移动用户所归属的移动通信网;MSIN是移动用户识别码,用以识别某一移动通信网中的移动用户,

IMSI与IMEI权限相同,获取代码:

1
2
3
4
//权限 <uses-permissionandroid:name="android.permission.READ_PHONE_STATE" />
TelephonyManager telephonyManager=(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
//获取IMSI号
String imsi=telephonyManager.getSubscriberId();

3.ANDROID_ID

ANDROID_ID 是一串64位的数字,并以16进制字符串的形式保存下来,是设备首次启动时随机生成的设备的第一个引导,其记录着一个固定值,通过它可以知道设备的寿命。ANDROID_ID也可视为作为唯一设备标识号的一个好选择,当设备没有手机号时,例如平板设备等,可以采用ANDROID_ID作为标识。
需要注意:

  • android_id在设备恢复出厂设置后,该值会改变
  • 部分定制手机获取到的android_id为null
  • 由于定制问题,不同的设备可能会产生相同的ANDROID_ID
  • Android 8.0后不同应用获得的值不同
    应用签署密钥、用户和设备的每个组合都具有唯一的 ANDROID_ID 值。因此,在相同设备上运行但具有不同签署密钥的应用将不会再看到相同的 Android ID(即使对于同一用户来说,也是如此)参考https://developer.android.com/about/versions/oreo/android-8.0-changes?hl=zh-cn

android_id获取方式:

1
2
import android.provider.Settings; 
String ANDROID_ID =Settings.System.getString(getContentResolver(),Settings.System.ANDROID_ID);

4.设备序列号(Serial Number 或 SN)

SN码是Serial Number的缩写,有时也叫SerialNo,也就是产品序列号,产品序列是为了验证“产品的合法身份”而引入的一个概念,它是用来保障用户的正版权益,享受合法服务的;一套正版的产品只对应一组产品序列号。别称:机器码、认证码、注册申请码等。

获取方式:

  • 1.adb shell

    1
    adb shell getprop ro.serialno
  • 2.android.os.Build

    1
    String SerialNumber = android.os.Build.SERIAL;
  • 3.android.os.SystemProperties.get
    此API为hidden API,需要反射获取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ClassLoader cl = context.getClassLoader();
    Class SystemProperties = cl.loadClass("android.os.SystemProperties");

    //参数类型
    Class[] paramTypes= new Class[2];
    paramTypes[0]= String.class;
    paramTypes[1]= String.class;

    Method get = SystemProperties.getMethod("get", paramTypes);

    //参数
    Object[] params= new Object[2];
    params[0]= new String(key);
    params[1]= new String(def);

    ret= (String) get.invoke(SystemProperties, params);

除了SN号,还有制造商、品牌、型号、设备名等其他信息和SN的获取方式相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
android.os.Build.BRAND:获取设备品牌
android.os.Build.MODEL :获取手机的型号 设备名称。
android.os.Build.MANUFACTURER:获取设备制造商
android.os.Build.BOARD:获取设备基板名称
android.os.Build.BOOTLOADER:获取设备引导程序版本号
android.os.Build.CPU_ABI:获取设备指令集名称(CPU的类型)
android.os.Build.CPU_ABI2:获取第二个指令集名称
android.os.Build.DEVICE:获取设备驱动名称
android.os.Build.DISPLAY:获取设备显示的版本包(在系统设置中显示为版本号)和ID一样
android.os.Build.FINGERPRINT:设备的唯一标识。由设备的多个信息拼接合成。
android.os.Build.HARDWARE:设备硬件名称,一般和基板名称一样(BOARD)
android.os.Build.HOST:设备主机地址
android.os.Build.ID:设备版本号。
android:os.Build.PRODUCT:整个产品的名称
android:os.Build.RADIO:无线电固件版本号,通常是不可用的 显示unknown
android.os.Build.TAGS:设备标签。如release-keys 或测试的 test-keys
android.os.Build.TIME:时间
android.os.Build.TYPE:设备版本类型 主要为"user" 或"eng".
android.os.Build.USER:设备用户名 基本上都为android-build
android.os.Build.VERSION.RELEASE:获取系统版本字符串。如4.1.2 或2.2 或2.3等
android.os.Build.VERSION.CODENAME:设备当前的系统开发代号,一般使用REL代替
android.os.Build.VERSION.INCREMENTAL:系统源代码控制值,一个数字或者git hash值
android.os.Build.VERSION.SDK:系统的API级别 一般使用下面大的SDK_INT 来查看
android.os.Build.VERSION.SDK_INT:系统的API级别 数字表示

5.MAC地址

1
2
android.net.wifi.WifiManager wifi = (android.net.wifi.WifiManager) context.getSystemService(Context.WIFI_SERVICE);
String macAddress = wifi.getConnectionInfo().getMacAddress();
  • 没有 WiFi 硬件或者 WiFi 不可用的设备可能返回 null 或空
  • Android 6.0开始,谷歌为保护用户数据,用此方法获取到的 Wi-Fi mac 地址都为02:00:00:00:00:00
  • 需要 ACCESS_WIFI_STATE 权限

Frida hook代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
Java.perform(function() {
var TelephonyManager = Java.use("android.telephony.TelephonyManager");

//IMEI hook
TelephonyManager.getDeviceId.overload().implementation = function () {
console.log("[*]Called - getDeviceId()");
var temp = this.getDeviceId();
console.log("real IMEI: "+temp);
return "867979021642856";
};
// muti IMEI
TelephonyManager.getDeviceId.overload('int').implementation = function (p) {
console.log("[*]Called - getDeviceId(int) param is"+p);
var temp = this.getDeviceId(p);
console.log("real IMEI "+p+": "+temp);
return "867979021642856";
};


//IMSI hook
TelephonyManager.getSimSerialNumber.overload().implementation = function () {
console.log("[*]Called - getSimSerialNumber(String)");
var temp = this.getSimSerialNumber();
console.log("real IMSI: "+temp);
return "123456789";
};
//////////////////////////////////////


//ANDOID_ID hook
var Secure = Java.use("android.provider.Settings$Secure");
Secure.getString.implementation = function (p1,p2) {
if(p2.indexOf("android_id")<0) return this.getString(p1,p2);
console.log("[*]Called - get android_ID, param is:"+p2);
var temp = this.getString(p1,p2);
console.log("real Android_ID: "+temp);
return "844de23bfcf93801";

}


//android的hidden API,需要通过反射调用
var SP = Java.use("android.os.SystemProperties");
SP.get.overload('java.lang.String').implementation = function (p1) {
var tmp = this.get(p1);
console.log("[*]"+p1+" : "+tmp);

return tmp;
}
SP.get.overload('java.lang.String', 'java.lang.String').implementation = function (p1,p2) {


var tmp = this.get(p1,p2)
console.log("[*]"+p1+","+p2+" : "+tmp);
return tmp;
}
// hook MAC
var wifi = Java.use("android.net.wifi.WifiInfo");
wifi.getMacAddress.implementation = function () {
var tmp = this.getMacAddress();
console.log("[*]real MAC: "+tmp);
return tmp;
}

})