Post

Frida

Frida

1. Advanced Frida Scripting: Controlling App Internals and Data Extraction

The core of Frida lies in its ability to control an app’s behavior at runtime through JavaScript-written scripts. Beyond simple function hooking, let’s explore the various APIs needed to manipulate app memory, access internal objects, and bypass complex business logic.

Key Frida APIs and Usage Examples

  • Java.use() / ObjC.classes: These allow you to access Android (Java/Kotlin) and iOS (Objective-C/Swift) classes to hook methods or create new instances.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    // Android Example: Hooking a method of a specific class
    Java.perform(function () {
        var SomeClass = Java.use('com.example.app.SomeClass');
        SomeClass.someMethod.implementation = function (arg1, arg2) {
            console.log("someMethod Called with: " + arg1 + ", " + arg2);
            // Call the original method and modify the return value
            var ret = this.someMethod(arg1, arg2);
            console.log("someMethod Original Return: " + ret);
            return false; // Example of modifying return value
        };
    });
    
    // iOS Example: Hooking a specific method
    if (ObjC.available) {
        var MyViewController = ObjC.classes.MyViewController;
        var originalImplementation = MyViewController['- (void)viewDidLoad'].implementation;
    
        MyViewController['- (void)viewDidLoad'].implementation = ObjC.implement(
            MyViewController['- (void)viewDidLoad'],
            function (self, _cmd) {
                console.log("viewDidLoad called!");
                // Call the original implementation
                originalImplementation(self, _cmd);
            }
        );
    }
    
  • Interceptor.attach(): This allows direct hooking to a specific memory address (function offset) to intercept native library (C/C++) function calls.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    // Native function hooking example (Android - SSL_read function in libcrypto.so)
    Interceptor.attach(Module.findExportByName('libssl.so', 'SSL_read'), {
        onEnter: function (args) {
            // Log arguments when SSL_read is called
            console.log('SSL_read called!');
            console.log('SSL Object:', args[0]);
            console.log('Buffer Pointer:', args[1]);
            console.log('Length:', args[2].toInt32());
        },
        onLeave: function (retval) {
            // Log when SSL_read returns
            console.log('SSL_read returned:', retval);
        }
    });
    
  • Memory.readByteArray(), Memory.writeByteArray(): Used to read or write data from an app’s memory. This is useful for finding sensitive information (API keys, user data) that exists in plaintext in memory, or for dynamically altering app behavior.

    1
    2
    3
    4
    
    // Memory read example
    var secretKeyPtr = ptr('0x12345678'); // Expected address where the actual key might be
    var secretKey = Memory.readByteArray(secretKeyPtr, 32); // Read 32 bytes
    console.log("Secret Key:", hexdump(secretKey));
    
  • send() / recv(): These enable communication between the Frida script and the client (e.g., Python). This is useful for processing complex data or dynamically controlling script behavior from the client.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    // Sending data from Frida script to Python
    var sensitiveData = "This is sensitive!";
    send(sensitiveData);
    
    // Receiving data in Python client
    # script.on('message', on_message)
    # def on_message(message, data):
    #     print(message)
    #     if message['type'] == 'send':
    #         print("Received from script:", message['payload'])
    

Tips for Effective Script Writing

  • Java.perform() / ObjC.perform(): Ensure that JavaScript code runs safely in Android/iOS environments. Always write platform-specific code within these blocks.
  • Error Handling and Logging: Use try...catch blocks to handle potential errors during script execution, and actively use console.log() to output debugging information.
  • Modularization: If your script becomes complex, it’s good practice to separate functionality into multiple files and manage them using require().

2. Real-World Mobile Penetration Testing Scenarios: Utilizing Frida

Now, let’s look at specific scenarios to understand how Frida can be used in real-world mobile penetration testing.

Overview of Frida Execution Commands

The most common way to execute Frida scripts is by using the frida CLI tool. The basic syntax is as follows:

1
frida [OPTIONS] TARGET

Here, TARGET can be an app’s package name, Process ID (PID), or app name. OPTIONS control aspects like specifying the script file or connecting to a USB device.

