天天看點

《Android安全技術揭秘與防範》—第8章8.節什麼是Hook技術

本節書摘來自異步社群《android安全技術揭秘與防範》一書中的第8章8.節什麼是hook技術,作者周聖韬,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

第8章 動态注入技術

android安全技術揭秘與防範

我們在讨論動态注入技術的時候,apihook的技術由來已久,在作業系統未能提供所需功能的情況下,利用apihook的手段來實作某種必需的功能也算是一種不得已的辦法。在windows平台下開發電子詞典的光标取詞功能,這項功能就是利用hook api的技術把系統的字元串輸出函數替換成了電子詞典中的函數,進而能得到螢幕上任何位置的字元串。無論是16位的windows95,還是32位的windws nt,都有辦法向整個系統或特定的目标程序中“注入”dll動态庫,并替換掉其中的函數。

但是在android上進行hook需要跨程序操作,我們知道在linux上的跨程序操作需要root權限。是以目前hook技術廣泛地應用在安全類軟體的主動防禦上,所見到的hook類病毒并不多。

android系統在開發中會存在兩種模式,一個是linux的native模式,而另一個則是建立在虛拟機上的java模式。是以,我們在讨論hook的時候,可想而知在android平台上的hook分為兩種。一種是java層級的hook,另一種則是native層級的hook。兩種模式下,我們通常能夠通過使用jni機制來進行調用。但我們知道,在java中我們能夠使用native關鍵字對c/c++代碼進行調用,但是在c/c++中卻很難調用java中的代碼。是以,我們能夠在java層級完成的事基本也不會在native層去完成。

8.1 什麼是hook技術

還沒有接觸過hook技術讀者一定會對hook一詞感覺到特别的陌生,hook英文翻譯過來就是“鈎子”的意思,那我們在什麼時候使用這個“鈎子”呢?我們知道,在android作業系統中系統維護着自己的一套事件分發機制。應用程式,包括應用觸發事件和背景邏輯處理,也是根據事件流程一步步地向下執行。而“鈎子”的意思,就是在事件傳送到終點前截獲并監控事件的傳輸,像個鈎子鈎上事件一樣,并且能夠在鈎上事件時,處理一些自己特定的事件。較為形象的流程如圖8-1所示。

hook的這個本領,使它能夠将自身的代碼“融入”被勾住(hook)的程式的程序中,成為目标程序的一個部分。我們也知道,在android系統中使用了沙箱機制,普通使用者程式的程序空間都是獨立的,程式的運作彼此間都不受幹擾。這就使我們希望通過一個程式改變其他程式的某些行為的想法不能直接實作,但是hook的出現給我們開拓了解決此類問題的道路。當然,根據hook對象與hook後處理的事件方式不同,hook還分為不同的種類,如消息hook、api hook等。

《Android安全技術揭秘與防範》—第8章8.節什麼是Hook技術

8.1.1 hook原理

hook技術無論對安全軟體還是惡意軟體都是十分關鍵的一項技術,其本質就是劫持函數調用。但是由于處于linux使用者态,每個程序都有自己獨立的程序空間,是以必須先注入到所要hook的程序空間,修改其記憶體中的程序代碼,替換其過程表的符号位址。在android中一般是通過ptrace函數附加程序,然後向遠端程序注入so庫,進而達到監控以及遠端程序關鍵函數挂鈎。

hook技術的難點,并不在于hook技術,初學者借助于資料“照葫蘆畫瓢”能夠很容易就掌握hook的基本使用方法。如何找到函數的入口點、替換函數,這就涉及了了解函數的連接配接與加載機制。

從android的開發來說,android系統本身就提供給了我們兩種開發模式,基于android sdk的java語言開發,基于androidndk的native c/c++語言開發。是以,我們在讨論hook的時候就必須在兩個層面上來讨論。對于native層來說hook的難點其實是在了解elf檔案與學習elf檔案上,特别是對elf檔案不太了解的讀者來說;對于java層來說,hook就需要了解虛拟機的特性與java上反射的使用。

8.1.1.1 hook工作流程

之前我們介紹過hook的原理就是改變目标函數的指向,原理看起來并不複雜,但是實作起來卻不是那麼的簡單。這裡我們将問題細分為兩個,一個是如何注入代碼,另一個是如何注入動态連結庫。

注入代碼我們就需要解決兩個問題。

需要注入的代碼我們存放在哪裡?

如何注入代碼?

注入動态共享庫我們也需要解決兩個問題:

我們不能隻在自己的程序載入動态連結庫,如何使程序附着上目标程序?

如何讓目标程序調用我們的動态連結庫函數?

這裡我也不賣關子了,說一下目前對上述問題的解決方案吧。對于程序附着,android的核心中有一個函數叫ptrace,它能夠動态地attach(跟蹤一個目标程序)、detach(結束跟蹤一個目标程序)、peektext(擷取記憶體位元組)、poketext(向記憶體寫入位址)等,它能夠滿足我們的需求。而android中的另一個核心函數dlopen,能夠以指定模式打開指定的動态連結庫檔案。對于程式的指向流程,我們可以調用ptrace讓pc指向lr堆棧。最後調用,對目标程序調用dlopen則能夠将我們希望注入的動态庫注入至目标程序中。

