APP 진단/iOS

9. Jailbreak Detection 3 - 탈옥 탐지 우회 실습 1

takudaddy 2022. 11. 16. 23:10

 

 

 

[목차]

 

 

 

1. DVIA - Jailbreak Test 1

       - 바이너리 파일 Export

       - Ghidra 실행 후 바이너리 파일 Import

       - 앱 탐지 동작 분석

       - 기드라 키워드 검색

       - otool로 ASLR(또는 PIE) 적용 여부 확인

       - JS 파일 작성 및 루팅 우회

               - 분기점 조건 별 주소 확인

               - 기본 코드 작성 및 설명

               - Frida에 파일 로드 후 주소 값 확인

               - 레지스터 값 확인

               - 코드 추가 작성 및 탈옥 탐지 우회

 

 


 

 

 

1. DVIA - Jailbreak Test 1

: 탈옥 탐지 테스트 시 'Device is Jailbroken' 알림 발생

 

 

- 작업 절차

: Ghidra로 로직 파악 > FRIDA로 탈옥 탐지 우회

 

 

 

 

1) 바이너리 파일 export

- 파일 경로 : Application(User) /var/containers/Bundle/Application/

- 파일 사이즈로 정렬 시키면 가장 큰 파일

 

 

 

 

2) Ghidra 실행 후 바이너리 파일 Import

OK!

 

 

Yes!

 

 

Analyze!

(시간 좀 걸림)

 

 

 

* 참고로 기드라의 기능 관련 사용방법은

Help > Contents에서 확인 가능

 

 

 

 

 

3) 기다리면서 앱 내 탐지 동작 분석

- 알림 문자열을 힌트로 삼아 키워드 검색해볼 수 있다

 

 

 

 

4) 기드라 키워드 검색

Search > For Strings

 

 

 

- 검색 값 세팅 해주고 Search!

 

 

 

- 알림 문자열 키워드 검색 시도 후

찾아진 키워드 더블클릭 시 해당 주소로 이동함

 

 

 

 

- 해당 문자열을 참조하는 곳 확인 (XREF[1]...)

- 해당 부분 더블클릭!

 

 

 

- 어셈블리 분석이 가능하면 그대로 살펴봐도 좋고

IDA Pro처럼 해당 어셈블리 부분을 그래프로

보여주는 기능의 도움을 받아도 좋음

 

 

Window > Function Graph

 

노란 부분이 검색 문자열 있는 부분,

각 블럭의 주소 값을 더블클릭 하면

해당 주소가 호출되는 블럭으로 이동하게 되며

이를 통해 구조 및 흐름 파악이 가능

 

 

예) 하단 이미지 윗 블럭의 마지막 어셈블리

(tbz w0, #0x0) 부분이 어떤 작업을 하는데 조건에 맞는 경우(If)

정해진 주솟값 (1001cc17c) 블럭으로 이동,

 

 

Device_is_Not_Jailbroken (우리 목적지)

 

 

조건이 맞지 않는 경우(else)

탈옥 탐지 주소(1001cbdd4) 블럭으로 이동한다.

 

대충 흐름 파악이 끝났으니

프리다로 후킹 코드를 작성해본다.

 

 

 

 

5) otool로 ASLR(또는 PIE) 적용 여부 확인

거의 모든 바이너리는 ASLR이 적용되어 있는데

ASLR( Address Space Layout Randomization)이란

데이터 영역의 주소를 랜덤하게 바꿔주는

메모리 보호 기법 중 하나이다.

 

해당 ASLR 설정이 되어 있는지 여부는

otool(object tool)로 확인이 가능하다.

 

- putty로 붙어준 뒤 해당 바이너리 경로에서

otool 명령어 실행 (# otool -Vh DVIA-v2)

 

PIE 값이 존재하는 것을 확인할 수 있는데

PIE는 바이너리 영역의 주소를 무작위화시키는

메모리 보호 기법이다.

 

여튼 메모리 보호기법이 걸려있기 때문에

바이너리가 메모리 어느 곳에 로딩될지 알 수 없으므로

find base address 문법 사용이 가능한

모듈을 통해 코드를 작성해 본다.

 

 

 

 

6) JS 파일 작성 및 루팅 우회

6-1) 분기점 조건 별 주소 확인

(분기점 클릭하면 해당 주소가 하이라이트됨)

 

1001cbdd0 => 0x1cbdd0

 

 

6-2) 기본 코드 작성 및 설명

