1. 程式人生 > >在未root的裝置上使用frida

在未root的裝置上使用frida

轉自:https://bbs.pediy.com/thread-229970.htm

在這篇教程中我們可以學會怎麼在未root裝置上使用Frida gadget。
指令碼和工具在這裡:materials
作者Romain Thomas - @rh0main


 

最近幾年,Frida已經成為這一行業進行hook的首選工具。它使用起來快速,靈活,且支援跨平臺。

大部分時候在root過後的裝置上使用Frida並沒有什麼限制,但某些場景中有些app可能會檢測執行環境。

@ikoz在他的博文Using Frida on Android without root中提到了一種修改Dalvik位元組碼的方法,以實現在未root裝置上使用Frida。在這篇教程中我們提出了一種不需要修改Dalvik位元組碼的新方法。(即classes.dex

Frida Gadget

在預設模式下,Frida需要在目的應用程式中注入一個代理以訪問目標進行的記憶體空間。

在Android和Linux中這種注入使用到了ptrace。它通過附加或啟動一個程式,然後注入對應的代理程式。在代理程式被注入後,它通過管道和伺服器進行通訊。

有些注入需要許可權。比如,我們不能使用普通使用者呼叫ptrace。為了解除這個限制,Frida提供了另一種模式,叫作“embedded”。在這一模式中,使用者需要注入frida-gadget庫。

這種注入需要:

  • 環境變數:LD_PRELOADDYLD_INSERT_LIBRARIES...
  • 使用dlopen
  • 在開源的目標中,使用linker連結frida-gadget.
  • ...

    要獲取關於Frida gadget的更多資訊,可以看官方文件:frida-gadget

Frida和LIEF

有一種不那麼出名但非常古老的注入技術是通過修改ELF格式。Mayhem 在Phrack詳細解釋了這一技術的原理,而LIEF(譯者注:LIEF,本文作者實現的一個庫)提供了一種使用者友好的API來實現。

 

簡而言之,可執行檔案格式包含了連結在可執行檔案上的庫。我們可以使用lddreadelf(Unix)列出這些庫,或者是使用elf_reader.py(Linux, Windows, OSX):

1

2

3

4

5

6

7

$ python ./elf_reader.py -/bin/ls

 

== Dynamic entries ==

 

|Tag    | Value | Info        |

|NEEDED | 0x1   | libcap.so.2 |

|NEEDED | 0x80  | libc.so.6   |

在這裡/bin/ls有兩個依賴:

  • libcap.so.2
  • libc.so.6

當可執行檔案載入的時候,載入器會遍歷這些庫,並把它們對映到程序到的記憶體空間中去,並在載入之後呼叫它的構造方法。

 

這一想法的原理是新增frida-agent.so作為APK的native庫的依賴。

 

新增這個依賴的程式碼非常簡單,像下面這樣:

1

2

3

4

5

import lief

 

libnative = lief.parse("libnative.so")

libnative.add_library("libgadget.so"# Injection!

libnative.write("libgadget.so")

Telegram

為了解釋這個程序,我們會注入frida gadget到Telegram這個應用中。Telegram是個好玩的目標,因為:

  • 它只包含一個native庫,這樣庫就會早點被載入。
  • 它表明了LIEF修改LEF檔案的可靠性
  • 這是個真實的app

關於環境,軟體是Telegram的4.8.4-12207版本(2018.2.18),系統是在Android 6.0.1上,架構是Samsung Galaxy S6的AArch64架構。

注入LIEF

正如上面解釋的,注入過程只需要在libtmessages.28.so上呼叫lief.ELF.Binary.add_library()

 

在注入之前,libtmessages.28.so與下列庫相連結:

1

2

3

4

5

6

7

8

9

10

11

$ readelf -d ./libtmessages.28.so|grep NEEDED

  0x0000000000000001 (NEEDED) Shared library: [libjnigraphics.so]

  0x0000000000000001 (NEEDED) Shared library: [liblog.so]

  0x0000000000000001 (NEEDED) Shared library: [libz.so]

  0x0000000000000001 (NEEDED) Shared library: [libOpenSLES.so]

  0x0000000000000001 (NEEDED) Shared library: [libEGL.so]

  0x0000000000000001 (NEEDED) Shared library: [libGLESv2.so]

  0x0000000000000001 (NEEDED) Shared library: [libdl.so]

  0x0000000000000001 (NEEDED) Shared library: [libstdc++.so]

  0x0000000000000001 (NEEDED) Shared library: [libm.so]

  0x0000000000000001 (NEEDED) Shared library: [libc.so]

在執行了telegram.add_library("libgadget.so")這條語句後,在第一個位置上,我們有了一條新的依賴。

1

2

3

4

5

6

7

8

9

10

11

12

$ readelf -d ./libtmessages.28.so|grep NEEDED

  0x0000000000000001 (NEEDED) Shared library: [libgadget.so]

  0x0000000000000001 (NEEDED) Shared library: [libjnigraphics.so]

  0x0000000000000001 (NEEDED) Shared library: [liblog.so]

  0x0000000000000001 (NEEDED) Shared library: [libz.so]

  0x0000000000000001 (NEEDED) Shared library: [libOpenSLES.so]

  0x0000000000000001 (NEEDED) Shared library: [libEGL.so]

  0x0000000000000001 (NEEDED) Shared library: [libGLESv2.so]

  0x0000000000000001 (NEEDED) Shared library: [libdl.so]

  0x0000000000000001 (NEEDED) Shared library: [libstdc++.so]

  0x0000000000000001 (NEEDED) Shared library: [libm.so]

  0x0000000000000001 (NEEDED) Shared library: [libc.so]

配置Frida Gadget

根據文件我們可以知道,Frida Gadgets可以使用配置檔案作為引數來進行互動。

  • Listing:互動和frida-server一樣
  • Script:使用配置檔案中指定的JS指令碼進行互動
  • ScriptDirectory:和Script一樣,但可以指定多個應用和多個指令碼
    Listing互動方式需要android.permission.INTERNET許可權。我們可以通過修改manifest檔案新增這個許可權。不過,如果我們使用的是Script這種互動方式就不需要這一許可權。

Frida payload會定位到/data/local/tmp/myscript.js檔案,gadget配置檔案的配置如下:

1

2

3

4

5

6

7

{

  "interaction": {

    "type""script",

    "path""/data/local/tmp/myscript.js",

    "on_change""reload"

  }

}

使用配置配置檔案必須遵循兩個條件:

  1. 檔案必須和gadget庫同名(例如:libgadget.so 和 libgadget.conf
  2. 配置檔案必須和gadget庫位於同一目錄中

第二個要求也就意味著在裝置中安裝之後,gadget庫會會在/data/app/org.telegram.messenger-1/lib目錄中尋找配置檔案。

在安裝app之後,當滿足下述條件時,Android包管理器會從APK的lib/目錄中複製檔案:

  • 名字具有lib字首
  • 名字具有.so字尾
  • 名字是gdbserver

Frida 實現這些要求的原始碼如下。因此我們只需要給libgadget.conf新增.so字尾就行了。

1

2

3

4

5

6

7

8

9

10

#if ANDROID

  if (!FileUtils.test (config_path, FileTest.EXISTS)) {

    var ext_index = config_path.last_index_of_char ('.');

      if (ext_index != -1) {

        config_path = config_path[0:ext_index] + ".config.so";

      else {

        config_path = config_path + ".config.so";

      }

  }

#endif

lib/gadget/gadget.vala

最終,新的Telegram的.apklib目錄結構如下:

1

2

3

4

5

6

$ tree lib

.

└── arm64-v8a

    ├── libgadget.config.so

    ├── libgadget.so

    └── libtmessages.28.so

libtmessages.28.so連結到了libgadget.so

執行

在滿足下述要求後:

  1. libtmessages.28.so的注入完成
  2. gadget庫及其配置檔案放在/lib/ABI目錄下
  3. 應用程式重新簽名

安裝new.apk這個重新打包的APK,並把myscript.js放在/data/local/tmp目錄下:

1

2

3

$ adb shell install new.apk

$ adb push myscript.js /data/local/tmp

$ adb shell chmod 777 /data/local/tmp/myscript.js

這篇教程中用到的Frida指令碼myscript.js只實現了一個對Android log函式呼叫的功能:

1

2

3

4

5

6

7

8

'use strict';

 

console.log("Waiting for Java..");

 

Java.perform(function () {

  var Log = Java.use("android.util.Log");

  Log.v("frida-lief""Have fun!");

});

myscript.js

最後,我們就可以執行telegram程式並檢視它的Android日誌了。

1

2

3

4

$ adb logcat -"frida-lief:V"

--------- beginning of system

--------- beginning of main

03-24 17:23:51.908 10243 10243 V frida-lief: Have Fun!

總結

在這篇教程中我們看到了靜態插樁和動態插樁的結合方法。

 

下面是這一技術的優/缺點

 

優點:

  • 不需要root
  • 不依賴frida-server
  • 可用於繞過anti-frida
  • 不需要修改AndroidManifest.xml和DEX檔案

缺點:

  • 需要向APK裡新增檔案
  • 需要程式有至少一個native庫
  • 注入進去的庫的載入順序不能控制

API

  • lief.ELF.Binary.add_library()

原文連結:https://lief.quarkslab.com/doc/latest/tutorials/09_frida_lief.html
編譯:看雪翻譯小組 夢野間
校對:看雪翻譯小組 lumou