最新消息:图 床

Android Native Hook 工具實踐

COOL IAM 116浏览 0评论

作者:GToad
作者博客:GToad Blog

本文章所對應項目長期維護與更新,因為在我自己的幾台測試機上用得還挺順手的。本項目作為作者本人的一個學習項目將會長期更新以修復當前可能存在的Bug以及跟進以後Android NDK可能出現的主流彙編模式。

前言

在目前的安卓APP測試中對於Native Hook的需求越來越大,越來越多的APP開始逐漸使用NDK來開發核心或者敏感代碼邏輯。個人認為原因如下:

  1. 安全的考慮。各大APP越來越注重安全性,NDK所編譯出來的so庫逆向難度明顯高於java代碼產生的dex文件。越是敏感的加密算法與數據就越是需要用NDK進行開發。
  2. 性能的追求。NDK對於一些高性能的功能需求是java層無法比擬的。
  3. 手游的興起。虛幻4,Unity等引擎開發的手游中都有大量包含遊戲邏輯的so庫。

因此,本人調查了一下Android Native Hook工具目前的現狀。儘管Java層的Hook工具多種多樣,但是Native Hook的工具卻非常少並且在安卓5.0以上的適配工具更是寥寥無幾。(文末說明1)而目前Native Hook主要有兩大技術路線:

  1. PLT Hook
  2. Inline Hook

這兩種技術路線本人都實踐了一下,關於它們的對比,我在《Android Native Hook技術路線概述》中有介紹,所以這裡就不多說了。最終,我用了Inline Hook來做這個項目。

本文篇幅已經較長,因此寫了一些獨立的學習筆記來對其中的細節問題進行解釋:

  1. 《Android Native Hook技術路線概述》
  2. 《Android Inline Hook中的指令修復》
  3. 項目倉庫
  4. 項目案例——Arm32
  5. 項目案例——Thumb-2

目標效果

根據本人自身的使用需求提出了如下幾點目標:

  1. 工具運行原理中不能涉及調試目標APP,否則本工具在遇到反調試措施的APP時會失效。儘管可以先去逆向調試patch掉反調試功能,但是對於大多數情況下只是想看看參數和返回值的Hook需求而言,這樣的前期處理實在過於麻煩。
  2. 依靠現有的各大Java Hook工具就能運行本工具,換句話說就是最好能用類似這些工具的插件的形式加載起本工具從而獲得Native Hook的能力。由於Java Hook工具如Xposed、YAHFA等對於各個版本的Android都做了不錯的適配,因此利用這些已有的工具即可向目標APP的Native層中注入我們的Hook功能將會方便很多小夥伴的使用。
  3. 既然要能夠讓各種Java Hook工具都能用本工具得到Native Hook的能力,那就這個工具就要有被加載起來以後自動執行自身功能邏輯的能力!而不是針對各個Java Hook工具找調用起來的方式。
  4. 要適配Android NDK下的armv7和thumb-2指令集。由於現在默認編譯為thumb-2模式,所以對於thumb16和thumb32的Native Hook支持是重中之重。
  5. 修復Inline Hook后的原本指令。
  6. Hook目標的最小單位至少是函數,最好可以是某行彙編代碼。

最終方案

最後完成項目的方案是:本工具是一個so庫。用Java Hook工具在APP的入口Activity運行一開始的onCreate方法處Hook,然後加載本so。

加載后,自動開始執行Hook邏輯。

為了方便敘述,接下來的Java Hook工具我就使用目前這類工具里最流行的Xposed,本項目的生成文件名為libautohook.so

自動執行

我們只是用Xposed加載了這個libautohook.so,那其中的函數該怎麼自動執行呢?

目前想到兩個方法:

  1. 利用JniOnload來自動執行。該函數是NDK中用戶可以選擇性自定義實現的函數。如果用戶不實現,則系統默認使用NDK的版本為1.1。但是如果用戶有定義這個函數,那Android VM就會在System.loadLibrary()加載so庫時自動先執行這個函數來獲得其返回的版本號。儘管該函數最終要返回的是NDK的版本號,但是其函數可以加入任意其它邏輯的代碼,從而實現加載so時的自動執行。這樣就能優先於所有其它被APP NDK調用的功能函數被調用,從而進行Hook。目前許多APP加固工具和APP初始化工作都會用此方法。

  2. 本文採用的是第二種方法。該方法網絡資料中使用較少。它是利用了__attribute__((constructor))屬性。使用這個constructor屬性編譯的普通ELF文件被加載入內存后,最先執行的不是main函數,而是具有該屬性的函數。同樣,本項目中利用此屬性編譯出來的so文件被加載后,儘管so里沒有main函數,但是依然能優先執行,且其執行甚至在JniOnload之前。於是逆向分析了一下編譯出來的so庫文件。發現具有constructor屬性的函數會被登記在.init_array中。(相對應的destructor屬性會在ELF卸載時被自動調用,這些函數會被登記入.fini_array)

ele7enxxh的博客


转载请注明:IAMCOOL » Android Native Hook 工具實踐

0 0 vote
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x