Android App Hooking with Frida(2)





이번 포스팅에서는지난시간에 이어서 Frida를 사용한 android app hooking에 대하여 다루도록 하겠습니다.

(도구 설치와 같은 기초 지식은 다루지 않습니다.)


문제파일은 아래 경로를 통하여 다운받을 수 있습니다.

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


석환

OS: Windows10

Tools: Frida, Frida-server, adb, Python3.6, Genymotion



문제파일(UnCrackable-Level2.apk)을 다운로드하여 설치합니다.

[그림 1 apk설치]



앱 설치 후 실행 시 루팅 탐지가 동작하며 ok버튼을 클릭하면 앱이 강제로 종료됩니다.

[그림 2 루팅탐지]



루팅탐지는  Level1 문제풀이때 설명하였으니 넘어가도록 하겠습니다.

문제파일의 MainActivity 살펴보면 Secret String입력 값에 따른 성공 및 실패 로직을 확인할 수 있습니다.

[그림 3 verify 함수 분석]



실제 CodeCheck 클래스를 살펴보면 bar함수에 Secret String이 전달되어 유효성을 체크하는 것을 확인할 수 있습니다.

[그림 4 CodeCheck bar 분석]



실제 해당 함수는 libfoo.so 라이브러리에서 찾을 수 있습니다.

[그림 5 libfoo.so 라이브러리 load 확인]



그럼 실제 해당 라이브러리 파일을 디스어셈블러(ida)를 사용하여 분석해보도록 하겠습니다.

genymotion의 경우 Intel x86으로 동작하게됩니다. 따라서 라이브러리 파일 분석 시 x86폴더 아래에 존재하는 libfoo.so 파일을 분석하도록 하겠습니다.

[그림 6 libfoo.so 분석]



함수를 분석하다보면 eax, 17h 를 비교하여 strncmp함수를 호출하는 영역으로 분기하는 구간을 확인할 수 있습니다.

17h는 십진수로 23이고 문자열의 길이가 23이면 strncmp함수를 호출하는 영역으로 넘어가도록 동작합니다.

우리는 여기서 Secret String의 길이가 23이라는 것을 파악할 수 있습니다.

[그림 7 b함수 분석]



strncmp함수는 문자열을 비교하여 그 결과를 반환하는 함수입니다.

Secret String을 입력받아 비교하여 결과를 반환하는 동작을 수행합니다.

그럼 우리는 strncmp함수의 인수를 출력하여 Secret String을 확인할 수 있을것입니다.


그럼 strncmp 함수를 후킹하여 실제 Secret String을 출력하는 코드를 작성하도록 하겠습니다.

Module.enumerateImportsSync() 를 이용하여 libfoo.so 라이브러리에 존재하는 함수 중 strncmp함수의 주소값을 얻어내고 hooking을 수행하여 Secret String을 얻어냅니다.

uncrackable2.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import frida, sys
 
def on_message(message, data):
    if message['type'== 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)
 
 
PACKAGE_NAME = "sg.vantagepoint.uncrackable2"
 
jscode= """
    Java.perform(function() {
        console.log("[*] Hooking calls to System.exit");
        exitClass = Java.use("java.lang.System");
        exitClass.exit.implementation = function() {
            console.log("[*] System.exit called");
        }
        var strncmp = undefined;
        func = Module.enumerateImportsSync("libfoo.so");
        for(i = 0; i < func.length; i++) {
        if(func[i].name == "strncmp") {
                strncmp = func[i].address;
                break;
            }
        }
        Interceptor.attach(strncmp, {
            onEnter: function (args) {
               if(args[2].toInt32() == 23 && Memory.readUtf8String(args[0],23) == "01234567890123456789012") {
                    console.log("[*] Secret string at " + args[1] + "" + Memory.readUtf8String(args[1],23));
                }
             },
        });
        console.log("[*] Intercepting strncmp");
    });
"""
 
try:
    device = frida.get_usb_device(timeout=10)
    pid = device.spawn([PACKAGE_NAME])  
    process = device.attach(pid)
    device.resume(pid)
    script = process.create_script(jscode)
    script.on('message',on_message)
    print('[*] Running Hook')
    script.load()
    sys.stdin.read()
except Exception as e:
    print(e)
 
 
cs

[그림 8 hooking code]



hooking 스크립트를 실행시킵니다.

[그림 9 hooking]


앱을 실행시킨 후 "01234567890123456789012"를 입력한 후 VERIFY를 클릭합니다.

[그림 10 VERIFY]


hooking이 성공하여 "thanks for all the fish" 라는 Secret String이 출력된 것을 확인할 수 있습니다.

[그림 11 Secret String 확인]


그럼 실제 해당 Secret String이 맞는지 확인해볼까요?

[그림 12 Secret String]


지금까지 Frida를 사용한 Android App Hooking에 대하여 알아봤습니다.

다음 포스팅에서는 세번째 Crackme 문제를 가지고 포스팅을 이어가도록 하겠습니다.

참고 : https://www.codemetrix.net/hacking-android-apps-with-frida-3/

'Mobile > Android' 카테고리의 다른 글

Android App Hooking with Frida(3)  (1) 2019.01.07
Android App Hooking with Frida(1)  (0) 2018.02.26

이 글을 공유하기

댓글