Frida

DOUIK·2022년 7월 27일
1

Android

목록 보기
2/7

Frida

  • Ole에서 개발한 Dynamic Binary Instrumentation(DBI) 프레임워크
    - DBI : 바이너리 프로그램이 실행되는 동안 명령어를 수정, 삽입하는 것.
  • Windows, macOS/iOS, Linux, Android, QNX의 다양한 운영체제의 애플리케이션을 동적으로 분석할 수 있게 도와주는 도구.
  • 스크립트 기반으로 동작해서 컴파일 없이 간편하게 분석 가능
  • Javascript, C, Swift API를 제공해서 이용자는 API를 통해 런타임 정보, 데이터 유형, 함수 주소와 같은 정보를 획득 가능함
  • 함수를 후킹해서 다른 코드를 오염시키지 않고 필요한 로직만 테스트하거나, 소스코드 없이 바이너리를 리버스 엔지니어링 해야 하는 경우 많이 사용됨

    Frida를 설치하기 위해서 python3와 pip이 설치되어있어야 함

사용방법

  1. 안드로이드 기기에서 Frida 서버를 연다
  2. 후킹 코드를 전달하고 후킹 결과를 확인할 수 있게 로컬 호스트에 Frida 클라이언트를 설치한다.

Frida 클라이언트 설치

AVD에 설치된 앱 분석하기 위해 로컬 호스트에 Frida 클라이언트를 설치함

  1. pip으로 Frida 클라이언트를 설치
$ python -m pip install frida-tools
  1. Frida가 설치된 위치를 환경 변수로 등록함
<python3 설치위치>/Scripts

설치 확인

설치가 완료되면 7개의 바이너리가 생성됨.

  • frida-create
  • frida-discover
  • frida-join
  • frida-kill
  • frida-ls-devices
  • frida-ps
  • frida-trace

바이너리가 정상적으로 동작하는지 확인하기 위해 frida-ls-devices 명령 실행해 연결된 모든 기기 정보를 확인한다.

$ frida-ls-devices
Id             Type    Name
-------------  ------  ---------------------
local          local   Local System
emulator-5554  usb     Android Emulator 5554
socket         remote  Local Socket

서버 설치

  1. github에서 android-(자기운영체제에 맞는 버전) 선택해서 다운
  2. 서버 파일 압축해제 한 후, adb 이용해서 AVD에 업로드
adb push frida-server-15.0.18-android-x86_64 /data/local/tmp/
  1. adb 이용해서 AVD 셸에 접근한 후, 실행권한을 부여하고 서버파일을 실행
$ adb shell
generic_x86_64_arm64:/ # cd /data/local/tmp/
generic_x86_64_arm64:/ # chmod 777 ./frida-server-15.0.18-android-x86_64
generic_x86_64_arm64:/ # ./frida-server-15.0.18-android-x86_64

설치 확인

frida-ps -D emulator-5554 명령어를 통해 연결된 기기의 프로세스 목록이 출력되는지 확인
-D 옵션 뒤에는 AVD의 디바이스 ID를 입력

$ frida-ps -D emulator-5554
 PID  Name
----  -------------------------------------------------------------
4656  Calendar
5348  Gmail
2166  Google
5804  Google Play Movies & TV
6109  Maps
3236  Messages
2856  Phone
6357  Photos
5934  YouTube
6721  adbd
 222  android.hardware.atrace@1.0-service
 308  android.hardware.audio.service.ranchu
 309  android.hardware.authsecret@1.0-service
 488  android.hardware.biometrics.face@1.0-service.example
 489  android.hardware.biometrics.fingerprint@2.1-service
 310  android.hardware.bluetooth@1.1-service.sim
...

뭔지는 모르겠지만 frida-ls-devices도, frida-ps -D emulator-5554도 되지 않는다.. 설치는 됐고 frida-ps -U로 서버 프로세스 올라온 것 까지는 확인 됐는데 frida에 기기가 붙지는 않은거 같다. ++ 다음 날 다시 해보니 됐다.. 뭐지?

Frida 주요 기능

