상세 컨텐츠

본문 제목

0x02 - Frida Hooking: 가슴이 웅장해지는 후-킹

Hooking

by 알 수 없는 사용자 2020. 7. 15. 22:33

본문

가슴이 웅-장해진다..

 

안녕하세요 춘식입니다.

본격적으로 안드로이드 후킹에 들어가봅시다.

 

---------------------------------------------------------(진지)---------------------------------------------------------

 

썸네일과 상관없이 오늘은 잠깐이지만 진지하게 한 가지 말씀드리고 싶습니다.

 

지난 게시글에서 후킹이란 무엇인지 설명하고, 후킹 테스트를 위한 환경 구축을 했었습니다.

 

한 가지 기술에 대해서 다룰 때 원론적인 부분부터 차근차근 이야기 하는 것이 맞으나,

 

후킹은 모바일에만 한정된 것이 아니고 다양한 분야에서 쓰이는 하나의 기술입니다.

 

그만큼 양도 방대하고 제대로 알고자 하면 끝이 없죠.

 

그래서 부득이 완전 낮은 단계에서 부터 차근차근 설명드리지 못하는 점 양해를 구합니다.

 

대신 도움이 되실만한 좋은 글을 추천합니다.

 

유명한 안드로이드 관련 커뮤니티에서 후킹 관련 내용을 정말 자세하게 설명한 게시글입니다.

 

linforum.kr/bbs/board.php?bo_table=android&wr_id=731

 

안드로이드 ARM 후킹 기술 강좌

이번편에는 안드로이드 후킹 기술에 대하여 살펴보려고 합니다. 'Hook'이라는 단어만 들었을때에는 갈고리가 먼저 생각이 나는데, 단어 그대로 갈고리로 낚아채는 방법이라고 생각하시면 이해가

linforum.kr

 

이 게시글을 보시면 Frida 라는 것이 어떤 것을 가능하게 해주는지 대충이나마 감을 잡을 수 있습니다만

 

바로 이해하기에는 난이도가 높아 기회가 된다면 조금 더 쉽게 풀어쓰는 게시글을 포스팅하겠습니다.

 

---------------------------------------------------------(진지)---------------------------------------------------------

 

본격적으로 안드로이드 후...후.. 불면은 구멍이 뚫리는 커다란 솜-사탕

 

후킹을 해봅시다.

 

오늘 순서는 ㉮슴이 웅-장해질만하게 뤄볼겁니다.

 

  1. Uncrackable?
  2. Uncrackable 앱 설치
  3. Uncrackable 앱 디컴파일 및 로직 분석(후킹 포인트 찾기)
  4. 후킹 코드 작성
  5. 후킹 코드 실행

 

 

 

 

 

 

1. Uncrackable?

 

Uncrackable 은 OWASP 에서 만든 후킹 테스트용 앱으로써, 안드로이드 버전과 IOS 버전 모두 있습니다.

 

단, Android 버전은 Level 1 ~ 3 까지 있고 IOS 버전은 Level 1 ~ 2 까지 있다는 차이가 있습니다. 껄껄

 

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

 

OWASP/owasp-mstg

The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering. - OWASP/owasp-mstg

github.com

Github에서 무료로 다운로드 받을 수 있죠

 

 

 

BAAAAM

 

 

2. 설치

 

우리는 이전 시간에 Nox 플레이어 설치를 마쳤죠.

 

이제는 앱을 설치할 차례 입니다.

 

 

https://github.com/OWASP/owasp-mstg/blob/master/Crackmes/Android/Level_01/UnCrackable-Level1.apk

 

OWASP/owasp-mstg

The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering. - OWASP/owasp-mstg

github.com

 

여기서,

 

 

저 부분을 클릭하면 다운로드 됩니다.

 

 

이제, Nox 플레이어를 실행합니다.

창 상단의 톱니바퀴 모양을 클릭하고 시작항목 > ROOT켜기를 체크하고 켜주시기 바랍니다.

 

 

 

 