The most frequently used execution commands are:

  • Injecting a script into a specific app (before/after app launch):

    • Attaching after app launch (USB connected device):

      1
      
      frida -U -l your_script.js -f com.example.app --no-pause
      

      -U: Connects to a USB-connected device. -l your_script.js: Loads and executes the your_script.js file. -f com.example.app: Launches the app with the package name com.example.app and attaches to it. (If already running, it attaches to that process.) --no-pause: Ensures the script is injected immediately without pausing the app at startup.

    • Attaching to an already running app (USB connected device):

      1
      
      frida -U -l your_script.js com.example.app
      

      Or, if using a PID:

      1
      
      frida -U -l your_script.js <PID>
      

      You can use frida-ps -Ua or frida-ps -Uai to list running apps and find their PIDs or package names.

  • Executing a script directly from the prompt (interactive mode):

    1
    
    frida -U com.example.app
    

    Executing this command connects to the Frida shell, where you can directly input and test JavaScript code.


Scenario 1: SSL Unpinning (Bypassing Certificate Pinning)

Many mobile apps implement SSL Pinning to prevent Man-in-the-Middle (MITM) attacks. This is a security mechanism that forces the app to trust only specific server certificates or public keys. Frida can bypass this validation logic at runtime, allowing you to intercept traffic with proxy tools like Burp Suite.

  • Android: Hook the certificate validation methods of SSL/TLS libraries used by the app, such as okhttp3, TlsX509ExtendedTrustManager, or WebViewClient, to always return true.

    1
    2
    3
    4
    5
    6
    7
    8
    
    // OkHttp3 SSL Pinning Bypass Example (your_ssl_unpinning_script.js)
    Java.perform(function () {
        var CertificatePinner = Java.use('okhttp3.CertificatePinner');
        CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function () {
            console.log('CertificatePinner.check bypassed!');
            return; // Skip validation logic
        };
    });
    

    Execution command example:

    1
    
    frida -U -l your_ssl_unpinning_script.js -f com.example.app --no-pause
    
  • iOS: Hook delegate methods of networking libraries like NSURLSession or AFNetworking (URLSession:didReceiveChallenge:completionHandler:) to ignore certificate validation.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    // iOS SSL Pinning Bypass Example (simplified) (your_ios_ssl_unpinning_script.js)
    if (ObjC.available) {
        try {
            var pinneDelegate = ObjC.classes.YOUR_APP_SSLPINNING_DELEGATE_CLASS; // Actual delegate class name of the app
            if (pinneDelegate) {
                var method = pinneDelegate['- (void)URLSession:(id)session didReceiveChallenge:(id)challenge completionHandler:(id)completionHandler'];
                Interceptor.attach(method.implementation, {
                    onEnter: function (args) {
                        var completionHandler = new ObjC.Block(args[3]);
                        completionHandler.call(0, 1); // NSURLSessionAuthChallengeUseCredential
                        this.completionHandler = completionHandler;
                        // Prevent original method call
                    },
                    onLeave: function (retval) {
                        // Post-processing if needed
                    }
                });
            }
        } catch (e) {
            console.log("SSL Pinning Bypass error: " + e);
        }
    }
    

    Execution command example:

    1
    
    frida -U -l your_ios_ssl_unpinning_script.js -f com.example.app --no-pause
    

Scenario 2: API Call Hooking and Manipulation

When an app makes a specific API call, you can modify the arguments sent or manipulate the returned values to bypass the app’s business logic. For example, you can attempt to activate premium features, bypass payments, or escalate user privileges.

  • Hooking loginUser(username, password) function: Hook the login function to force a login with specific credentials or always return a successful response.
  • Hooking checkPremiumStatus() function: Change this function to always return true to enable premium features.
    1
    2
    3
    4
    5
    6
    7
    8
    
    // Android Example: Premium Feature Bypass (premium_bypass.js)
    Java.perform(function () {
        var FeatureChecker = Java.use('com.example.app.FeatureChecker');
        FeatureChecker.isPremiumUser.implementation = function () {
            console.log("isPremiumUser bypassed!");
            return true; // Always return true
        };
    });
    

    Execution command example:

    1
    
    frida -U -l premium_bypass.js com.example.app
    

Scenario 3: Bypassing Root/Jailbreak Detection

Many mobile apps check if the device is rooted (Android) or jailbroken (iOS) for security purposes. Frida can hook these detection logics to prevent the app from realizing the rooted/jailbroken state.

  • Hooking file existence checks: Hook File.exists() or -[NSFileManager fileExistsAtPath:] methods that check for the existence of root/jailbreak indicator files like /system/bin/su or /Applications/Cydia.app to always return false.
  • Hooking specific library loads: Detect and block the loading of libraries used for root/jailbreak detection (e.g., libsubstrate.dylib).

3. Tips and Troubleshooting

Here are some tips for using Frida effectively and solutions for common problems you might encounter.

