利用Frida修改Android裝置的唯一識別符號
Android裝置的唯一識別符號
1.IMEI (手機的身份證號碼)
IMEI(International Mobile Equipment Identity)是國際移動裝置身份碼的縮寫,國際移動裝備辨識碼,是由15位數字組成的”電子串號”,它與每臺行動電話機一一對應,而且該碼是全世界唯一的。每一隻行動電話機在組裝完成後都將被賦予一個全球唯一的一組號碼,這個號碼從生產到交付使用都將被製造生產的廠商所記錄。
有些裝置的IMEI有兩個,可以在撥號鍵盤輸入“*#06#”檢視。普通APP獲取需要申請許可權():
//許可權 <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許可權相同,獲取程式碼:
//許可權 <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獲取方式:
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
adb shell getprop ro.serialno
2.android.os.Build
String SerialNumber = android.os.Build.SERIAL;
3.android.os.SystemProperties.get
此API為hidden API,需要反射獲取
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的獲取方式相同
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地址
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程式碼
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;
}
})