1、Xposed:Java層的HOOK框架,由于要修改Zgote進(jìn)程,需要Root;

我們提供的服務(wù)有:成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、孟連ssl等。為上千企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢(xún)和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的孟連網(wǎng)站制作公司
2、CydiaSubstrator:本地層的HOOK框架,本質(zhì)上是一個(gè)inline Hook;
3、dexposed框架
4、AndFix框架;
5、Sophix 框架;
6、AndroidMethodHook框架;
7、Legend框架:在AndFix框架的基礎(chǔ)上,在方法進(jìn)行替換前進(jìn)行了方法的備份;
8、YAHFA框架;
9、EPIC框架;
10、VirtualXposed:Virtual APP與Xposed的一個(gè)結(jié)合。
擴(kuò)展資料
使用框架的原因
因?yàn)檐浖到y(tǒng)很復(fù)雜,特別是服務(wù)器端軟件,涉及到的知識(shí),內(nèi)容,問(wèn)題太多。在某些方面使用別人成熟的框架,就相當(dāng)于讓別人幫助完成一些基礎(chǔ)工作,只需要集中精力完成系統(tǒng)的業(yè)務(wù)邏輯設(shè)計(jì)。
而且框架一般是成熟,穩(wěn)健的,可以處理系統(tǒng)很多細(xì)節(jié)問(wèn)題,比如,事務(wù)處理,安全性,數(shù)據(jù)流控制等問(wèn)題。
還有框架一般都經(jīng)過(guò)很多人使用,所以結(jié)構(gòu)很好,所以擴(kuò)展性也很好,而且它是不斷升級(jí)的,可以直接享受別人升級(jí)代碼帶來(lái)的好處。框架一般處在低層應(yīng)用平臺(tái)(如J2EE)和高層業(yè)務(wù)邏輯之間的中間層。
框架開(kāi)發(fā)
框架的最大好處就是重用。面向?qū)ο笙到y(tǒng)獲得的最大的復(fù)用方式就是框架,一個(gè)大的應(yīng)用系統(tǒng)往往可能由多層互相協(xié)作的框架組成。
由于框架能重用代碼,因此從一已有構(gòu)件庫(kù)中建立應(yīng)用變得非常容易,因?yàn)闃?gòu)件都采用框架統(tǒng)一定義的接口,從而使構(gòu)件間的通信簡(jiǎn)單。
框架能重用設(shè)計(jì)。它提供可重用的抽象算法及高層設(shè)計(jì),并能將大系統(tǒng)分解成更小的構(gòu)件,而且能描述構(gòu)件間的內(nèi)部接口。
這些標(biāo)準(zhǔn)接口使在已有的構(gòu)件基礎(chǔ)上通過(guò)組裝建立各種各樣的系統(tǒng)成為可能。只要符合接口定義,新的構(gòu)件就能插入框架中,構(gòu)件設(shè)計(jì)者就能重用構(gòu)架的設(shè)計(jì)。
框架還能重用分析。所有的人員若按照框架的思想來(lái)分析事務(wù),那么就能將它劃分為同樣的構(gòu)件,采用相似的解決方法,從而使采用同一框架的分析人員之間能進(jìn)行溝通。
參考資料來(lái)源:百度百科-框架
Binder Hook可以Hook掉 當(dāng)前App 用到的系統(tǒng)Service服務(wù)。
以L(fǎng)ocationManager為例,在獲取一個(gè)LocationManager時(shí)分為兩步。第一,獲取IBinder對(duì)象;第二:IBinder對(duì)象通過(guò)asInterface()轉(zhuǎn)化為L(zhǎng)ocationMangerService對(duì)象。最后初始化LocationManager,application層用到的都是LocationManager。
Hook的大致原理是:ServiceManager在獲取某個(gè)Binder時(shí),如果本地有緩存的Binder,就不再跨進(jìn)程請(qǐng)求Binder了。我們可以在緩存中加入自己的Binder,使得ServiceManager查詢(xún)本地緩存時(shí)得到一個(gè)自定義的CustomBinder對(duì)象,不再跨進(jìn)程向系統(tǒng)請(qǐng)求。并且ILocationManager.Stub.asInterface(CustomBinder)方法返回我們自定義的Service對(duì)象。
這里面有兩個(gè)地方需要用到自定義的對(duì)象。由于我們只Hook其中一部分的功能,其他功能還需要保留,所以用動(dòng)態(tài)代理的方式創(chuàng)建自定義的Binder和自定義的Service。
在理解后面的內(nèi)容前你需要了解這些知識(shí)點(diǎn):
Activity等類(lèi)在獲取系統(tǒng)Service時(shí),都是調(diào)用getSystemService(serviceName)方法獲取的。
Context 的 getSystemService() 方法調(diào)用了 SystemServiceRegistry 的 getSystemService() 方法。
SystemServiceRegistry 中有一個(gè)常量 SYSTEM_SERVICE_FETCHERS,這是一個(gè)Map。保存了ServiceName和對(duì)應(yīng)的ServiceFetcher。ServicFetcher是用于創(chuàng)建具體Service的類(lèi)。ServiceFetcher 的關(guān)鍵方法是 createService() 方法。
在 ServiceFetcher 的 createService() 方法中,調(diào)用了 ServiceManager.getService(name) 方法。以 LocationManager 對(duì)應(yīng)的 ServiceFetcher 為例,它的createService()方法源碼如下:
假如我們要修改 LocationManager 的 getLastKnownLocation() 方法(下文都是)。我們要做的就是讓ServiceManager.getService("location")返回我們自定義的Binder。先看一下這個(gè)方法簡(jiǎn)化后的源碼:
sCache是一個(gè)Map,緩存了已經(jīng)向系統(tǒng)請(qǐng)求過(guò)的Binder。如果我們需要讓這個(gè)方法返回我們我們自己的binder,只需要事先往sCache中put一個(gè)自定義的Binder就行了。
在put之前,需要先創(chuàng)建出一個(gè)自定義的Binder。這個(gè)Binder在被 ILocationManager.Stub.asInterface 處理后,可以返回一個(gè)自定義的 LocationManagerService。
先看一下Binder的 asInterface() 的實(shí)現(xiàn):
如果把 queryLocalInterface()方法返回一個(gè)自定義的Service,使得走if語(yǔ)句內(nèi)部,不走else,那就算是Hook成功了。
假設(shè)我們想讓系統(tǒng)的LocationManager返回的位置信息全是在天安門(mén)(116.23, 39.54)。那我們需要使得 LocatitionManagerService 的 getLastLocation() 方法 返回的全是 (116.23, 39.54)。
由于我們不能直接拿到系統(tǒng)的這個(gè)Service對(duì)象,可以先用反射的方式拿到系統(tǒng)的LocationManagerService。然后攔截getLastLocation()方法。
原生的Binder對(duì)象在調(diào)用 queryLocalInterface() 方法時(shí)會(huì)返回原生的Service對(duì)象。我們希望返回3.1中的自定義Service。所以這里攔截 queryLocalInterface() 方法。
有了自定義的Binder后,將它注入到ServiceManger的sCache變量中就完成Hook了~
當(dāng)onClick被調(diào)用的時(shí)候,Toast和Log都會(huì)顯示天安門(mén)的坐標(biāo)(116.23, 39.54)。證明Hook成功!
你甚至可以用Binder Hook的方式Hook掉 ActivityManager 。
前面插件化一和二說(shuō)了下插樁式加載未安裝的APK,主要是重寫(xiě)了getResource和getClassloader兩個(gè)方法來(lái)實(shí)現(xiàn)的。以及每個(gè)組件要實(shí)現(xiàn)一個(gè)接口,通過(guò)接口注入上下文來(lái)達(dá)到它的生命周期。
那么插樁式和hook式的實(shí)現(xiàn)方式有什么不同呢?
插樁式是怎么加載到插件中的class文件呢,是通過(guò)將將APK轉(zhuǎn)化成插件的Classloader,然后想要加載插件的class文件,我們的去拿這個(gè)插件的classloader去loadClass。所以是有一個(gè)中間者的。
hook式呢是將插件apk融入到了我們的宿主apk,那直接在里面就可以直接loadClass了,在不用這個(gè)插件的ClassLoader了,這樣的話(huà)對(duì)于插件和宿主就沒(méi)什么區(qū)別了,不像插樁式有一個(gè)中間者。
那么要實(shí)現(xiàn)hook式 就要知道android中一個(gè)class文件式怎樣被加載到內(nèi)存中去的。其實(shí)就是通過(guò)PathClassLoader來(lái)加載的。
那么我們先看下ClassLoader
任何一個(gè)java程序都是由一個(gè)或者多個(gè)class組成的,在程序運(yùn)行時(shí),需要將class文件加載到JVM中才可以使用,負(fù)責(zé)加載這些class文件的就是java的類(lèi)加載機(jī)制。CLassLoader的作用就是加載class文件提供給程序運(yùn)行時(shí)使用,每個(gè)Class對(duì)象內(nèi)部都有一個(gè)ClassLoader來(lái)標(biāo)示自己是有那個(gè)classLoade加載的。
Android app的所有的java文件都是通過(guò)PathClassLoader來(lái)加載的,那么它的父類(lèi)是BaseDexClassLoader,還有一個(gè)兄弟類(lèi)是DexClassLoader,那么他們有什么區(qū)別呢。
從上面可以看出這兩個(gè)類(lèi)的構(gòu)造函數(shù)不同。(在26的源碼中DexClassLoader中的optimizedDirectory也廢棄了)
PathClassLoader:用于Android應(yīng)用程序類(lèi)加載器。可以加載指定的dex,以及jar、zip、apk中的classes.dex
DexClassLoader:加載指定的dex以及jar、zip、apk中的classes.dex。
可以看到創(chuàng)建ClassLoader的時(shí)候需要接收一個(gè)CLassLoader parent的參數(shù),這個(gè)parent的目的就在于實(shí)現(xiàn)類(lèi)加載的委托。
某個(gè)類(lèi)加載器在接到加載類(lèi)的請(qǐng)求時(shí),首先將加載任務(wù)委托給父類(lèi)加載器,一次遞歸,如果父加載器可以完成加載任務(wù),那么就返回,只有當(dāng)父加載器無(wú)法完成加載任務(wù)時(shí),才自己去加載。
因此我們自己創(chuàng)建的ClassLoader:newPathClassLoader("/sdcard/xx.dex",getClassLoader()),并不僅僅只能加載我們的xx.dex中的class。
需要注意的是,findBootstrapClassOrNull 這個(gè)方法,當(dāng)parent為null的時(shí)候,去這個(gè)BootCLassLoader進(jìn)行加載,
但是在Android當(dāng)中的實(shí)現(xiàn):
所以new PathClassLoader("/sdcard/xx.dex",null),是不能加載Activity.class的。
上面分析了加載了一個(gè)class,是利用了雙親委托機(jī)制,那么要是都找不到那就開(kāi)始調(diào)用自己的findCLass方法
在ClassLoader類(lèi)中findClass:
任何ClassLoader的子類(lèi),都可以重寫(xiě)loadClass和findClass。如果你不想使用雙親委托,就重寫(xiě)loadClas修改實(shí)現(xiàn),重寫(xiě)findClass則表示在雙親委托機(jī)制下,父ClassLoader都找不到class的情況下,定義自己去查找一個(gè)class。
而我們的PathClassLoader會(huì)自己負(fù)責(zé)加載Activity這樣的類(lèi),利用雙親委托父類(lèi)去加載activity,而我們的PathClassLoader沒(méi)有重寫(xiě)findClass,是在它的父類(lèi)里面。因此我們可以看看父類(lèi)的findClass是如何實(shí)現(xiàn)的。
可以看到加載PathClassLoader加載class,轉(zhuǎn)化為從DexPathList中加載class了,那么我們看看DexPathList中的findClass
那么從上面分析得到
到這里我們想要加載一個(gè)插件的apk ,其實(shí)最終加載的是一個(gè)dex文件(先說(shuō)class文件,加載資源后面說(shuō)),有沒(méi)有辦法吧這個(gè)dex文件給轉(zhuǎn)化成一個(gè) Element 對(duì)象,給放到 Elemeng數(shù)組 當(dāng)中,這樣直接就可以加載我們插件中的類(lèi)了。
1、首先我們肯定是要得到插件APK的的中DexPathList對(duì)象中的dexElement數(shù)組
2、插件的dexElements數(shù)組我們拿到了,那么是不是要開(kāi)始拿我們系統(tǒng)里面的 ,我們反射獲取,和上面的一樣。
3、上面我們獲取到了系統(tǒng)和我們插件的dexElement數(shù)組,然后我們將這個(gè)數(shù)組合并到一個(gè)新的數(shù)組里面去,并且給注入到系統(tǒng)里面
至此,加載插件的一個(gè)流程基本就完成了。但是上面只是處理了class文件,沒(méi)有處理資源。資源的話(huà)我們也是采用hook的方式去實(shí)現(xiàn)
在宿主的Application中hook這個(gè)方法,然后去重寫(xiě)getAsserts和getResources兩個(gè)方法:
然后在插件的BaseActivity中繼續(xù)重寫(xiě)getAssets和getResources兩個(gè)方法
這樣就可以完成hook式加載一個(gè)未安裝的APK了。至此基本就完成了插樁式和Hook式插件化的基本實(shí)現(xiàn)。(后面幾篇是優(yōu)化)。
用注解吧 打個(gè)@SuppressLint("ClickableViewAccessibility") 這個(gè)警告是說(shuō),有可能會(huì)和點(diǎn)擊事件發(fā)生沖突如果你在touch中返回了true,那么就不會(huì)響應(yīng)onClick事件了你必須調(diào)用一下view.performClick(),才會(huì)觸發(fā) view.setOnTouchListener(new View.OnTouchListener() { @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub return false; } });
源碼的執(zhí)行是按照一定流程思路進(jìn)行的,hook就是在源碼的執(zhí)行流程之間插入一步操作,起到攔截,替換的作用;被改變的對(duì)象稱(chēng)為hook點(diǎn),一般將不易發(fā)生變化的類(lèi)作為hook點(diǎn);
學(xué)習(xí)hook必須了解代理模式,可以參考我這篇文章: 反射和動(dòng)態(tài)代理
首先需要知道startactivity的流程: Android進(jìn)階解密①——activity的啟動(dòng)過(guò)程
我們知道startActivity會(huì)通過(guò)mInstrumentation這個(gè)類(lèi),我們可以將這個(gè)類(lèi)作為hook點(diǎn);
自定義一個(gè)Instrumentation,在activity的工作過(guò)程中通過(guò)反射替換原來(lái)的Instrumentation,將原來(lái)的Instrumentation傳到代理類(lèi)里面,通過(guò)method invoke保證原來(lái)的功能不變,然后可以添加自己的自定義操作;
首先拿到activity原來(lái)的Instrumentation對(duì)象,通過(guò)原來(lái)的Instrumentation構(gòu)建出一個(gè)InstrumentationProxy對(duì)象,將Proxy設(shè)置給activity,然后只要在startActivity()之前調(diào)用這個(gè)方法替換就可以了;
首先我們可以用Xposed框架來(lái)hook計(jì)數(shù)傳感器的隊(duì)列函數(shù)dispatchSensorEvent(),這個(gè)函數(shù)在android.hardware.SystemSensorManager$SensorEventQueue這個(gè)類(lèi)中。隨后在微信運(yùn)動(dòng)每次詢(xún)問(wèn)行走步數(shù)的時(shí)候,我們先獲取當(dāng)前步數(shù),然后在目前的步數(shù)的基礎(chǔ)上加1000步,然后將信息返回給微信運(yùn)動(dòng)。微信運(yùn)動(dòng)就會(huì)誤以為我們運(yùn)動(dòng)了1000步,從而達(dá)到了欺騙的效果。
關(guān)鍵代碼如下:
首先hook android.hardware.SystemSensorManager$SensorEventQueue這個(gè)類(lèi)的dispatchSensorEvent()函數(shù):
final Class? sensorEL = findClass("android.hardware.SystemSensorManager$SensorEventQueue",lpparam.classLoader);
XposedBridge.hookAllMethods(sensorEL, "dispatchSensorEvent", new XC_MethodHook()
接著我們?cè)谟洸絺鞲衅靼巡綌?shù)信息返回給微信運(yùn)動(dòng)之前,將返回的步數(shù)加上1000步:
protected void beforeHookedMethod(MethodHookParam param) throws
Throwable {
XposedBridge.log(" mzheng Hooked method: " + param.method);
((float[]) param.args[1])[0]=((float[]) param.args[1])[0]+1000*WechatStepCount;
WechatStepCount+=1;
…
另外我們還可以使用一些傳感器的接口獲取一些數(shù)據(jù)的信息:
Sensor ss = ((SparseArraySensor) field.get(0)).get(handle);
XposedBridge.log(" SensorEvent: sensor=" + ss);
比如說(shuō)x就代表開(kāi)機(jī)以來(lái)行走的步數(shù),timestamp是獲取步數(shù)時(shí)候的時(shí)間戳等。
另外,我們不僅在android上可以hook計(jì)步器,在iOS上也是可以通過(guò)越獄后hook iHealth的API接口達(dá)到同樣的作弊效果,有興趣的同學(xué)可以繼續(xù)研究。
文章名稱(chēng):androidhook的簡(jiǎn)單介紹
分享URL:http://chinadenli.net/article6/dsshjog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、動(dòng)態(tài)網(wǎng)站、搜索引擎優(yōu)化、網(wǎng)站設(shè)計(jì)公司、用戶(hù)體驗(yàn)、域名注冊(cè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)