naroSEC
article thumbnail

개요

보안이 잘 된 안드로이드 앱은 Java 코드뿐만 아니라 C/C++ 언어로 작성된 네이티브 코드를 활용하여 루팅, 무결성, 디버깅과 같은 보안 위협을 탐지한다. 이러한 네이티브 코드로 작성된 파일은 라이브러리(.so) 형태로 제공되며 또한, ollvm이나 링킹과 같은 라이브러리 보호 매커니즘이 적용된 경우 분석이 어려워진다. 그 일례로 ollvm이 적용된 라이브러리는 코드 내에 존재하는 문자열이 모두 암호화되어 있어 평문 값이 노출되지 않는다. 따라서, 이는 분석 시 검사에 사용되는 문자열을 검색하는 방식으로 탐지 로직을 찾는게 어렵다는 뜻이다. 하지만, 이때 Frida 백트레이스를 활용한다면 어렵지 않게 보안 탐지 로직을 찾을 수 있다. 이번 포스팅에서는 Frida 백트레이스 사용 방법을 기술하고자 한다.


백트레이스 코드

아래의 코드는 필자가 사용하는 Frida 백트레이스 코드로 필요 시 함수를 호출하여 사용하면 된다.

// 사용법
BackTrace(this) // 함수 호출 시에는 인자 값으로 반드시 컨텍스트 정보를 전달해줘야 한다.
function BackTrace(mContext) {
    const btc= Thread.backtrace(mContext.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n');
    console.log(`*********[ BACK-TRACE ]*********`)
    console.log(btc)
}

실습

앞서 설명했던 것과 같이 백트레이스는 어떠한 로직에서 탐지가 이루어지는지 알지 못 했을 때 사용한다. 해당 포스팅에서는 A사의 앱을 대상으로 탐지 로직을 찾지 못하는 상황을 가정하고 실습을 진행해보겠다. 필자의 경우 앱 분석 시 Java 코드를 분석하기 전에 네이티브 코드를 통해서도 루팅, 무결성과 같은 보안 위협을 탐지하고 있는지 frida-trace 이용하여 먼저 확인해보는 편이다.

frida-trace란?
frida-trace는 Frida 프레임워크의 일부로 타겟 애플리케이션의 함수 호출 및 동작을 트레이싱하고 모니터링할 수 있도록 지원해주며, 애플리케이션의 함수 호출, 매개변수, 반환값 등을 실시간 확인이 가능해진다.

네이티브 코드에서는 루팅과 같은 OS 변조 여부를 감지하기 위해서 디바이스에 설치된 패키지나 파일들을 검사한다. 파일 검사 시 파일의 접근 여부 및 열람이 가능한지 확인할 때 사용되는 대표적인 함수로 fopen, open, openat가 있다. 여기서는 "open" 함수를 타겟으로 트레이싱 해보겠다.

frida-trace -U -i open -f [앱 이름]

트레이싱 결과 [그림 1]과 같이 네이티브 코드를 통해 /system/bin/su, /sbin/su, /data/local/tmp/re.frida.server 등 루팅 및 Frida 탐지 시 사용되는 파일들이 열람되고 있으며, 이를 통해 루팅과 Frida를 탐지하고 있다고 추정할 수 있다.

[그림 1] frida-trace 실행 결과

이제 어떠한 로직에서 함수가 호출되어 파일들을 검사하고 있는지 확인하기 위해서 frida-trace의 "handlers" 스크립트에 [그림 2]와 같이 백트레이스 코드를 추가하고 다시 frida-trace로 트레이싱 해준다.

[그림 2] 정규식을 통해 su 파일 열람 시 open() 함수를 추적할 수 있도록 코드를 수정했다.

출력된 백트레이스 확인 결과 [그림 3]과 같이 "libdxbase.so" 라이브러리의 "0x6348" 주소에서 함수가 호출되었고 해당 함수의 반환 결과가 "0x94a0" 주소로 전달된 것을 알 수 있다.

[그림 3] 백트레이스 결과 출력

"libdxbase.so" 라이브러리 파일을 디컴파일 후 [그림 3]에서 확인한 "0x6348" 주소를 살펴보면 "sub_6330()" 함수 내부에서 fopen() 함수가 호출된 것을 볼 수 있다. 참고로 Unix 계열의 운영체제에서 fopen() 함수를 통해 파일 열람 시 내부적으로 open() 함수를 호출하여 파일 디스크립터(File Descriptor) 값을 가져오기 때문에 [그림 4]의 로직에서는 open() 함수가 쓰이지 않았지만 [그림 3]에서는 open() 함수가 호출된 것으로 나온다.

[그림 4] "libdxbase.so!0x6348" 주소의 로직

[그림 5]의 "0x94a0" 주소도 살펴보면 [그림 4]의  "sub_6330()" 함수의 반환 값이 v3 변수에 할당된 것을 확인할 수 있다. 따라서, "sub_6330()" 함수에서 루팅 파일들을 검사한 다음 그 결과 값을(v3 변수) 통해 디바이스의 OS 변조 여부를 감지하고 있는 것으로 추측할 수 있으며, 탐지 우회를 위해서 해당 로직부터 하나씩 분석해가면 되겠다.

[그림 5] "libdxbase.so!0x94a0" 주소의 로직

마무리

지금까지 Frida 백트레이스 활용법에 대해서 살펴봤다. 백트레이스는 위와 같이 분석 엔트리 포인트를 찾지 못할 때 유용하게 사용할 수 있으며, exit와 같은 프로세스 종료 함수도 역추적이 가능하다. 다만, 이러한 백트레이스는 네이티브 코드로 작성된 라이브러리(또는 모듈) 환경이 아닌 Java 코드에서는 사용이 제한적이어서 Java 코드에서는 다른 방법을 사용하여 추적해야 한다. 다음 포스팅에서는 Java 환경에서 백트레이스 대용으로 사용할 수 있는 코드를 소개하도록 하겠다.

profile

naroSEC

@naroSEC

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...