UnCrackable-Level1.apk - 2 (Secret String)
OWASP에는 모바일 보안 테스트 할 수 있는 앱을 제공함
분석을 하면서 참고해야하는 부분을 풀이할 예정
진단 환경
- 단말 : Nexus6P - 7.1.1
- jadx-gui : Dex to Java decompiler
- APK Easy Tool : Decompile, Compile, Signing 등 쉽게해주는 툴
- APP : UnCrackable-Level1.apk
https://github.com/OWASP/owasp-mstg/tree/master/Crackmes/Android
1. Frida
2. 코드 패치(나중에)
3. gdb(나중에)
분석 1 - 앱 구동 확인
앱 실행하면 루팅 탐지를 하며, 앱이 종료됨
정적분석 진행
1. "AndroidManifest.xml" 파일에서 앱 구동시 시작되는 Activity를 확인
2. "onCreate"에서 루팅 및 디버거 탐지를 하고 있음
***************************************** 안드로이드 생명주기 경로 추가 *****************************************
2-1 루팅탐지 : sg.vantagepoint.a.c 클래스에 있는 각 메소드는 boolean 타입이며, 리턴값이 True 일 경우 루팅 판단
c.a()
- 시스템 PATH에 "su" 파일이 존재하는지 확인
c.b()
- Build.TAGS가 Null이 아니면서 "test-keys"가 있는지 확인
: "test-keys"를 확인하는 이유
→ 커널이 컴파일/빌드될 때 서명을 "test-keys"로 하고 있음
→ 커널이 컴파일/빌드됐다 == 변조된 OS일 가능성이 있다
c.c()
- str 변수에 있는 파일이 있는지 확인
2-2 디버거탐지 : sg.vantagepoint.a.b 클래스에서 디버거 판단
c.b()
- "context.getApplicationContext().getApplicationInfo().flags" 리턴되는 값이 0이 아닐경우 디버거 사용
풀이 1 - 1 FRIDA
공통점은 "String"을 이용해 루팅 탐지 하고 있음
소스코드를 봤을 때 아래와 같이 시도할 수 있다고 생각함
1. String 함수를 후킹할 것인가
- 장점 : 패턴을 만들 수 있음
- 단점 : 루팅 탐지 하지 않는 곳에서도 후킹을 계속 함(모든 문자열 후킹)
2. 리턴값을 변경할 것인가
- 장점 : 직관적
- 단점 : 소스코드 길어짐
3. 루팅탐지에 사용된 import 함수를 후킹할 것인가
- 장점 : 자신만의 루팅탐지 함수를 만들 수 있음
- 단점 : ...
코드 예상 순서
1. 루팅 탐지에 사용된 문자열 정리
2. 루팅 탐지에 사용된 모듈 후킹 (Bulid.TAGS, java.io.File)
3. 루팅 탐지에 사용된 문자열이 있는지 확인
4. 사용된 문자열이 있을 경우 리턴 값 변경
1. 루팅 탐지에 사용된 문자열 정리
sg.vantagepoint.a.c 클래스에서 루팅탐지에 사용된 문자열 정리
var checkRoot() = [
//sg.vantagepoint.a.c.a()
"su",
//sg.vantagepoint.a.c.b()
"test-keys",
//sg.vantagepoint.a.c.c()
"/system/app/Superuser.apk",
"/system/xbin/daemonsu",
"/system/etc/init.d/99SuperSUDaemon",
"/system/bin/.ext/.su",
"/system/etc/.has_su_daemon",
"/system/etc/.installed_su_daemon",
"/dev/com.koushikdutta.superuser.daemon/"
]
2. 호출되는 문자열 후킹
테스트 단말기는 OS 빌드를 하지 않아 Bulid.TAGS 테스트를 제외하며, java.io.File만 후킹할 예정
아래코드는 "exists()" 함수를 후킹해 파일명 출력하는 코드임
var File_exists = Java.use('java.io.File');
File_exists.exists.implementation = function () {
var File_Name = File_exists.getName.call(this);
console.log(File_Name)
return this.exists.call(this);
}
"exists()" 함수에 사용된 파일명 모두 출력함
frida -l test.js -U --no-pause -f owasp.mstg.uncrackable1
3. 루팅 탐지에 사용된 문자열이 있는지 확인
출력된 파일명이 루팅 탐지에 사용된 문자열이 있는지 "indexOf" 함수로 확인
var File_exists = Java.use('java.io.File');
File_exists.exists.implementation = function () {
var File_Name = File_exists.getName.call(this);
if (checkRoot.indexOf(File_Name) > -1) {
console.log(File_Name)
}
return this.exists.call(this);
}
모든 파일명이 출력되는게 아니라 "su" 파일명만 출력함
frida -l test.js -U --no-pause -f owasp.mstg.uncrackable1
4. 사용된 문자열이 있을 경우 리턴 값 변경
exists는 파일이 있을 경우 "true"를 반환
var File_exists = Java.use('java.io.File');
File_exists.exists.implementation = function () {
var File_Name = File_exists.getName.call(this);
if (checkRoot.indexOf(File_Name) > -1) {
return false;
}
return this.exists.call(this);
}
루팅탐지 문자열이 있을 경우 리턴 값을 "false"로 변경
frida -l test.js -U --no-pause -f owasp.mstg.uncrackable1
최종 소스
/*
frida -l test.js -U --no-pause -f owasp.mstg.uncrackable1
*/
Java.perform(function () {
var checkRoot = [
//sg.vantagepoint.a.c()
"su",
//sg.vantagepoint.a.b()
"test-keys",
//sg.vantagepoint.a.c()
"/system/app/Superuser.apk",
"/system/xbin/daemonsu",
"/system/etc/init.d/99SuperSUDaemon",
"/system/bin/.ext/.su",
"/system/etc/.has_su_daemon",
"/system/etc/.installed_su_daemon",
"/dev/com.koushikdutta.superuser.daemon/"
]
var File_exists = Java.use('java.io.File');
File_exists.exists.implementation = function () {
var File_Name = File_exists.getName.call(this);
if (checkRoot.indexOf(File_Name) > -1) {
console.log(File_Name)
return false;
}
return this.exists.call(this);
}
});
풀이 1 - 2 코드패치
풀이 1 - 3 디버거(gdb)
'Technical Docs > Android' 카테고리의 다른 글
[AVD] Play Store? (0) | 2022.07.21 |
---|---|
[분석] UnCrackable-Level1.apk - 2 (Secret String) (0) | 2022.06.28 |
[Frida] Root Check : getpid (0) | 2022.06.22 |
[AVD] 환경구성 : 생성 및 환경변수 설정[AVD&ADB] / MAC & Windows (0) | 2022.06.21 |
내돈내산 전자책 PDF 로 바꿀 수 없을까? (0) | 2022.06.07 |