1. Injection

  • 임의 코드를 애플리케이션에 주입할 수 있음
  • 커스텀 라이브러리를 앱에 로드해 사용하거나 임의 코드를 애플리케이션에 주입해서 실행하는 방식으로 사용

2. Interception

  • 특정 함수 후킹해서 함수의 매개 변수나 반환값 수정 가능
  • 특정 함수 대신 자체적으로 작성한 함수를 동작시키기 위해 함수를 재작성 할 수도 있음

3. Stalking

  • 애플리케이션에서 명령어 레벨의 코드 추적 가능
  • 실행 중인 애플리케이션을 디버깅하고 메모리 내의 데이터를 검색하거나 추출함

Frida Tools

  • Frida는 REPL(Read-Eval-Print Loop) 인터페이스를 지원해서 쉘에서 대화형 인터페이스를 사용할 수 있어 편하다.

frida

  • 앱을 실행하고, 분석하고자 하는 앱을 Frida와 손쉽게 연결 가능
  • 원하는 기능을 수행하는 Frida 스크립트를 작성한 경우 해당 명령어를 통해 애플리케이션에 스크립트를 로드할 수 있음

frida-ps

  • 프로세스 목록 출력

frida-trace

  • 함수 호출 추적

frida-ls-devices

  • 연결된 기기 목록 출력

frida-kill

  • 동작중인 프로세스 종료

공용 옵션

  • 모든 인터페이스에 공용으로 사용하는 옵션

-h, --help : 옵션별 상세 사용법 출력

-U, --usb : USB로 연결된 기기 연결

-D (DEVICE ID) : 가상 기기 연결 (단독 사용 X)

Attach

기기 지정한 다음에 Frida를 부탁할 앱을 명시함

옵션

-F : 현재 기기의 Foreground 프로세스에 frida 연결
-n (package name) : 앱 패키지 이름을 통해 앱에 부착
-p (PID) : 앱의 프로세스 id를 통해 앱에 부착

Spawn

-f (package name) : 앱 실행하고 frida와 연결. 인자로 패키지명 붙이면 패키지 명에 해당하는 앱을 실행할 수 있음
기기에 분석할 앱이 실행되지 않은 경우 이옵션을 사용해 앱을 실행하고 frida와 연결할 수 있음

앱을 spawn 하면 프로세스 시작하고 메인 스레드를 실행하기 전에 일시정지가 되기 때문에 메인 스레드 시작 전에 함수를 후킹 해볼 수 있음.
만약 프로세스 일시정지하지 않고 앱 실행하고 싶으면 --no-pause 옵션 사용

Attach vs Spawn
두 가지 모두 frida와 분석할 앱을 연결하지만 Attach는 이미 실행된 프로세스와 frida를 연결하고 Spawn은 프로세스를 실행시킴과 동시에 frida를 연결함

USB로 연결된 기기에 frida attach

$ frida -U -F
     ____
    / _  |   Frida 15.0.18 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
[iPad::Cydia]->

가상기기에서 캘린더 앱 spawn

$ frida -D emulator-5554 -f com.google.android.calendar --no-pause
     ____
    / _  |   Frida 15.0.18 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
Spawned `com.google.android.calendar`. Resuming main thread!
[Android Emulator 5554::com.google.android.calendar]->

frida

Load Script

-l (script) : frida script 파일을 로드
스크립트 파일 을 통해 frida를 사용해서 수행할 동작 명시해두고 앱과 frida를 attach함과 동시에 스크립트를 실행할 수 있음

frida script 파일 로드

$ echo "console.log(\"script loaded.\");" > script.js
$ frida -U -F -l script.js 
     ____
    / _  |   Frida 15.0.18 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
script loaded.
[iPad::Cydia]->
  • -U 옵션과 -F 옵션 사용해서 USB로 연결된 기기의 foreground로 실행되고 있는 앱에 frida를 attach하고 -l 옵션으로 script.js파일을 로드

frida-trace

함수 호출을 동적으로 추적함. 공용 옵션으로 연결할 기기 지정하고 분석할 앱에 attach 하거나 새롭게 spawn하면서 추적하고자 하는 함수를 지정함

