본문으로 바로가기

가. Frida Python Binding 이란?

- 프로그래밍에서 "바인딩(binding)"은 특정 리소스나 기능을 서로 연결하거나 연동시키는 것을 의미한다.

- 즉, Frida Python Binding은 Python 코드로 Frida의 기능을 사용할 수 있도록 해주는 것을 뜻한다.

- Frida Script를 통해 후킹된 데이터를 Python으로 즉시 분석하는 등의 장점이 있다.

 

나. Binding 방법

※ 모바일 디바이스에서 프리다 서버가 동작하고 있어야 한다.

1. App 실행 후 Frida Script 실행 방법

- App이 실행중인 상태에서 스크립트를 실행하고 싶을때 사용하는 방법이다.

 

1-1. 코드 양식

import frida
import sys

# 패키지 이름
PACKAGE_NAME = "com.your.package.name"

# 삽입할 JavaScript 코드
jscode = """
Interceptor.attach(Module.findExportByName(null, 'target_function'), {
    onEnter: function (args) {
        console.log('Function called with argument: ' + args[0].toInt32());
    }
});
"""

# 메시지 핸들러
def on_message(message, data):
    if message['type'] == 'send':
        print("[*] Message from script:", message['payload'])
    elif message['type'] == 'error':
        print("[!] Error in script:", message['stack'])

try:
    # USB 장치에 연결
    print("[*] Connecting to device...")
    device = frida.get_usb_device(timeout=5)

    # 실행 중인 프로세스 ID 가져오기
    print(f"[*] Finding the process for package: {PACKAGE_NAME}")
    processes = device.enumerate_processes()
    pid = next((p.pid for p in processes if p.name == PACKAGE_NAME), None)

	# 실행 중인 프로세스가 없다면 종료
    if pid is None:
        print(f"[!] Could not find a running process for package: {PACKAGE_NAME}")
        sys.exit(1)

    print(f"[*] Found process: {PACKAGE_NAME} (pid: {pid})")

    # 프로세스에 세션 연결
    print("[*] Attaching to the running process...")
    session = device.attach(pid)

    # JavaScript 코드 로드
    print("[*] Creating and loading the script...")
    script = session.create_script(jscode)
    script.on('message', on_message)  # 메시지 핸들러 설정
    script.load()

    # 후킹 스크립트 실행 유지, 엔터를 누를 시 종료
    print("[*] Hook is running. Press Enter to exit.")
    input()

except frida.ServerNotRunningError:
    print("[!] Frida server is not running. Please start the Frida server on your device.")
except frida.TransportError:
    print("[!] Unable to connect to the device. Check your USB connection and adb status.")
except Exception as e:
    print(f"[!] Unexpected error: {e}")

 

1-2. 활용 예시

- 아래 예시는 OWASP UnCrackable L1 App의 Secret String을 찾기위한 코드이다.

- 'PACKAGE_NAME'은 frida-ps -Ua 명령어를 쳐서 찾는다. 

 

- 위에서 찾은 프로세스 이름과 프리다 코드를 입력하여 실행한다.

import frida
import sys

# 패키지 이름
PACKAGE_NAME = "Uncrackable1"

# 삽입할 JavaScript 코드
jscode = """
setImmediate(function(){
    Java.perform(function(){
        var class_a = Java.use("sg.vantagepoint.a.a");
        class_a.a.implementation = function (arg1, arg2){ 
            var findCode = this.a(arg1, arg2);
            var secret = "";
            for (var i=0; i<findCode.length; i++){
                secret = secret + String.fromCharCode(findCode[i]);
            }
            console.log("[+] SecretKey : " + secret);
            return findCode;
        }
    })
})
"""

# 메시지 핸들러
def on_message(message, data):
    if message['type'] == 'send':
        print("[*] Message from script:", message['payload'])
    elif message['type'] == 'error':
        print("[!] Error in script:", message['stack'])

try:
    # USB 장치에 연결
    print("[*] Connecting to device...")
    device = frida.get_usb_device(timeout=5)

    # 실행 중인 프로세스 ID 가져오기
    print(f"[*] Finding the process for package: {PACKAGE_NAME}")
    processes = device.enumerate_processes()
    pid = next((p.pid for p in processes if p.name == PACKAGE_NAME), None)

	# 실행 중인 프로세스가 없다면 종료
    if pid is None:
        print(f"[!] Could not find a running process for package: {PACKAGE_NAME}")
        sys.exit(1)

    print(f"[*] Found process: {PACKAGE_NAME} (pid: {pid})")

    # 프로세스에 세션 연결
    print("[*] Attaching to the running process...")
    session = device.attach(pid)

    # JavaScript 코드 로드
    print("[*] Creating and loading the script...")
    script = session.create_script(jscode)
    script.on('message', on_message)  # 메시지 핸들러 설정
    script.load()

    # 후킹 스크립트 실행 유지, 엔터 입력시 종료
    print("[*] Hook is running. Press Enter to exit.")
    input()

except frida.ServerNotRunningError:
    print("[!] Frida server is not running. Please start the Frida server on your device.")
