보안정보
전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.
악성 APK을 이용한 Dynamic Dex Loading 분석
2022.05.31
20,592
01. 개요
악의적 목적의 파일을 탐지하기 위해 백신프로그램(AV)이외에도 EDR, 머신러닝, AVT(Advanced Volatile Threat)등의 기술이 활용되기 시작한 것은 악성코드의 회피기술(Evasion)발전과 연관이 있다. 일반적으로 악성코드는 PE(Portable Executable)구조로 시그니처나 행위기반 등으로 프로세스를 탐지할 수 있었으나, 최근에는 메모리에만 올려서 실행하는 인 메모리 악성코드(In-Memory Malware)라고 명명되는 파일리스(Fileless)기반의 공격기법이 각광을 받고 있다. 앞선 PE구조의 파일의 경우와 달리 컴퓨터를 재부팅하는 경우에는 데이터가 소실되는 휘발성의 특징을 갖는 메모리 영역에서 구동되기 때문에 악성행위를 수행하는 직접적인 주체인 PE 파일이 존재하지 않아 악성코드의 채증 및 분석을 저해하는 효과를 갖게 된다.
Android OS에서 어플리케이션이 구동되는 환경에서도 Windows환경에서 살펴봤던 파일리스 기법과 유사하게 메모리 영역을 활용하는 난독화 기법 ‘Dynamic Dex Loading’을 사용하면 모바일 앱을 실행하기 위한 소스코드가 포함되어 있는 Dex 파일을 메모리에서 동작시켜서 앱을 실행시키기 때문에 일반적인 디컴파일 방법으로는 원본 소스코드에 접근할 수 없게 만든다.
‘Dynamic Dex Loading’기법의 효과를 분석하기 위해 악성 모바일 앱 2종(△ Renaming, String Encryption, Control Flow 등의 난독화 기술이 적용된 ‘Android:Banker-UJ’ 앱, △ Dynamic Dex Loading기법만 적용한 ‘Android.Trojan.Banker.ZF’)을 대상으로 Virus Total의 탐지내역을 확인해본 결과, ‘Android:Banker-UJ’은 약 48%의 백신 솔루션에서 탐지가 된 반면 ‘Android.Trojan.Banker.ZF’은 약 3%의 백신 솔루션에서만 탐지되어 ‘Dynamic Dex Loading’을 적용하였을 때 악성 모바일 앱의 백신 프로그램 탐지율이 현저하게 저하되게 된다.
분류 |
HASH(MD5) |
적용한 난독화 기법 |
VT탐지율 |
Android:Banker-UJ |
76953E56348140DF43F4E9DF3CE8F1F9 |
Renaming, String Encryption, Control Flow |
29/62 |
Android.Trojan.Banker.ZF |
D3BD37D67BC5CB9B5C400A42175D900D |
Dynamic Dex Loading |
2/62 |
[표 1] 난독화 기능 적용에 따른 악성코드 탐지율 비교 (VT, Virus Total : 2022.04.15 기준)
이처럼 ‘Dynamic Dex Loading’ 기술이 백신 프로그램의 탐지율에 영향을 미친다는 점을 통해서 소스코드 가독성 저해 뿐만 아니라 정상 모바일 앱의 리버싱을 저해하기 위한 목적으로 해당 기술의 활용이 가능하게 된다. 따라서 본 문서에서는 ‘Dynamic Dex Loading’ 기법의 구동원리를 분석하고 이를 통해 모바일 앱 환경에서 사용 가능한 다양한 난독화 기법에 대해서 살펴보고자 한다.
02. Dynamic Dex Loading 개요
‘Dynamic Dex Loading’ 기법은 모바일 앱의 분석을 저해하기 위한 목적으로 중요 로직이나 소스코드를 보호하기 위해 사용되는 일종의 난독화 기술이다. 악성 앱의 경우에는 주로 백신 솔루션 탐지를 위한 회피 목적으로 사용되고 있으며, 정상 앱의 경우에는 로직 및 기능을 보호하기 위한 목적으로 사용되고 있다. 앞서 언급한 난독화(Obfuscation)는 소스코드의 가독성을 저해하는 일련의 모든 기술을 의미하며, 난독화가 적용되지 않은 앱은 역공학(Reverse Engineering)을 통해 앱의 로직 분석이 용이해져 소스코드 분석을 통한 공격의 트리거를 확보하는데 근간이 될 수 있기 때문에 반드시 적용해야 하는 보호조치 중 하나다.
본격적으로 ‘Dynamic Dex Loading’ 기술을 살펴보기에 앞서 Android APK구조와 ‘Dynamic Dex Loading’ 분석을 위한 AndroidManifest.xml구조에 대해서 설명하고자 한다.
1) APK 구조
APK파일은 시그니처가 PK(50 4B 03 04)로 압축파일(ZIP)과 동일한 확장자를 가지고 있기 때문에, APK파일의 확장자를 ZIP으로 변경하고 압축을 해제하면 APK 파일 구조를 트리 형태로 확인할 수 있다.
[그림 1] APK 압축 해제 후 구성 확인
Dex 파일에 대해 추가적인 설명을 하자면 Android 런타임에서 실행되는 소스코드가 포함되어 있는 실행파일이다. Dex 파일을 디컴파일하면 앱에서 실행되는 Smali의 형태로 소스코드를 확인할 수 있으며 Java로 변환이 가능하다.
2) Entry Point를 찾기 위한 AndroidManifest.xml 분석
AndroidManifest.xml은 모든 모바일 앱에 필수적으로 존재해야 하는 파일이다. Android 빌드 도구, Android 운영 체제, App에서 필요한 Device 권한 등의 정보를 설명하고 있기 때문에 모바일 앱을 분석할 때 가장 먼저 확인하게 되는 파일이며 패키지 명, Entry Point 경로, 앱 권한 등의 정보를 얻을 수 있다.
[그림 2] AndroidManifest.xml 구조
AndroidManifest.xml에는 모바일 앱 실행 시 최초로 실행되는 Class 파일의 경로인 Entry Point 값이 존재하며, Entry Point를 표현하는 방식은 2가지로 선언될 수 있다. 먼저 첫 번째는 [그림 2] L9에 있는
[그림 3] AndroidManifest.xml –
두 번째는 [그림 3] L10에 있는
3) Dynamic Dex Loading 개요
Dex 파일은 Java로 짜여진 코드가 컴파일되어 변경된 Bytecode와 구조에 대한 설계를 함께 포함하고 있기 때문에 디컴파일을 통한 소스코드 접근이 용이하다. ‘Dynamic Dex Loading’ 기법은 난독화 기법 중 하나로 소스코드가 컴파일된 Original Dex 파일을 일반적인 경로(APK 구조의 루트 디렉터리에 존재하는 Classes.dex)가 아닌 다른 경로(App 내부 저장소, assets Dir 등)에 저장해두고 앱이 실행될 때 Original Dex가 메모리에 로드되고 원본 앱이 실행된다.
[표 2] Dynamic Dex Loading 적용 전〮후 비교
‘Dynamic Dex Loading’ 기법 적용 전후의 AndroidManifest.xml파일 내용을 비교하였을 때, 두 파일은 똑같이
[그림 4] Multi Dex - Original Dex를 Loading 하기 위한 Classes.dex
Classes.dex는 암호화되어 있는 Original Dex 파일(Classes01.dex, Classes02.dex)을 복호화하고 원본 앱 전환을 위해 복호화된 Original Dex를 메모리에 로딩하여 앱을 실행키는 역할을 한다.
[그림 5] 난독화 적용 과정 : Dynamic Dex Loading Process
모든 ‘Dynamic Dex Loading’ 기법이 [그림 5]과 같이 이뤄져 있지는 않지만 대략적인 과정은 비슷하다고 볼 수 있다. Dex 파일을 앱 소스코드에서 직접 생성하지는 않기 때문에 Encryption Dex 파일은 Device 내 앱의 설치 경로나 APK 내부 등에 존재하고 있다. 모바일 앱 실행 시 최초로 실행되는 Entry Point Class에서 Encryption Dex 파일을 복호화하는 과정을 거친 뒤 복호화된 Dex 파일인 Original Dex File을 Loading시키기 때문에 앱은 기존과 동일하게 동작되게 된다.
[그림 6] Dynamic Dex Loading 기법의 LifeCycle
‘Dynamic Dex Loading’ 기법이 적용된 다양한 앱을 분석하며 [그림 6]과 같이 정리 할 수 있었다. 암호화된 Dex File은 어딘가에 존재해야 했으며, 경로는 App이 설치된 경로, App만 접근할 수 있는 내부 저장소, APK 내부가 될 수 있다. 암호화된 Dex 파일을 복호화하기 위해서는 Entry Point Class에 존재하는 복호화 Method에 의해서 이루어 질 수도 있고 JNI Library 파일을 불러와서 복호화하는 등 방법이 존재한다. 마지막으로 복호화한 Dex File을 Loading 시키는 방법은 Java Code 내에서 기존 앱의 정보를 변경시켜 Loading 시키거나 Memory에 Dex 파일을 올려서 앱을 실행시키는 기법이 존재하였다.
03. Dynamic Dex Loading 기법이 적용된 모바일 앱 분석
Dynamic Dex Loading 기법을 분석하기 위해서 [표 3]의 분석환경 및 디컴파일 도구를 활용하여 분석을 진행하였다.
분류 |
설명 |
|
분석 환경 |
Device : Galaxy A8 (Rooting Device, 9.0 version) Tools : Python 3.7, Frida 15.1.14, Frida-tools 10.5.4 |
|
디컴파일 도구 |
Apktool |
APK 컴파일 및 디컴파일 도구 |
Dex2jar |
Classes.dex 파일을 jar 파일로 변환시키는 도구 |
|
Jd-gui |
Jar 파일을 java 코드로 볼 수 있게 해주는 도구 |
|
Jadx |
Apk 파일을 별도의 과정 없이 바로 Java 코드로 보여주는 도구 |
|
JEB, IDA |
Apk 파일을 다양한 형태로 분석할 수 있는 상용 소프트웨어 |
[표 3] 모바일 앱 분석을 위한 환경 및 도구
1) 악성 APK 분석을 위한 구조분석
‘Dynamic Dex Loading’ 기법이 적용된 악성 APK(파일명 : hanasaving.apk, MD5 : D3BD37D67BC5CB9B5C400A42175D900D)를 통해 숨겨진 Original Dex 파일을 얻는 과정을 분석하였다.
[그림 7] Apk 압축 해제
‘hanasaving.apk’ 파일에는 총 3개의 dex 파일(Classes.dex, secret-classes.dex, secret-classes2.dex)이 존재한다. Classes.dex는 Dex파일의 시그니처 값 64 65 78 0A 을 가지고 있기 때문에 디컴파일을 통해 Smali코드를 확인할 수 있지만, secret-classes.dex와 secret-classes2.dex은 시그니처 값 OB FD 91 CD(암호화 방식에 따라 상이)이기 때문에 Original Dex파일일 것으로 추정이 가능하다.
[표 4] Dex 파일 Signature 값 비교
2) AndroidManifest.xml
[그림 8] hanasaving.apk – AndroidManifest.xml
hanasaving.apk는 Activity Class(com.anlopui.marc07.activity.MainActivity)와 Application Class(com.ttcn.mmcab.maind.xbgZKmyinv)를 갖고 있다. Application Class에서는 암호화되어 있는 Dex 파일을 복호화하고 메모리에 로딩하여 앱을 실행시키고 Activity Class는 앱 실행을 위한 소스코드이며 현재는 암호화되어 있어 확인할 수 없다.
[그림 9] hanasaving.apk – 패키지 계층 구조
Activity Class(com.anlopui.marc07.activity.MainActivity)는 [그림 9]와 같이 경로를 찾아갔을 때 존재하지 않았으며, 앞서 설명한 바와 같이 Application Class와 Activity Class가 설정되어 있을 경우에는 Application Class가 Entry Point가 되기에 가장 먼저 분석할 대상은 ‘com.ttcn.mmcab.maind.xbgZKmyinv’이다.
3) 소스코드 분석 : 암호화된 Dex 파일 복호화 과정
[그림 10] hanasaving.apk – 함수 명 : unZip
앱이 실행되면 ‘/data/app/com.anlopui.marc07-EJ6HjP4icdDJPJtj5XhaJw==’ 경로에 존재하는 base.apk 파일을 압축 해제하며, classes.dex 파일을 제외한 dex 파일이 존재할 경우 [그림 10] L19 ‘xbgZKmyinv.runFile’ Method에 의해 2개의 파일(secret-classes.dex, secret-classes2.dex)이 처리된다.
[그림 11] hanasaving.apk – 함수 명 : runFile$run()
‘runFile$run’ 함수 [그림 11] L12에서 암호화된 Dex 파일을 ‘tVmVhGDjy.decrypt’ 함수를 통해 복호화 시키는데 복호화 대상이 되는 dex 파일의 경로는 모바일 앱 내부에서만 접근이 가능한 내부 저장소(/data/user/0/com.anlopui.marc07/app_com.anlopui.marc07.MainApplication_dexDir_1.0/app/) 내 존재하는 파일(secret-classes2.dex, secret-classes.dex)이다.
[그림 12] hanasaving.apk – 함수 명 : decrypt
‘tVmVhGDjy.decrypt’ Method는 Libraries 경로에 있는 ‘libdn_ssl.so’ JNI Library를 호출한다. ‘libdn_ssl.so’ 내에는 ‘Java_com_ttcn_mmcab_maind_tVmVhGDjy_decrypt’란 함수가 존재하고 있으며 해당 함수를 통해 암호화된 dex 파일을 복호화한다.
[그림 13] libdn_ssl.so – 함수 명 : Java_com_ttcn_mmcab_maind_tVmVhGDjy_decrypt
libdn_ssl.so 내 존재하는 ‘Java_com_ttcn_mmcab_maind_tVmVhGDjy_decrypt’ 함수에서는 복호화한 dex 파일을 [그림 13] L14에 있는 fopen 함수를 이용하여 생성한다. C언어에서 fopen을 이용하기 위해 헤더 파일(stdio.h)을 include 하는 것 처럼 JNI Library에서도 마찬가지로 ‘libc.so’ 파일을 import 한다. 그렇기 때문에 DBI(Dynamic Binary Instrumentation) 도구인 Frida를 통해 JNI Library인 libc.so(fopen)을 후킹하여 복호화된 Dex 파일을 얻을 수 있다.
[그림 14] Frida JavaScript – libc.so Method Hooking Code
Frida에서 사용된 Script는 앱이 실행될 때 ‘libc.so’ 함수 내 fopen 대상을 출력하여 복호화된 dex 파일명 및 경로를 알 수 있다.
[그림 15] Frida JavaScript – 출력 값
코드 실행 결과, 암호화된 dex 파일을 복호화 한 뒤 기존 파일(secret-classes.dex, secret-classes2.dex)에 덮어 쓰기 한 것을 알 수 있다. 복호화 된 dex 파일의 Header 값을 확인해 보면 정상 값(64 65 78 0A)을 갖고 있었으며, 해당 파일을 디컴파일하면 기존에는 볼 수 없었던 Activity Class에 접근할 수 있게 된다.
[그림 16] Decrypt Dex - MainActivity
‘Dynamic Dex Loading’ 기법을 분석하기 위해 사용한 악성 APK(hanasaving.apk)에서는 Anti-Debugging이나 Rooting Detection, 다른 종류의 난독화 등의 모바일 앱 보호 기법이 적용되어 있지 않아 Original Dex 파일을 복호화하고 불러오는 과정을 분석하는데 제한 사항이 없었다.
05. 대응 방안
모바일 앱을 위한 전반적인 구성을 도식화하면 [그림 17]과 같다. 모바일 앱의 소스코드 흐름 분석, 주요기능 및 로직을 발견하기 위해 ‘Static Analysis’를 수행한다. ‘Static Analysis’을 통해 기본적인 앱의 정보(난독화 여부, 앱에서 제공하는 기능 등)을 확인한 후에는 이를 토대로
동적 분석 방법에는 △동적 디버깅, △API 후킹을 이용한 Class/Method Tracing, △행위 분석, △네트워크 패킷 분석, △실행 및 Logcat 정보 분석 등 다양한 방법이 존재한다. 이와 같이 동적 분석은 파일의 실제 실행 환경에서 다양한 변화를 관찰할 수 있기에 정교한 분석이 가능하여 난독화가 적용된 앱도 상대적으로 수월한 분석이 가능해진다. ‘Dynamic Analysis’ 행위를 방지하기 위해 Anti-TECH(Rooting Detection, Anti-Tampering, Anti-Debugging, Memory Protection 등의 보안 기술을 의미)기술 요소가 존재하는데 적용되어 있을 경우 일반적인 방법으로는 동적 분석 행위가 불가능해진다.
[그림 17] 모바일 앱 분석 프로세스 도식도
Anti-TECH가 적용되어 있는 앱에서 ‘Dynamic Analysis’의 기법 중 동적 디버깅을 하기 위해서는 [그림 18]의 과정이 필요하다. Anti-TECH를 우회하기 위해서는 Code Tampering, API Hooking 등의 기법이 존재한다. 그 중에서 API Hooking기법을 살펴보면 Anti-Debugging을 우회하기 위해서는 Hooking Platform Detection, Rooting Detection 두 가지 보안 기술을 우회 해야 하는 전제 조건이 붙으며, 이와 같은 구조에 의해서 공격자 개개인의 기량에 따라서 분석을 진행하는데 걸리는 시간을 지연시키거나 분석을 제한할 수 있게 된다.
[그림 18] Anti-Debugging을 우회하기 위한 요구 사항
1) 모바일 앱 난독화 기술유형
앞서 분석했던 악성 앱인 ‘hanasaving.apk’은 단순히 ‘Dynamic Dex Loading’ 기법만 적용되어 있었기에 암호화된 Dex 파일을 복호화하여 Loading 시키는 과정까지 큰 어려움 없이 소스코드 레벨에서 분석이 가능하였다. 반대로 실제 서비스 중인 상용 앱의 경우에는 Dynamic Dex Loading 외에도 [그림 19]과 같이 다양한 난독화 기법이 적용되어 있어서 소스코드의 흐름을 분석하고 원하는 특정 로직을 찾기 위해 ‘hanasaving.apk’를 분석할 때보다 더욱 많은 시간이 요구된다.
[그림 19] 코드를 대상으로 한 난독화 기술 종류
(출처 : Android Code Protection via Obfuscation Techniques: Past, Present and Future Directions)
해외 보안 포럼 DEVOPSdigest의 기술문서에 따르면 모바일 앱은 API 패키지를 중심으로 구축되는 특징이 있다고 한다. ‘OWASP API Security Top 10’의 취약점 중 8개의 취약점은 앱 개발 프로세스와 직접적인 관련이 있으며 이를 보호하기 위한 보안 기능은 다수 존재하고 있다. 코드 난독화만 적용을 한다고 해서 궁극적인 보안 조치가 될 수는 없지만 매우 효과적이라 볼 수 있다. OWASP 취약점 목록 10개의 취약점 중 7개의 취약점이 난독화 적용을 통해 보안성 향상 효과를 볼 수 있다.
|
Data Encryption |
Code Obfuscation |
App&API Shielding |
Secure Communications |
API Segmentation |
Broken Object Level Authorization |
O |
|
|
O |
O |
Broken Authentication |
O |
O |
|
O |
O |
Excessive Data Exposure |
O |
O |
O |
O |
O |
Broken Function Level Authorization |
O |
O |
O |
O |
O |
Mass Assignment |
O |
O |
O |
O |
O |
Security Misconfiguration |
O |
O |
O |
O |
O |
Injection |
O |
O |
O |
O |
O |
Improper Assets Management |
O |
O |
O |
O |
O |
[표 5] OWASP API TOP 10에 대한 보안 조치
(출처 : DEVOPS digest, “Avoiding the Top Mobile API Security Weaknesses”)
2) 모바일 앱을 보호하기 Anti-TECH 적용
모바일 앱에 존재하는 잠재적 취약성에는 △앱을 무단으로 변조하여 중요 로직을 우회하는 Tampering(위∙변조), △ 기계어를 Java로 변환시키는 Decompile, △Device의 시스템을 제한 없이 조작이 가능하게 하는 Rooting 등이 있다. 대부분의 민감한 정보를 다루는 모바일 앱에서는 잠재적으로 존재하는 취약성을 방지하기 위해 난독화와 함께 Anti-TECH 요소들을 적용하고 있으며 요소 별 기능과 얻을 수 있는 기대 효과는 [표 6]과 같다.
Anti-TECH |
설명 |
Anti-Tampering |
불법적인 데이터 위/변조 방지 |
Anti-Debugging |
앱의 동작 방식을 분석하는 동적 디버깅 방지 |
Rooting Detection |
루팅된 기기에서 실행 차단 |
Platform Detection |
루팅 Tool 또는 특정 해킹 관련 플랫폼(Frida, Xposed 등) 감지 및 차단 |
Virtual Machine Detection |
가상 머신 탐지 및 차단 |
Anti-Decompile |
일반적인 방법으로 APK를 디컴파일 할 수 없도록 재구성 |
Hacking Tool Detection |
해킹툴(NetHunter, AndroRAT 등) 동작 탐지 및 차단 |
Memory Protection |
메모리 덤프 및 변조 방지 |
[표 6] Anti-TECH : 모바일 앱을 보호하기 위한 기능 예시
06. 결론
보안 요소(난독화, Anti-TECH)가 적절히 적용되어 있는 앱을 분석하기 위해서는 상황에 따라 특정 보안 요소 우회가 필요하다. 그러나 우회를 하기 위해서는 또 다른 보안 요소를 우회해야 하는 [그림 20]와 같은 Life Cycle 구조를 갖고 있기 때문에 앱에 존재하는 잠재적인 취약성(금융 피해, 민감정보 유출 등)을 효과적으로 방지할 수 있다. 그렇기에 민감정보를 활용하는 앱 서비스 제공 벤더사의 경우 사용자 데이터를 보호하기 위해서는 필수적으로 보안 기술을 적용해야 하며, 효과적인 보안 안전성을 위해서 일부 기능만 적용하기 보다는 서비스 특성에 맞게 필수적인 기능과 선택적인 기능을 종합적으로 적용하여 다양한 방면의 위협을 방지하는 것이 필요하다.
[그림 20] Mobile Vulnerability Analysis Cycle
07. 참고 자료
[1]https://www.virustotal.com/gui/file/b038b5dfceeb5b59d2abcd376814defb2a7022ba5b65cf917bf857439835e2e5
[2]https://www.virustotal.com/gui/file/6f4e50b8e9e601e3af042a89b9e2f071d975308b07c89578ad3645bea4274867
[3] https://developer.android.com/guide/topics/manifest/manifest-intro
[4] https://frida.re/docs/home/
[5] https://github.com/ClaudiuGeorgiu/Obfuscapk
[7] https://www.devopsdigest.com/avoiding-the-top-mobile-api-security-weaknesses
[8]https://docs.microsoft.com/ko-kr/microsoft-365/security/intelligence/fileless-threats?view=o365-worldwide