Include / Exclude

모듈에 있는 모든 함수를 추적하거나 추적하고 싶지 않은 경우 사용

-I (MODULE) : include module 지정
-X (MODULE) : exclude module 지정
-i (MODULE!FUNTION) : include function 지정
-x (MODULE!FUNTION) : exclude function 지정
-a (FUNTION!offset) : -i와 마찬가지로 include function을 지정할 수 있지만 offset을 기반으로 동작. 추적을 원하는 함수 명이 부모 모듈에도 선언되어 있으면 -i로 특정할 수 없어서 이 옵션으로 ㅅ함수의 offset을 같이 전달해 함수를 추적함

함수명은 glob pattern 사용해서 나타낼 수 있음
일반적으로 -i (module!function)와 같이 입력해서 사용하지만 glob pattern을 통해 -i "mem*"과 같이 mem 문자열로 시작하는 모든 함수를 추적할 수 있음 (실제 앱 분석시 후자를 자주 사용)

가상 기기의 chrome앱에서 recv 와 send 함수 추적

$ frida-trace -D emulator-5554 -f com.android.chrome -i "recv*" -i "send*"
Instrumenting...
recv: Loaded handler at "/home/user/libc.so/recv.js"
recvfrom: Loaded handler at "/home/user/libc.so/recvfrom.js"
recvmsg: Loaded handler at "/home/user/libc.so/recvmsg.js"
recvmmsg: Loaded handler at "/home/user/libc.so/recvmmsg.js"
sendfile64: Loaded handler at "/home/user/libc.so/sendfile64.js"
sendmmsg: Loaded handler at "/home/user/libc.so/sendmmsg.js"
send: Loaded handler at "/home/user/libc.so/send.js"
sendfile: Loaded handler at "/home/user/libc.so/sendfile.js"
sendmsg: Loaded handler at "/home/user/libc.so/sendmsg.js"
sendto: Loaded handler at "/home/user/libc.so/sendto.js"
Started tracing 10 functions. Press Ctrl+C to stop.
           /* TID 0x7f05 */
  1959 ms  recvfrom() [libc.so]
           /* TID 0x7f38 */
  2059 ms  recvfrom() [libc.so]
  2062 ms  recvfrom() [libc.so]
           /* TID 0x7f05 */
  2085 ms  recvfrom() [libc.so]
  2085 ms  recvfrom() [libc.so]
  2089 ms  recvfrom() [libc.so]
  3569 ms  recvfrom() [libc.so]
  3570 ms  recvfrom() [libc.so]
  3576 ms  recvfrom() [libc.so]
           /* TID 0x7f53 */
  4196 ms  sendmsg() [libc.so]
           /* TID 0x7f05 */
  4211 ms  recvfrom() [libc.so]
  4211 ms  recvfrom() [libc.so]
  4211 ms  recvfrom() [libc.so]
  4212 ms  sendto() [libc.so]
           /* TID 0x7f53 */
  4281 ms  recvmsg() [libc.so]
  ...

Logging

-d, --decorate : 로그에 모듈 이름 함께 기록 가능. 함수 추적할 때 만약 여러 모듈에 같은 이름의 함수가 존재한다면, 어떤 모듈의 함수인지 알기 어려움. 그래서 이 옵션 사용하면 함수를 추적하면서 남기는 로그에 해당 함수가 속한 모듈 이름을 함께 기록해 어떤 모듈의 함수인지 확실히 알 수 있음

Others

-O (TEXT FILE) : 사용할 옵션과 옵션에 대한 매개변수를 파일로 입력할 수 있음. 명령줄이 길면 텍스트 파일에 명령줄 작성해서 -O 옵션 뒤에 파일을 전달하면 명령줄에 입력한 것처럼 동작함

$ frida-trace -U -O additional-options.txt
  • additional-options.txt에는 -f [package name], -i [include module] 등 이후에 입력한 명령줄 작성
-f com.android.chrome --decorate -i "recv*" -i "send*"

가상 기기의 chrome앱에서 recv 와 send 함수 추적