// (1) 사전 준비
// (1-1) 먼저 DVIA-v2 바이너리가 메모리에 올라갔을때 실제 할당된 주소를 변수(realBase)에 담는다
var realBase = Module.findBaseAddress('DVIA-v2') // <-- 실제 바이너리 이름 또는 프로세스 이름을 넣어줘야함! ($ frida

// (1-2) 주소 한번 출력해 확인해보자
console.log(realBase) 

// (1-3) 주소값(16진수) 까지 더해주면 사전 준비 끝
var Jailbreak_address = realBase.add('0x1cbdd0') 

// (2) 변조 시도 (interceptor - 반환값 또는 특정 무언가를 변조시 선언하여 사용)
Interceptor.attach(Jailbreak_address, {    // target 설정은 첫 번째 인자, 다음으로 콜백 지정
  onEnter:function(args){     // 콜백은 onEnter:function(args) <-- 기본 구조, onLeave:(반환값 변조시 사용) 여기서는 사용 안함
    // console.log(this.context)  // context는 할당된 레지스터 값을 받는다 
    console.log(JSON.stringify(this.context))  // JSON 형태로 출력 - 앱 실행 시 레지스터 값 확인 가능
 }
})

-------------------------------------

// jailBreak_test1.js 최종 정리 본

var realBase = Module.findBaseAddress('DVIA-v2')
console.log(realBase)

var jailBreak_address = realBase.add('0x1cbdd0')
console.log(jailBreak_address)

Interceptor.attach(jailBreak_address, {
	onEnter:function(args){
		console.log(JSON.stringify(this.context))
	}
})

 

 

 

6-3) Frida에 파일 로드 후 주소 값 확인

$ frida -U -l "파일.js" DVIA-v2    (-l = load)
 
 

 

console.log로 출력시킨 첫 번째 주소는

DVIA-v2 바이너리가 실제 할당된 주소,

두 번째 주소는 수정하고 싶은 주소

(0x0 인 경우, 루팅된 디바이스가 아니다! 의 경우)

 

참고로 앱을 재실행 할때마다

ALSR 정책 때문에 주소는 매번 달라진다

 

 

 

6-4) 레지스터 값 확인

프리다로 단말기 연결된 상태에서

Jailbreak Test 1 눌러주면

 

레지스터 값들 확인이 가능하고

우리가 출력한 메모리 주소를 지나가는데

확인이 필요한 중요한 부분은

 

x0 : 0x1

x0 레지스터 값이 현재 1이다.

 

 

기드라에서 확인했을 때

특정 조건(If/else),

 

w0, #0x0

 

w0을 0(0x0)과 비교했을 때

w0이 0인 경우 참이므로

0x1cbdd0 주소(탈옥아님!)로 이동해

정상적인 앱 이용이 가능하지만

 

현재 결과는

x0: 0x1 이기 때문에

탈옥 탐지에 걸리게 되는 것!

 

[참고] 표현 방식은 차이가 있지만

64 비트인 경우 x0~x30

32 비트인 경우 w0~w30

 

탈옥 탐지 우회를 위해서는

현재 0x 값인 1을 0으로 바꿔주면 된다.

 

 

 

6-5) 코드 추가 작성 및 탈옥 탐지 우회

// jailBreak_test1.js

var realBase = Module.findBaseAddress('DVIA-v2')
console.log(realBase)

var jailBreak_address = realBase.add('0x1cbdd0')
console.log(jailBreak_address)

Interceptor.attach(jailBreak_address, {
	onEnter:function(args){
		console.log(JSON.stringify(this.context))
     // 위 코드는 주소 값을 확인하기 위해 그냥 두고 아래부터 추가 설정!
     // 레지스터 지정 및 변경 시도 (레지스터 받을 때는 this.context)
        this.context.x0 = 0x0   // 현재 코드 블럭내 레지스터 값은 x0 : 1x0 인데 이를 강제 변경
        console.log(JSON.stringify(this.context)) // 출력해서 결과 본다!
     	}
})

 

 

프리다에서 스크립트 로딩 후

Jailbreak_Test1 눌러보면

 

 

x0 레지스터가 1이었는데 이것을

0으로 바꿔주었고 그 결과

 

탈옥 탐지 우회 성공!

 

 

실무에서는 위 사례처럼

쉽게 나오는 경우도 있지만

난독화로 인해 로직 파악이 어려워

탈옥 우회 하기가 불가능한 경우도 있어

 

다양한 형태의 실습 및

경험을 쌓는 것이 중요하다!

 

 

 

 

 

[도움 출처]

: 보안프로젝트 김태영 팀장 iOS 모바일 앱 모의해킹(기초) 강의

 

 

728x90