이전 글에서 탈옥 탐지 우회를 코드 패치하는 방식으로 진행해 보았다면 이번에는 frida를 활용하여 우회해보기로 한다.
그 전에 아래 깃허브에서 iOS용 유용한 스크립트 몇 개를 사용하기로 했다.
https://github.com/noobpk/frida-ios-hook/tree/master/frida-ios-hook/frida-scripts
raptor_frida_ios_enum.js 파일을 다운 받아 아래 class와 method를 찾는 로직에서 주석을 제거하고 jail이 포함된 class와 method를 찾도록 수정했다.
frida로 앱을 실행하고 Jailbreak Detection 메뉴에 진입하면 cmd 창에 위와 같이 출력되는데, DVIA_v2.JailbreakDetectionViewController 클래스가 눈에 띈다.
IDA에서 해당 클래스로 검색하고, 그 중 jailbreakTest1Tapped function을 분석해보기로 한다.
내부에서는 Device is Jailbroken 메시지를 띄우는 로직은 보이지 않았고,
__T07DVIA_v232JailbreakDetectionViewControllerC20jailbreakTest1TappedyypF
라는 메소드로 분기하는 명령어가 있어 이를 클릭하였음.
여기서도 알림창을 띄우는 로직은 보이지 않았지만, 분기문이 여러개 있는 것으로 보아 이곳에서 lldb 동적 디버깅을 통해 분석해보기로 했다.
lldb가 설치된 아이폰 내부에서 위 명령어를 통해 DVIA-v2 앱에 attach 하였고,
image list 명령어를 통해 Base Address가 0x0000000100a94000 인 것을 확인하였다.
그리고 __T07DVIA_v232JailbreakDetectionViewControllerC20jailbreakTest1TappedyypF 메소드 시작 주소가 0x0000000100192C10 이고,
시작 주소 0x0000000100000000을 뺀 0x192C10을 더해줘서 break point를 설정한다.
break point 설정 후 앱에서 Jailbreak Test 1을 터치하면 break 되는 것을 확인할 수 있다.
n(Next, Step Over) 명령어로 순차적으로 진행하다가, 두 번째 blr 명령어에서 사용하는 x9 레지스터의 값을 확인해보면
showAlert... 이라는 메소드를 확인할 수 있는데
IDA에서 해당 메소드를 검색해서 로직을 확인해보면 탈옥 여부 확인 후 분기하여 알림창을 띄운다는 것을 알 수 있었다.
이전에서 코드 패치했을 때 확인했던 것처럼 tbz 명령어에서 값을 확인해보기로 한다.
s(Step In) 명령어로 분기된 함수로 진입하고,
tbz 명령어까지 진행 한 후 w0 레지스터의 값을 확인하면 1이 저장되어 있는 것을 알 수 있다.
w0 레지스터의 값을 0으로 변경한 후 c 명령어로 process를 resume 시킨다.
이제 앱에서 탈옥되지 않은 장치라는 알림창이 뜨는 것을 알 수 있다.
이러한 과정을 frida 코드로 구현해보자.
if(ObjC.available){
try{
var base_address = Module.findBaseAddress('DVIA-v2');
var target_address = base_address.add('0x1cbdd0');
Interceptor.attach(target_address, {
onEnter: function (args) {
console.log("");
console.log("베이스 주소 : " + base_address);
console.log("후킹 타겟 주소 : " + target_address);
console.log("[+] 타겟 명령어 실행");
console.log(JSON.stringify(this.context));
},
onLeave: function (retval) {
}
});
}
catch(err){
console.log("[!] Error: " + err.message);
}
}
else {
console.log("Objective-C Runtime is not available!");
}
일단 베이스 주소와 후킹 타겟 주소를 출력하고 해당 명령어가 실행됐을 때 모든 레지스터에 저장된 데이터를 확인했다.
하지만 이 중에서 동적 디버깅을 했을 때 수정했던 w0 레지스터가 보이지 않았다.
그 중 "x0" 레지스터에 "0x1" 값이 저장되어 있어서 이 레지스터 값을 수정해야 할 것으로 보고 수정해보았다.
if(ObjC.available){
try{
var base_address = Module.findBaseAddress('DVIA-v2'); //앱 Base명 입력
var target_address = base_address.add('0x1cbdd0'); // 오프셋 값 입력
Interceptor.attach(target_address, {
onEnter: function (args) {
console.log("");
console.log("베이스 주소 : " + base_address);
console.log("후킹 타겟 주소 : " + target_address);
console.log("[+] 타겟 명령어 실행");
this.context.x0 = 0x0;
},
onLeave: function (retval) {
}
});
}
catch(err){
console.log("[!] Error: " + err.message);
}
}
else {
console.log("Objective-C Runtime is not available!");
}
this.context.x0 = 0x0; 코드를 추가하여 x0 레지스터 값을 0으로 변경하도록 하고, frida를 실행하여 앱을 후킹하면 Jailbreak Test 1을 터치했을 때 탈옥되지 않은 장치라는 알림창이 표시된다.