詳解 三 種 Android 平臺注入技術

語言: CN / TW / HK

背景

在android系統中,程序之間是相互隔離的,兩個程序之間是沒辦法直接跨程序訪問其他程序的空間資訊的。那麼在android平臺中要對某個app程序進行記憶體操作,並獲取目標程序的地址空間內資訊或者修改目標程序的地址空間內的私有資訊,就需要涉及到注入技術。

通過注入技術可以將指定so模組或程式碼注入到目標程序中,只要注入成功後,就可以進行訪問和篡改目標程序空間內的資訊,包括資料和程式碼。

Android的注入技術的應用場景主要是進行一些非法的操作和實現如遊戲輔助功能軟體、惡意功能軟體。

下面主要進行對zygote注入、ptrace注入、修改so檔案注入,這三種注入方式進行詳細解析。

zygote注入

zygote是一個在android系統中是非常重要的一個程序,因為在android中絕大部分的應用程式程序都是由它孵化(fork)出來的,fork是一種程序複用技術。也就是說在android系統中普通應用APP程序的父親都是zygote程序。

zygote注入目的就是將指定的so模組注入到指定的APP程序中,這個注入過程不是直接向指定程序程序注入so模組,而是先將so模組注入到zygote程序。

在so模組注入到zygote程序後,在點選操作android系統中啟動的應用程式APP程序,啟動的App程序中包括需要注入到指定程序的so模組,太都是由zygote程序fork生成,因而在新建立的程序中都會包含已注入zygote程序的so模組。

這種的注入是通過間接注入方式完成的,也是一種相對安全的注入so模組方式。目前xposed框架就是基於zygote注入。

zygote注入so模組流程

1.通過注入器將要注入的so模組注入到zygote程序;

2.手動啟動要注入so模組的APP程序,由於APP程序是通過zygote程序fork出來的,所以啟動的APP程序都包含zygote程序中所有模組;

3.注入的so模組劫持被注入APP程序的控制權,執行注入so模組的程式碼;

4.注入so模組歸還APP程序的控制權,被注入程序正常執行。

Zygote注入器的實現流程

(注入器主要是基於ptrace注入shellcode方式的程序注入)

  •  通過ptrace進行附加到zygote程序。
  •  呼叫mmap申請目標程序空間,用於儲存注入的shellcode彙編程式碼。
  •  執行注入shellcode程式碼(shellcode程式碼是注入目標程序中並執行的彙編程式碼)。
  •  呼叫munmap函式釋放申請的記憶體。
  •  通過ptrace進行剝離zygote程序。

下面是關鍵的zygote程式碼注入實現

ptrace注入

ptrace注入實現上分類:

  •  通過利用ptrace函式將shellcode注入遠端程序的記憶體空間中,然後通過執行shellcode載入遠端程序so模組。
  •  通過直接遠端呼叫dlopen、dlsym、dlclose等函式載入被注入so模組,並執行指定的程式碼。

ptrace直接呼叫函式注入流程:

  •  通過利用ptrace進行附加到要注入的程序;
  •  儲存寄存環境;
  •  遠端呼叫mmap函式分配記憶體空間;
  •  向遠端程序記憶體空間寫入載入模組名稱和函式名稱;
  •  遠端呼叫dlopen函式開啟注入模組;
  •  遠端呼叫dlsym函式或需要呼叫的函式地址;
  •  遠端呼叫被注入模組的函式;
  •  恢復暫存器環境;
  •  利用ptrace從遠端程序剝離。

關鍵的ptrace直接呼叫系統函式實現

ptrace的shellcode注入原理

shellcode注入就是通過將dlopen/dlsym庫函式的操作放在shellcode程式碼中,注入函式只是通過對遠端APP程序進行記憶體空間申請,接著修改shellcode 程式碼中有關dlopen、dlsymdlclose等函式使用到的引數資訊,然後將shellcode程式碼注入到遠端APP程序申請的空間中,最後通過修改PC暫存器的方式來執行shellcode 的程式碼。

ptrace注入shellcode的詳細步驟

1.在shellcode中編寫好dlopen、dlsym等函式的呼叫,來載入so模組和執行函式,但需要將引數地址、函式地址、暫存器地址先隨便填充值為我們真實地址保留;

2.附加到遠端APP程序、儲存APP程序中暫存器的資料,為後面恢復遠端程序的繼續執行準備;

3.向遠端APP程序申請記憶體空間,選好shellcode存放的具體位置,準備存放shellcode和引數資料;

4.計算本地so模組函式對應到,遠端APP程序中的so模組函式地址,填充到shellcdoe中的引數中。計算好庫函式引數、暫存器存值相對shellcode起始位置的偏移再加上遠端程序中shellcode存放的起始位置,得到的結果就是遠端程序的記憶體空間中這些引數存放的位置,將這些地址填充到shellcode的引數中;

5.設定暫存器的值來讓執行庫函式;

6.恢復暫存器的值讓遠端程序繼續正常執行。

關鍵 的ptrace注入shellcode程式碼實現

修改ELF檔案注入

在android平臺Native層的可執行檔案SO檔案,它是屬於ELF檔案格式,通過修改ELF檔案格式可以實現對so檔案的注入。

通過修改ELF二進位制的可執行檔案,並在ELF檔案中新增自己的程式碼,使得可執行檔案在執行時會先執行自定義新增的程式碼,最後在執行ELF檔案的原始邏輯。

修改二進位制ELF檔案需要關注兩個重要的結構體:

ELF Header、Program Header Table

其中ELF Header 它是ELF檔案中唯一的,一個固定位置的檔案結構,它儲存著Program Header Table和Section Header Table的位置和大小資訊。

Program Header Table 它儲存ELF檔案的載入過程中各Section的記憶體對映和依賴庫相關資訊,用來告訴android系統中如何建立程序映像。

修改ELF檔案實現so檔案注入實現原理為:通過修改 Program Header Table中的依賴庫資訊,新增自定義的so檔案資訊,APP程序執行載入被該修改過的ELF檔案,它也同時會載入並執行自定義的so檔案。

Program Header Table表項結構

程式頭表項中的型別選項有如下

當程式頭表項結構中的型別為PT_DYNAMIC也就是動態連結資訊的時候,它是由程式頭表項的偏移(p_offset)和p_filesz(大小)指定的資料塊指向.dynamic段。這個.dynamic段包含程式連結和載入時的依賴庫資訊。

修改ELF檔案的注入實現過程

1.修改.dynamic段指向的字串表中新增 自定義的so模組名稱;

2.通過修改Program Header Table中新增PT_LOAD表項,新新增的表項將保護so模組名稱的字串表資料對映到記憶體中。同時將Program Header Table移動到檔案末尾;

3.修改.dynamic段的陣列資料,使得指向新的字串表,並指向自定義的so模組名稱;

4.修改ELF HEADER結構中 Program Header Table的位置資訊,並指向新的Program Header Table。

關鍵ELF檔案修改程式碼實現

【責任編輯:龐桂玉 TEL:(010)68476606】