成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

AndroidJava層的anti-hooking技巧是怎樣的

本篇文章給大家分享的是有關(guān)Android Java層的anti-hooking技巧是怎樣的,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

創(chuàng)新互聯(lián)公司專注于德城企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站設(shè)計(jì),商城網(wǎng)站建設(shè)。德城網(wǎng)站建設(shè)公司,為德城等地區(qū)提供建站服務(wù)。全流程按需定制開(kāi)發(fā),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)

0x00 前言

一個(gè)最近關(guān)于檢測(cè)native hook框架的方法讓我開(kāi)始思考一個(gè)Android應(yīng)用如何在Java層檢測(cè)Cydia  Substrate或者Xposed框架。

聲明:

下文所有的anti-hooking技巧很容易就可以被有經(jīng)驗(yàn)的逆向人員繞過(guò),這里只是展示幾個(gè)檢測(cè)的方法。在最近DexGuard和GuardIT等工具中還沒(méi)有這類anti-hooking檢測(cè)功能,不過(guò)我相信不久就會(huì)增加這個(gè)功能。

0x01 檢測(cè)安裝的應(yīng)用

一個(gè)最直接的想法就是檢測(cè)設(shè)備上有沒(méi)有安裝Substrate或者Xposed框架,可以直接調(diào)用PackageManager顯示所有安裝的應(yīng)用,然后看是否安裝了Substrate或者Xposed。

#!java

PackageManager packageManager = context.getPackageManager();

List applicationInfoList =  packageManager.getInstalledApplications(PackageManager.GET_META_DATA);

for(ApplicationInfo applicationInfo : applicationInfoList) {

if(applicationInfo.packageName.equals("de.robv.android.xposed.installer"))  {

Log.wtf("HookDetection", "Xposed found on the system.");

}

if(applicationInfo.packageName.equals("com.saurik.substrate")) {

Log.wtf("HookDetection", "Substrate found on the system.");

}

}

0x02 檢查調(diào)用棧里的可疑方法

另一個(gè)想到的方法是檢查Java調(diào)用棧里的可疑方法,主動(dòng)拋出一個(gè)異常,然后打印方法的調(diào)用棧。代碼如下:

#!java

public class DoStuff {

public static String getSecret() {

try {

throw new Exception("blah");

}

catch(Exception e) {

for(StackTraceElement stackTraceElement : e.getStackTrace()) {

Log.wtf("HookDetection", stackTraceElement.getClassName() + "->" +  stackTraceElement.getMethodName());

}

}

return "ChangeMePls!!!";

}

}

當(dāng)應(yīng)用沒(méi)有被hook的時(shí)候,正常的調(diào)用棧是這樣的:

#!bash

com.example.hookdetection.DoStuff->getSecret

com.example.hookdetection.MainActivity->onCreate

android.app.Activity->performCreate

android.app.Instrumentation->callActivityOnCreate

android.app.ActivityThread->performLaunchActivity

android.app.ActivityThread->handleLaunchActivity

android.app.ActivityThread->access$800

android.app.ActivityThread$H->handleMessage

android.os.Handler->dispatchMessage

android.os.Looper->loop

android.app.ActivityThread->main

java.lang.reflect.Method->invokeNative

java.lang.reflect.Method->invoke

com.android.internal.os.ZygoteInit$MethodAndArgsCaller->run

com.android.internal.os.ZygoteInit->main

dalvik.system.NativeStart->main

但是假如有Xposed框架hook了com.example.hookdetection.DoStuff.getSecret方法,那么調(diào)用棧會(huì)有2個(gè)變化:

在dalvik.system.NativeStart.main方法后出現(xiàn)de.robv.android.xposed.XposedBridge.main調(diào)用

如果Xposed  hook了調(diào)用棧里的一個(gè)方法,還會(huì)有de.robv.android.xposed.XposedBridge.handleHookedMethod  和de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative調(diào)用