對于代碼的注入(hook api),我們可以使用mmap函數配置設定一段臨時的記憶體來完成代碼的存放。對于目标程序中的mmap函數位址的尋找與hook api函數位址的尋找都需要通過目标程序的虛拟位址空間解析與elf檔案解析來完成,具體算法如下。

通過讀取 /proc//maps檔案找到連結庫的基位址。

讀取動态庫,解析elf檔案,找到符号(需要對elf檔案格式的深入了解)。

計算目标函數的絕對位址。

目标程序函數絕對位址= 函數位址 + 動态庫基位址

上面說了這麼多,向目标程序中注入代碼總結後的步驟分為以下幾步。

(1)用ptrace函數attach上目标程序。

(2)發現裝載共享庫so函數。

(3)裝載指定的.so。

(4)讓目标程序的執行流程跳轉到注入的代碼執行。

(5)使用ptrace函數的detach釋放目标程序。

對應的工作原理流程如圖8-2所示。

《Android安全技術揭秘與防範》—第8章8.節什麼是Hook技術

https://yqfile.alicdn.com/b7f12bd9b13e8202d3e5547157ba0750ef5c268d.png" >

8.1.1.2 ptrace函數

說到了hook我們就不能不說一下ptrace函數,ptrace提供了一種使父程序得以監視和控制其他程序的方式,它還能夠改變子程序中的寄存器和核心映像,因而可以實作斷點調試和系統調用的跟蹤。使用ptrace,你可以在使用者層攔截和修改系統調用(這個和hook所要達到的目的類似),父程序還可以使子程序繼續執行,并選擇是否忽略引起終止的信号。

ptrace函數定義如下所示:

int ptrace(int request, int pid, int addr, int data);

request是請求ptrace執行的操作。

pid是目标程序的id。

addr是目标程序的位址值。

data是作用的資料。

對于ptrace來說,它的第一個參數決定ptrace會執行什麼操作。常用的有跟蹤指定的程序(ptrace_attach)、結束跟蹤指定程序(ptrace_detach)等。詳細的參數與使用方式如表8-1所示。

《Android安全技術揭秘與防範》—第8章8.節什麼是Hook技術
《Android安全技術揭秘與防範》—第8章8.節什麼是Hook技術
《Android安全技術揭秘與防範》—第8章8.節什麼是Hook技術

8.1.2 hook的種類

我們所讨論的hook,也就是平時我們所說的函數挂鈎、函數注入、函數劫持等操作。針對android作業系統,根據api hook對應的api不一樣我們可以分為使用android sdk開發環境的java api hook與使用android ndk開發環境的native api hook。而對于android中so庫檔案的函數hook,根據elf檔案的特性能分為got表hook、sym表hook以及inline hook等。當然,根據hook方式的應用範圍我們在android這樣一個特殊的環境中還能分别出全局hook與單個應用程式hook。本節,我們就具體地說說這些hook的原理以及這些hook方式給我們使用hook帶來的便利性。

tips

 對于hook程式的運作環境不同,還可以分為使用者級api hook與核心級api hook。使用者級api hook主要是針對在作業系統上為使用者所提供的api函數方法進行重定向修改。而核心級api hook則是針對android核心linux系統提供的核心驅動模式造成的函數重定向,多數是應用在rootkit中。

8.1.2.1 java層api hook

通過對android平台的虛拟機注入與java反射的方式,來改變android虛拟機調用函數的方式(classloader),進而達到java函數重定向的目的。這裡我們将此類操作稱為java api hook。因為是根據java中的發射機制來重定向函數的,那麼很多java中反射出現的問題也會在此出現,如無法反射調用關鍵字為native的方法函數(jni實作的函數),基本類型的靜态常量無法反射修改等。

8.1.2.2 native層so庫hook

主要是針對使用ndk開發出來的so庫檔案的函數重定向,其中也包括對android作業系統底層的linux函數重定向,如使用so庫檔案(elf格式檔案)中的全局偏移表got表或符号表sym表進行修改進而達到的函數重定向,我們有可以對其稱為got hook和sym hook。針對其中的inline函數(内聯函數)的hook稱為inline hook。

8.1.2.3 全局hook

針對hook的不同程序來說又可以分為全局hook與單個應用程式程序hook,我們知道在android系統中,應用程式程序都是由zygote程序孵化出來的,而zygote程序是由init程序啟動的。zygote程序在啟動時會建立一個dalvik虛拟機執行個體,每當它孵化一個新的應用程式程序時,都會将這個dalvik虛拟機執行個體複制到新的應用程式程序裡面去,進而使每一個應用程式程序都有一個獨立的dalvik虛拟機執行個體。是以如果選擇對zygote程序hook,則能夠達到針對系統上所有的應用程式程序hook,即一個全局hook。對比效果如圖8-3所示。

《Android安全技術揭秘與防範》—第8章8.節什麼是Hook技術

而對應的app_process正是zygote程序啟動一個應用程式的入口,常見的hook架構xposed與cydiasubstrate也是通過替換app_process來完成全局hook的。

8.1.3 hook的危害

api hook技術是一種用于改變api執行結果的技術,能夠将系統的api函數執行重定向。一個應用程式調用的函數方法被第三方 hook 重定向後,其程式執行流程與執行結果是無法确認的,更别提程式的安全性了。而hook技術的出現并不是為病毒和惡意程式服務的,hook技術更多的是應用在安全管理軟體上面。但是無論怎麼說,已經被hook後的應用程式,就毫無安全可言了。