Useful Tips

  • Utilize frida-trace: This is useful for quickly tracing calls to specific functions or classes. For example, you can use frida-trace -U -f com.example.app -i "recvfrom" to trace calls to the recvfrom function.
  • Check processes with frida-ps: Use this to check currently running processes and the list of apps that Frida can connect to, which helps in identifying the correct package name/Process ID.
    1
    2
    3
    
    frida-ps -Ua # Lists all running apps on a USB-connected device
    frida-ps -Uai # Lists all installed apps (including bundle IDs) on a USB-connected device
    frida-ps -Ups # Lists all processes on a USB-connected device
    
  • Prevent script caching: If your script modifications aren’t taking effect, try using the frida -f <app_package> -l script.js --no-pause option, or consider restarting the Frida server to clear caches.
  • Check device logs: If the app crashes or your Frida script doesn’t work as expected, check detailed error logs using logcat on Android or Console.app on iOS.

Common Problems and Solutions

  • “Failed to attach: unable to find process”: Verify that the app’s package name or Process ID is correct. Ensure the app is running or in the background.
  • “Access denied” or “Permission denied”: Check if the Frida server is running with appropriate permissions. On rooted/jailbroken devices, you might need to run the Frida server with su privileges.
  • Script not loading or not working:
    • Syntax errors: Check your JavaScript script for any syntax errors.
    • Timing issues: The app might call a specific function before the Frida script is loaded, causing hooking to fail. You can try delaying the hooking time using setImmediate() or setTimeout(), or injecting the script before the app fully starts using the frida -f ... --no-pause option.
    • Class/method name errors: Confirm that the class or method name you are trying to hook is accurate. You may need to use reflection or decompilers (like Jadx, Ghidra, etc.) to determine the correct names.
  • Anti-Frida/Anti-debugging detection: Some apps can detect Frida’s presence and terminate or behave differently. In such cases, you will need to write a script that bypasses Frida’s detection logic (e.g., checks for specific files, listening ports, etc.).

Conclusion

Frida is a powerful and flexible tool that can significantly enhance the efficiency of mobile penetration testing. Through the advanced scripting, real-world scenarios, and essential execution commands covered in this article, you’ll be able to understand app internals more deeply and effectively discover various security vulnerabilities using Frida.