所以如果hook了getSecret方法,調(diào)用棧就會(huì)如下:

#!bash

com.example.hookdetection.DoStuff->getSecret

de.robv.android.xposed.XposedBridge->invokeOriginalMethodNative

de.robv.android.xposed.XposedBridge->handleHookedMethod

com.example.hookdetection.DoStuff->getSecret

com.example.hookdetection.MainActivity->onCreate

android.app.Activity->performCreate

android.app.Instrumentation->callActivityOnCreate

android.app.ActivityThread->performLaunchActivity

android.app.ActivityThread->handleLaunchActivity

android.app.ActivityThread->access$800

android.app.ActivityThread$H->handleMessage

android.os.Handler->dispatchMessage

android.os.Looper->loop

android.app.ActivityThread->main

java.lang.reflect.Method->invokeNative

java.lang.reflect.Method->invoke

com.android.internal.os.ZygoteInit$MethodAndArgsCaller->run

com.android.internal.os.ZygoteInit->main

de.robv.android.xposed.XposedBridge->main

dalvik.system.NativeStart->main

下面看下Substrate hook  com.example.hookdetection.DoStuff.getSecret方法后,調(diào)用棧會(huì)有什么變化:

dalvik.system.NativeStart.main調(diào)用后會(huì)出現(xiàn)2次com.android.internal.os.ZygoteInit.main,而不是一次。

如果Substrate  hook了調(diào)用棧里的一個(gè)方法,還會(huì)出現(xiàn)com.saurik.substrate.MS$2.invoked,com.saurik.substrate.MS$MethodPointer.invoke還有跟Substrate擴(kuò)展相關(guān)的方法(這里是com.cigital.freak.Freak$1$1.invoked)。

所以如果hook了getSecret方法,調(diào)用棧就會(huì)如下:

#!bash

com.example.hookdetection.DoStuff->getSecret

com.saurik.substrate._MS$MethodPointer->invoke

com.saurik.substrate.MS$MethodPointer->invoke

com.cigital.freak.Freak$1$1->invoked

com.saurik.substrate.MS$2->invoked

com.example.hookdetection.DoStuff->getSecret

com.example.hookdetection.MainActivity->onCreate

android.app.Activity->performCreate

android.app.Instrumentation->callActivityOnCreate

android.app.ActivityThread->performLaunchActivity

android.app.ActivityThread->handleLaunchActivity

android.app.ActivityThread->access$800

android.app.ActivityThread$H->handleMessage

android.os.Handler->dispatchMessage

android.os.Looper->loop

android.app.ActivityThread->main

java.lang.reflect.Method->invokeNative

java.lang.reflect.Method->invoke

com.android.internal.os.ZygoteInit$MethodAndArgsCaller->run

com.android.internal.os.ZygoteInit->main

com.android.internal.os.ZygoteInit->main

dalvik.system.NativeStart->main

在知道了調(diào)用棧的變化之后,就可以在Java層寫代碼進(jìn)行檢測(cè):

#!java

try {

throw new Exception("blah");

}

catch(Exception e) {

int zygoteInitCallCount = 0;

for(StackTraceElement stackTraceElement : e.getStackTrace()) {

if(stackTraceElement.getClassName().equals("com.android.internal.os.ZygoteInit"))  {

zygoteInitCallCount++;

if(zygoteInitCallCount == 2) {

Log.wtf("HookDetection", "Substrate is active on the device.");

}

}

if(stackTraceElement.getClassName().equals("com.saurik.substrate.MS$2")  &&

stackTraceElement.getMethodName().equals("invoked")) {

Log.wtf("HookDetection", "A method on the stack trace has been hooked using  Substrate.");

}

if(stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge")  &&

stackTraceElement.getMethodName().equals("main")) {

Log.wtf("HookDetection", "Xposed is active on the device.");

}

if(stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge")  &&

stackTraceElement.getMethodName().equals("handleHookedMethod")) {

Log.wtf("HookDetection", "A method on the stack trace has been hooked using  Xposed.");

}

}

}