두 가지 방법이 있는데 하나는 Uncrackable 앱을 더블 클릭해서 설치하거나, 드래그 하는 방법입니다.

 

 

저는 알아서 설치하겠습니다.

 

 

 

 

설치하면 바로 앱이 실행되면서 루팅이 탐지되었다라는 알림창이 나타납니다.

 

 

시작부터 순탄치 않지만

 

 

5252  언크레커블 네 녀석 이름보고 와타시는 예상하고 있었다귯!!

 

 

 

얼핏 보이는 창을 보아하니, 저 알 수 없는 입력 폼에 뭔가 글자를 입력하고

 

VERIFY 라는 버튼을 눌러 입력한 값이 맞는지 틀린지 확인하는 앱 같군뇨..

 

 

쿠쿸.. 벌써 다 파악해버리다닛

 

 

야레야레~

 

 

무당도 아니고 관상만 보고 다 파악할 순 없으니

 

진짜 한 번 제대로 까봅시다!

 

 

 

3. Uncrackable 앱 디컴파일 및 로직 분석

 

Uncrackable 앱은 Java 라는 언어로 개발되어 있습니다.

 

우리가 이 Uncrackable 이라는 앱이 어떤 방식으로 동작하는지 알려면

 

이 Uncrackable 이란 녀석이 어떻게 움직이도록 개발자가 만들었는지 그 의도를 파악해야 하고

 

조금 더 구체적으로 어떤 클래스의 어떤 함수를 불러와서..! 내 앞 길을 막는지!!!!!(급발진)

 

후욱후욱.. 알아야 하기 때문에 "디컴파일" 이라는 것을 해야합니다.

 

방법이 정말 다양한데 오늘은 jadx-gui 라는 도구를 사용하겠습니다.

 

 

https://github.com/skylot/jadx/releases

 

Releases · skylot/jadx

Dex to Java decompiler. Contribute to skylot/jadx development by creating an account on GitHub.

github.com

 

요오기서 설치하시믄 되는데 따로 설명은 안하겠습니다. 그냥 exe 파일 실행하면 되고, 혹여나

 

다른 문제가 발생해도 설치가 아주 간단하기 때문에 넘어가도록 하죠!

 

 

 

실행하고 대상 apk 파일인 Uncrackable-Level1.apk 파일을 선택하고 Open file!

 

 

 

로직을 분석하기 앞서, 우리가 할 일과 안드로이드 앱에 대한 토막 지식을 살펴보겠습니다.

 

 

사알짝만 얘기할게요(빵-긋)

 

 

먼저, 우리가 할 일 입니다.

 

 

 

- 앱을 켜자마자 바로 뭔가가! 앱을 종료시키기 때문에 켜자마자 실행되는 곳의 위치를 알아야 합니다.

- 앱을 종료시키는 것이 무엇인지 알아야 합니다.

 

 

 

안드로이드 앱에는 AndroidManifest.xml 이라는 설정 파일이 있는데요.

 

이 파일은 앱을 이루는 구성 요소들에 대한 설명이 적힌 파일이라고 보면 되겠습니다.

 

학교로 치면 출석부라고 할 수 있겠네요.

 

 

반에 누가 있는지, 반장은 누구고 또 그 이름은 무엇인지 적혀있죠.

 

 

먼저 이 파일을 보겠습니다.

 

좌측 탭에 Resources 하위에 AndroidManifest.xml 이라는 파일이 있네요~

 

 

 

더블클릭하면 우측에 이쁘게 열립니다.

 

 

        <activity android:label="@string/app_name" android:name="sg.vantagepoint.uncrackable1.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

 

 

눈여겨 봐야 할 부분은 이 부분인데요 <태그></태그> 이런 형식으로 구분되어 있고

 

바깥쪽 부터 들어가봅시다

 

 

우리가 휴대폰을 딱 집어서 앱을 실행하면 화면이 꽉 차면서 앱이 실행되죠?

 

