FridaLab 문제 풀이 #2

wisdom·2024년 12월 27일
0

준비

  1. Android Studio + AVD (Pixel 5, API 31, x86_64)
    1. Download Android Studio
  2. frida, frida-server (16.2.1)
    1. https://github.com/frida/frida
  3. Jadx-gui
    1. https://github.com/skylot/jadx
  4. adb
    1. https://developer.android.com/tools/releases/platform-tools?hl=ko
  5. Fridalab.apk
    1. https://rossmarks.uk/blog/fridalab/

문제

❓ Run chall02()

분석

우선 apk 내 chall02() 함수를 찾아보니 MainActivity 내에 존재했고, xrefs 를 찍어 보니 없었음. 따라서 MainActivity에서 호출해주는 코드를 직접 만들어야 함

후킹 코드

1차

Challenge 1 때와 같이 Java.use(MainActivity) 후 onCreate 메소드 내에서 직접 호출을 해주면 되지 않을까 싶었는데 안 됨

import frida, sys

def on_message(message, data):
    if message["type"] == "send":
        print(f"[+] {message['payload']}")
    else:
        print(message)

def hook():
    jscode = """
    Java.perform(function() {
        // 1
        var challenge_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
        challenge_01.getChall01Int.implementation = function() {
            send("challenge_01::getChall01Int called");
            var result = this.getChall01Int();
            send("myMethod returned: " + result);
            send("modified result: 1");
            return 1;
        };

        // 2
        var MainActivity = Java.use("uk.rossmarks.fridalab.MainActivity");
        MainActivity.onCreate.implement = function(v) {
            send("MainActivity::onCreate called");
            this.onCreate();
        }
    });
    """

    process = frida.get_usb_device().attach("FridaLab")
    script = process.create_script(jscode)
    script.on("message", on_message)
    script.load()
    sys.stdin.read()

if __name__ == "__main__":
    hook()

2차

찾아 보니 런타임에 올라가 있는 클래스 인스턴스를 후킹할 때는 Java.use가 아닌 Javs.choose를 사용해야 한다고 함 (https://velog.io/@resur/Java.use-Java.choose-차이)

static 메소드가 아닌 경우 instance 메소드에 해당되고, 이 경우 런타임에 로드 된 인스턴스 자체를 후킹 하는 방식으로만 동작함. Java.use와 Java.choose를 사용할 수 있는 경우를 정리하면 아래와 같음

  • Java.use: 함수에 static 키워드가 붙어 있거나, 아니면 public으로 선언되어 별도 객체 생성 없이도 직접 호출 가능한 경우
  • Java.choose: 함수명에 static 키워드가 붙어 있지 않고, private으 로 선언되어 인스턴스를 통해서만 직접 호출 가능한 경우

Java.use를 사용하면 클래스의 메소드에 직접 접근하여 후킹할 수 있습니다. Frida는 내부적으로 래퍼 객체를 생성하여 메소드 호출을 가로채고 수정할 수 있도록 해줍니다.

하지만 주의해야 할 점은 Java.use를 사용하여 후킹한 메소드는 해당 클래스의 모든 인스턴스에 영향을 줍니다. 즉, 후킹된 메소드는 해당 클래스의 모든 객체에서 동일하게 동작하게 됩니다. 따라서 특정 인스턴스에 대해서만 메소드를 후킹하고 싶다면 Java.choose를 사용하여 해당 인스턴스를 찾아 후킹해야 합니다.

Java.use를 사용한 메소드 후킹은 간단하고 편리하지만, 클래스의 모든 인스턴스에 영향을 줄 수 있다는 점을 고려해야 합니다.

Java.choose 인자는 후킹할 클래스명, 콜백 함수이며 콜백 함수는 onMatch와 onComplete로 구성됨. 여기서 유의해야 할 점은 onMatch, onComplete 모두 정의해 줘야 한다는 것 (onComplete 누락시 에러 발생)

아래 코드를 통해 MainActivity 인스턴스를 후킹하고 chall02() 함수를 직접 호출

import frida, sys

def on_message(message, data):
    if message["type"] == "send":
        print(f"[+] {message['payload']}")
    else:
        print(message)

def hook():
    jscode = """
    Java.perform(function() {
        // 1
        var challenge_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
        challenge_01.getChall01Int.implementation = function() {
            send("challenge_01::getChall01Int called");
            var result = this.getChall01Int();
            send("myMethod returned: " + result);
            send("modified result: 1");
            return 1;
        };

        // 2
        Java.choose("uk.rossmarks.fridalab.MainActivity", {
            onMatch: function(instance) {
                send("Found instance: " + instance);
                send("call MainActivity::chall02");
                instance.chall02();
            },
            onComplete: function() {}
        });
    });
    """

    process = frida.get_usb_device().attach("FridaLab")
    script = process.create_script(jscode)
    script.on("message", on_message)
    script.load()
    sys.stdin.read()

if __name__ == "__main__":
    hook()

실행 결과

참고 사항

아래 코드를 이용해 로드된 모든 클래스를 열거할 수 있음

Java.enumerateLoadedClasses({
    "onMatch" : function(className) {
	    console.log(className)
    },
    "onComplete" : function() {}
});
profile
보안, 개발, 일상을 기록합니다

0개의 댓글