0x03 檢測(cè)并不應(yīng)該native的native方法

Xposed框架會(huì)把hook的Java方法類型改為"native",然后把原來(lái)的方法替換成自己的代碼(調(diào)用hookedMethodCallback)??梢圆榭碭posedBridge_hookMethodNative  的實(shí)現(xiàn),是修改后app_process里的方法。

利用Xposed改變hook方法的這個(gè)特性(Substrate也使用類似的原理),就可以用來(lái)檢測(cè)是否被hook了。注意這不能用來(lái)檢測(cè)ART運(yùn)行時(shí)的Xposed,因?yàn)闆](méi)必要把方法的類型改為native。

假設(shè)有下面這個(gè)方法:

#!java

public class DoStuff {

public static String getSecret() {

return "ChangeMePls!!!";

}

}

如果getSecret方法被hook了,在運(yùn)行的時(shí)候就會(huì)像下面的定義:

#!java

public class DoStuff {

// calls hookedMethodCallback if hooked using Xposed

public native static String getSecret();

}

基于上面的原理,檢測(cè)的步驟如下:

定位到應(yīng)用的DEX文件

枚舉所有的class

通過(guò)反射機(jī)制判斷運(yùn)行時(shí)不應(yīng)該是native的方法

下面的Java展示了這個(gè)技巧。這里假設(shè)了應(yīng)用本身沒(méi)有通過(guò)JNI調(diào)用本地代碼,大多數(shù)應(yīng)用都不需要調(diào)用本地方法。不過(guò)如果有JNI調(diào)用的話,只需要把這些native方法添加到一個(gè)白名單中即可。理論上這個(gè)方法也可以用于檢測(cè)Java庫(kù)或者第三方庫(kù),不過(guò)需要把第三方庫(kù)的native方法添加到一個(gè)白名單。檢測(cè)代碼如下:

#!java

for (ApplicationInfo applicationInfo : applicationInfoList) {

if (applicationInfo.processName.equals("com.example.hookdetection")) {

Set classes = new HashSet();

DexFile dex;

try {

dex = new DexFile(applicationInfo.sourceDir);

Enumeration entries = dex.entries();

while(entries.hasMoreElements()) {

String entry = entries.nextElement();

classes.add(entry);

}

dex.close();

}

catch (IOException e) {

Log.e("HookDetection", e.toString());

}

for(String className : classes) {

if(className.startsWith("com.example.hookdetection")) {

try {

Class clazz = HookDetection.class.forName(className);

for(Method method : clazz.getDeclaredMethods()) {

if(Modifier.isNative(method.getModifiers())){

Log.wtf("HookDetection", "Native function found (could be hooked by Substrate  or Xposed): " + clazz.getCanonicalName() + "->" + method.getName());

}

}

}

catch(ClassNotFoundException e) {

Log.wtf("HookDetection", e.toString());

}

}

}

}

}

0x04 通過(guò)/proc/[pid]/maps檢測(cè)可疑的共享對(duì)象或者JAR

/proc/[pid]/maps記錄了內(nèi)存映射的區(qū)域和訪問(wèn)權(quán)限,首先查看Android應(yīng)用的映像,***列是起始地址和結(jié)束地址,第六列是映射文件的路徑。

#!bash

#cat /proc/5584/maps

40027000-4002c000 r-xp 00000000 103:06 2114 /system/bin/app_process

4002c000-4002d000 r--p 00004000 103:06 2114 /system/bin/app_process

4002d000-4002e000 rw-p 00005000 103:06 2114 /system/bin/app_process

4002e000-4003d000 r-xp 00000000 103:06 246 /system/bin/linker

4003d000-4003e000 r--p 0000e000 103:06 246 /system/bin/linker

4003e000-4003f000 rw-p 0000f000 103:06 246 /system/bin/linker