앱에서 메뉴를 누르거나 하면 앱의 화면이 쑥쑥 넘어갑니다

 

 

안드로이드 앱은 이 화면 단위로 이루어져 있는데요.

 

이 화면을 액티비티라 합니다.

 

 

아까 AndroidManifest.xml 파일이 출석부라고 했죠?

 

화면(액티비티)으로 된 학생이 하나 있는 듯 합니다.

 

activity 라는 태그 안에 name 이라는 속성이 있는데 이 속성에

 

. 으로 구분된 곳의 마지막이 이 액티비티의 이름입니다.

 

 

저 파일에 의하면 이 학생은 MainAcitivity 라는 이름을 가지고 있군요..!

 

나머지 앞의 내용 sg.vantagepoint.uncrackable1 은 학교이름이랑 책상 자리 정도로 알고 있으면 될 거같네요!

 

 

 

 

액티비티는 그냥 화면이고 화면을 불러올 신호가 있어야 합니다.

 

갑자기 혼자 화면이 켜지진 않겠죠..; 엄청 무서울 듯

 

 

이 화면을 부르는 신호를 인텐트라고 하는데 보통 activity 태그 안에 명시를 해준답니다..!

 

 

                <action android:name="android.intent.action.MAIN"/>

 

 

이 부분이 우리가 찾던 부분입니다 액티비티의 이름이 MainActivity 인게 중요한 게 아닙니다.

 

이 android.intent.action.MAIN 이라는 부분이 앱 실행의 시작점을 알리는 부분인거죠..!

 

sg.vantagepoint.uncrackable1 이라는 교실의 MainActivity 라는 학생은 반장(시작점) 이었던 겁니다..!

 

 

 

첫번째 할 일 끝

 

 

다음으로 넘어갑시다.

 

이제 교실 안을 볼까요? 다시 Jadx-gui 로 돌아갑시다

 

 

 

 

우리는 Java로 된 코드를 봐야합니다.

 

설정이나, 앱과 관련된 문서들이 아니라(이런건 Resources에 있습니다)

 

어떻게 돌아가는지 알아야 하기 때문에 Source Code 탭에서 우리의 교실을 찾아갑니다.

 

 

아까 교실 이름은 sg.vantagepoint.uncrackable1 이었구요

 

 

sg.vantagepoint 학년 uncrackable1 반 인 듯 하네요.

 

 

그곳에서 우리가 찾은 시작 액티비티인 MainActivity를 찾아 들어갑니다.

 

 

액티비티가 어떤 건지 알았는데 막상 코드로 보니 당황스럽습니다..

 

너무 자세히 다룰 수는 없지만 모든 액티비티는 클래스입니다..! 함수들의 묶음이죠

 

 

그렇다면 화면에 어떤 함수가 들어갈까요?

 

 

이 클래스는 화면에 대해 정의하는 부분이기 때문에 이 클래스로 구현된 화면이 켜진다면 어떤 행동을 할 것이다 

 

혹은 그냥 어떤 행동을 할 것이다 라는 것도 모두 코드로 구현을 해야 합니다.. 

 

 

이 함수는 안드로이드 안에서 약속이 되어 있는데요..!

 

onCreate 라는 이름의 함수입니다

 

 

이 함수 안에 있으면 화면이 켜질 때 어떤 행동을 할 지 구현할 수 있죠..!

 

 

코드를 살펴볼까요?

 

 

 

 

public class MainActivity extends Activity {
    private void a(String str) {
        AlertDialog create = new AlertDialog.Builder(this).create();
        create.setTitle(str);
        create.setMessage("This is unacceptable. The app is now going to exit.");
        create.setButton(-3, "OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialogInterface, int i) {
                System.exit(0);
            }
        });
        create.setCancelable(false);
        create.show();
    }

    /* access modifiers changed from: protected */
    public void onCreate(Bundle bundle) {
        if (c.a() || c.b() || c.c()) {
            a("Root detected!");
        }
        if (b.a(getApplicationContext())) {
            a("App is debuggable!");
        }
        super.onCreate(bundle);
        setContentView(R.layout.activity_main);
    }
    
    // 이하 생략

 

 

