Android

Android hooking with Frida Framework(feat. Uncrackable1.apk)

Ate1es 2022. 1. 5. 16:42

오늘은 Frida 를 이용한 안드로이드 후킹을 해보려고 합니다. 후킹이라는 기술은 특정 분야에서만 사용하는게 아닌 다양한 분야에서 활용되므로 알아두는 것이 좋을 것 같습니다.

 

우선적으로 Hooking(후킹)이라 함은 컴퓨터공학 관점에서는 소프트웨어나 응용프로그램들 사이에서 발생하는 함수 호출, 메시지, 이벤트 등을 중간에서 가로채 해당 기능이나 내용을 변경하는 기술을 말합니다. 후킹이 정확하게 어떤 값을 조작하는지는 좀 더 깊게 공부해봐야 할 것 같습니다.

 

실습에 사용될 apk에는 보통 OWASP 에서 만들어둔 Uncrackable 시리즈를 씁니다.

https://github.com/OWASP/owasp-mstg/tree/master/Crackmes/Android

 

GitHub - OWASP/owasp-mstg: The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security testing an

The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes the technical processes for verifying the controls listed in...

github.com

해당 앱을 다운 후 adb 를 통해 애뮬레이터에 설치 후 실행시켰더니. 

으잉? 루팅이 감지되었다고 Ok 버튼을 누르면 무조건 앱이 종료되는군요..우선 어떤 호출들이 이런 결과를 만드는지 소스코드를 봐야 할 것 같습니다. jadx를 통해서 소스코드를 까보겠습니다.

c 클래스에 a,b,c 메소드를 통해 검증을 해서 뭔가 걸리면 루팅이 탐지되었다는 구문을 a 메소드로 보내고 있네요. 그럼 알람 창은 a 메소드가 아웃풋하는 것 같으니. a 메소드로 가보겠습니다.

우리가 알람창에서 봤던 구문을 보여주고, ok버튼을 클릭하면

System.exit(0) 함수를 call 해서 앱을 종료하는 거였군요.

이러면 구조는 전부 파악을 했습니다. 

 

이제 frida 를 통해 후킹을 진행해보겠습니다. 아래 코드는 기본 후킹 코드 예제로 많이 쓰이고 있어서 가져왔습니다. 해당 jscode 함수에 내가 원하는 행동을 정의하고 후킹을 진행할 수 있습니다.

import frida, sys
#후킹할 앱 클래스
Hook_package = "owasp.mstg.uncrackable1"

def on_message(message, data):
    print("{} -> {}".format(message, data))
#조작할 행위
jscode = """
Java.perform(function(){
    var hookClass = Java.use("java.lang.System")
    hookClass.exit.implementation = function() {
        console.log("Hooking Success!!!");
    }
});
"""

try:
    device = frida.get_usb_device(timeout=10)
    pid = device.spawn([Hook_package])
    print("App is starting.. pid:{}".format(pid))
    process = device.attach(pid)
    device.resume(pid)
    script = process.create_script(jscode)
    script.on('message', on_message)
    print("[-] Running FR1DA!")
    script.load()
    sys.stdin.read()

except Exception as e:
    print(e)

frida 환경 구축 과정은 생략하였습니다! 

위의 jscode 에 의하면 원래는 꺼져야할 앱이 꺼지지 않고, 콘솔에 hooking success 라는 문구가 출력될 것입니다.

 

해당 코드를 실행시키면, 이제 ok 버튼을 눌러도 꺼지지않고 콘솔에 공격자가 조작한 문구가 출력되는 것을 볼 수 있습니다.!!

VERIFY 버튼이 있는것을 보니 뭔가 검증과 일치하는 문자열을 넣어야하는 기분이 싸악 듭니다. 다시 코드로 넘어가보죠.

verify 라는 함수에서 저의 입력값을 a 클래스의 a함수로 넘겨 검증하고 있었습니다. a.a를 가보면 되겠죠? 

저의 입력값(str)과 sg.vantagepoint.a.a.a() 에서 넘어온 값을 비교하고 있네요!

 

그렇다면 vantagepoint.a.a.a() 메소드로 가보겠습니다.

 

여기서 bArr = b("8d ~~~), bArr2 = Base64.decode("~~~") 입니다.

바이트 인자를 두개 받고있습니다. 첫번째 인자는 SecretKeySpec() 함수에 사용되고 있습니다. 

해당 함수를 오라클 독스에 찾아보면, 첫 번째 인자는 암호화에 사용되는 key에 사용된다고 합니다. ->bArr의 정체는 키였습니다.

그리고 위의 bArr2(Base64)는 instance.doFinal() 함수에 사용되면서 리턴값으로 사용되고 있네요.

그렇다면 또 오라클 독스로 가봅시다.

한줄요약 - 해당 바이트 복호화해주는 함수입니다.

특이하게 암호화된 데이터를 base64로 디코딩한 데이터를 받아서 복호화하는 것 같습니다. 자바 특징인가..?

 

쨋든 우리가 원하는 문자열이 저기에 있는 것이죠 !!

 

후킹 코드입니다.

해당 기능을 하는 함수를 불러와 인자 값을 arg1(=키), arg2(=base64디코딩된 암호화데이터값) 으로 받아왔습니다.

 

그리고 다시 a 메소드로 보내서 복호화를 진행하여 복호화가 완료된 값(우리가 원하는 값) 을 result에 저장하여 console.log() 하려 했으나

byte로 리턴되기 때문에 for문을 사용해서 한글자씩 변수에 넣고 한번에 출력해주었습니다.

#불러올 메서드
var hookClass = Java.use("sg.vantagepoint.a.a");
		#행동조작 - 인자값 가져옴
        hookClass.a.implementation = function(arg1, arg2){
        #함수에 넣고 리턴값 가져옴(복호화된 데이터)
        var result = this.a(arg1,arg2);
        var flag = "";
        for(var i=0; i<result.length; i++){
            flag += String.fromCharCode(result[i]);
        }
        #복호화된 데이터 출력
        console.log("FLAG : "+flag);
        #원래 함수에서 반환해야할 값 반환해주어야 함(그래야 에러가 안납니다)
        return result
        }

이제 frida를 실행하고 아무 값이나 넣으면 콘솔에 정답이 출력되겠죠?

 

짜잔! 

후킹이라는 기술에 굉장히 감탄했고, 사용자에 따라 무궁무진하게 발전할 수 있는 것 같습니다. 앞으로 열공할 분야 !!!