日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

攻防:如何防止动态hook绕过jni签名校验

發(fā)布時間:2024/4/15 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 攻防:如何防止动态hook绕过jni签名校验 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

我們知道jni校驗簽名也不可靠,可以被動態(tài)hook繞過。代碼如下:

class HookSignHandler(var base : Any) : InvocationHandler {companion object{internal var signature = "xxx"fun hook(context: Context){try{var activityThreadClass = Class.forName("android.app.ActivityThread")var currentActicityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread")var currentActivityThread = currentActicityThreadMethod.invoke(null)var sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager")sPackageManagerField.isAccessible = true;var sPackageManager = sPackageManagerField.get(currentActivityThread)var iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager")var proxy = Proxy.newProxyInstance(iPackageManagerInterface.classLoader, arrayOf(iPackageManagerInterface), HookSignHandler(sPackageManager))sPackageManagerField.set(currentActivityThread, proxy)var pm = context.packageManagervar mPMField = pm.javaClass.getDeclaredField("mPM")mPMField.isAccessible = truemPMField.set(pm, proxy)}catch (e : Exception){Log.e("hook", "hook", e)}}}override fun invoke(proxy: Any?, method: Method, args: Array<out Any>): Any {if("getPackageInfo".equals(method.name)){var flag = args[1] as Intif(flag == PackageManager.GET_SIGNATURES){var sign = Signature(signature)var info = method.invoke(base, *args) as PackageInfoinfo.signatures[0] = signreturn info}}return method.invoke(base, *args)}}

只要得到了簽名的signature,并且在application中添加

HookSignHandler.Companion.hook(this);

這時無論java層還是jni層,當(dāng)獲取getPackageManager()時,它的mPM都是已經(jīng)被代理的對象,這樣當(dāng)執(zhí)行g(shù)etPackageInfo()函數(shù)(實際上是執(zhí)行mPM的對應(yīng)函數(shù))就會返回設(shè)置好的signature,而不是當(dāng)前app的簽名,這樣就繞過了。

那么怎么防止這種手段?
那就是每次使用getPackageManager()時都檢查一下它是否被代理。代碼如下:

try {Field mPM = getPackageManager().getClass().getDeclaredField("mPM");mPM.setAccessible(true);if(Proxy.isProxyClass(mPM.get(getPackageManager()).getClass())){Toast.makeText(this, "hook!!", Toast.LENGTH_LONG).show();} } catch (Exception e) {e.printStackTrace(); }

Proxy本身提供了一個函數(shù)isProxyClass來檢查當(dāng)前對象的類是否是代理類。

我們將mPM對象獲取到,用isProxyClass驗證它的class即可。

那么這個這就涉及到了動態(tài)代理proxy的原理了。

動態(tài)代理

首先,動態(tài)代理一定需要一個接口,就是說代理的類必須實現(xiàn)某個接口,否則無法代理該類。比如上面的mPM就是實現(xiàn)接口android.content.pm.IPackageManager

這是為什么?這也與動態(tài)代理的原理有關(guān)。

簡單來說,當(dāng)我們設(shè)置動態(tài)代理后,實際上會自動生成一個類

public final class $Proxy0 extends Proxy implements XXXXX {public $Proxy0(InvocationHandler paramInvocationHandler) throws {super(paramInvocationHandler);}... }

這樣就一下子清晰了,因為實現(xiàn)了同一個接口,所以可以設(shè)置給原對象而不產(chǎn)生問題。

但是它又繼承了Proxy類,而且可以看到構(gòu)造函數(shù)中將之前創(chuàng)建的InvocationHandler也傳進來了,這樣就可以調(diào)用到原對象的函數(shù)了。

它的詳細代碼就不展示和一一解釋了,簡單來說就是它實現(xiàn)了接口,在每個函數(shù)中再去執(zhí)行InvocationHandler的invoke,就實現(xiàn)了代理。

這也是為什么動態(tài)代理一定需要一個接口的原因。

Proxy.newProxyInstance()函數(shù)就是創(chuàng)建一個$Proxy0這個類的對象,然后設(shè)置給原對象,就代理上了。

那么isProxyClass的原理就清晰了,我們只要知道這個對象是不是繼承Proxy即可。代碼:

public static boolean isProxyClass(Class<?> cl) {return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl); }

可以看到使用了isAssignableFrom,那么再來說一說這個函數(shù)。

isAssignableFrom和instanceof

這兩個作用類似,從例子上看:B extends A

A.class.isAssignableFrom(B.class); 表示A是B的父類,注意兩邊都是Class

b instanceOf A 判斷A是否是b對象的類。這里b是B類的對象。A是B的父類,所以也一樣是b對象的類

關(guān)注公眾號:BennuCTech,發(fā)送“HookSignHandler”獲取完整源碼

總結(jié)

以上是生活随笔為你收集整理的攻防:如何防止动态hook绕过jni签名校验的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。