As Frida is a constantly evolving tool, it’s crucial to regularly check the official documentation (https://frida.re/docs/) and refer to various scripting examples to improve your skills.

Is there any specific scenario or Frida feature you’d like to delve into further? Feel free to let me know!


1. Frida 스크립팅 심화: 앱 내부 제어 및 데이터 추출

Frida의 핵심은 JavaScript로 작성된 스크립트를 통해 런타임에 앱의 동작을 제어하는 능력입니다. 단순한 함수 후킹을 넘어, 앱의 메모리를 조작하고, 내부 객체에 접근하며, 복잡한 비즈니스 로직을 우회하는 데 필요한 다양한 API들을 알아봅시다.

주요 Frida API 및 활용 예시

  • Java.use() / ObjC.classes: Android(Java/Kotlin) 및 iOS(Objective-C/Swift) 클래스에 접근하여 메소드를 후킹하거나 새로운 인스턴스를 생성할 수 있습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    // Android 예시: 특정 클래스의 메소드 후킹
    Java.perform(function () {
        var SomeClass = Java.use('com.example.app.SomeClass');
        SomeClass.someMethod.implementation = function (arg1, arg2) {
            console.log("someMethod Called with: " + arg1 + ", " + arg2);
            // 원본 메소드 호출 및 반환 값 변경
            var ret = this.someMethod(arg1, arg2);
            console.log("someMethod Original Return: " + ret);
            return false; // 반환 값 변경 예시
        };
    });
    
    // iOS 예시: 특정 메소드 후킹
    if (ObjC.available) {
        var MyViewController = ObjC.classes.MyViewController;
        var originalImplementation = MyViewController['- (void)viewDidLoad'].implementation;
    
        MyViewController['- (void)viewDidLoad'].implementation = ObjC.implement(
            MyViewController['- (void)viewDidLoad'],
            function (self, _cmd) {
                console.log("viewDidLoad called!");
                // 원본 구현 호출
                originalImplementation(self, _cmd);
            }
        );
    }
    
  • Interceptor.attach(): 특정 메모리 주소(함수 오프셋)에 직접 후킹하여 네이티브 라이브러리(C/C++) 함수 호출을 가로챕니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    // 네이티브 함수 후킹 예시 (Android - libcrypto.so의 SSL_read 함수)
    Interceptor.attach(Module.findExportByName('libssl.so', 'SSL_read'), {
        onEnter: function (args) {
            // SSL_read 호출 시 인자 로깅
            console.log('SSL_read called!');
            console.log('SSL Object:', args[0]);
            console.log('Buffer Pointer:', args[1]);
            console.log('Length:', args[2].toInt32());
        },
        onLeave: function (retval) {
            // SSL_read 반환 시 로깅
            console.log('SSL_read returned:', retval);
        }
    });
    
  • Memory.readByteArray(), Memory.writeByteArray(): 앱의 메모리에서 데이터를 읽거나 쓰는 데 사용됩니다. 이는 민감한 정보(API 키, 사용자 데이터)가 메모리에 평문으로 존재하는 경우를 찾거나, 앱의 동작을 동적으로 변경하는 데 유용합니다.

    1
    2
    3
    4
    
    // 메모리 읽기 예시
    var secretKeyPtr = ptr('0x12345678'); // 실제 키가 있을 것으로 예상되는 주소
    var secretKey = Memory.readByteArray(secretKeyPtr, 32); // 32바이트 읽기
    console.log("Secret Key:", hexdump(secretKey));
    
  • send() / recv(): Frida 스크립트와 클라이언트(Python 등) 간에 데이터를 주고받을 수 있게 합니다. 복잡한 데이터를 처리하거나, 클라이언트에서 동적으로 스크립트의 동작을 제어할 때 유용합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    // Frida 스크립트에서 Python으로 데이터 전송
    var sensitiveData = "This is sensitive!";
    send(sensitiveData);
    
    // Python 클라이언트에서 데이터 수신
    # script.on('message', on_message)
    # def on_message(message, data):
    #     print(message)
    #     if message['type'] == 'send':
    #         print("Received from script:", message['payload'])
    

효과적인 스크립트 작성을 위한 팁

  • Java.perform() / ObjC.perform(): Android/iOS 환경에서 JavaScript 코드가 안전하게 실행되도록 보장합니다. 항상 이 블록 내에서 플랫폼 관련 코드를 작성하세요.
  • 오류 처리 및 로깅: try...catch 블록을 사용하여 스크립트 실행 중 발생할 수 있는 오류를 처리하고, console.log()를 적극적으로 사용하여 디버깅 정보를 출력하세요.
  • 모듈화: 스크립트가 복잡해지면 기능을 분리하여 여러 파일로 나누고 require()를 사용하여 관리하면 좋습니다.

2. 실제 모바일 펜테스팅 시나리오: Frida 활용

이제 Frida가 실제 모바일 펜테스팅에서 어떻게 활용될 수 있는지 구체적인 시나리오를 통해 살펴보겠습니다.

Frida 실행 커맨드 개요

Frida 스크립트를 실행하는 가장 일반적인 방법은 frida CLI 툴을 사용하는 것입니다. 기본 문법은 다음과 같습니다:

1
frida [OPTIONS] TARGET

여기서 TARGET은 앱의 패키지 이름, 프로세스 ID (PID), 또는 앱 이름이 될 수 있습니다. OPTIONS는 스크립트 파일 지정, USB 장치 연결 등을 제어합니다.

가장 흔히 사용되는 실행 커맨드는 다음과 같습니다:

  • 특정 앱에 스크립트 주입 (앱 실행 전/후):

    • 앱 실행 후 연결 (USB 연결 장치):

      1
      
      frida -U -l your_script.js -f com.example.app --no-pause
      

      -U: USB로 연결된 장치에 연결합니다. -l your_script.js: your_script.js 파일을 로드하여 실행합니다. -f com.example.app: com.example.app 패키지 이름을 가진 앱을 실행하고 연결합니다. (만약 이미 실행 중이면 해당 프로세스에 연결) --no-pause: 앱이 시작될 때 일시 중지되지 않고 즉시 스크립트가 주입되도록 합니다.

    • 이미 실행 중인 앱에 연결 (USB 연결 장치):

      1
      
      frida -U -l your_script.js com.example.app
      

      또는 PID를 사용하는 경우:

      1
      
      frida -U -l your_script.js <PID>
      

      frida -Ua 또는 frida -Uai를 사용하여 실행 중인 앱 목록을 확인하고 PID나 패키지 이름을 찾을 수 있습니다.

  • 프롬프트에서 직접 스크립트 실행 (대화형 모드):

    1
    
    frida -U com.example.app
    

    이 커맨드를 실행하면 Frida 셸에 접속하여 직접 JavaScript 코드를 입력하고 테스트할 수 있습니다.


시나리오 1: SSL Unpinning (인증서 고정 우회)

많은 모바일 앱은 중간자 공격(MITM)을 방지하기 위해 SSL Pinning을 구현합니다. 이는 앱이 특정 서버 인증서 또는 공개 키만 신뢰하도록 강제하는 보안 메커니즘입니다. Frida는 런타임에 이 검증 로직을 우회하여 Burp Suite와 같은 프록시 도구로 트래픽을 가로챌 수 있게 합니다.

  • Android: okhttp3, TlsX509ExtendedTrustManager, WebViewClient 등 앱에서 사용하는 SSL/TLS 라이브러리의 인증서 검증 메소드를 후킹하여 항상 true를 반환하도록 만듭니다.

    1
    2
    3
    4
    5
    6
    7
    8
    
    // OkHttp3 SSL Pinning 우회 예시 (your_ssl_unpinning_script.js)
    Java.perform(function () {
        var CertificatePinner = Java.use('okhttp3.CertificatePinner');
        CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function () {
            console.log('CertificatePinner.check bypassed!');
            return; // 검증 로직을 건너뜀
        };
    });
    

    실행 커맨드 예시:

    1
    
    frida -U -l your_ssl_unpinning_script.js -f com.example.app --no-pause
    
  • iOS: NSURLSession 또는 AFNetworking 등 네트워킹 라이브러리의 델리게이트 메소드(URLSession:didReceiveChallenge:completionHandler:)를 후킹하여 인증서 유효성 검사를 무시합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    // iOS SSL Pinning 우회 예시 (간단화) (your_ios_ssl_unpinning_script.js)
    if (ObjC.available) {
        try {
            var pinneDelegate = ObjC.classes.YOUR_APP_SSLPINNING_DELEGATE_CLASS; // 앱의 실제 델리게이트 클래스 이름
            if (pinneDelegate) {
                var method = pinneDelegate['- (void)URLSession:(id)session didReceiveChallenge:(id)challenge completionHandler:(id)completionHandler'];
                Interceptor.attach(method.implementation, {
                    onEnter: function (args) {
                        var completionHandler = new ObjC.Block(args[3]);
                        completionHandler.call(0, 1); // NSURLSessionAuthChallengeUseCredential
                        this.completionHandler = completionHandler;
                        // 원본 메소드 호출 방지
                    },
                    onLeave: function (retval) {
                        // 필요시 후처리
                    }
                });
            }
        } catch (e) {
            console.log("SSL Pinning Bypass error: " + e);
        }
    }
    

    실행 커맨드 예시:

    1
    
    frida -U -l your_ios_ssl_unpinning_script.js -f com.example.app --no-pause
    

시나리오 2: API 호출 후킹 및 변조

앱이 특정 API를 호출할 때, 전송되는 인자 값을 변경하거나 반환되는 값을 조작하여 앱의 비즈니스 로직을 우회할 수 있습니다. 예를 들어, 프리미엄 기능 활성화 로직, 결제 우회, 또는 사용자 권한 상승 등을 시도할 수 있습니다.

  • loginUser(username, password) 함수 후킹: 로그인 함수를 후킹하여 특정 사용자 이름과 비밀번호로 강제 로그인하거나, 항상 성공적인 응답을 반환하도록 조작합니다.
  • checkPremiumStatus() 함수 후킹: 이 함수가 항상 true를 반환하도록 변경하여 프리미엄 기능을 활성화시킬 수 있습니다.
    1
    2
    3
    4
    5
    6
    7
    8
    
    // Android 예시: 프리미엄 기능 체크 우회 (premium_bypass.js)
    Java.perform(function () {
        var FeatureChecker = Java.use('com.example.app.FeatureChecker');
        FeatureChecker.isPremiumUser.implementation = function () {
            console.log("isPremiumUser bypassed!");
            return true; // 항상 true 반환
        };
    });
    

    실행 커맨드 예시:

    1
    
    frida -U -l premium_bypass.js com.example.app
    

시나리오 3: 루팅/탈옥 감지 우회

많은 모바일 앱은 보안을 위해 기기가 루팅(Android)되거나 탈옥(iOS)되었는지 확인합니다. Frida는 이러한 감지 로직을 후킹하여 앱이 루팅/탈옥 상태를 인지하지 못하도록 할 수 있습니다.

  • 파일 존재 여부 확인 후킹: /system/bin/su, /Applications/Cydia.app 등 루팅/탈옥 흔적 파일의 존재를 확인하는 File.exists() 또는 -[NSFileManager fileExistsAtPath:] 메소드를 후킹하여 항상 false를 반환하도록 합니다.
  • 특정 라이브러리 로드 후킹: 루팅/탈옥 감지에 사용되는 라이브러리(libsubstrate.dylib 등)의 로드를 감지하고 차단합니다.

3. 팁 및 트러블슈팅

Frida를 효과적으로 사용하기 위한 몇 가지 팁과 흔히 발생할 수 있는 문제에 대한 해결책입니다.

유용한 팁

  • frida-trace 활용: 특정 함수나 클래스의 호출을 빠르게 추적하고 싶을 때 유용합니다. frida-trace -U -f com.example.app -i "recvfrom"과 같이 사용하여 recvfrom 함수의 호출을 추적할 수 있습니다.
  • frida-ps로 프로세스 확인: 현재 실행 중인 프로세스와 Frida에 연결할 수 있는 앱 목록을 확인하여 정확한 패키지 이름/프로세스 ID를 파악하는 데 도움이 됩니다.
    1
    2
    3
    
    frida-ps -Ua # USB 연결 장치의 모든 앱 목록
    frida-ps -Uai # USB 연결 장치의 모든 설치된 앱 목록 (bundle ID 포함)
    frida-ps -Ups # USB 연결 장치의 모든 프로세스 목록
    
  • 스크립트 캐싱 방지: 스크립트를 수정했는데 적용되지 않는다면, frida -f <app_package> -l script.js --no-pause 옵션을 사용하거나, 캐시 문제를 고려하여 Frida 서버를 재시작해 볼 수 있습니다.
  • 장치 로그 확인: 앱이 크래시되거나 Frida 스크립트가 예상대로 작동하지 않을 때, Android의 logcat이나 iOS의 Console.app을 통해 자세한 오류 로그를 확인하세요.

흔한 문제 및 해결 방법

  • “Failed to attach: unable to find process”: 앱의 패키지 이름 또는 프로세스 ID가 정확한지 확인하세요. 앱이 실행 중이거나 백그라운드에 있는지 확인해야 합니다.
  • “Access denied” 또는 “Permission denied”: Frida 서버가 적절한 권한으로 실행되고 있는지 확인하세요. 루팅/탈옥된 기기에서는 su 권한으로 Frida 서버를 실행해야 할 수 있습니다.
  • 스크립트가 로드되지 않거나 작동하지 않음:
    • 문법 오류: JavaScript 스크립트에 문법 오류가 없는지 확인하세요.
    • 타이밍 문제: 앱이 Frida 스크립트가 로드되기 전에 특정 함수를 호출하여 후킹이 실패할 수 있습니다. setImmediate()setTimeout()을 사용하여 후킹 시점을 늦추거나, frida -f ... --no-pause 옵션을 사용하여 앱이 실행되기 전에 스크립트를 주입하도록 시도할 수 있습니다.
    • 클래스/메소드 이름 오류: 후킹하려는 클래스나 메소드 이름이 정확한지 확인하세요. 리플렉션이나 디컴파일러(Jadx, Ghidra 등)를 사용하여 정확한 이름을 파악해야 합니다.
  • 안티-Frida/안티-디버깅 탐지: 일부 앱은 Frida의 존재를 감지하고 종료되거나 다르게 동작할 수 있습니다. 이 경우, Frida의 감지 로직(예: 특정 파일 존재 여부, 포트 리스닝 여부 등)을 우회하는 스크립트를 작성해야 합니다.

결론

Frida는 모바일 펜테스팅의 효율성을 극대화할 수 있는 강력하고 유연한 도구입니다. 이 글에서 다룬 스크립팅 심화 내용과 실제 시나리오, 그리고 핵심적인 실행 커맨드를 통해, 여러분은 앱의 내부 동작을 더 깊이 이해하고 다양한 보안 취약점을 발견하는 데 Frida를 효과적으로 활용할 수 있을 것입니다.

Frida는 계속 발전하는 도구이므로, 공식 문서(https://frida.re/docs/)를를) 주기적으로 확인하고 다양한 스크립팅 예제를 참고하며 실력을 향상시키는 것이 중요합니다.

혹시 더 자세히 다루고 싶은 특정 시나리오나 Frida 기능이 있으신가요? 언제든지 말씀해주세요!

This post is licensed under CC BY 4.0 by the author.