onCreate 함수가 보이네요.

 

함수가 호출되자마자 즉, MainActivity 라는 화면이 시작되자마자 웬 if 문이 등장합니다.

 

 

c 라는 클래스의 a 함수, b 함수, c 함수를 차례대로 실행하고 조건이 참이면

 

 

MainActivity 클래스의 a 함수에 Root detected 라는 문자열을 인자로 전달하는 군요..!

(루팅 탐지 로직인 듯 합니다)

 

 

또 따라 갑시다!

 

아직 우리는 찾아야 할 것이 있습니다...! 앱을 꺼뜨리는 몬땐 코드를 찾아야하죠!

 

다음으로 호출되는 MainActivity 클래스의 a 함수를 따라가봅시다.

 

    private void a(String str) {
        AlertDialog create = new AlertDialog.Builder(this).create();
        create.setTitle(str);
        create.setMessage("This is unacceptable. The app is now going to exit.");
        create.setButton(-3, "OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialogInterface, int i) {
                System.exit(0);
            }
        });
        create.setCancelable(false);
        create.show();
    }

 

문자열을 전달받아 AlterDialog를 만들고 ..! 참고로 이 녀석은 그냥 알림창 입니다.

 

알림창 위에 적힐 제목(Title)을 전달받은 인자로 설정하네요..!

 

그리고 This is unacceptable. The app is now going to exit. 이라는 메시지를 내용으로 설정한답니다.

 

볼까요?

 

 

 

다시 보니까 맞네요! 찾았다!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

 

흥분을 가라앉히고 계속 볼까요?

 

 

이 알림창에 버튼을 놓을 건데 이름은 OK 이고..

 

 

버튼 리스너(클릭하면 어떤 행동을 할지 따로 함수로 정의하는 게 아니라 코드 블록 안에 적어주도록 하는 녀석)를

 

통해서 OK 버튼을 클릭했을 때 어떤 행동을 할지 보는데..

 

 

 

System.exit(0);

 

 

 

 

와씨 소름;

 

 

슬슬 가슴이 웅-장해진다

 

 

이 녀석 때문에 OK 만 누르면 꺼졌군요!

 

 

두번째 할 일 끝

 

자, 우리는 할 일을 모두 끝냈습니다. 다음으로 넘어가죠! 레쓰고!

 

- 앱을 켜자마자 바로 뭔가가! 앱을 종료시키기 때문에 켜자마자 실행되는 곳의 위치를 알아야 합니다.

-> MainActivity

 

- 앱을 종료시키는 것이 무엇인지 알아야 합니다.

-> MainActivity 클래스의 a 함수, 루팅 탐지 후 루팅이 되어 있으면 System.exit(0) 으로 앱을 종료시킨다

 

 

 

4. 후킹 코드 작성

 

후킹으로 우리가 그래서 뭘 할 거냐면 가장 먼저!

 

앱이 종료 안되게 할 겁니다..! 그리고 아까 살짝 살펴봤지만

 

VERIFY 라는 버튼을 눌러 뭔가 맞는 값인지 틀린 값인지 검사를 하는데 우리는 어떤 값이 맞는지 틀린지 모르기 때문에

 

틀린 값을 넣어도 맞다고 판단되도록 흐름을 바꾸겠습니다.(이 부분은 뒤에서 다시 자세히 다룰게요)

 

 

그럼 두가지 방식으로 정리할 수 있겠군요?

 

- Java 클래스의 함수를 후킹하여 함수가 기존에 정의된 대로 동작하는 것이 아니라 임의의 흐름대로 동작하도록 조작한다.

- Java 특정 클래스의 함수가 어떤 인자를 받고, 어떤 값을 반환하는지 확인한다.

 

해봅시당

 

