기본 동작 확인
먼저 기본적으로 동작을 확인해 봐야지

버튼을 눌렀을 때 내부적으로 탈옥 여부를 판단하는 루틴이 수행되고, 결과를 메세지 창으로 띄워준다.
지금은 장치를 탈옥한 상태이므로 정상적으로 탈옥장치라고 출력하는 것을 확인할 수 있다.
클래스 덤프
MobSF로 정적분석을 수행하였다.
[기본정보 파악]
- Objective-C로 작성됨
- ARM 32bit임

[클래스 덤프 수행]
먼저 Jail, JB 등의 키워드로 검색해 봄.
난독화가 되어 있지 않고 정직하게 적혀있어 쉽게 찾아볼 수 있다.

이름에서부터 버튼을 눌렀을 때 Jailbreak를 탐지하는 느낌이 나지만, 클래스에서 채택한 프로토콜을 보면 입력하는 텍스트 창이 있고 거기서 발생한 이벤트를 받아서 처리하는 UITextFieldDelegate를 채택했다.
우리가 본 화면에서는 텍스트 입력 창이 없었으니 이 함수는 아닌 것으로 추정할 수 있다.

두번째로 찾은 것은 showAlert인 것을 보니 버튼을 눌렀을 때 띄워지는 메세지 창과 관련된 함수인 것 같다.
인자를 보면 _Bool 값인 것을 확인할 수 있고 클래스 메소드이므로 바로 한번 확인해 보자.
#PID을 알아내기 위한 조회 ps -ef | grep Damn #cycript 후킹 cycript -p 621 #클래스 덤프로 알아낸 메소드 호출 [DamnVulnerableAppUtilities showAlertForJailbreakTestIsJailbroken: 1] # Jailbroken [DamnVulnerableAppUtilities showAlertForJailbreakTestIsJailbroken: 0] # Not Jailbroken

우회의 목적이 되는 (여기서는 메세지 창이 Not Jailbroken으로 뜨도록 만드는 것) 코드를 임의로 실행시킬 수 있으니 성공이라고 볼 수 있다.
하지만 좀 더 나아가 버튼을 눌렀을 때 알아서 검사 루틴이 우회되어 메세지 창을 띄우게 하고 싶으므로 좀 더 살펴보자.

버튼 탭과 관련된 함수가 2개 있고, isJailbroken은 반환값이 _Bool인 것으로 보아 탈옥 탐지 여부를 판단하는 함수로 생각된다.
바로 cycript로 바꿔봐도 되겠지만, 일단 버튼과 맵핑되어 있는 함수들 내부를 먼저 살펴보자.
(void)jailbreakTest1Tapped:(id)arg1;
[디스어셈블 창]

[헥스레이 디컴파일 결과]

ios는 함수 호출 시 기본적으로 인자를 $x0~$x7에 인자 순서대로 가져온다.
- arg0 : JailbreakDetectionVC
- arg1 : selector id
어셈블리를 보면 첫번째 objc_msgSend() 함수 호출까지 $x0는 변화가 없으므로 인자를 그대로 사용한다고 보면 되고, $x1에는 isJailbroken 셀렉터가 들어간다.
따라서 첫번째 objc_msgSend() 함수 호출은 아래 코드와 같다.
[JailbreakDetectionVC isJailbroken];
두번째 msgSend() 함수는 $x19에 만들어 놨던 DamnVulnerableAppUtilities를 X0에 넣고,
$x1에는 showAlertForJailbreakTestIsJailbroken 셀렉터를 담는다.
마지막으로 중요한 세번째 인자인 $x2에는 앞서 호출한 isJailbroken 함수의 반환값을 사용하였다.
[DamnVulnerableAppUtilities showAlertForJailbreakTestIsJailbroken:<isJailbroken 함수 호출 반환값>];
정리하면 (void)jailbreakTest2Tapped:(id)arg1; 함수는 isJailbroken 함수의 반환 값에 따라 메세지를 출력하는 함수이다.
isJailbroken 함수는 _Bool 값을 반환하는 함수였으므로, 항상 탈옥이 아닌 값을 반환하도록 메소드 스위즐링을 해주면 첫번째 탈옥탐지 함수는 우회할 수 있다는 판단이 선다.
[메소드 스위즐링]
#무조건 false를 반환하도록 함수의 구현부를 바꿔치기함. JailbreakDetectionVC.prototype.isJailbroken=function(){return false}

기존의 함수 동작을 먼저 확인하고, 메소드 스위즐링 후 다시 변화된 동작을 확인한 것이다.
추가 팁 :
cycript로 임의로 인스턴스 메소드를 호출하려면 생성된 객체부터 먼저 찾아야함.
따라서 객체가 생성되도록 관련 화면이나 동작을 먼저 수행되도록 만들어 놓는게 중요.
다음으로 cycript에서 제공하는 choose() 함수를 통하여 힙 메모리에 있는 객체 주소를 찾아온다.
찾은 객체 주소를 바탕으로 인스턴스 메소드 호출.
isJailbroken 함수를 항상 false를 반환하도록 만들었으므로 아래와 같이 탈옥탐지 우회에 성공하였다.

(void)jailbreakTest2Tapped:(id)arg1;
[디스어셈블 창]

내용을 보면 isJailbroken 함수의 내용이 그대로 박혀있다. 이런 경우 메소드 스위즐링은 그닥 효율적이지 않다.
디스어셈블 명령어를 분석해서 자동으로 우회하도록 바이너리를 패치하는 것이 낫다. 따라서 해당 함수는 Cycript로 우회하지 않고, 코드패치에서 추가로 다루겠다. (물론 후킹이 짱..)
여기서, 보안 측면에서는 두번째 함수처럼 만들어야겠다는 생각이 들지 않는가?
실제로 첫번째 함수처럼 특정 함수의 반환값을 바꾸는 것만으로도 쉽게 우회할 수 있도록 만드는 것은 보안을 신경 썼다곤 하나 너무나도 쉽게 우회가 가능했다.
두번째 함수처럼 만든다고 우회가 불가능 한 것은 아니지만, 클라이언트 측 보안의 핵심은 최대한 공격자를 귀찮게 만드는 것이다.
따라서 보안 관련 함수는 인라인 함수로 만들고, 프로그램 수행 곳곳에 흩뿌려 놓는 것이 효과적이다.