본문으로 바로가기

가. 런타임 조작 취약점 및 대응방안

- 런타임 조작에 대한 설명 및 대응방안은 아래의 게시글을 참고하길 바란다.

[AOS App 취약점 진단 · 모의해킹] - [AOS 취약점 진단] 14강 - 런타임 조작 취약점 점검(Frida/ADB)

 

- 본글에서는 Frida 코드가 많이 나오므로, 초보자들은 아래의 게시글을 참고하여 실습을 진행하길 바란다.

[Mobile App 취약점 진단 · 모의해킹] - 프리다(Frida) 문법 및 후킹에 사용되는 함수 설명

 

프리다(Frida) 문법 및 후킹에 사용되는 함수 설명

가. 기초 문법 1. ObjC.available - 현재 프로세스에 Objective-C 런타임이 로드되었는지 여부를 지정하는 Boolean(True, False) - 해당 앱에서 FIRDA가 실행가능한 환경인지 체크 2. ObjC.classes - 현재 등록된 클래

hagsig.tistory.com

 

나. Frida 설명 및 설치방법

- Frida Server/Client 설치방법은 아래의 게시글을 참고하길 바란다.

[AOS App 취약점 진단 · 모의해킹] - 안드로이드 프리다 서버/클라이언트 설치방법

 

안드로이드 프리다 서버/클라이언트 설치방법

Frida Server/Client 설치 방법 - Android(AOS) 가. 설치 프로그램 설명 1. 아나콘다(Anaconda) - 오픈소스 라이브러리를 모아둔 개발 플랫폼이다. - 아나콘다를 사용하면 파이썬을 버전별로 설치해서 사용할

hagsig.tistory.com

 

다. FridaLab 설치방법

- 아래의 사이트에 접속하여 Download 버튼을 클릭, 다운로드된 FridaLab.apk 파일을 모바일 디바이스에 설치한다.

https://rossmarks.uk/blog/fridalab/

 

FridaLab

I was struggling with a recent test using frida, knowing it could do what I want but unsure how. After lots of googling and trial and error I eventually got it working. So I decided

rossmarks.uk

FridaLab 실행 후 메인화면

 

- FridaLab에서는 다음과 같은 항목을 실습할 수 있다.

실습 항목 실습 내용
1. Change class challenge_01's variable 'chall01' to: 1 클래스 challenge_01의 변수 chall01을 1로 변경하기
2. Run chall02() chall02() 메서드 실행하기
3. Make chall03() return true chall03() 메서드가 true 반환하게 만들기
4. Send "frida" to chall04() chall04() 메서드에 frida 문자열 전송하기
5. Always send "frida" to chall05() 버튼 클릭 시 chall05() 메서드에 frida 문자열 전송하기
6. Run chall06() after 10 seconds with correct value 올바른 값으로 10초 후 chall06() 메서드 실행하기
7. Bruteforce check07Pin() then confirm with chall07() chall07Pin() 메서드를 무차별대입공격으로 확인하기
8. Change 'check' button's text value to 'Confirm' 'check' 버튼의 텍스트를 'Confirm'으로 변경하기

 

라. FridaLab 문제 풀이

1번 문제풀이 : Change class challenge_01's variable 'chall01' to: 1

- 아래의 링크에 접속하여 jadx-gui-x.x.x-with-jre-win.zip 파일을 다운로드한 뒤, 압축을 해제한다.
https://github.com/skylot/jadx/releases/tag/v1.4.7

 

Release 1.4.7 · skylot/jadx

