Android 繞過(guò)反射黑名單的方法
限制原理
Google 從 Android P 開(kāi)始引入了針對(duì)非公開(kāi) API 的限制,這一點(diǎn)可以從 Native 相關(guān)的源碼中找到限制的原理,從而從中找到解決辦法,不過(guò)非必要原因不太建議去挑戰(zhàn)這種限制,畢竟不清楚在后續(xù)的版本中會(huì)不會(huì)做限制,維護(hù)起來(lái)挺麻煩的。
在 Native 層有幾個(gè)訪問(wèn)級(jí)別:
class HiddenApiAccessFlags {
public:
enum ApiList {
kWhitelist = 0,
kLightGreylist,
kDarkGreylist,
kBlacklist,
};
}
另外還有幾個(gè)對(duì)應(yīng)的響應(yīng)級(jí)別:
enum Action {
kAllow, //通過(guò)
kAllowButWarn, //通過(guò),但日志警告
kAllowButWarnAndToast, //通過(guò),且日志警告和彈窗
kDeny //拒絕訪問(wèn)
};
這里介紹一下網(wǎng)上的一些解決方式,此外,還可以把我們調(diào)用了反射方法的類的類加載器設(shè)置為系統(tǒng)類加載器,這樣就可以繞過(guò) Native 層的限制了。
系統(tǒng)類偽裝
黑名單在系統(tǒng)中有一個(gè) fn_caller_is_trusted 的條件:如果調(diào)用者是系統(tǒng)類,那么就允許被調(diào)用。即如果我們能以系統(tǒng)類的身份去反射,那么就能暢通無(wú)阻:
- 首先通過(guò)反射 API 拿到 getDeclaredMethod 方法。getDeclaredMethod 是 public 的,不存在問(wèn)題;這個(gè)通過(guò)反射拿到的方法網(wǎng)上稱之為元反射方法。
- 然后通過(guò)剛剛的元反射方法去反射調(diào)用 getDeclardMethod。這里我們就實(shí)現(xiàn)了以系統(tǒng)身份去反射的目的——反射相關(guān)的 API 都是系統(tǒng)類,因此我們的元反射方法也是被系統(tǒng)類加載的方法;所以我們的元反射方法調(diào)用的 getDeclardMethod 會(huì)被認(rèn)為是系統(tǒng)調(diào)用的,可以反射任意的方法。
偽代碼如下:
// 公開(kāi)API,無(wú)問(wèn)題
Method metaGetDeclaredMethod = Class.class.getDeclaredMethod("getDeclardMethod");
// 系統(tǒng)類通過(guò)反射使用隱藏 API,檢查直接通過(guò)。
Method hiddenMethod = metaGetDeclaredMethod.invoke(hiddenClass, "hiddenMethod", "hiddenMethod參數(shù)列表");
// 正確找到 Method 直接反射調(diào)用
hiddenMethod.invoke
豁免條件
隱藏 API 的調(diào)用有「豁免」條件,即只要它是豁免的,則即使它在黑名單中,也會(huì)被放行。這種方式暴露給了 Java 層,因此可以通過(guò) VMRuntime.setHiddenApiExemptions 方法來(lái)實(shí)現(xiàn)。再結(jié)合上面這個(gè)方法,我們只需要通過(guò) 「元反射」 來(lái)反射調(diào)用 VMRuntime.setHiddenApiExemptions 就能將我們自己要使用的隱藏 API 全部都豁免掉了。另外系統(tǒng)在檢查豁免時(shí)是通過(guò)方法簽名進(jìn)行前綴匹配的,而 Java 方法簽名都是 L 開(kāi)頭的,因此我們可以把直接傳個(gè) L 進(jìn)去,那么所有的隱藏API全部被赦免了!
源碼直接參考網(wǎng)上大佬的開(kāi)源項(xiàng)目: FreeReflection。
public final class BootstrapClass {
private static final String TAG = "BootstrapClass";
private static Object sVmRuntime;
private static Method setHiddenApiExemptions;
static {
if (SDK_INT >= Build.VERSION_CODES.P) {
try {
Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
sVmRuntime = getRuntime.invoke(null);
} catch (Throwable e) {
Log.w(TAG, "reflect bootstrap failed:", e);
}
}
}
/**
* make the method exempted from hidden API check.
*
* @param method the method signature prefix.
* @return true if success.
*/
public static boolean exempt(String method) {
return exempt(new String[]{method});
}
/**
* make specific methods exempted from hidden API check.
*
* @param methods the method signature prefix, such as "Ldalvik/system", "Landroid" or even "L"
* @return true if success
*/
public static boolean exempt(String... methods) {
if (sVmRuntime == null || setHiddenApiExemptions == null) {
return false;
}
try {
setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{methods});
return true;
} catch (Throwable e) {
return false;
}
}
/**
* Make all hidden API exempted.
*
* @return true if success.
*/
public static boolean exemptAll() {
return exempt(new String[]{"L"});
}
}
以上就是Android 繞過(guò)反射黑名單的方法的詳細(xì)內(nèi)容,更多關(guān)于Android 繞過(guò)反射黑名單的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot結(jié)合ProGuard實(shí)現(xiàn)代碼混淆(最新版)
- Retrofit和OkHttp如何實(shí)現(xiàn)Android網(wǎng)絡(luò)緩存
- Android Handler內(nèi)存泄漏原因及解決方案
- Android-SPI學(xué)習(xí)筆記
- 解決Android原生定位的坑
- Android如何讓APP無(wú)法在指定的系統(tǒng)版本上運(yùn)行(實(shí)現(xiàn)方法)
- Android Filterable實(shí)現(xiàn)Recyclerview篩選功能的示例代碼
- Android 一些常用的混淆Proguard
相關(guān)文章
Kotlin Service服務(wù)組件開(kāi)發(fā)詳解
這幾天分析了一下的啟動(dòng)過(guò)程,于是乎,今天寫一下Service使用; 給我的感覺(jué)是它并不復(fù)雜,千萬(wàn)不要被一坨一坨的代碼嚇住了,雖然彎彎繞繞不少,重載函數(shù)一個(gè)接著一個(gè),就向走迷宮一樣,但只要抓住主線閱讀,很快就能找到出口2022-12-12
Android自定義控件實(shí)現(xiàn)帶文本與數(shù)字的圓形進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)帶文本與數(shù)字的圓形進(jìn)度條,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Android BadgeView紅點(diǎn)更新信息提示示例代碼
本篇文章主要介紹了Android BadgeView紅點(diǎn)更新信息提示示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01
Kotlin實(shí)現(xiàn)半圓形進(jìn)度條的方法示例
這篇文章主要給大家介紹了關(guān)于Kotlin實(shí)現(xiàn)半圓形進(jìn)度條的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03
android獲取附近藍(lán)牙設(shè)備并計(jì)算距離的實(shí)例代碼
下面小編就為大家分享一篇android獲取附近藍(lán)牙設(shè)備并計(jì)算距離的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
Android利用繪制緩沖實(shí)現(xiàn)代碼雨效果
看過(guò)很多代碼雨的前端實(shí)現(xiàn),卻很少看到過(guò)Android代碼雨效果的實(shí)現(xiàn),當(dāng)然 open gl es的實(shí)現(xiàn)是有的,一個(gè)主要的原因是,在Android Canvas繪制時(shí),很少有人考慮使用繪制緩沖,所以本文將給大家介紹Android如何利用繪制緩沖實(shí)現(xiàn)代碼雨效果,需要的朋友可以參考下2024-03-03

