❶ Android Binder Hook的實現
Binder Hook可以Hook掉 當前App 用到的系統Service服務。
以LocationManager為例,在獲取一個LocationManager時分為兩步。第一,獲取IBinder對象;第二:IBinder對象通過asInterface()轉化為LocationMangerService對象。最後初始化LocationManager,application層用到的都是LocationManager。
Hook的大致原理是:ServiceManager在獲取某個Binder時,如果本地有緩存的Binder,就不再跨進程請求Binder了。我們可以在緩存中加入自己的Binder,使得ServiceManager查詢本地緩存時得到一個自定義的CustomBinder對象,不再跨進程向系統請求。並且ILocationManager.Stub.asInterface(CustomBinder)方法返回我們自定義的Service對象。
這裡面有兩個地方需要用到自定義的對象。由於我們只Hook其中一部分的功能,其他功能還需要保留,所以用動態代理的方式創建自定義的Binder和自定義的Service。
在理解後面的內容前你需要了解這些知識點:
Activity等類在獲取系統Service時,都是調用getSystemService(serviceName)方法獲取的。
Context 的 getSystemService() 方法調用了 SystemServiceRegistry 的 getSystemService() 方法。
SystemServiceRegistry 中有一個常量 SYSTEM_SERVICE_FETCHERS,這是一個Map。保存了ServiceName和對應的ServiceFetcher。ServicFetcher是用於創建具體Service的類。ServiceFetcher 的關鍵方法是 createService() 方法。
在 ServiceFetcher 的 createService() 方法中,調用了 ServiceManager.getService(name) 方法。以 LocationManager 對應的 ServiceFetcher 為例,它的createService()方法源碼如下:
假如我們要修改 LocationManager 的 getLastKnownLocation() 方法(下文都是)。我們要做的就是讓ServiceManager.getService("location")返回我們自定義的Binder。先看一下這個方法簡化後的源碼:
sCache是一個Map,緩存了已經向系統請求過的Binder。如果我們需要讓這個方法返回我們我們自己的binder,只需要事先往sCache中put一個自定義的Binder就行了。
在put之前,需要先創建出一個自定義的Binder。這個Binder在被 ILocationManager.Stub.asInterface 處理後,可以返回一個自定義的 LocationManagerService。
先看一下Binder的 asInterface() 的實現:
如果把 queryLocalInterface()方法返回一個自定義的Service,使得走if語句內部,不走else,那就算是Hook成功了。
假設我們想讓系統的LocationManager返回的位置信息全是在天安門(116.23, 39.54)。那我們需要使得 LocatitionManagerService 的 getLastLocation() 方法 返回的全是 (116.23, 39.54)。
由於我們不能直接拿到系統的這個Service對象,可以先用反射的方式拿到系統的LocationManagerService。然後攔截getLastLocation()方法。
原生的Binder對象在調用 queryLocalInterface() 方法時會返回原生的Service對象。我們希望返回3.1中的自定義Service。所以這里攔截 queryLocalInterface() 方法。
有了自定義的Binder後,將它注入到ServiceManger的sCache變數中就完成Hook了~
當onClick被調用的時候,Toast和Log都會顯示天安門的坐標(116.23, 39.54)。證明Hook成功!
你甚至可以用Binder Hook的方式Hook掉 ActivityManager 。