編寫Xposed模塊
了解完Xposed框架的相關(guān)知識后,我們還要編寫一些模塊代碼梗摇,才能實現(xiàn)我們的監(jiān)測操作。
首先在gradle里面依賴一下xposed的api:
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
在進(jìn)行Xposed模塊開發(fā)之前格遭,我們有必要了解一下Xposed API愚铡。完成一個模塊的開發(fā)至少有兩步要做:
1、編寫一個java類并實現(xiàn)**IXposedHookLoadPackage**接口幔摸,實現(xiàn)**handleLoadPackage**方法進(jìn)行自定義的監(jiān)測操作
2摸柄、注冊這個java類
編寫代碼
假如我們需要監(jiān)測的方法是:
[圖片上傳失敗...(image-819ac2-1696475692002)]
那么,我們的初始方法就可以寫成這個樣子:
public class HookTrack implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
}
}
在handleLoadPackage中既忆,調(diào)用XposedHelpers類的findMethodHook來進(jìn)行驱负,在寫代碼的時候,我們發(fā)現(xiàn)其實有兩個方式可以選用:
[圖片上傳失敗...(image-219c78-1696475692002)]
區(qū)別在于第一個方法傳入的是class本體患雇,然后源碼那邊使用的classLoader就是class.getClassLoader;第二種不需要class本體跃脊,只需要指定這個class的名字,然后再指定加載這個class的classLoader苛吱。從便捷上來說酪术,第一種無疑是便捷的。但是第二種的靈活度比第一種高翠储。假如有一些類是第三方SDK里面的绘雁,而這個SDK沒在你源碼里面橡疼,是以插件形式在你app安裝完后才加進(jìn)來的。這時候咧七,你在編碼階段是沒有辦法得到這個class本體的衰齐,所以第二種方法可以看作是能hook運(yùn)行時的class,并且官方注釋還給出了第二種的使用模式:
[圖片上傳失敗...(image-c3e6d8-1696475692002)]
因此继阻,按照官方提供的思路耻涛,我們可以這樣寫:
XposedHelpers.findAndHookMethod(
android.telephony.TelephonyManager.class.getName(),
lpparam.classLoader,
"getDeviceId",
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getDeviceId()獲取了imei");
}
}
);
注意到我們最后的那個回調(diào)函數(shù)XC_methodHook,
[圖片上傳失敗...(image-4ef009-1696475692002)]
首先,這是一個抽象類瘟檩,不是接口抹缕。beforeHookMethod和afterHookMethod從字面意思也能看出是在hook前后的調(diào)用回調(diào)。然后其構(gòu)造函數(shù)有兩個墨辛,有一個是帶int類型的卓研,傳入的是一個設(shè)置hook優(yōu)先級的數(shù)字。
[圖片上傳失敗...(image-7e38fd-1696475692002)]
從方法注釋上看睹簇,這個priority會影響后面beforeHookMethod和afterHookMethod的調(diào)用順序奏赘。優(yōu)先級越高的Hook,其beforeHook方法會越先執(zhí)行,然后其afterHook方法會在最后執(zhí)行太惠。如果存在hook多個方法磨淌,且所有的priority都相同,會依次此執(zhí)行完這個方法的before和after在執(zhí)行下一個方法的before和after凿渊,以此類推梁只。
而采用無參構(gòu)造的,其priority是一個系統(tǒng)默認(rèn)值50:
[圖片上傳失敗...(image-1a4b70-1696475692002)]
假如我們Hook了3個方法A,B,C埃脏。在priority相同和不同時的調(diào)用關(guān)系可以參考下圖:
[圖片上傳失敗...(image-1d1204-1696475692002)]
知道了上面的原理后搪锣,我們就應(yīng)該選用默認(rèn)或者相同priority的方式來進(jìn)行hook。
扯了這么多彩掐,大家也別嫌麻煩构舟,工欲善其事,必先利其器《掠模現(xiàn)在再回到之前的代碼旁壮。我們在beforeHookMethod里面調(diào)用了
XposedBridge.log(lpparam.packageName + "調(diào)用getDeviceId()獲取了imei");
XposedBridge也是rovo89開發(fā)的一個Xposed的輔助庫,調(diào)用其log方法后可以在手機(jī)端的Xposed管理器里面顯示相關(guān)信息谐檀,這一步的意思表示我們監(jiān)測了app調(diào)用android.telephony.TelephonyManager這個類的getDeviceId方法
打印方法調(diào)用棧
上面的所有操作知識標(biāo)記了調(diào)沒調(diào)用指定的方法抡谐。但是如果調(diào)用了,是誰調(diào)用的桐猬,其實我們時不清楚的麦撵。這樣其實不利于我們查找問題的根源。回看本文的第一張信通院的圖免胃,發(fā)現(xiàn)他們檢測時音五,其實給了方法調(diào)用棧。那么我們現(xiàn)在就來模擬一下這種操作羔沙。
我們需要打印的是整個hook期間的方法棧躺涝,那么這個操作就應(yīng)該放在afterHookMethod里面,于是扼雏,我們可以寫成這樣:
XposedHelpers.findAndHookMethod(
android.telephony.TelephonyManager.class.getName(),
lpparam.classLoader,
"getDeviceId",
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getDeviceId()獲取了imei");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//在這里寫調(diào)用方法棧過程
}
}
);
日志打印的話自然還是用到XposedBridge的log方法坚嗜。由于我們需要hook的方法不止一個,而我們打印方法調(diào)用棧又是一樣的操作诗充,于是乎我們可以自己寫一個抽象類繼承XC_MethodHook,只實現(xiàn)afterMethodHook方法苍蔬,在里面做統(tǒng)一的方法棧追蹤操作。因此蝴蜓,我們先自定義一個DumpMethodHook的類碟绑,代碼如下:
public abstract class DumpMethodHook extends XC_MethodHook {
/**
* 該方法會在Hook了指定方法后調(diào)用
* @param param
*/
@Override
protected void afterHookedMethod(MethodHookParam param) {
//在這里,我們dump一下調(diào)用的方法棧信息
dump2();
}
/**
* dump模式一:根據(jù)線程進(jìn)行過濾
*/
private static void dump() {
for (Map.Entry<Thread, StackTraceElement[]> stackTrace : Thread.getAllStackTraces().entrySet()) {
Thread thread = (Thread) stackTrace.getKey();
StackTraceElement[] stack = (StackTraceElement[]) stackTrace.getValue();
// 進(jìn)行過濾
if (thread.equals(Thread.currentThread())) {
continue;
}
XposedBridge.log("[Dump Stack]" + "**********線程名字:" + thread.getName() + "**********");
int index = 0;
for (StackTraceElement stackTraceElement : stack) {
XposedBridge.log("[Dump Stack]" + index + ": " + stackTraceElement.getClassName()
+ "----" + stackTraceElement.getFileName()
+ "----" + stackTraceElement.getLineNumber()
+ "----" + stackTraceElement.getMethodName());
}
// 增加序列號
index++;
}
XposedBridge.log("[Dump Stack]" + "********************* over **********************");
}
/**
* dump模式2:類信通院報告模式
*/
private static void dump2(){
XposedBridge.log("Dump Stack: "+"---------------start----------------");
Throwable ex = new Throwable();
StackTraceElement[] stackElements = ex.getStackTrace();
if (stackElements != null) {
for (int i= 0; i < stackElements.length; i++) {
StringBuilder sb=new StringBuilder("[方法棧調(diào)用]");
sb.append(i);
XposedBridge.log("[Dump Stack]"+i+": "+ stackElements[i].getClassName()
+"----"+stackElements[i].getFileName()
+"----" + stackElements[i].getLineNumber()
+"----" +stackElements[i].getMethodName());
}
}
XposedBridge.log("Dump Stack: "+ "---------------over----------------");
}
}
通過查詢資料茎匠,我寫了兩種方法棧打印的操作格仲。第一種打印得比較細(xì)一些,但是實際測試要卡頓一點(diǎn)诵冒。第二種就和信通院報告差不多了凯肋,而且沒有明顯卡頓。
寫好了自定義的回調(diào)造烁,這時我們只需要將前面的XC_MethodHook替換為DumpMethodHook即可:
XposedHelpers.findAndHookMethod(
android.telephony.TelephonyManager.class.getName(),
lpparam.classLoader,
"getDeviceId",
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getDeviceId()獲取了imei");
}
}
);
需要監(jiān)測的方法
既然合規(guī)這件事情是工信部搞出來的否过,那么我們自然要看一下當(dāng)時的這份紅頭文件——工信部信管函「164號文」
下面是我目前整理出來的需要hook的一些方法:
方法名字 | 所屬包名 | 作用 |
---|---|---|
getDeviceId | android.telephony.TelephonyManager | 獲取設(shè)備號 |
getDeviceId(int) | android.telephony.TelephonyManager | getDeviceId的帶參版本 |
getImei | android.telephony.TelephonyManager | 安卓8增加的獲取IMEI的方法 |
getImei(int) | android.telephony.TelephonyManager | getImei的帶參版本 |
getSubscriberId | android.telephony.TelephonyManager | 獲取IMSI |
getMacAddress | android.net.wifi.WifiInfo | 獲取MAC地址 |
getHardwareAddress | java.net.NetworkInterface | 獲取MAC地址 |
getString | android.provider.Settings.Secure | 獲取系統(tǒng)相關(guān)信息字符來拼接deviceId |
getLastKnownLocation | LocationManager | 獲取GPS定位信息 |
requestLocationUpdates | LocationManager | 位置午笛、時間發(fā)生改變的時候獲取定位信息 |
上面的方法信息可能不全惭蟋,如果大家有更好的意見可以留言。我看網(wǎng)上很多資料是沒有對requestLocationUpdates和安卓8的新增方法getImei進(jìn)行監(jiān)控的药磺,這里我加了進(jìn)來告组。
對Hook的APP進(jìn)行過濾,設(shè)置白名單
一般來講癌佩,你的手機(jī)安裝的不止一個app木缝。如果用上面的代碼去監(jiān)測,實際會監(jiān)測你手機(jī)上所有的app围辙。這就導(dǎo)致日志會很雜亂我碟,我們其實只關(guān)心指定的app。因此我們需要設(shè)置一個白名單進(jìn)行過濾:
/**
* 需要Hook的包名白名單
*/
private static final String[] whiteList = {
"com.cjs.drv",
"com.cjs.hegui30.demo"
};
里面填寫的就是你需要監(jiān)測的app的包名姚建。
然后我們在HandleLoadPackage方法的最開始矫俺,寫一段過濾的操作:
/*判斷hook的包名*/
boolean res = false;
for (String pkgName : whiteList) {
if (pkgName.equals(lpparam.packageName)) {
res = true;
break;
}
}
if (!res) {
Log.e(TAG, "不符合的包:" + lpparam.packageName);
return;
}
最終,貼上一個成品的代碼:
public class HookTrack implements IXposedHookLoadPackage {
private static final String TAG = "HookTrack";
/**
* 需要Hook的包名白名單
*/
private static final String[] whiteList = {
"com.cjs.drv",
"com.bw30.zsch",
"com.bw30.zsch.magic",
"com.cjs.hegui30.demo"
};
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
if (lpparam == null) {
return;
}
Log.e(TAG, "開始加載package:" + lpparam.packageName);
/*判斷hook的包名*/
boolean res = false;
for (String pkgName : whiteList) {
if (pkgName.equals(lpparam.packageName)) {
res = true;
break;
}
}
if (!res) {
Log.e(TAG, "不符合的包:" + lpparam.packageName);
return;
}
//固定格式
XposedHelpers.findAndHookMethod(
android.telephony.TelephonyManager.class.getName(), // 需要hook的方法所在類的完整類名
lpparam.classLoader, // 類加載器,固定這么寫就行了
"getDeviceId", // 需要hook的方法名
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getDeviceId()獲取了imei");
}
}
);
XposedHelpers.findAndHookMethod(
android.telephony.TelephonyManager.class.getName(),
lpparam.classLoader,
"getDeviceId",
int.class,
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getDeviceId(int)獲取了imei");
}
}
);
XposedHelpers.findAndHookMethod(
android.telephony.TelephonyManager.class.getName(),
lpparam.classLoader,
"getSubscriberId",
int.class,
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getSubscriberId獲取了imsi");
}
}
);
XposedHelpers.findAndHookMethod(
android.telephony.TelephonyManager.class.getName(),
lpparam.classLoader,
"getImei",
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getImei獲取了imei");
}
}
);
XposedHelpers.findAndHookMethod(
android.telephony.TelephonyManager.class.getName(),
lpparam.classLoader,
"getImei",
int.class,
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getImei(int)獲取了imei");
}
}
);
XposedHelpers.findAndHookMethod(
android.net.wifi.WifiInfo.class.getName(),
lpparam.classLoader,
"getMacAddress",
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getMacAddress()獲取了mac地址");
}
}
);
XposedHelpers.findAndHookMethod(
java.net.NetworkInterface.class.getName(),
lpparam.classLoader,
"getHardwareAddress",
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getHardwareAddress()獲取了mac地址");
}
}
);
XposedHelpers.findAndHookMethod(
android.provider.Settings.Secure.class.getName(),
lpparam.classLoader,
"getString",
ContentResolver.class,
String.class,
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用Settings.Secure.getstring獲取了" + param.args[1]);
}
}
);
XposedHelpers.findAndHookMethod(
LocationManager.class.getName(),
lpparam.classLoader,
"getLastKnownLocation",
String.class,
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用getLastKnownLocation獲取了GPS地址");
}
}
);
XposedHelpers.findAndHookMethod(
LocationManager.class.getName(),
lpparam.classLoader,
"requestLocationUpdates",
String.class,
new DumpMethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log(lpparam.packageName + "調(diào)用requestLocationUpdates獲取了GPS地址");
}
}
);
}
}
注冊模塊代碼
上面的操作到目前為止也只是在你的安卓項目中添加了一個java類厘托。如何讓xposed識別到我們寫的代碼是個xposed模塊呢友雳?這就需要注冊一下這個類。
注冊分兩步操作:
1铅匹、在AndroidManifest.xml中編寫meta信息
<!-- 標(biāo)志該 apk 為一個 Xposed 模塊押赊,供 Xposed 框架識別-->
<meta-data
android:name="xposedmodule"
android:value="true" />
<!--模塊說明,一般為模塊的功能描述-->
<meta-data
android:name="xposeddescription"
android:value="這個模塊是用來檢測用戶隱私合規(guī)的包斑,在用戶未授權(quán)同意前流礁,調(diào)用接口獲取信息屬于違規(guī)" />
<!--模塊兼容版本-->
<meta-data
android:name="xposedminversion"
android:value="54" />
在application節(jié)點(diǎn)里面加上這三個meta信息。那個說明會最終顯示在xposed管理器上面:
[圖片上傳失敗...(image-beb013-1696475692002)]
注意:填寫meta信息是標(biāo)記我們這個apk是個xposed模塊的關(guān)鍵舰始,否則xposed installer不會識別崇棠。
2、在項目asset文件夾下面新建xposed_init文件
[圖片上傳失敗...(image-d81e84-1696475692002)]
在里面寫上我們實現(xiàn)IXposedHookLoadPackage那個類的包名+類名
com.cjs.hegui30.HookTrack
這樣我們就寫好了自定義的xposed模塊丸卷。Xposed在加載的時候會從這個文件里面讀取需要初始化的類枕稀。
至此,我們的所有代碼就編寫完成了谜嫉,此時裝在手機(jī)后萎坷,可以在xposed installer里面識別激活了。
其他
源碼同時捆綁了一個快速測試的demo和相關(guān)的apk文件沐兰,demo可以單獨(dú)編譯成apk,記得切換
[圖片上傳失敗...(image-9f72eb-1696475692002)]
[圖片上傳失敗...(image-dae7f9-1696475692002)]
操作手冊
一哆档、準(zhǔn)備條件
1、編譯合規(guī)檢測的Xposed模塊源碼
下載源碼住闯,修改設(shè)置白名單瓜浸,編譯成apk,安裝到手機(jī)
相關(guān)操作參考《安卓端自行實現(xiàn)工信部要求的隱私合規(guī)檢測一(教你手寫Xposed模塊代碼)》
注意:源碼里面包含了各種安裝包及demo
2比原、已經(jīng)root的手機(jī)可以下載Xposed.apk
Xposed在github上面開源插佛,可以自己下載XposedInstaller的源碼進(jìn)行編譯,也可以直接下載已經(jīng)編譯好的apk量窘。
需要注意的是雇寇,安卓5以上和以下的安裝版本是不一樣的
支持安卓5及以上的XposedInstaller
支持安卓5以下的XposedInstaller
3、沒有root的手機(jī)可以下載VirtualXposed.apk
VirtualXposed在github上面有專門的release頁面蚌铜,其作者在0.20.x的版本的時候放棄了對32位應(yīng)用的支持锨侯,理由是谷歌商店未來只允許64位的app上架,不想花更多精力維護(hù)32位的開發(fā)冬殃。如果你的app為32位應(yīng)用囚痴,因此不能用0.20.x及之后版本的VirtualXposed
0.20.3版本(支持64位應(yīng)用)
0.18.2版本(支持32位應(yīng)用)
注意:由于0.20.x版本更換了包名,所以它和0.18.x的版本能同時安裝
4审葬、下載合規(guī)檢測測試程序
該項非必須深滚,僅作為合規(guī)快速校驗
下載地址:合規(guī)檢測測試程序apk
二骂束、具體操作
這里以對“合規(guī)檢測測試程序“的校驗進(jìn)行說明。
1展箱、安裝
- 已root的用戶
1. 安裝xposed.apk
在root手機(jī)上安裝xposed框架的操作可能會比較麻煩混驰,詳情問問度娘
2. 安裝合規(guī)檢測xposed模塊.apk
3. 安裝合規(guī)檢測測試程序.apk
- 未root用戶
1. 先安裝virtual-xposed.apk
2. 后續(xù)操作有兩種方案:
第一種可以和已root用戶一樣,直接將合規(guī)檢測xposed模塊.apk和合規(guī)檢測測試程序.apk安裝在手機(jī)真機(jī)上栖榨,然后在virtual-xposed里面克隆這兩個app;
第二種的話就是不在真機(jī)裝明刷,直接在virtual-xposed里面裝婴栽,具體操作如下:
打開virtual-xposed,點(diǎn)擊底部的菜單按鈕轰枝,進(jìn)入到virtual-xposed的菜單界面
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715095447417.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖1" align=center />
</div>在菜單界面有兩個關(guān)鍵點(diǎn)需要注意鞍陨,一個是頂部的添加應(yīng)用,一個是底部的重啟寿烟。后者在激活模塊的時候需要使用韧衣。這里我們先點(diǎn)擊添加應(yīng)用氏淑。
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715100616238.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖2" align=center />
</div>添加應(yīng)用界面默認(rèn)的tab項就是克隆APP,如果使用克隆的方式的話缭贡,就要先找到安裝的合規(guī)檢測xposed模塊和合規(guī)檢測測試程序谍失,并勾選快鱼,然后選擇底部的安裝;如果選擇的是虛擬機(jī)安裝窃判,就直接點(diǎn)擊右下角的加號按鈕袄琳,選擇本地的apk安裝包進(jìn)行安裝。
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715101257676.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖3" align=center />
</div>在克隆APP中窗轩,會彈出是否使用太極安裝,我們還是選擇virtual-xposed安裝
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715101819206.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖4" align=center />
</div>安裝完app后堤舒,下一步就是激活模塊。我們返回到1中的界面国撵,上滑,進(jìn)入到app列表界面环础,在這里可以看見我們剛剛安裝的3個app
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715102701144.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖5" align=center />
</div>最右邊的那邊Xposed Installer就是我們的xposed控制界面 饶唤,點(diǎn)擊進(jìn)入搬素。大大的綠勾表示我們的xposed框架已經(jīng)激活。點(diǎn)擊左上角三杠粱哼。
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715102939132.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖6" align=center />
</div>在彈出來的菜單界面中有兩個項要注意:模塊用于安裝/卸載xposed模塊,日志用于查看合規(guī)檢測的結(jié)果绊含,后面會用到。這里我們點(diǎn)擊模塊充甚。
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715103119338.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖7" align=center />
</div>可以看見有一個合規(guī)檢測的xposed模塊,勾上它技矮。勾上后需要重啟系統(tǒng)。如果是root用戶在真機(jī)下操作xposed框架耿币,就需要真機(jī)重啟。但是我們用的是virtual-xposed塑悼,所以只需要重啟虛擬機(jī)就行了厢蒜。這時候,返回到2的界面巷屿,點(diǎn)擊重啟。
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715103340219.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖8" align=center />
</div>重啟成功的話,底部會有提示語展示
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715103551253.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖9-1" align=center />
<img src="https://img-blog.csdnimg.cn/20210715103629292.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖9-2" align=center />
</div>
2问拘、如何檢測
- 先打開我們安裝的測試app
里面有四個按鈕,分別對應(yīng)四種不同的檢測條件或油,我們以第一種模擬獲取IMSI來說明,先別點(diǎn)擊任何按鈕辖佣。
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715103931453.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖10" align=center />
</div>
- 查看日志
回到我們在安裝講解中的第7步界面,里面有個日志選項端逼,點(diǎn)擊它顶滩。該界面右上角有保存按鈕,還有個三個點(diǎn)的菜單按鈕仅醇,點(diǎn)擊菜單按鈕后有兩個項需要注意:
- 立即清理日志會清空當(dāng)前界面的所有日志,我們先點(diǎn)擊清空一下甲抖。
- 重新載入會刷新最新的日志進(jìn)界面。因為日志的顯示不是自動的柱衔,要想看到最新的結(jié)果,就要手動刷新艾岂。
<div align="center">
<img src="https://img-blog.csdnimg.cn/20210715104617934.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖11-1" align=center />
<img src="https://img-blog.csdnimg.cn/20210715104640552.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NqczE1MzQ3MTcwNDA=,size_16,color_FFFFFF,t_70" width = "300" alt="圖11-2" align=center />
</div>
接下來回到我們的測試app界面梅猿,點(diǎn)擊模擬獲取IMSI钞啸,然后再返回到日志界面体斩,并且重新載入哨毁,接著就能看見如下的日志記錄:
[圖片上傳失敗...(image-19438-1696475692002)]
上面的截圖主要針對virtual-xposed來講的想幻。對于xposed而言脏毯,操作大同小異渣淤。最大的區(qū)別就是xposed需要真實地重啟手機(jī),這點(diǎn)的話要麻煩一點(diǎn)。