[FRIDA] Frida를 이용한 Native Hooking

2018. 7. 4. 11:34 - Song's IT

개발자가 C ++ 또는 C 언어로 코드를 개발하고 APK의 기능에 액세스 할 수있는 Android NDK를 사용하여 루팅 탐지와 같은 다양한 작업을 수행하는 경우에 Frida를 사용하여 C ++ 또는 C로 개발 된 함수를 동적으로 분석.


# Root Inpector 분석

 - C ++로 작성된 원시 코드를 사용하여 루트 탐지에 대한 검사를 구현하는 Rootinspector라는 앱의 루팀 탐지 로직을 우회


 1. rootinspector에 구현 된 루팅 탐지 로직은 두가지로 구성

    java 함수 checkRootMethodNative12() 와 C++함수 checkifstream()



<그림 1. JAVA 메서드를 통한 Native 함수 호출>



<그림 2. 클래스 파일 내 선언된 Native 함수>



2. 네이티브 소스 코드 내 해당 함수는 Java_com_devadvance_rootinspector_Root_checkifstream로 작성되어 있음.
   ( _구분자로 된 패키지명 + 함수명)


<그림 3. C++로 작성된 Java_com_devadvance_rootinspector_Root_checkifstream 함수>



<그림 4. C++로 작성된 Java_com_devadvance_rootinspector_Root_checkfopen 함수>



3. 네이티브 코드 후킹을 위해 Frida의 Interceptor API 참조

  - 링크 : https://www.frida.re/docs/javascript-api/#interceptor

  - Interceptor를 이용하여 Low Memory나 지정된 라이브러리에 접근 가능



4. APK 파일 내 C++로 구현된 Target .so파일 확인

  

<그림 4. APK 내 C++로 구현된 네이티브 라이브러리 확인>



5. 후킹할 함수명 확인을 위해 디스어셈블러 사용

  - Target : Java_com_devadvance_rootinspector_Root_checkfopen



6. 후킹 코드 작성





7. 로드 최초 실패 해결 및 전체우회코드

import frida

import sys


package_name = "com.devadvance.rootinspector"



def get_messages_from_js(message, data):

            #print(message)

            print (message['payload'])

 


def instrument_debugger_checks():

    hook_code = """

var didHookApis = false;

Interceptor.attach(Module.findExportByName(null, 'dlopen'), {

  onEnter: function (args) {

    this.path = Memory.readUtf8String(args[0]);

console.log(this.path);

  },

  onLeave: function (retval) {

    if(!retval.isNull() && this.path.indexOf('libnative2.so')!== -1 && !didHookApis) {

  didHookApis = true;

      console.log("File loaded hooking");

      hooknative2();

    }

  }

});

function hooknative2(){

Interceptor.attach (Module.findExportByName ( "libnative2.so", "Java_com_devadvance_rootinspector_Root_checkifstream"), {

            onLeave: function (retval) {

                retval.replace(0);

    }

});

Interceptor.attach (Module.findExportByName ( "libnative2.so", "Java_com_devadvance_rootinspector_Root_checkfopen"), {

onLeave: function (retval) {

retval.replace(0);

}

});

Interceptor.attach (Module.findExportByName ( "libnative2.so", "Java_com_devadvance_rootinspector_Root_checkfopen"), {

onLeave: function (retval) {

retval.replace(0);

}

});

Interceptor.attach (Module.findExportByName ( "libnative2.so", "Java_com_devadvance_rootinspector_Root_statfile"), {

onLeave: function (retval) {

retval.replace(0);

}

});

Interceptor.attach (Module.findExportByName ( "libnative2.so", "Java_com_devadvance_rootinspector_Root_runsu"), {

onLeave: function (retval) {

retval.replace(0);

}

});

Interceptor.attach (Module.findExportByName ( "libnative2.so", "Java_com_devadvance_rootinspector_Root_runls"), {

onLeave: function (retval) {

retval.replace(0);

}

});

Interceptor.attach (Module.findExportByName ( "libnative2.so", "Java_com_devadvance_rootinspector_Root_runpmlist"), {

onLeave: function (retval) {

retval.replace(0);

}

});

}

"""

    return hook_code


device=frida.get_usb_device()

#run package

p1=device.spawn(["com.devadvance.rootinspector"])

process = device.attach(p1)

script = process.create_script(instrument_debugger_checks())

script.on('message',get_messages_from_js)

script.load()

#Extremely important to add this else the app would freeze

device.resume(p1)

sys.stdin.read()

다른 카테고리의 글 목록

Android/Diagnostics 카테고리의 포스트를 톺아봅니다