후킹 코드는 이 포스팅을 통해 처음으로 감을 잡는 것이기 때문에 한 땀 한 땀 정성들여 짜보겠습니다.

 

 

너무 늦기 전에 Frida를 실행해봅시다.

 

Frida를 실행하는 방법은 이전 글을 참고하세요.

 

https://redteam-securitylab.tistory.com/14

 

0x01 - Frida Hooking: 거대한 전쟁의 시작

안녕하세요. 춘식입니다. 1일 3깡이 대세인 만큼 츄랜드에 맞추기 위해 대표 이미지도 그에 걸맞게 준비했습니다. 화려한 조명이 감싸고 있는 카페에서 마스크 쓰고 있으니 답답해 죽겠네요. 퍽�

redteam-securitylab.tistory.com

 

 

 

 

frida-ps -U를 실행했을 때 혹은 frida-ps 를 실행했을 때 이런 화면이 나온다면 정상적으로 실행된겁니다.

 

이제 Notepad++ 를 실행합시다. (다른 에디터도 상관없어요)

 

자바스크립트로 이루어진 후킹 스크립트는 자바 스크립트를 로드하는 방법과 파이썬을

 

이용한 방법이 있는데 저는 후자를 선택하겠습니다.

 

바탕화면에 uncrackable 이라는 폴더를 생성하고  파이썬 스크립트를 하나 만듭니다.

 

 

import frida, sys

Hook_package = "owasp.mstg.uncrackable1"
# Hooking 하는 대상 패키지 이름(앱의 본명)은 여기에 적습니다.
# 패키지 이름은 nox_adb shell 로 접속 후 pm list packages 에서 조회 가능합니다

def on_message(message, data):
    print("{} -> {}".format(message, data))

# 후킹 코드는 여기에 적습니다.
jscode = """
"""

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)

 

유용하게 쓰일 파이썬 스크립트 입니다.

 

이름은 uncrackableLevel1.py 로 대애충 지었습니다.

 

 

이제 후킹 후킹 코드를 짜봅시다.

 

    Java.perform(function() {
        var exitClass = Java.use("java.lang.System");
        exitClass.exit.implementation = function() {
            console.log('[*] System.exit 함수 후킹 성공!');
        }
    });

 

Java 클래스의 함수를 후킹할 때 Java.perform(function() { }); 은 기본이고 {} 코드 블록 안에 후킹 코드를 삽입하는 형태입니다.

 

변수로 후킹할 클래스를 먼저 담습니다.

(자바스크립트에서 변수 선언은 var를 이용합니다. 다른 방법도 있지만 일단 varvar)

 

저는 System 클래스의 본명인 java.lang.System 클래스를 지정하고 변수 이름을 exitClass 로 지었습니다.

 

 

exitClass의 exit 함수를 후킹할건데 후킹 대상 함수를 지정할 때 implementation 을 사용합니다.

 

 

즉,  java.lang.System 클래스의 exit 함수를 후킹 대상으로 지정할 거고 코드블록 안에서 그 함수의 기능을 다시 정의할거야.

 

라는 의미입니다.

 

 

import frida, sys

Hook_package = "owasp.mstg.uncrackable1"
# Hooking 하는 대상 패키지 이름(앱의 본명)은 여기에 적습니다.
# 패키지 이름은 nox_adb shell 로 접속 후 pm list packages 에서 조회 가능합니다

def on_message(message, data):
    print("{} -> {}".format(message, data))

