Engineering
보이스피싱 애플리케이션 분석 1부
2024년 5월 8일
원문에서 보기 ↗
들어가며
안녕하세요. NHN Cloud 서비스보안팀 지우중입니다.
처음 기술 공유 글을 맡은지라 어떤 주제로 작성할까 많은 고민을 하였습니다. 때마침 지난 설 연휴에 고향에 내려갔을 때 친척분이 보이스피싱 피해를 입었다는 소식을 접하였습니다. 그로 인해 자연스레 보이스피싱 애플리케이션에 관심을 가지게 되었고 기술 공유와 더불어 실생활에서 많은 사람들이 보이스피싱 범죄에 노출되지 않기를 바라는 마음으로 이 글을 준비하였습니다.
따라서 보안을 접하지 않은 분들도 이해하기 쉽도록 풀어 적었기 때문에 다소 글이 길어질 수 있는 점 이해 부탁드립니다. 그럼 시작하겠습니다.
악성 애플리케이션이란?
영화 '보이스'와 '스마트폰을 떨어뜨렸을 뿐인데'
혹시 '보이스[1]'와 '스마트폰을 떨어뜨렸을 뿐인데[2]'라는 영화를 보셨나요?
안 보신 분들도 계실 것 같아 짧게 줄거리를 설명해 드리자면 일반 사용자의 스마트폰에 악성 애플리케이션을 설치하여 해커는 자신의 PC에서 스마트폰 주인의 취미, 취향, 직업, 동선, 경제력, 인간관계 등 모든 일상을 알아내 피해자의 삶을 붕괴시키는 이야기를 다룬 영화입니다. 이처럼 현재 우리는 스마트폰이라는 손바닥만 한 크기의 기계에 우리의 일거수일투족을 담고 살고 있습니다. 또한 은행 업무, 결제 등 스마트폰 하나만으로 수많은 업무를 처리할 수 있기 때문에 우리에게 스마트폰은 꼭 필요한 존재가 되었습니다. 나의 많은 정보를 작은 기기 하나에 다 담아낼 수 있다는 편리한 도구의 이면에는 그만큼 나의 수많은 개인정보와 금융 정보가 스마트폰 분실 시 모두 노출된다는 매우 치명적이고 위험한 단점이 있습니다.
그림으로 쉽게 표현하자면 아래의 시소 그림[3]처럼 사용(Usable)이 편하면 그만큼 보안성(Secure)이 떨어질 수밖에 없습니다. 즉, 사용성이 높아지면 보안은 그만큼 취약해질 수 있다고 이해해 주시면 될 것 같습니다.
사용성과 보안성의 관계(source: How Monerujo’s CrAzYpass (crazy secure password scheme) works
보이스피싱 애플리케이션이란?
보이스피싱 애플리케이션은 금융 사기를 목적으로 제작된 것으로 사용자들이 신뢰할 수 있는 기관(금융권, 공공기관)을 사칭하여 개인정보나 금융 정보를 탈취하는 애플리케이션을 말합니다. 보이스피싱에는 일반적으로 검찰, 금융감독원 등 공공기관을 사칭하여 의심 계좌가 발견되었다며 수사를 할 것처럼 겁을 주어 안전한 계좌로 돈을 이체 또는 전달하라는 ‘기관 사칭형’, 저리에 대출을 하기 위해 거래 실적을 만들어야 한다거나 추가 대출을 위해서는 기존 대출금을 모두 상환해야 한다는 ‘대출 사기형’, 그 외에도 아들·딸 등 지인을 사칭하는 방법, ‘재난지원금’, ‘대환대출’ 등을 받기 위해서는 개인정보를 입력하고 관련 비용을 먼저 납부해야 한다는 ‘선비용 수법(advance payment)’ 활용[4] 등 다양한 종류가 있습니다.
최근 5년간(2018년~2023년 상반기, 전체 금융회사)[5] 보이스피싱 피해자 수는 148,760명, 피해 건수 237,859건, 피해 금액 1조 7천499억으로 드러났습니다.

이처럼 보이스피싱 범죄자들은 악성 애플리케이션 설치를 유도하여 개인정보 및 금융 정보를 탈취하는 조직적으로 범죄를 저지르고 나날이 수법을 달리하여 보이스피싱은 사회적 문제로 자리 잡았습니다. 따라서 이러한 사회적 문제를 해결하고자 보이스피싱 애플리케이션을 분석하였습니다. 이를 통해 이러한 앱들이 사용자의 신뢰를 얻어 정보를 탈취하는 수법과 보이스피싱의 위험성을 알리고자 이 글을 작성하게 되었습니다.
보이스피싱 애플리케이션 분석
1 설치
이제 본격적으로 보이스피싱 애플리케이션에 대한 분석 과정을 설명하겠습니다. 여기에서는 보이스피싱 범죄에 가장 많이 사용되는 '대출사기형'으로 분석을 해 보겠습니다. 보이스피싱 애플리케이션을 설치하면 아래와 같이 Google Play 프로텍트[6]에 의해 차단되는 것을 볼 수 있습니다.

스마트폰에 어떤 애플리케이션을 설치할 때 차단되거나 아래와 같이 '출처를 알 수 없는 앱 설치'라는 문구가 발생하는 것 자체가 위험한 애플리케이션이라는 증거입니다.

위의 Google Play 프로텍트나 기타 모바일 백신 애플리케이션에서 악성 애플리케이션이 탐지된다면 또 다른 악성 애플리케이션으로 수정하여 빠르게 다시 배포합니다. 이렇게 새로운 악성 애플리케이션을 배포하게 된다면 Google Play 프로텍트나, 기존의 악성 애플리케이션 탐지 솔루션에서는 빠르게 탐지하지 못할 수 있습니다. 따라서 Google Play 프로텍트, 모바일 전용 백신 등에서 차단 및 알람 문구를 보신다면 이 경우는 꼭 한번 다시 확인하시고 설치해 주시기를 바랍니다.
하지만 저는 분석을 진행해야 하므로 Google Play 프로텍트 설정을 해제한 다음 단말기(스마트폰)에 설치해 봤습니다.

2 분석 탐지 우회
보이스피싱 애플리케이션을 분석하는 도중 원활하게 분석하지 못하도록 방해하는 행위가 발견되었습니다. 방해하는 행위는 어떤 것이 있었는지, 또 어떻게 우회하고 분석을 진행했는지에 대해 설명하고자 합니다.
Google Play 프로텍트를 해제한 후 설치를 진행하면 '모바일 신청서'라는 악성 애플리케이션이 설치됩니다. 애플리케이션 아이콘도 'A 금융'으로 되어 있어 겉으로 보기에는 정상적인 애플리케이션으로 보입니다.

분석 환경은 보이스 피싱 애플리케이션의 인앱(In-App) 활동을 분석하기 위해 루팅(안드로이드)7된 단말기에 설치하였으며 C&C 서버[8]와의 통신도 분석하기 위해 웹 프락시 도구인 Fiddler[9]와 Burp Suite[10]를 사용하였습니다. 아래는 웹 프락시[11]를 사용하기 위해 Android 설정에서 프락시의 IP와 Port 번호를 설정해 주는 과정입니다.

위의 그림처럼 프락시를 설정해 준다면 오른쪽 그림처럼 Android에서 발생하는 모든 네트워크 패킷을 모니터링할 수 있습니다. 기본적으로 분석 환경을 설정해 주고 루팅된 단말기에서 실행을 해 보니 바로 종료되는 현상이 발생하였습니다. Logcat으로 분석한 결과 com.fzbXad.kqfSua.MainActivity에서 onDestroyed가 발생하였습니다.

따라서 onDestroyed가 발생한 원인을 찾기 위해 Android 애플리케이션 디컴파일 도구인 Jadx[12] 또는 JEB[13]를 통해 com.fzbXad.kqfSua.MainActivity를 검색하였지만 com.fzbXad.kqfSua.MainActivity가 존재하지 않았습니다.

이처럼 디컴파일 도구로 특정 Activity, Class, Method, String 등의 값을 검색하였을 때 나오지 않는다면 크게 2가지로 볼 수 있습니다.
1. 암호화된 DEX 파일 사용
2. Dynamic Loading(동적 로딩) 사용
따라서 위의 2가지 중 어떤 기법을 사용하는지 분석하기 위해 애플리케이션의 시작점인 com.tkzCRw.ljYflr.apeuEe.wgrlYZrkff에서 분석을 진행하였습니다.

보이스피싱 애플리케이션의 시작점인 com.tkzCRw.ljYflr.apeuEe.wgrlYZrkff 클래스의 attachBaseContext 메서드를 살펴보면 unZip이라는 메서드가 존재합니다. 아래의 코드는 unZip 메서드 코드 중 일부인데 코드를 해석해 보면 classes.dex가 아니고 파일 확장자가 .dex인 파일이 존재하면 if문 안으로 진입하게 됩니다.

DEX 파일은 Android 시스템에서 실행될 수 있는 바이트코드로써 APK 파일 내부에 존재하는 파일입니다. 따라서 위의 코드로 보아 classes.dex가 아닌 dex라는 파일 확장자를 찾는 행위이고 해당 파일을 찾기 위해서는 APK 파일 내부를 살펴볼 필요성이 있습니다.
보이스피싱 애플리케이션의 APK 파일을 분석한 결과 classes.dex 파일 외 secret-classes.dex 파일이 존재하는 것을 확인할 수 있습니다.

이름으로 유추할 수 있듯이 secret-classes.dex 파일은 일반적인 DEX 파일의 포맷이 아닌 암호화된 파일이라는 것을 알 수 있습니다.

또한, wgrlYZrkff.runFile(zipFile, zipEntry, file, arg15)의 3번째 인자인 file에는 secret-classes.dex가 전달되는 것을 알 수 있습니다. 그 후 runFile 메서드를 보면 최종적으로 loadXFile 메서드를 통해 secret-classes.dex 복호화를 진행합니다.

그 이유는 loadXFile 메서드를 살펴보면 아래 decrypt 메서드가 실행됩니다. 이는 아까 인자로 전달 받았던 secret-classes.dex 파일을 복호화하는 역할을 합니다.

이렇게 메서드명을 난독화하지 않으면 쉽게 해당 메서드 내부 코드를 분석하지 않아도 어떤 행위를 할 것인지 쉽게 유추할 수 있기 때문입니다. 아래의 decrypt 메서드를 살펴보면 아무런 내용이 없고 native라는 키워드가 보입니다.

이는 해당 decrypt 메서드가 Java로 작성된 것이 아니라 dn_ssl.so 라는 파일에 정의되어 있다는 의미입니다. 따라서 decrypt 메서드가 어떤 암호화 알고리즘을 사용하고 어떤 key를 사용하는지 분석하기 위해서는 dn_ssl.so 파일을 추가로 분석해야 합니다. 그렇다면 왜 Java단이 아닌 굳이 Native단에서 수행하는 것일까요?
개발 측면에서 보자면 Java보다 C/C++로 작성된 Native 코드가 더 빠르다는 장점으로 Native 코드를 사용할 수 있지만 보안 측면에서 생각해 본다면 해당 로직을 숨기고 싶다는 의미로 볼 수 있습니다. 이런 이유로 모바일 보안 솔루션 업체나 악성 애플리케이션에서 숨기고 싶은 중요 로직은 Java단이 아닌 Native 코드단에서 실행하고 처리하는 이유입니다. 즉, 핵심 로직을 숨기고 싶다는 이유가 가장 큽니다.
APK는 Java로 이루어진 파일이기 때문에 Jadx나 JEB로 분석하였다면 Native 코드(.so) 파일을 분석하기 위해서는 IDA라는 프로그램을 이용해서 분석을 진행해야 합니다. 따라서 dn_ssl.so 파일을 IDA로 열어 분석을 진행해 보았습니다.
확인한 결과, 아래의 그림처럼 decrypt 함수가 보입니다. 해당 코드를 분석한 결과 aes/128/ecb 모드를 사용하고 있는 것으로 나타납니다.

또한 EVP_CIPHER_CTX_new, EVP_aes_128_ecb, EVP_DecryptInit_ex 등으로 코드가 작성되어 있는 것으로 보아 해당 암호화 로직은 OpenSSL에서 사용하고 있는 암호화 로직을 사용하는 것으로 파악됩니다.
OpenSSL에서 사용하는 복호화 로직은 다음과 같습니다.

EVP_DecryptInit_ex 함수의 원형은 다음과 같습니다.

복호화하기 위해서는 암호화 과정에 사용한 알고리즘, key, iv 값을 알아야 하므로 EVP_DecryptInit_ex 함수를 살펴보았습니다. EVP_DecryptInit_ex 함수에서 off_19A004가 암호화 key을 의미하고, 0은 iv 값을 의미합니다. 따라서 off_19A004로 가보면 key가 dbcdcfghijklmaop로 하드 코딩된 것을 볼 수 있습니다.

암호화 알고리즘과 key 값, iv 값을 알았으니 암호화된 secret-classes.dex 파일을 복호화할 경우 아래처럼 원본의 dex 파일을 획득할 수 있습니다.

원래의 목적인 com.fzbXad.kqfSua.MainActivity를 분석하기 위해서 복호화 된 원본의 secret-classes.dex 파일을 악성 APK 파일에 추가한 후 다시 리패키징하여 Jadx나 JEB 같은 디컴파일로 분석을 진행하였습니다. 복호화된 Dex 파일이 포함된 APK 파일을 디컴파일한 뒤 com.fzbXad.kqfSua.MainActivity 검색하면 아래와 같이 코드를 볼 수 있습니다.

이렇게까지 숨긴 이유를 생각해 보면 com.fzbXad.kqfSua.MainActivity는 악성 행위를 하는 코드가 존재할 것으로 파악됩니다. com.fzbXad.kqfSua.MainActivity.onCreate 함수를 분석하면 super.onCreate 메서드로 부모 클래스인 com.fzbXad.kqfSua.base.BaseActivity의 onCreteat 함수를 제일 먼저 호출합니다. 부모 클래스인 com.fzbXad.kqfSua.base.BaseActivity의 onCreteat 메서드를 분석한 결과 com.fzbXad.kqfSua.a.c.j 메서드의 return 값이 true이면 finish() 메서드가 실행되기 때문에 Destroy() 메서드가 호출되었다는 것을 알 수 있습니다.

따라서 com.fzbXad.kqfSua.a.c.j 메서드의 return 값을 알기 위해 해당 메서드를 분석하였습니다. com.fzbXad.kqfSua.a.c.j 메서드는 6개의 if문으로 구성되어 있습니다.

각 분기문의 return 값이 true인 것으로 보아 각 분기에 존재하는 메서드에 대한 분석을 진행해야만 악성 애플리케이션이 종료되는 정확한 이유를 알 수 있기 때문에 모든 분기문에 대해서 분석을 시작하였습니다.
첫 번째 분기의 메서드 com.fzbXad.kqfSua.a.c.h는 애플리케이션이 설치된 단말기의 언어 설정이 한국어인지를 확인하는 것을 알 수 있습니다.

따라서 해당 보이스피싱 애플리케이션은 한국을 타깃으로 한 악성 애플리케이션인 것을 알 수 있습니다.
두 번째 분기문인 com.fzbXad.kqfSua.a.c.d 메서드는 Android 애플리케이션에서 디바이스가 테스트용 키(testkeys)를 사용하고 있는지 확인하는 메서드입니다.

일반적으로 단말기가 루팅되었거나 테스트용으로 사용되는 경우를 탐지할 때 사용하는 방법입니다. 분석하는 단말기도 루팅이 되어 있기 때문에 getprop | grep test-keys 명령어로 Build.TAGS에 test-keys가 있는지를 확인한 결과 존재하지 않기 때문에 애플리케이션이 종료되지 않고 다음 분기로 넘어간다는 것을 알 수 있었습니다.

세 번째 분기문인 com.fzbXad.kqfSua.a.c.c 메서드에서는 /system/app/ 경로에 Superuser.apk 파일이 존재하는지 확인하는 메서드입니다. Superuser.apk 애플리케이션은 루팅과 관련된 애플리케이션으로 피싱 애플리케이션에서도 루팅 탐지 로직이 존재한다는 것을 알 수 있습니다.

이로써 피싱 애플리케이션에서도 자신의 악의적인 행위에 대해서 분석하지 못하도록 루팅된 단말기를 확인한다는 것도 알 수 있습니다. 네 번째 분기문인 com.fzbXad.kqfSua.a.c.b 메서드는 /proc/tty/drivers이라는 파일을 열어 수정이 가능한지 파악하는 메서드입니다.

/proc/tty/drivers를 수정하기 위해서는 root 권한이 있어야 하며 따라서 com.fzbXad.kqfSua.a.c.b 메서드도 루팅 탐지 로직으로 보입니다.
다섯 번째 분기문인 com.fzbXad.kqfSua.a.c.f 메서드는 adb_enabled이 설정되어 있는지, 즉 USB 디버깅 모드가 되어 있는지 확인하는 메서드입니다.

해당 메서드의 역할은 동적으로 애플리케이션을 분석하기 위해서는 PC와 USB로 연결되어야 하는데 이것을 탐지하기 위해서 사용되는 메서드로 보입니다. 다섯 번째 분기문에는 메서드가 2개가 있기 때문에 com.fzbXad.kqfSua.a.c.e 메서드를 분석하면 VPN을 사용하고 있는지 탐지하는 로직입니다.

또한 다섯 번째 분기문에서는 com.fzbXad.kqfSua.a.c.f와 com.fzbXad.kqfSua.a.c.e 두 개의 메서드에서 true가 반환되어야만 분기문이 실행됩니다. 하지만 분석하는 단말기에서는 USB 디버깅은 사용하지만 VPN을 사용하고 있지 않기 때문에 최종적으로 다섯 번째 분기문은 실행되지 않고 다음 분기문으로 넘어가게 됩니다.
여섯 번째 분기문 안에는 com.fzbXad.kqfSua.a.c.f 메서드로 USB 디버깅을 사용 중이기 때문에 분기문이 실행됩니다. 분기문이 실행되면서 com.fzbXad.kqfSua.a.c.n 메서드가 실행되는데 해당 메서드는 단말기에서 프락시를 사용하고 있는지를 판단하는 로직으로 확인됩니다.

따라서 com.fzbXad.kqfSua.a.c.n 메서드에서 true가 반환되기 때문에 애플리케이션이 종료되는 것으로 확인할 수 있었습니다.

그렇다면 악성 애플리케이션은 왜 루팅 탐지와 VPN, Proxy를 탐지하는 걸까요?
정답은 간단합니다. 자신의 악성 행위를 분석하지 못하게 하기 위해서입니다. 루팅은 양날의 검이라고 생각하면 쉬울 것 같습니다. 공격자의 입장에서는 편하게 공격하기 위해서 루팅을 하기도 하고, 방어하는 입장에서는 악성 행위를 편하게 분석하기 위해서도 루팅을 진행합니다.
그렇다면 Proxy는 왜 탐지하는 걸까요? 바로 악성 애플리케이션이 설치된 단말기 내부에 존재하는 민감한 정보를 공격자의 C&C 서버로 보내기 위해서 어쩔 수 없이 통신해야 하는데 프락시를 사용한다면 C&C 서버와 어떤 데이터를 주고받는지까지 알 수 있기 때문에 프락시를 탐지하는 것입니다. 따라서 프락시 탐지 메서드인 com.fzbXad.kqfSua.a.c.n 메서드를 변조하여 프락시를 사용해도 애플리케이션이 실행될 수 있게 코드를 다음과 같이 수정하였습니다.

코드를 수정한 뒤 apktool[14]이라는 도구를 이용하여 리패키징을 진행하였습니다. Proxy 탐지를 우회한 APK 파일을 JEB로 디컴파일한 결과 변조가 성공적으로 이루어진 것을 볼 수 있습니다.

프락시 탐지 메서드를 우회한 APK를 설치한 결과 Proxy가 설정된 단말기에서도 정상적으로 실행할 수 있었습니다.
마치며
보이스피싱 애플리케이션 분석 1편은 여기까지 진행하겠습니다. 다음 분석편에서는 보이스피싱 애플리케이션에서 어떤 데이터를 C&C 서버로 보내는지, 단말기에서는 어떤 것이 이루어지는지, 보이스피싱 애플리케이션의 핵심인 '전화 가로채기'의 원리는 무엇인지에 대한 내용을 공유하려고 합니다.
'전화 가로채기'에 대해 먼저 짧게 설명해 드리자면 피해자가 보이스 피싱 조직원들에게 전화를 받고 확인하기 위해서 금융기관 등에 전화할 때 사용자에게 보이는 화면에서는 금융기관에 전화한 것처럼 보이지만 실제로는 보이스피싱 조직원들에게 연결되게 하는 기법입니다. '전화 가로채기'가 동작하는 방식을 아래 영상을 통해 확인하실 수 있는데요, 이 영상에서는 '엔에이치엔클라우드'라는 금융기관이 있다는 가정하에 보이스피싱 피해자가 확인을 위해 엔에이치엔클라우드 대표 번호로 발신하는 과정을 보여줍니다. 엔에이치엔클라우드 대표 번호로 발신하였음에도 정작 보이스 피싱 조직원에게 전화가 오는 모습을 볼 수 있습니다. 
👉 영상 바로 가기
그럼, 2편에서 다시 뵙겠습니다. 긴 글 읽어 주셔서 감사합니다. 😀
참고 문헌
- [1] 보이스
- [2] 스마트폰을 떨어뜨렸을 뿐인데
- [3] Playgrounds are full of useful metaphors.
- [4] [범죄·안전] 보이스피싱 현황, 유형, 추이와 대응관련 시사점
- [5] 최근 5년간(2018 ~ 2023년 상반기) 보이스피싱 피해금액 1조7천499억원
- [6] Google Play 프로텍트로 앱을 안전하게 보호하고 데이터를 비공개로 유지하기
- [7] 루팅 (안드로이드)
- [8] C&C (악성 소프트웨어)
- [9] Fiddler
- [10] Burp Suite
- [11] 프록시 서버
- [12] Jadx
- [13] JEB
- [14] apktool