Frida를 설치하기 위해서 python3와 pip이 설치되어있어야 함
AVD에 설치된 앱 분석하기 위해 로컬 호스트에 Frida 클라이언트를 설치함
$ python -m pip install frida-tools
<python3 설치위치>/Scripts
설치가 완료되면 7개의 바이너리가 생성됨.
바이너리가 정상적으로 동작하는지 확인하기 위해 frida-ls-devices 명령 실행해 연결된 모든 기기 정보를 확인한다.
$ frida-ls-devices
Id Type Name
------------- ------ ---------------------
local local Local System
emulator-5554 usb Android Emulator 5554
socket remote Local Socket
adb push frida-server-15.0.18-android-x86_64 /data/local/tmp/
$ 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를 부탁할 앱을 명시함
-F : 현재 기기의 Foreground 프로세스에 frida 연결
-n (package name) : 앱 패키지 이름을 통해 앱에 부착
-p (PID) : 앱의 프로세스 id를 통해 앱에 부착
-f (package name) : 앱 실행하고 frida와 연결. 인자로 패키지명 붙이면 패키지 명에 해당하는 앱을 실행할 수 있음
기기에 분석할 앱이 실행되지 않은 경우 이옵션을 사용해 앱을 실행하고 frida와 연결할 수 있음
앱을 spawn 하면 프로세스 시작하고 메인 스레드를 실행하기 전에 일시정지가 되기 때문에 메인 스레드 시작 전에 함수를 후킹 해볼 수 있음.
만약 프로세스 일시정지하지 않고 앱 실행하고 싶으면 --no-pause 옵션 사용
Attach vs Spawn
두 가지 모두 frida와 분석할 앱을 연결하지만 Attach는 이미 실행된 프로세스와 frida를 연결하고 Spawn은 프로세스를 실행시킴과 동시에 frida를 연결함
$ 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]->
$ 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]->
-l (script) : frida script 파일을 로드
스크립트 파일 을 통해 frida를 사용해서 수행할 동작 명시해두고 앱과 frida를 attach함과 동시에 스크립트를 실행할 수 있음
$ 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]->
함수 호출을 동적으로 추적함. 공용 옵션으로 연결할 기기 지정하고 분석할 앱에 attach 하거나 새롭게 spawn하면서 추적하고자 하는 함수를 지정함
모듈에 있는 모든 함수를 추적하거나 추적하고 싶지 않은 경우 사용
-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 문자열로 시작하는 모든 함수를 추적할 수 있음 (실제 앱 분석시 후자를 자주 사용)
$ 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]
...
-d, --decorate : 로그에 모듈 이름 함께 기록 가능. 함수 추적할 때 만약 여러 모듈에 같은 이름의 함수가 존재한다면, 어떤 모듈의 함수인지 알기 어려움. 그래서 이 옵션 사용하면 함수를 추적하면서 남기는 로그에 해당 함수가 속한 모듈 이름을 함께 기록해 어떤 모듈의 함수인지 확실히 알 수 있음
-O (TEXT FILE) : 사용할 옵션과 옵션에 대한 매개변수를 파일로 입력할 수 있음. 명령줄이 길면 텍스트 파일에 명령줄 작성해서 -O 옵션 뒤에 파일을 전달하면 명령줄에 입력한 것처럼 동작함
$ frida-trace -U -O additional-options.txt
-f com.android.chrome --decorate -i "recv*" -i "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를 연결할 수 있는 기기 목록 출력. 여러 기기를 연결해 두고 Device ID를 기반으로 각각의 기기와 상호작용 할 수 있음
동작중인 프로세스 종료. frida-kill -D [DEVICE-ID][PID]와 같은 형태로 사용. PID는 frida-ps를 통해 확인 가능
특정 함수를 명시하고, 해당 함수가 호출되면 임의의 코드를 실행하고 정보를 조회할 수 있는 기능 제공
동적으로 바이너리를 분석하는 데에 있어 핵심이자 자주 사용하는 객체 중 하나
attach는 콜백을 등록할 수 있으며 콜백 형식은 다음과 같다. 명시한 함수가 호출되면 함수가 실행될 때와 종료될 때의 레지스터와 스택 등을 확인할 수 있으며 임의 코드를 추가로 실행할 수 있다.
onEnter(args) { code } , onLeave(retval) { code }
target에 해당하는 함수가 호출되면 함수의 기능을 실행하지 않고 미리 정의된 임의 코드를 실행.
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);
}
});
앱 분석 과정에서 실행 흐름을 동적으로 파악하기 위한 방법. Interceptor를 통해 임의 함수를 후킹하고, Thread.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 VM을 로드해 동작할 때 사용하며, Java와 관련된 기능 제공
현재 Frida 스레드를 Java VM에 attach 하고, fn 인자로 전달된 함수를 호출합니다. 이 때 fn 함수는 자바 문법이 아닌 자바스크립트 형태의 문법으로 작성되어도 정상적으로 작동합니다.
클래스 이름을 인자로 전달받아 해당 클래스를 자바스크립트에서 사용할 수 있도록 Wrapper를 제공합니다. Wrapper를 통해 클래스 내의 메소드를 자유롭게 호출하고, 후킹할 수 있습니다.
자바 힙 메모리 내에서 인자로 전달된 클래스가 이미 객체화되어 있는 객체를 찾습니다. callbacks 인자로 전달된 콜백 함수에서 객체를 찾았을 때와 검색이 완료되었을 때의 콜백을 추가할 수 있습니다.
JavaVM 객체를 반환합니다. 일반적으로 JNI 관련 함수를 후킹하기 위해 JNIEnv 구조체의 주소를 얻어올 때 사용합니다. JNIEnv 주소는 Java.vm.getEnv()를 통해 얻을 수 있습니다.
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();
});
$ 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]->
Object-C 클래스를 로드하는 macOS 또는 iOS앱에서 사용하며 Objective-C와 관련된 정보를 제공
대상 프로세스에 Objective-C 클래스가 로드되었는지 확인하는 기능입니다. 이는 macOS/iOS 앱인지를 판단하는 용도로 사용합니다.
ObjC 클래스의 메소드를 사용할 수 있도록 주소를 반환합니다.
ObjC의 클래스 정보를 모두 반환합니다. 해당 기능을 통해 다양한 함수를 앱 내에서 실행할 수 있습니다.
queue에서 지정한 대기열에 work 자바스크립트 함수를 예약합니다.
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();
});