난독화 솔루션의 종류
1. 에러기반 난독화
- 리패키징 방지 기능
- smali 코드에서 자바 코드로 변환할 때 사용되는 dex2jar 도구의 에러를 유발
- 오픈소스 APKProtect가 존재 (취약점이 발견되어 개발 중단)
2. 소스코드기반 난독화
- 자바 코드의 클래스, 메소드명, 필드명, 변수명 등을 임의의 문자(a, b, c)로 치환
- 오픈소스 Proguard가 존재
3. 문자열기반 난독화
- 중요 정보를 다루는 평문의 문자열을 암호화하여 숨김 (대칭키)
- 꼭 필요한 구간에 난독화를 적용해야 하며, 모든 곳에 적용하면 앱 설치 및 기능이 정상적으로 동작하지 않음
- 상용 존재
4. 멀티덱스기반 난독화
- 실질적인 앱을 구동하기 위한 코드, 원본 코드가 존재
- 원본 코드는 리소스 파일에 암호화하여 숨김
- 상용 Dexguard가 존재
소스코드 및 멀티덱스 난독화 (난독화 솔루션)
1. 프로가드
- 대표적인 소스코드 난독화
- 특정 프로그램을 이용하면 일부 난독화 해제 기능 제공
- 분석가는 특정 프로그램을 이용하지 않음 (경험으로 인해 평문 수준의 소스코드 확인 가능)
2. 덱스가드
- 대표적인 멀티덱스 상용 난독화
- 실제 앱을 구동하기 위한 코드를 숨기거나 삭제할 때 취약점 발생 (취약점 조치)
쓰레기 코드 삽입 (코딩)
- 불필요한 클래스, 메소드, 오버라이딩, 변수 등 쓰레기 코드 삽입
- 앱 구동 시 필요한 코드, 비슷한 코드, 의미 없는 코드 등 삽입
- 전혀 의미 없는 암호화 코드 삽입
중요 변수 인코딩/암호화 (코딩)
- 아이디, 패스워드, 결재, 대칭키, 서명 값 등 중요 정보를 다루는 변수는 인코딩/암호화
- char[]형 배열로 처리하지 말 것 (메모리 덤프 시 평문 확인 가능)
검증 코드 은닉 (코딩)
- 예상하기 어려운 함수 내부에 검증 코드 구현
- 쓰레기 검증 코드를 쉽게 확인이 가능한 곳에 위치
문자열 조립 (코딩)
- 문자열 검색을 피하기 위해 문자열을 조립해서 사용
- 검증 루틴의 경우 평문의 문자열을 사용하지 말고, 한글자씩 비교
- superuser.apk (X)
- "s" + "up" + "e" + "r" + "u" ... (O)
의미 없는 클래스명 (코딩)
- 프로가드는 일부 클래스, 메소드, 변수만 치환
- 그 외의 것들은 치환되지 않으므로 전혀 의미 없는 이름으로 치환
- CryptoClass.java, Autofill.java 등 --> cc.java, aa.java
NDK (코딩)
- 중요 정보는 NDK를 이용해 개발
- JNI 이용
프로가드 적용 예시
안드로이드 난독화 대응 방안으로 쉽게 수행할 수 있는 프로가드를 적용하는 방법을 소개한다.
보통 프로가드만 적용하면 분석가에 의해 7~80% 이상의 원본 수준의 소스코드를 확인할 수 있다. 하지만, 최소한 프로가드는 적용해야 한다.
프로가드를 적용하려면 안드로이드 스튜디오 좌측 프로젝트의 Gradle Scripts 항목에서 build.gradle을 더블클릭하면 기본적으로 minifyEnable의 속성이 "false"로 설정되어 있다. 이 속성을 "true"로 변경하면 프로가드가 적용된다.
Gradle 파일이 변경되었으므로 현재 프로젝트와 동기화를 하기 위해 상단의 "Sync Now"를 클릭한다.
코드를 변경했으니 배포용 APK 파일을 빌드하고, dex2jar 파일로 빌드된 APK 파일을 디컴파일해서 jd-gui로 열면 대부분의 클래스, 메소드, 변수 이름은 단순한 문자열로 변환이 되었다.
프로가드가 적용된 APK 파일을 디컴파일하여 smali 코드를 변조하는 것은 가능하지만, 방대한 소스 코드를 분석하는데 시간이 오래걸리게 할 수 있다는 장점이 존재한다.
▶ 안드로이드 암호화 구현 취약점 (Android AES 복호화)
▶ 안드로이드 루팅 탐지 우회 (Frida Hooking)