$ frida-trace -D emulator-5554 -O additional-options.txt
Instrumenting...
recv: Loaded handler at "/home/user/libc.so/recv.js"
recvfrom: Loaded handler at "/home/user/libc.so/recvfrom.js"
recvmsg: Loaded handler at "/home/user/libc.so/recvmsg.js"
recvmmsg: Loaded handler at "/home/user/libc.so/recvmmsg.js"
sendfile64: Loaded handler at "/home/user/libc.so/sendfile64.js"
sendmmsg: Loaded handler at "/home/user/libc.so/sendmmsg.js"
send: Loaded handler at "/home/user/libc.so/send.js"
sendfile: Loaded handler at "/home/user/libc.so/sendfile.js"
sendmsg: Loaded handler at "/home/user/libc.so/sendmsg.js"
sendto: Loaded handler at "/home/user/libc.so/sendto.js"
Started tracing 10 functions. Press Ctrl+C to stop.
           /* TID 0x181c */
  2618 ms  recvfrom() [libc.so]
           /* TID 0x184b */
  2767 ms  recvfrom() [libc.so]
  2768 ms  recvfrom() [libc.so]
           /* TID 0x181c */
  2793 ms  recvfrom() [libc.so]
  2794 ms  recvfrom() [libc.so]
  2799 ms  recvfrom() [libc.so]
  4246 ms  recvfrom() [libc.so]
  4246 ms  recvfrom() [libc.so]
           /* TID 0x186d */
  4665 ms  sendmsg() [libc.so]
  4666 ms  recvmsg() [libc.so]
  4667 ms  recvmsg() [libc.so]
  4667 ms  sendmsg() [libc.so]
  4667 ms  sendmsg() [libc.so]
  ...

frida-ls-devices

현재 frida를 연결할 수 있는 기기 목록 출력. 여러 기기를 연결해 두고 Device ID를 기반으로 각각의 기기와 상호작용 할 수 있음

frida-kill

동작중인 프로세스 종료. frida-kill -D [DEVICE-ID][PID]와 같은 형태로 사용. PID는 frida-ps를 통해 확인 가능

Interceptor

특정 함수를 명시하고, 해당 함수가 호출되면 임의의 코드를 실행하고 정보를 조회할 수 있는 기능 제공
동적으로 바이너리를 분석하는 데에 있어 핵심이자 자주 사용하는 객체 중 하나

attach는 콜백을 등록할 수 있으며 콜백 형식은 다음과 같다. 명시한 함수가 호출되면 함수가 실행될 때와 종료될 때의 레지스터와 스택 등을 확인할 수 있으며 임의 코드를 추가로 실행할 수 있다.

onEnter(args) { code } , onLeave(retval) { code }

Interceptor.attach(target, callbacks[, data])

  • target에 해당하는 함수가 호출되면 등록한 콜백에 따라 임의 코드를 실행. 함수의 인자를 조회하거나 조작 등 실행 흐름을 파악할 수 있다.

Interceptor.replace(target, replacement[, data])

target에 해당하는 함수가 호출되면 함수의 기능을 실행하지 않고 미리 정의된 임의 코드를 실행.

Interceptor 사용 예시

var open = Module.findExportByName(null, "open");
Interceptor.attach(open, {
	onEnter(args) {
		console.log("Filename: " + args[0].readCString() + ", " + this.context.rdi.readCString());	// Android
		// console.log("Filename: " + args[0].readCString() + ", " + this.context.x0.readCString());	// iOS
		console.log("flags: " + args[1].toInt32() + ", " + this.context.rsi);	// Android
		// console.log("flags: " + args[1].toInt32() + ", " + this.context.x1);	// iOS
	},
	onLeave(retval) {
		console.log("ret: " + retval);
	}
});
  • open 함수 주소 알아내고 attach 함수의 인자로 전달.
  • open 함수가 실행되면 onEnter 콜백 함수에서 첫번째 인자와 두번째 인자를 출력
  • 인자를 조회하는 방법은 args 배열과 this.context 내 레지스터 이름을 이용하는 방법이 있음
  • 마지막으로 함수가 종료될 때 onLeave 콜백 함수에서 반환값 출력

