2주차
안드로이드 파일시스템과 데이터 구조
<왜 알아하는지?!>
앱 취약점 분석 시 - 앱을 디버깅/수정/설치할 때 리눅스 시스템 안에서 작업
-> 터미널 창에서 접속을 해서 리눅스랑 똑같이 명령어 입력해서 작업함
앱이 어떤 데이터를 저장을 한다 -> 유출 위험성을 확인하고 싶다!
앱 안에서 사진을 찍고 -> 폰 안에 있는 사진첩 안에 저장 / 앱 안에 저장하게 되면 앱 삭제하면 데이터도 삭제됨
==> 분석하는 과정에서 파일 시스템을 봐야 함, 어디에 저장되는지를 알아야 함!
1. 안드로이드 파일시스템
1-1) 파일 시스템 ; 파일을 저장하기 위해 관리하는 체계
->운영체제마다 다르다.
- 윈도우 계열: FAT(File Allocation Table), NTFS(NT File System)
- 리눅스 계열: 확장 파일 시스템(ext, ext2, ext3, ext4), ZFS, ResierFS, XFS
안드로이드는 리눅스 기반 - 리눅스 계열의 파일 시스템을 사용 + 추가적으로 안드로이드에 필요한 파일 시스템 포함
<OS (ios, android, window)>
boot.img (어떤 OS를 구동시킬지에 대한 정보)
system.img
- <Linux> etc, home
- <Window> AppData, ProgramFiles(x86), ProgramFiles
1-2) 파일시스템의 사본
boot | 부팅이미지. 커널 이미지와 ramdisk를 포함 |
system | Android 프레임워크 |
recovery | OTA(On The Air) 프로세스 중에 부팅된 복구 이미지 |
cache | 임시 데이터 |
misc | 복구에 사용되는 파티션 |
!!userdata | 맞춤 설정 데이터 + 사용자가 설치한 애플리케이션과 데이터 |
metadata | 기기 암호화 + 16MB 이상인 경우에만 사용됨 |
vendor | Android 오픈소스 프로젝트(AOSP)에 배포할 수 없는 바이너리 포함 ; 기본 시스템 앱 말고 추가로 설치하는 앱 |
radio | 무선 이미지(무선 관련 소프트웨어 있는 기기만) |
tos | Trusty OS의 바이너리 이미지 저장 |
2. 부팅 순서
1. 부트로더 로드
2. 부트로더가 메모리를 초기화
3. A/B업데이트를 사용하는 경우 - 부팅할 현재 슬롯을 결정
ㄴ> 이미지 업데이트할 때 매번 직접 usb 디바이스 쓰기/읽기 할 수 없음 -> OTA 기술(On The Air) ; 특정 서버로부터 부트 이미지를 받아서 업데이트!
온라인에서 업데이트를 할 때는 악성 이미지를 받을 수 있는 위험성 있음 -> 이를 방지하고자 A, B 업데이트 파일 복사를 해서 업데이트
4. 복구 모드를 대신 부팅해야 하는지 확인
5. 부트로더 - 커널과 RAM 디스크가 포함된 이미지를 로드
6. 부트로더 - 자체적으로 실행할 수 있는 압축된 바이너리로 커널을 메모리에 로드 시작
<메모리로 로드해서 압출을 풀고 메모리로 실행>
7. 커널 - 자체적으로 압축을 풀고 메모리로 실행 시작
8. 해당 시점에서 오래된 기기는 RAM 디스크에서 init을 로드하고, 새로 나온 기기는 /system 파티션에서 이를 로드
9. /system에서 init이 실행되며 /vendor, /oem, /odm 등 다른 모든 파티션이 마운트 되기 시작하고, 이후에는 코드 실행이 시작되어 기기가 시작
ㄴ> init 프로세스가 실행되면서 os 프로세스 실행
oem / odm - 다른 회사에서 만든 앱
3. 안드로이드 데이터 구조
3-1) 데이터구조의 사본
데이터 구조를 특히 집중적으로! - 사진 앱으로 사진 찍으면 다 data 폴더 안으로 들어감
패키지 이름 = 앱 이름
/data/data/[패키지이름]/shared_prefs | 어플리케이션의 공유 설정 파일이 저장되는 영역 |
/data/data/[패키지이름]/cache | 어플리케션이 필요한 임시파일이 저장되는 영역 |
/data/data/[패키지이름]/database | 어플리케이션이 필요한 데이터베이스 파일이 저장되는 영역 |
/data/data/[패키지이름]/files | (데이터베이스, 캐시 제외) 어플리케이션에서 사용하는 일반 파일이 저장되는 영역 |
/data/data/[패키지이름]/lib | 어플리케이션이 필요한 라이브러리 파일이 저장되는 영역 |
만약에 카카오톡 리버싱하고 싶으면? -> apk 뜯어서 -> 데이터구조 보면 됨
+) 전체 디렉토리를 보기 위해서는 root 권한 필요! - ls 해도 극히 일부밖에 안 나옴
3주차
안드로이드 앱 디컴파일, 리패키징 수행하기
1. 디컴파일(Decomplie)
1-1) 디컴파일?
compile의 반대 ; decomplie : new.apk -> file1, file2 ...
ㄴ compile : file1, file2 ... -> new.apk
1-2) 디컴파일을 통해 할 수 있는 것? ; 디컴파일을 왜?
-앱의 로직 분석 가능 (소스를 볼 수 있으니까 - 상세한 내부 로직 알 수 있음)
-앱의 이미지 수정 - apk 파일 만들 때 리소스 파일에 저장
-앱의 기능 수정 (마찬가지로 소스를 볼 수 있으니까 but 쉽지는 않음. 완전히 동일하게 디컴파일되는 것이 아님)
1-3) 디컴파일 단계
1. apk 내부 파일 추출 (apk == zip 파일 -> apk 압축 툴로 압축 풀면 그나마 읽을 수 있는 형태로 풀림)
2. apk 파일을 java class 파일로 변환
3. jar 파일 올리면 디컴파일 수행됨!
=> 애플리케이션 공개 후 디컴파일 가능하기 때문에 취약함! -> 난독화(변수 이름 바꾸기, 순서 바꾸기)
[실습]
분석 apk 찾기 - https://apkpure.com/kr/
1. APK 내부 파일 추출 - APKtool 설치
APKtool (https://ibotpeaches.github.io/Apktool/install/)
decode 명령어 -> $ apktool d testapp.apk
2. APK 파일을 java class 파일로 변환 - 상세한 분석을 위해서 dex2jar 도구 이용
오류 나면 dex2jar 2.1 버전으로 설치!
-> $ d2j-dex2jar.bat testapp.apk
-> $ ./d2j-dex2jar.sh testapp.apk
smali 코드 - 어셈블리어(기계어코드)
아직은 java 수준은 안돼서 한번 더 변환하는 작업 필요
수정은 가능하지만 이해는 어려움
dex -> (smali) -> java
: Dex2jar(단계 건너뛰고 한번에 jar 파일로)
dex
^
smali - class.dex
^
jar(java 코드들을 합친 거)
3. 디컴파일 수행; 변환된 파일을 자바 디컴파일러(Bytecode-Viewer) 사용하여 디컴파일 후 내부 소스코드 분석
Bytecode-Viewer (https://bytecodeviewer.com/)
*javaDecomliler - jd gui
android.support
androidx
-> 내정된 부분!
===
+)
*build / generate 차이?
generate : 서명+build(서명이 되어야만 제대로 설치가 됨 - 앱의 무결성/앱 개발자를 위해서)
키는 아무나 만들 수 있음(ios는 키 만들기 어려움)
*debug / release 차이?
dubug - debug 로그 메세지 전부 포함
release - 위 내용 전부 제외 (컴파일 옵션이 다름) (나중에 gdb 명령어가 안 먹히는 상태)
-> 앱에 대한 디테일한 정보 유무 차이
*동적(나중에 따로 연결!)/정적 라이브러리(포함하는거)
2. 리패키징(Repackaging)
; 재포장! - 디컴파일하고, 추출한 소스/이미지를 수정해서 재빌드하는 것
new.apk(ZIP) -decompile-> files -repackaging-> ZIP
2-1) 리패키징 단계
- APK decompile
- APK decompile을 통해 추출한 소스 코드 수정 ; smali 코드 단계에서 해야 함 (java 소스코드와 비교하면서!)ㄴ수정을 힘들게 하는 게 난독화의 역할
- APK 재빌드
- 서명
[실습]
1, 2번은 위 실습 참고
3. APK 재빌드
// apktool b [패키징 할 폴더명] -o [apk파일명 지정]
apk 빌드 명령어 실행 후 -> dist 디렉토리가 생성 + 해당 디렉토리 내 apk 파일이 생성됨
4. 서명
안드로이드에서는 앱의 무결성을 검증을 위해 앱을 빌드할 때 서명을 하도록 되어있음.
-> 변조된 앱에 신뢰할 수 있는 서명이 없는 경우 - 설치 실패 문구를 발생시켜 설치하지 못하게 함
변조된 앱은 디컴파일 하는 순간 무결성이 깨져 서명이 깨짐 -> 이를 다시 설치 가능한 apk로 만들기 위해서
=> 서명 파일을 생성하여 리패키징한 앱에 재서명 작업 필요!
서명을 하려면 키 파일을 만들고 주입을 해야 함
(키 파일을 pem 형식으로 넣어야 됨. 이미 만들어진 키 파일을 넣는다고 가정!)
$ java -jar signapk.jar testkey.x509.pem testkey.pk8 [서명할 APK 이름] [서명 후의 APK 명]
->?!
[과제]
✔️ Mission1: 디컴파일을 수행하고 앱 로직을 분석해서 password 값 알아내기
1. APK 파일을 java class 파일로 변환하기
성공적으로 변환 완료!
2. 디컴파일 수행
jd-gui 자바 디컴파일러로 jar 파일을 열어 디컴파일 수행
-> 여러 폴더를 열어 살펴보던 중.. 로그인 관련 소스코드 파일 발견!
mainactivity에서 login 함수 호출하는 부분
login(String paramString1, String paramString2, String paramString3, Context paramContext)
paramString1 -> username(사용자 입력 부분)
paramString2 -> password(사용자 입력 부분)
paramString3 -> str (변수)
String str = MainActivity.this.getString(2131755116);
return byteArrayToHex(arrayOfByte1).equals(paramString3);
-> 해당 구절에서 .equals(paramString3) 을 보아 paramString3 (== str == 2131755116 )을 이용해 패스워드를 찾아야하는것 같다
2131755116 -> hex 값으로 변환; 0x7f10006c
3 . APK 내부 파일 추출
\res\values 위치에서 public.xml 파일에서 위 hex 값 이용해 id 찾기
strings.xml 에서 비밀번호 찾기
203d233e382c1e215a6a7c6c7e725c6b
[비밀번호 찾기]
비밀번호 입력 값이 login 함수를 통해 어떤 값이 됨.
어떤 값 == 203d233e382c1e215a6a7c6c7e725c6b
-> 입력 값(패스워드)을 찾기 위해서는 login 함수 알고리즘을 역으로 적용하여 패스워드를 찾아야한다!
byteArrayToHex(arrayOfByte1) ; 10진수 -> 16진수 변환 함수
==> 16진수 -> 10진수 (+ stringBuilder.append(String.format("%02x" ~ ; 2자리 16진수로 변환)
20 -> 32
3d -> 61
23 -> 35
3e -> 62
38 -> 56
2c -> 44
1e -> 30
21 -> 33
5a -> 90
6a -> 106
7c -> 124
6c -> 108
7e -> 126
72 -> 114
5c -> 92
6b -> 107
[32, 61, 35, 62, 56, 44, 30, 33, 90, 106,124, 108, 126, 114, 92, 107] ; arrayOfByte1
arrayOfByte1 = arrayOfByte2 + arrayOfByte3 (X)
+) ?? 왜 2 3 순서가 바뀜 ?
arrayOfByte1 = arrayOfByte3 + arrayOfByte2 (O)
arrayOfByte3 - 0 ~ i/2
arrayOfByte2 - i/2 ~ i
근데 arrayCopy는 arrayOfByte2 부터!
arrayOfByte2 = [32, 61, 35, 62, 56, 44, 30, 33,
arrayOfByte3 = 90, 106,124, 108, 126, 114, 92, 107]
for 문에서 arrayOfByte4에 담긴 값들과 xor 연산 -> xor 연산을 두 번 해주면 원래 값이 된다는 것 이용!
arrayOfByte2 = [48, 56, 49, 51, 50, 54, 35, 36
arrayOfByte3 = 74, 111, 110, 97, 116, 104, 97, 110]
48, 56, 49, 51, 50, 54, 35, 36
74, 111, 110, 97, 116, 104, 97, 110
이제 아스키로 변환해주면, 비밀번호가 나타난다!
081326#$Jonathan
안됨
혹시 몰라서 순서 바꿔서 입력해봤더니 된다!!!
Jonathan081326#$
ㅠㅠ
감격
✔️ Mission2: otp 인증 단계 통과하기
로그인 성공하면 위와 같은 otp 인증 단계 화면이 나온다.
다시 MainActivity 확인해보면 로그인 성공 시 SubActivity.class 로 전환됨.
SubActivity 확인하기
'보안 > android' 카테고리의 다른 글
[앱][리버싱] 앱 후킹 도구 frida 설치 (0) | 2021.10.28 |
---|---|
[앱][리버싱] 6주차 정리 ; drozer로 앱 분석 (0) | 2021.10.28 |
[앱][리버싱] 4,5주차 정리 ; ADB로 앱 디버깅 (0) | 2021.10.28 |
[앱][리버싱] 과제보충 (0) | 2021.09.17 |
[앱] 1주차 정리+과제 ; 안드로이드 앱 만들기 (0) | 2021.08.27 |