# 후킹 코드는 여기에 적습니다.
jscode = """
    Java.perform(function() {
        var exitClass = Java.use("java.lang.System");
        exitClass.exit.implementation = function() {
            console.log('[*] System.exit function 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)

 

한글 주석은 다 지우고 진행해주세요.

 

이대로 넣고 실행해봅시다.

 

터미널을 실행하고 해당 파이썬 스크립트 위치까지 이동한 다음 python [스크립트 이름] 으로 실행하면!

 

 

 

뽕맛이 오집니다!!!

 

 

이제 꺼지지 않는군요.. 

 

참고로 System.exit function hooking Success! 라는 부분은 알림창의 OK 버튼을 누른 후

 

(MainActivity의 a 함수가 실행되었다는 얘기겠죠?)

 

실행되어 정상적으로 출력된 것입니다..!

 

두가지 예상 동작 중 한가지를 이용하여 기존에 정의된 흐름을 바꿔버렸죠!!!!!

 

- Java 클래스의 함수를 후킹하여 함수가 기존에 정의된 대로 동작하는 것이 아니라 임의의 흐름대로 동작하도록 조작한다.

 

이제 거의 다 왔습니다!

 

 

이제 저 입력 폼에 들어갈 데이터를 찾아야 하는데..!

 

 

VERIFY 라는 버튼을 눌렀을 때 실행되는 함수 코드입니다.

    public void verify(View view) {
        String str;
        String obj = ((EditText) findViewById(R.id.edit_text)).getText().toString();
        AlertDialog create = new AlertDialog.Builder(this).create();
        if (a.a(obj)) {
            create.setTitle("Success!");
            str = "This is the correct secret.";
        } else {
            create.setTitle("Nope...");
            str = "That's not it. Try again.";
        }
        create.setMessage(str);
        create.setButton(-3, "OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialogInterface, int i) {
                dialogInterface.dismiss();
            }
        });
        create.show();
    }

 

뭔가 맞으면 Success ! 안맞으면 Nope... 이라는 글자가 AlertDialog를 이용해 표시된다는 군요!

 

 

제가 입력한 문자열은 obj 라는 이름의 변수에 담겨 a 클래스의 a 함수의 인자로 전달된다는 소문!

 

 

a 클래스의 a 함수를 살펴봅시다!

 

public class a {
    public static boolean a(String str) {
        byte[] bArr;
        byte[] bArr2 = new byte[0];
        try {
            bArr = sg.vantagepoint.a.a.a(b("8d127684cbc37c17616d806cf50473cc"), Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0));
        } catch (Exception e) {
            Log.d("CodeCheck", "AES error:" + e.getMessage());
            bArr = bArr2;
        }
        return str.equals(new String(bArr));
    }

 

 

입력한 데이터를 str 이라는 이름의 인자로 가져와

 

암호화한 다음에 기존 데이터와 값이 같은지를 비교하는 로직 같아보이네요!

 

한줄한줄 다 이해할 순 없어도

 

 

sg.vantagepoint.a 패키지의 a 클래스의 a 함수를 호출한다는 것과

 

호출될 때 두번째 인자가 디코딩된 Base64 데이터 인 거 같아 보입니다..!

 

 

 

 

public class a {
    public static byte[] a(byte[] bArr, byte[] bArr2) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, "AES/ECB/PKCS7Padding");
        Cipher instance = Cipher.getInstance("AES");
        instance.init(2, secretKeySpec);
        return instance.doFinal(bArr2);
    }
}

 

 

a 클래스의 a 함수는 바이트 형태의 인자 2개를 받고 있네요..!

 

암호화 방식은 역시 AES 네요..!

 

전달받은 인자가 어떻게 사용되는지 볼까요?

 

다시 등장~ Back to the LA

 

첫번째 부터~ SecretKeySpec은 암호화에 사용될 키 객체를 생성하는 클래스인데

 

SecretKeySpec(키, 암호화 방식)과 같은 형태로 사용됩니다.

 

첫번째 인자는 bArr이 SecretKeySpec의 첫번째 인자니까 첫번째 인자 bArr은 암호화에 사용될 가 되겠군요..!

 

두번째 인자를 살펴 봅시다

 

우리는 아까 이 함수가 호출될 때  두번째 인자가 Base64로 디코딩 되었다는 것만 알고있죠?

 

Java 에서 AES로 된 데이터를 복호화할 때

 

Cipher.doFinal(Base64로 디코딩된 암호화 데이터) 와 같은 형태로 사용합니다. (필요한 것만 호다닥 취합시다!)

 

 

Base64로 디코딩된 데이터가 두번째 인자니까 이 녀석은 암호화된 데이터라는 것이겠군요?

 

 

즉, 이 함수가 return 하는 데이터는 우리가 원하는..!! 키워드란 말인 겁니다!

 

 

        var decryptClass = Java.use("sg.vantagepoint.a.a");
        decryptClass.a.implementation = function(args1,args2) {
        console.log('[*] Hooking Call Decrypt');
        var retVal = this.a(args1,args2);

        var flag="";
        for(var i=0; i<retVal.length; i++){
            flag+=String.fromCharCode(retVal[i]);
        }
        
        console.log("[*] Passcode: "+flag);
        return retVal;
        }

 

자 후킹 코드입니다

 

우선, sg.vantagepoint.a.a 클래스의 a라는 함수의 반환 데이터가 키워드 인것을 알았으니

 

Java.use 로 클래스 지정, implementation 을 통해 후킹 대상 함수로 지정해줍니다.

 

이번에는 이 전에 했던 exit 함수 후킹과는 다르게 인자도 있고 반환 데이터도 있기 때문에

 

- Java 특정 클래스의 함수가 어떤 인자를 받고, 어떤 값을 반환하는지 확인한다.

 

이 유형이 되겠군요?

 

 

이 함수는 키와 복호화될 데이터 2개를 인자로 받기 때문에 갯수만 맞춰줍니다.

 

args1, args2 이름 지을게요~

 

그리고 this 키워드를 이용해서 이 함수의 return 값을 미리 변수 retVal에 저장합니다.

 

이제... console.log(retVal); 하면 끝나겠네요?!

 

아 근데.. 아쉽게도 sg.vantagepoint.a.a 함수는 return 값의 형태가 바이트 형태네요..

 

단순히 console.log로 출력할 수 없습니다..

 

 

var flag="";
for(var i=0; i<retVal.length; i++){
        flag+=String.fromCharCode(retVal[i]);
}

 

임의로 문자열 flag를 선언해준다음

 

for문을 이용해서 한글자씩 빼와 String 클래스의

 

문자열로 변환해주는 메소드 fromCharCode를 이용해서

 

retVal의 i번째 글자를 flag에 차곡차곡 쌓습니다!!

 

console.log(flag) 해주면 끝!!! 

 

 

당연히 정상적으로 앱이 동작하도록 원래 return 값 retVal은 return 해주고요..!

 

이제 실행하면!! (아무값이나 입력해도 나오겠죠?)

 

 

 

 

 

 

 

다시 앱으로 돌아와서 찾은 Passcode를 입력하면!!!!!???????

 

 

저 AlertDialog 를 보니 가슴이 웅-장해지지 않습니까?

 

 

 

 

[요약]

- 후킹 포인트를 찾아야 한다.(어떤 데이터를 불러올건지, 어떤 함수의 흐름을 바꿀건지 대상 선정)

- 후킹 코드는 자바스크립트 문법으로 작성한다.

- Java.use 함수로 후킹할 클래스를 지정한다(Java 기본 클래스일 수도 있고, 개발자가 만든 임의의 클래스 일 수 있다.)

- [클래스].implementation = function([args]) { } 의 코드 블록 안에 후킹 코드를 작성한다.

- 인자로 전달받는 데이터 형태가 byte일 때 변환이 필요하다.

- 후킹을 통해 특정 함수의 흐름을 변경할 수 있다.

- 후킹을 통해 특정 함수가 어떤 데이터를 반환하는지 확인할 수 있다.

 

 

 

'Hooking' 카테고리의 다른 글

0x03 모리부터 발끝까지! 후킹 문제 있어?!  (1) 2020.08.20
0x01 - Frida Hooking: 거대한 전쟁의 시작  (4) 2020.06.20
0x00 - Frida Hooking  (0) 2020.05.29

관련글 더보기