FridaLab 문제 풀이 #8

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/

문제

❓ Change ‘check’ button’s text value to ‘Confirm’

분석

MainActivity에서 R.id.check의 text 값이 Confirm과 일치하는지 확인해주는 함수를 호출함

조금 찾아보니 리소스 영역을 직접 바꾸는 것은 불가능하다고 하고, 대신 findViewById로 Button 객체를 불러와서 setText 함수를 호출함으로써 내부 텍스트를 변경해줄 수 있다고 함

관련 기법을 잘 몰라서 검색을 좀 해봤는데 MainActivity 인스턴스에 붙어서 findViewById로 내가 원하는 객체의 핸들러를 가져온 뒤, Java.cast(handle, klass) 함수를 호출하여 자바 클래스로 형변환을 하고, setText 함수를 직접 호출할 수 있나 봄

Java.cast는 주어진 객체를 다른 타입으로 캐스팅하는 데 사용됩니다. 이는 주로 findViewById 같은 메서드로 반환된 View 객체를 더 구체적인 뷰 타입, 예를 들어 Button이나 TextView로 캐스팅할 때 사용됩니다.

R.id.check를 더블클릭 해보면 실제 리소스 ID 값을 확인할 수 있음. 이 숫자 값을 findViewById 인자로 넣어주면 View 객체를 불러올 수 있음

이 View 객체를 Button 으로 캐스팅 하기 위해서는 Jadx-gui에서 import 해주는 부분을 참고하면 됨. String 타입은 import 구문에서 안 보이고 기본적으로 외워두는 것이 좋을 듯 (java.lang.String)

그리고 setText 함수를 호출할 때 바로 문자열을 넘겨주면 안 됨. 인자 또한 Java의 String클래스 타입이어야 함. Java.use(’java.lang.String’).$new(’문자열’); 이렇게 넘겨줘야 문자열 타입으로 인식하고 오류가 안 남

var Button = Java.use('android.widget.Button');
var buttonInstance = Java.cast(viewInstance, Button);
if (buttonInstance !== null) {
    var StringClass = Java.use('java.lang.String');
    buttonInstance.setText(StringClass.$new("Confirm"));
} else {
    console.log("Casting failed.");
}

$new는 Java.use로 불러온 프록시 객체로부터 새로운 인스턴스를 생성해주는 함수라고 함. Java.use와의 정확한 차이점은 아래 GPT의 답변을 참고

Java.useJava.use().$new는 서로 관련이 있지만, 각기 다른 역할을 수행하는 두 가지 주요 기능입니다. 이 두 기능을 이해하려면 Java의 리플렉션과 객체 생성 방식에 대한 기본적인 이해가 필요합니다. 자세히 설명해 드리겠습니다.

Java.use

Java.use는 Frida의 Java 브리지를 통해 특정 Java 클래스에 접근할 수 있게 해주는 함수입니다. 이 함수는 해당 클래스의 메타데이터를 로드하여, 그 클래스의 인스턴스 메서드, 정적 메서드, 필드 등을 사용할 수 있는 프록시 객체를 반환합니다. 이 프록시 객체를 통해 클래스의 메서드를 호출하거나 필드 값을 변경할 수 있습니다.

예제:

javascriptCopy code
var Button = Java.use('android.widget.Button');
Button.setEnabled(true); // 정적 메서드 호출 (가정)

여기서 Buttonandroid.widget.Button 클래스의 모든 메서드와 필드에 접근할 수 있는 프록시 객체입니다.

Java.use().$new

Java.use().$newJava.use로 얻은 프록시 객체를 통해 해당 클래스의 새로운 인스턴스를 생성하는 함수입니다. Java의 new 키워드와 유사하게 작동하며, 클래스의 생성자를 호출하여 객체를 생성합니다. 이 방법은 주로 생성자에 인자가 필요한 경우 또는 새로운 객체 인스턴스가 필요할 때 사용됩니다.

예제:

javascriptCopy code
var StringClass = Java.use('java.lang.String');
var newString = StringClass.$new("Hello, World!"); // 새 String 인스턴스 생성

여기서 newString은 "Hello, World!" 값을 가진 새로운 Java 문자열 객체입니다.

차이점

  • Java.use: 특정 클래스의 정적 구성요소(메서드, 필드)에 접근할 수 있게 해주는 프록시 객체를 반환합니다.
  • Java.use().$new: 해당 클래스의 생성자를 호출하여 새로운 인스턴스를 생성합니다. 생성된 인스턴스를 통해 인스턴스 메서드와 필드에 접근할 수 있습니다.

후킹 코드


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('getChall01Int returned: ' + result);
        send('modified result: 1\n');
        return 1; // Or challenge_01.chall01.value = 1
    };

    // 2, 3, 4, 6, 7, 8
    Java.choose('uk.rossmarks.fridalab.MainActivity', {
        onMatch: function (instance) {
            send('Found instance: ' + instance);

            // 2
            send('call MainActivity::chall02\n');
            instance.chall02();

            // 3
            // instance.chall03.implementation = function () {
            //     send('call MainActivity::chall03');
            //     var result = instance.chall03();
            //     send('chall03 returned: ' + result);
            //     send('modified result: true\n');
            //     return true;
            // }

            // 4
            send('call MainActivity::chall04("frida")\n')
            instance.chall04('frida');

            // 6
            var challenge_06 = Java.use('uk.rossmarks.fridalab.challenge_06');
            challenge_06.confirmChall06.implementation = function (i) {
                send('call callenge_06::confirmChall06 with i: ' + i + '\n');
                send('timeStart: ' + this.timeStart.value);
                send('chall06: ' + this.chall06.value);

                send('call challenge_06:confirmChall06 with i: ' + this.chall06.value + '\n');
                var result = this.confirmChall06(this.chall06.value);
                return result;
            };

            send('sleep 10 seconds');
            // Thread.sleep(10);

            send('call MainActivity::chall06');
            instance.chall06(10000);

            // 7
            var challenge_07 = Java.use('uk.rossmarks.fridalab.challenge_07');
            send('brute force check07Pin');
            for (let index = 1000; index < 10000; index++) {
                var result = challenge_07.check07Pin(index.toString());
                if (result) {
                    send('check07Pin result: ' + index.toString() + '\n');
                    instance.chall07(index.toString());
                }
            }

            // 8
            var checkButtonId = instance.findViewById(0x7f07002f);
            send('checkButton id: ' + checkButtonId);
            var checkButton = Java.cast(checkButtonId, Java.use('android.widget.Button'));
            checkButton.setText(Java.use('java.lang.String').$new('Confirm'));
            send('Change check button text value to Confirm \n');
        },
        onComplete: function () { }
    });

    // 3
    var MainActivity = Java.use('uk.rossmarks.fridalab.MainActivity');
    MainActivity.chall03.implementation = function () {
        send('call MainActivity::chall03');
        var result = this.chall03();
        send('chall03 returned: ' + result);
        send('modified result: true\n');
        return true;
    };

    // 5
    MainActivity.chall05.implementation = function (str) {
        send('call MainActivity::chall05 with str: ' + str);
        send('call MainActivity::chall05 with str: frida\n');
        this.chall05('frida');
    };
});

실행 결과

profile
보안, 개발, 일상을 기록합니다

0개의 댓글