Features [core] Inline lambdas by instance field (#1800) [plugins] Allow to load classes using input stream or byte array in jadx-input plugin (#1457) Bug Fixes [core] Restore missing type param...

github.com

 

- jadx-gui-x.x.x.exe를 실행한 뒤 'FridaLab.apk' 파일을 로드한 다음 challenge_01 클래스 파일을 열람한다.

- getChall01Int() 메소드의 반환값인 chall01 변수의 값을 1로 변경하는 것이 이 문제의 목표이다.

 

- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.

- 예제 1은 chall01 변수의 값을 변조하는 것이고, 예제 2는 함수 반환값 자체를 변조하는 것이다.

//후킹 예제 소스코드 1 : chall01 변수 값 조작
setImmediate(function(){
    Java.perform(function(){
        var Question_01 = Java.use("uk.rossmarks.fridalab.challenge_01");
        console.log("[+] 변경전의 chall01 변수 값 : " + Question_01.chall01.value);

        Question_01.chall01.value = 1;
        console.log("[+] 변경후의 chall01 변수 값 : " + Question_01.chall01.value);
    })
})

//후킹 예제 소스코드 2 : 함수 리턴 값 조작
setImmediate(function(){
    Java.perform(function(){
        var Question_01 = Java.use('uk.rossmarks.fridalab.challenge_01');
        Question_01.getChall01Int.implementation = function(){
            return 1;
        }
    })
})

 

- 위에서 작성한 코드를 PC의 frida client를 통해 실행시킨다.

//현재 디바이스에서 실행중인 앱 정보를 출력
frida-ps -Ua

//Frida Code 실행 명령어
//frida -U -l [파일경로] [PID/ProcessName/PackageName]
frida -U -l hagsig_hooking.js FridaLab

 

- 후킹코드를 실행한 다음 CHECK 버튼을 누르면 1번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.

 

2번 문제풀이 : Run chall02()

- chall02() 함수를 강제로 호출하는 게 목표인 문제이다. 문자열검색을 통해 chall02() 함수를 찾아낸다.

 

- 'MainActivity'에 chall02 메소드가 존재하는 것을 확인하였다. 런타임 조작을 통해 해당 메소드를 강제로 실행할 것이다.

 

- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.

- 두 예제는 동일한 결과를 내지만 클래스를 저장하고 호출하는 방식에 차이가 있다.

- 문자는 더블쿼터("), 싱글쿼터(') 중 무엇을 사용하든 상관없으면 본인에게 편한 방식을 사용하면 된다.

//후킹 예제 소스코드 1
setImmediate(function(){
    Java.perform(function(){
        var Question_02 = Java.choose("uk.rossmarks.fridalab.MainActivity",{
            "onMatch" : function(Question_02){
                Question_02.chall02();
            },
            "onComplete" : function() {
                console.log("[+] chall02 메소드 호출 완료");
            }			
        })
    })
})

//후킹 예제 소스코드 2
setImmediate(function(){
    Java.perform(function(){
        var Question_02;
        Java.choose('uk.rossmarks.fridalab.MainActivity',{
            onMatch: function(instance) {
                Question_02 = instance;
                Question_02.chall02();
            },
            onComplete : function() {
                console.log('[+] chall02 메소드 호출 완료');
            }			
        })
    })
})

 

- 후킹코드를 실행한 다음 CHECK 버튼을 누르면 2번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.

 

 

3번 문제풀이 : Make chall03() return true

- chall03() 메소드의 리턴값을 true로 변조하는 것이 목표인 문제이다.

 

- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.

//후킹 예제 소스코드
setImmediate(function(){
    Java.perform(function(){
        var Question_03 = Java.use("uk.rossmarks.fridalab.MainActivity");
        Question_03.chall03.implementation = function(){
            return true;
        }
    })
})

 

- 후킹코드를 실행한 다음 CHECK 버튼을 누르면 3번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.

 

 

4번 문제풀이 : Send "frida" to chall04()

- chall04() 메소드를 강제로 호출하면서 인자값으로 "frida" 문구를 입력하는 것이 목표인 문제이다.

 

- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.

//후킹 예제 소스코드 1
setImmediate(function(){
    Java.perform(function(){
        var Question_04 = Java.choose("uk.rossmarks.fridalab.MainActivity", {
            "onMatch" : function(Question_04){
                Question_04.chall04("frida");
            },
            "onComplete" : function() {
                console.log("[+] chall04 메소드 호출 완료");
            }
        })
    })
})

//후킹 예제 소스코드 2
setImmediate(function(){
    Java.perform(function(){
        var Question_04;
        Java.choose('uk.rossmarks.fridalab.MainActivity', {
            onMatch: function(instance) {
                Question_04 = instance;
                Question_04.chall04('frida');
            },
            onComplete: function() {
                console.log('[+] chall04 메소드 호출 완료');
            }
        })
    })
})

 

- 후킹코드를 실행한 다음 CHECK 버튼을 누르면 4번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.

 

 

5번 문제풀이 : Always send "frida" to chall05()

- 4번 문제와 같이 chall05()메소드 호출 시 인자값에 "frida" 문구를 입력하여 실행하는 것이 목표인 문제이다.

- 'MainActivity' 클래스의 chall05 메소드 내용을 보면 "frida" 문구 입력 여부로 성공/실패를 구분하는 것을 알 수 있다.

 

- 4번과 동일한 코드로 후킹을 시도하고 'CHECK' 버튼을 누르면 실패하는 것을 알 수 있다.

- 버튼 클릭 이벤트 onClick()의 소스를 보면 버튼 클릭 시 "notfrida!"가 입력되어 실패하는 것을 알 수 있다.

 

- chall05() 메소드가 호출될 때 무조건 "frida" 문구가 인자값으로 입력되도록 수정한다.

- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.

*overload와 implementation를 이해하지 못했다면, '가. 런타임 조작 취약점 및 대응방안'에 적힌 Frida 문법 설명 게시글을 참고하자.

//후킹 예제 소스코드
setImmediate(function(){
    Java.perform(function(){
        var Question_05 = Java.use("uk.rossmarks.fridalab.MainActivity");
        Question_05.chall05.overload("java.lang.String").implementation = function(arg){
            this.chall05("frida");
            console.log("[+] chall05 메소드 오버로드 완료")
        }
    })
})

 

- 후킹코드를 실행한 다음 'CHECK' 버튼을 누르면 5번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.

 

6번 문제풀이 : Run chall06() after 10 seconds with correct value

- 10초가 지난 이후 chall06() 함수를 호출하면서 인자값으로 정확한 정수를 입력하는 것이 목표인 문제이다.

- 'MainActivity' 클래스의 chall06() 함수를 보면 challenge_06 클래스의 confirmChall06() 메소드를 호출하는 것을 알 수 있다.

 

- 그리고 앱 실행 시 가장먼저 실행되는 이벤트 메소드 onCreate()의 소스코드를 보면, 'challenge_06' 클래스의 startTime(), addChall06() 메소드를 실행하는 것을 알 수 있다.

- 특히 addChall06() 메소드는 0~50 사이의 랜덤값을 인자값으로 입력하여 호출하는 것을 알 수 있다.

 

- StartTime() 메소드는 현재 시간을 timeStart 변수에 저장한다.

*System.currentTimeMillis() : 1970년 1월 1일부터 경과한 시간을 1/1000초로 계산하여 long 타입으로 리턴한다.

- addChall06() 메소드는 변수 chall06에 인자값을 더하고, chall06의 값이 9000보다 크다면 입력된 값으로 지정한다.

- confirmChall06() 메소드는 입력된 인자값이 chall06 변수와 같고, 앱이 실행된지 10초가 지났으면 Ture(1)를 리턴한다.

 

- 후킹 시도로부터 10초 이후, 'MainActivity' 클래스의 chall06()메소드를 'challenge_06' 클래스의 변수 chall06 값을 인자값으로 입력하여 호출하는 후킹 소스를 작성한다.

- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.

//후킹 예제 소스코드 1
setImmediate(function() {
    Java.perform(function() {
        var Question_06 = Java.use('uk.rossmarks.fridalab.challenge_06');
        Java.choose('uk.rossmarks.fridalab.MainActivity', {
            onMatch: function(instance) {
                console.log("[+] 10초 후 chall06 메소드가 실행됩니다");
                setTimeout(function() {
                    console.log("[+] chall06 변수의 값 : " + Question_06.chall06.value);
                    instance.chall06(Question_06.chall06.value);
                    console.log("[+] chall06 메소드 후킹 완료");
                }, 10000); 
            },
            onComplete: function() {
            }
        })
    })
})

//후킹 예제 소스코드 2
setTimeout(function(){   
    console.log("[+] 10초 후 chall06 메소드가 실행됩니다");
    setImmediate(function(){
        Java.perform(function(){
            let main;
            Java.choose("uk.rossmarks.fridalab.MainActivity", {
                onMatch: function(instance) {
                    main = instance;
                    const Question_06 = Java.use("uk.rossmarks.fridalab.challenge_06");
                    Question_06.confirmChall06.implementation = function () {
                        console.log("[+] chall06 변수의 값 : " + Question_06.chall06.value);
                        return true;
                    }
                    main.chall06(1);
                    console.log("[+] chall06 메소드 후킹 완료");
                },
                onComplete: function() {}
            });
        })
    })
}, 10000);

 

- 후킹코드를 실행한 다음 10초가 지나 완료문구가 출력되면 'CHECK' 버튼을 누른다.

- 6번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.

 

 

7번 문제풀이 : Bruteforce check07Pin() then confirm with chall07()

- 7번 문제는 무차별대입공격(brute-force attack)을 통해 정확한 pin코드를 입력하는 것이 목표인 문제이다.

- 'MainActivity' 클래스의 chall07() 메소드를 인자값을 입력하여 호출하면 'challenge_07' 클래스의 check07Pin() 메소드 반환값을 통해 성공/실패를 구분하는 것을 확인할 수 있다.

 

- 그리고 앱 실행 시 가장먼저 실행되는 이벤트 메소드 onCreate()의 소스코드를 보면, 'challenge_07' 클래스의 setChall07() 메소드를 실행하는 것을 알 수 있다.

 

- 'challenge_07' 클래스의 setChall07() 메소드는 4 자릿수 난수 값을 문자열 형 chall07 변수에 저장한다.

- check07Pin() 메소드는 입력된 인자값이 chall07 변수와 같은지 비교하여 true/false를 반환한다.

 

- 정확한 값을 입력할 때까지 4자리 난수 pin 코드를 생성하는 후킹코드를 작성한다.

- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.

//후킹 예제 소스코드 1
setImmediate(function(){
    Java.perform(function(){
        var Question_07 = Java.use("uk.rossmarks.fridalab.challenge_07"); 
        Java.choose("uk.rossmarks.fridalab.MainActivity",{
            onMatch : function(instance){
                for(var i=9999; i>=1000; i--){
                    var hagsig = String(i);
                    if(Question_07.check07Pin(hagsig)){
                        console.log("[+] chall07 pin 값 :" + hagsig);
                        instance.chall07(hagsig);
                        break;
                    }
                }
            },
            onComplete : function(){
                console.log("[+] 7번 메소드 후킹 완료");
            }
        })
    })
})

//후킹 예제 소스코드 2
setImmediate(function() {
    Java.perform(function() {
        var main;
        Java.choose('uk.rossmarks.fridalab.MainActivity', {
            onMatch: function(instance) {
                main = instance;
            },
                onComplete: function() {}
            });
            var Question_07 = Java.use('uk.rossmarks.fridalab.challenge_07');
            for (var i = 1 < 9999 ; i <= 9999 ; i++) {
            var hagsig = i.toString(10);
            if(Question_07.check07Pin(hagsig.padStart(4,'0'))) {
                main.chall07(hagsig);
                console.log("[+] chall07 pin 값" + hagsig);
                break;
            }
        }
        console.log("[+] 메소드 후킹 완료");
    })
})

 

- 후킹코드를 실행한 다음 'CHECK' 버튼을 누르면 7번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.

 

 

8번 문제풀이 : Change 'check' button's text value to 'Confirm'

- 메인 화면 버튼의 텍스트를 'check'에서 'Confirm'으로 변경하는 것이 목표인 문제이다.

- 'MainActivity' 클래스의 chall08()을 호출하여 button의 텍스트가 "Confirm"인지 검사하여 참과 거짓을 반환한다.

 

참고) findViewById() 함수를 통해 R.id 클래스의 check 변수에 저장된 값을 통하여 View를 찾는다.

 

- 아래의 프리다 후킹 소스코드를 메모장에서 작성한 후 .js 확장자로 저장한다.

- 예제 1은 View의 ID를 직접 지정하여 버튼의 텍스트를 변조하는 것이고, 예제 2는 동적으로 ID를 찾아 버튼의 텍스트를 변조하는 것이다.

//후킹 예제 소스코드 1 : Button ID를 지정하여 변조
setImmediate(function() {
    Java.perform(function() {
        var klass = Java.use("android.widget.Button");
        Java.choose("uk.rossmarks.fridalab.MainActivity",{
            onMatch : function(instance){
                var checkid = instance.findViewById(0x7f07002f);
                var check = Java.cast(checkid, klass);
                var string = Java.use("java.lang.String");
                console.log("[+] 변경전 Button Text 값 : " + check.getText());
                check.setText(string.$new("Confirm"));  
                console.log("[+] 변경후 Button Text 값 : " + check.getText());
            },
            onComplete : function(){
                console.log("[+] 8번 메소드 후킹 완료");
            }
        })
    })
})

//후킹 예제 소스코드 2 : Button ID를 알아내어 변조
setImmediate(function() {
    Java.perform(function() {
        var id = Java.use('uk.rossmarks.fridalab.R$id');
        var check_id = id.check.value;
        console.log("[+] check id : " + check_id);

        var button = Java.use('android.widget.Button');
        var main;
        Java.choose('uk.rossmarks.fridalab.MainActivity', {
            onMatch: function(instance) {
            main = instance;
        },
            onComplete: function() {}
        });
        var check = Java.cast(main.findViewById(check_id), button);
        console.log("[+] 변경전 Button Text 값 : " + check.getText());

        var str = Java.use('java.lang.String');
        check.setText(str.$new('Confirm'));
        console.log("[+] 변경후 Button Text 값 : " + check.getText());
    })
})

 

- 후킹코드를 실행한 다음 'CHECK' 버튼을 누르면 8번 라벨이 초록색으로 변하면서 문제풀이에 성공했다는 것을 알려준다.

 

 

 

https://takudaddy.tistory.com/622

 

8. 프리다 연습 - FridaLab (2) 문제 풀이 (1-5번)

[목차] 1. Change class challenge_01's variable 'chall01' to 1 2. Run chall02() 3. Make chall03() return true 4. Send "frida" to chall04() 5. Always send "frida" to chall05() 1. Change class challenge_01's variable 'chall01' to 1 > 클래스 challenge

takudaddy.tistory.com

 

https://blog.naver.com/PostView.naver?blogId=6yujin6&logNo=221732108444&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView

 

[프리다(Frida)를 이용한 안드로이드 앱 모의해킹] FridaLab - Always send "frida" to chall05()

Always send "frida" to chall05() (05. chall05() 메소드에 Frida 문자열 항상 전송하기) Ch...

blog.naver.com

 

https://leemon.tistory.com/78

 

Level 1 ~ 8

앱 정보 앱을 실행하면 1 ~ 8번까지 조건들이 나열되어 있으며, CHECK 버튼을 눌렀을 때 해당 조건이 만족되면 초록색 그렇지 않으면 빨간색으로 바뀌는 애플리케이션이다. Level 1 Change class challenge_

leemon.tistory.com

https://snowjeon2.tistory.com/36

 

[Android] Fridalab 4번 풀이

Fridalab 4번 풀이 4번 문제는 chall04() 함수에게 "frida" 라는 값을 전송하는것이다. 먼저 /uk/rossmarks/fridalab/MainActivity.class 파일안에 있는 chall04() 함수를 보면 만약 변수 var1 의 값이 "frida" 라면 completeArr

snowjeon2.tistory.com

 

https://leemon.tistory.com/78