4003f000-40042000 rw-p 00000000 00:00 0

40042000-40043000 r--p 00000000 00:00 0

40043000-40044000 rw-p 00000000 00:00 0

40044000-40047000 r-xp 00000000 103:06 1176 /system/lib/libNimsWrap.so

40047000-40048000 r--p 00002000 103:06 1176 /system/lib/libNimsWrap.so

40048000-40049000 rw-p 00003000 103:06 1176 /system/lib/libNimsWrap.so

40049000-40091000 r-xp 00000000 103:06 1237 /system/lib/libc.so

... Lots of other memory regions here ...

因此可以寫代碼檢測(cè)加載到當(dāng)前內(nèi)存區(qū)域中的可疑文件:

#!java

try {

Set libraries = new HashSet();

String mapsFilename = "/proc/" + android.os.Process.myPid() + "/maps";

BufferedReader reader = new BufferedReader(new FileReader(mapsFilename));

String line;

while((line = reader.readLine()) != null) {

if (line.endsWith(".so") || line.endsWith(".jar")) {

int n = line.lastIndexOf(" ");

libraries.add(line.substring(n + 1));

}

}

for (String library : libraries) {

if(library.contains("com.saurik.substrate")) {

Log.wtf("HookDetection", "Substrate shared object found: " + library);

}

if(library.contains("XposedBridge.jar")) {

Log.wtf("HookDetection", "Xposed JAR found: " + library);

}

}

reader.close();

}

catch (Exception e) {

Log.wtf("HookDetection", e.toString());

}

Substrate會(huì)用到幾個(gè)so:

#!bash

Substrate shared object found:  /data/app-lib/com.saurik.substrate-1/libAndroidBootstrap0.so

Substrate shared object found:  /data/app-lib/com.saurik.substrate-1/libAndroidCydia.cy.so

Substrate shared object found:  /data/app-lib/com.saurik.substrate-1/libDalvikLoader.cy.so

Substrate shared object found:  /data/app-lib/com.saurik.substrate-1/libsubstrate.so

Substrate shared object found:  /data/app-lib/com.saurik.substrate-1/libsubstrate-dvm.so

Substrate shared object found:  /data/app-lib/com.saurik.substrate-1/libAndroidLoader.so

Xposed會(huì)用到一個(gè)Jar:

#!bash

Xposed JAR found:  /data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar

0x05 繞過(guò)檢測(cè)的方法

上面討論了幾個(gè)anti-hooking的方法,不過(guò)相信也會(huì)有人提出繞過(guò)的方法,這里對(duì)應(yīng)每個(gè)檢測(cè)方法如下:

hook PackageManager的getInstalledApplications,把Xposed或者Substrate的包名去掉

hook Exception的getStackTrace,把自己的方法去掉

hook getModifiers,把flag改成看起來(lái)不是native

hook 打開(kāi)的文件的操作,返回/dev/null或者修改的map文件

以上就是Android Java層的anti-hooking技巧是怎樣的,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

新聞名稱:AndroidJava層的anti-hooking技巧是怎樣的
文章地址:http://jinyejixie.com/article24/iisgce.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、虛擬主機(jī)、靜態(tài)網(wǎng)站、自適應(yīng)網(wǎng)站、商城網(wǎng)站面包屑導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司
岚皋县| 闽清县| 佛学| 南涧| 当涂县| 措勤县| 库车县| 瑞安市| 广元市| 黄平县| 华蓥市| 广元市| 赣州市| 安图县| 玛纳斯县| 乐安县| 大丰市| 侯马市| 武清区| 瑞丽市| 正安县| 伊金霍洛旗| 金寨县| 留坝县| 宣城市| 岑巩县| 贵德县| 广水市| 西藏| 兖州市| 巴马| 灌南县| 新干县| 彭泽县| 新乡县| 吴川市| 吴旗县| 元阳县| 靖西县| 桃江县| 固始县|