Backtrace

앱 분석 과정에서 실행 흐름을 동적으로 파악하기 위한 방법. Interceptor를 통해 임의 함수를 후킹하고, Thread.backtrace를 사용하면 함수가 호출되기까지의 과정을 알아낼 수 있다.

Interceptor & Backtrace 사용 예시

var open = Module.findExportByName(null, "open");
Interceptor.attach(open, {
	onEnter(args) {
		console.log('called from:\n' + 
			Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join('\n') + '\n');
	},
	onLeave(retval) {
		console.log("ret: " + retval);
	}
});

Java

Java는 대상 프로세스가 Java VM을 로드해 동작할 때 사용하며, Java와 관련된 기능 제공

함수

Java.perform(fn)

현재 Frida 스레드를 Java VM에 attach 하고, fn 인자로 전달된 함수를 호출합니다. 이 때 fn 함수는 자바 문법이 아닌 자바스크립트 형태의 문법으로 작성되어도 정상적으로 작동합니다.

Java.use(className)

클래스 이름을 인자로 전달받아 해당 클래스를 자바스크립트에서 사용할 수 있도록 Wrapper를 제공합니다. Wrapper를 통해 클래스 내의 메소드를 자유롭게 호출하고, 후킹할 수 있습니다.

Java.choose(className, callbacks)

자바 힙 메모리 내에서 인자로 전달된 클래스가 이미 객체화되어 있는 객체를 찾습니다. callbacks 인자로 전달된 콜백 함수에서 객체를 찾았을 때와 검색이 완료되었을 때의 콜백을 추가할 수 있습니다.

Java.vm

JavaVM 객체를 반환합니다. 일반적으로 JNI 관련 함수를 후킹하기 위해 JNIEnv 구조체의 주소를 얻어올 때 사용합니다. JNIEnv 주소는 Java.vm.getEnv()를 통해 얻을 수 있습니다.

Java 사용 예시

  • Java.use를 통해 클래스를 객체화하고 Toast 메소드를 실행해 알림을 띄움
Java.perform(function() {
    var context = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
    var toast = Java.use("android.widget.Toast");
    toast.makeText(context, Java.use("java.lang.String").$new("Welcome to Dreamhack"), 1).show();
});

Toast 클래스의 makeText 메소드 호출해서 알림창 띄우는 코드 예시

Toast.makeText 문서

$ frida -D emulator-5554 -f com.google.android.calendar --no-pause -l java.js
     ____
    / _  |   Frida 15.0.18 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
Spawned `com.google.android.calendar`. Resuming main thread!
[Android Emulator 5554::com.google.android.calendar]->

ObjC

Object-C 클래스를 로드하는 macOS 또는 iOS앱에서 사용하며 Objective-C와 관련된 정보를 제공

ObjC.availiable

대상 프로세스에 Objective-C 클래스가 로드되었는지 확인하는 기능입니다. 이는 macOS/iOS 앱인지를 판단하는 용도로 사용합니다.

ObjC.api

ObjC 클래스의 메소드를 사용할 수 있도록 주소를 반환합니다.

ObjC.classes

ObjC의 클래스 정보를 모두 반환합니다. 해당 기능을 통해 다양한 함수를 앱 내에서 실행할 수 있습니다.

ObjC.schedule(queue, work)

queue에서 지정한 대기열에 work 자바스크립트 함수를 예약합니다.

ObjC 예시

  • ObjC.classes를 통해 UIKit 프레임워크의 함수 주소를 구한 후 해당 함수의 인자를 설정하고 호출하여 앱 View에 알림창을 띄우는 것을 확인할 수 있다.
var UIAlertView = ObjC.classes['UIAlertView'];
ObjC.schedule(ObjC.mainQueue, function () {
    var view = UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(
        "Dreamhack",
        "Welcome from iOS Frida",
        NULL,
        "OK",
        NULL);
    view.show();
    view.release();
});

ObjC.classes로 가져온 함수에 대한 정보 확인

0개의 댓글