except frida.TransportError:
    print("[!] Unable to connect to the device. Check your USB connection and adb status.")
except Exception as e:
    print(f"[!] Unexpected error: {e}")

 

- 아래와 같은 실행결과가 출력된다.

 

 

2. App 실행 전 Frida Script 실행 방법

- 보안 기능을 우회하여야 App을 실행할 수 있을때 사용하는 방법이다.

 

2-1. 코드 양식

import frida
import sys
import time

# 패키지 이름 설정
PACKAGE_NAME = "com.your.package.name"

# 삽입할 JavaScript 코드
jscode = """
javascript_code
"""

# 메시지 콜백 함수 정의
def on_message(message, data):
    if message['type'] == 'send':
        print("[*] Message from script:", message['payload'])
    elif message['type'] == 'error':
        print("[!] Error in script:", message['stack'])

try:
    # USB 장치 연결
    print("[*] Connecting to device...")
    device = frida.get_usb_device(timeout=5)
    
    # 프로세스 생성 및 일시 정지
    print(f"[*] Spawning process for package: {PACKAGE_NAME}")
    pid = device.spawn([PACKAGE_NAME])
    
    # 프로세스에 세션 연결
    print("[*] Attaching to the spawned process...")
    session = device.attach(pid)
    
    # JavaScript 코드 로드
    print("[*] Creating and loading the script...")
    script = session.create_script(jscode)
    script.on('message', on_message)  # 메시지 핸들러 설정
    script.load()
    
    # JavaScript 코드가 로드될때까지 대기
    print("[*] Waiting for the script to load...")
    time.sleep(1)

    # 프로세스 실행 재개
    print("[*] Resuming the process...")
    device.resume(pid)

    # 후킹 스크립트 실행 유지
    print("[*] Hook is running. Press Enter to exit.")
    input()

except frida.ServerNotRunningError:
    print("[!] Frida server is not running. Please start the Frida server on your device.")
except frida.TransportError:
    print("[!] Unable to connect to the device. Check your USB connection and adb status.")
except Exception as e:
    print(f"[!] Unexpected error: {e}")

 

2-2. 활용 예시

- 아래는 OWASP UnCrackable L1 App의 Rooting 탐지 우회 기능을 수행하기 위한 코드이다.

import frida
import sys
import time

# 패키지 이름 설정
PACKAGE_NAME = "owasp.mstg.uncrackable1"

# 삽입할 JavaScript 코드
jscode = """
setImmediate(function(){
    if (Java.available) {
        Java.perform(function () {
            try {
                var c_class = Java.use("sg.vantagepoint.a.c");
                c_class.a.implementation = function () {
                    console.log("[+] 루팅탐지 a 메소드 반환값 FALSE로 변조 완료");
                    return false;
                }

                c_class.b.implementation = function () {
                    console.log("[+] 루팅탐지 b 메소드 반환값 FALSE로 변조 완료");
                    return false;
                };

                c_class.c.implementation = function () {
                    console.log("[+] 루팅탐지 b 메소드 반환값 FALSE로 변조 완료");
                    return false;
                };

                var b_class = Java.use("sg.vantagepoint.a.b");
                b_class.a.implementation = function (context) {
                    console.log("[+] 디버그 탐지 a 메소드 반환값 FALSE로 변조 완료");
                    return false;
                };
            }
            catch (error) {
                console.log("[-] 아래와 같은 오류가 발생함");
                console.log(string(error.stack));
            }
        });
    }
    else {
        console.log("[-] Java가 활성화되지 않음");
    }
})
"""

# 메시지 콜백 함수 정의
def on_message(message, data):
    if message['type'] == 'send':
        print("[*] Message from script:", message['payload'])
    elif message['type'] == 'error':
        print("[!] Error in script:", message['stack'])

try:
    # USB 장치 연결
    print("[*] Connecting to device...")
    device = frida.get_usb_device(timeout=5)
    
    # 프로세스 생성 및 일시 정지
    print(f"[*] Spawning process for package: {PACKAGE_NAME}")
    pid = device.spawn([PACKAGE_NAME])
    
    # 프로세스에 세션 연결
    print("[*] Attaching to the spawned process...")
    session = device.attach(pid)
    
    # JavaScript 코드 로드
    print("[*] Creating and loading the script...")
    script = session.create_script(jscode)
    script.on('message', on_message)  # 메시지 핸들러 설정
    script.load()
    
    # JavaScript 코드가 로드될때까지 대기
    print("[*] Waiting for the script to load...")
    time.sleep(1)

    # 프로세스 실행 재개
    print("[*] Resuming the process...")
    device.resume(pid)

    # 후킹 스크립트 실행 유지
    print("[*] Hook is running. Press Enter to exit.")
    input()

except frida.ServerNotRunningError:
    print("[!] Frida server is not running. Please start the Frida server on your device.")
except frida.TransportError:
    print("[!] Unable to connect to the device. Check your USB connection and adb status.")
except Exception as e:
    print(f"[!] Unexpected error: {e}")

 

- 실행 결과