FridaLab 문제 풀이 #6

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 call06() after 10 seconds with correct value

분석

우선 challenge_06 클래스는 아래와 같음

  • startTime: 현재 시간을 timeStart 멤버변수에 저장
  • confirmChall06: 애플리케이션이 실행된 후 10초가 경과했는지, 그리고 chall06 변수와 인자로 전달 받은 i가 동일한지 확인
  • addChall06: chall06 멤버변수에 인자로 전달 받은 i 값을 더해줌. 만약 9000보다 값이 큰 경우 i값을 그대로 대입

MainActivity의 onCreate 함수에서 startTime 함수를 호출하고, 랜덤 값을 로드한 뒤 addChall06 함수를 두 번 호출함. addChall06 함수가 onCreate 함수 내에서 바로 1번, 그리고 Timer를 활용해 10초 뒤 1번 호출되도록 구현되어 있음

confirmChall06 로직상 실행 후 10초가 경과해야 최소한의 && 조건을 충족할 수 있으므로, chall06 값 또한 바로 가져오지 말고 10초 뒤에 동적으로 가져와야 함 (랜덤 값을 더해주는 방식이어서 정적으로 확인 불가)

그리고 confirmChall06을 호출하는 함수는 MainActivity 내 아래와 같이 존재하는데, xrefs가 없어서 10초 뒤 확인한 chall06 값을 인자로 넣어 직접 호출해 줘야 함

이제 분석한 내용을 바탕으로 코드를 작성하면 됨

후킹 코드

이미 MainActivity에서 생성된 인스턴스를 활용해야 하므로 Java.choose 함수를 이용함

먼저 10초 슬립 후 임의의 숫자 값과 함께 chall06을 호출 → chall06에서 내부적으로 confirmChall06 호출 → chall06 값을 불러와서 그대로 confirmChall06 다시 호출 (임의의 숫자 값을 실제 chall06 값으로 바꿔치기)

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
    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);
        },
        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개의 댓글