입력한 계정 정보 입력 후 Login Method 1을 클릭하면 이를 확인 후 잘못된 계정을 입력하면 위와 같은 메시지를 출력한다.
출력되는 메시지를 검색하여 어느 로직에서 사용되고 있는 지 확인한다.
...loginMethod1Tapped... 메소드에서 사용하고 있는 것을 알 수 있다.
해당 메소드의 로직을 살펴 보면 TBZ 지시어에 따라 분기하여 결과를 보여주는데, 그 위에 isLoginValidated 메소드를 사용하여 해당 메소드의 리턴값에 따라 분기하는 것으로 예상할 수 있다.
그래서 isLoginValidated 메소드의 시작 주소를 확인한다.
if(ObjC.available){
try{
var base_address = Module.findBaseAddress('DVIA-v2');
var target_address = base_address.add('0x15E38C');
Interceptor.attach(target_address, {
onEnter: function (args) {
console.log("");
console.log("베이스 주소 : " + base_address);
console.log("후킹 타겟 주소 : " + target_address);
console.log("[+] 타겟 실행");
},
onLeave: function (retval) {
console.log("리턴 값 : " + retval);
}
});
}
catch(err){
console.log("[!] Error: " + err.message);
}
}
else {
console.log("Objective-C Runtime is not available!");
}
그리고 위 frida 코드를 작성하여 실행한다.
실행했을 때 해당 메소드의 리턴값이 0x0 인것을 확인할수 있었다.
if(ObjC.available){
try{
var base_address = Module.findBaseAddress('DVIA-v2');
var target_address = base_address.add('0x15E38C');
Interceptor.attach(target_address, {
onEnter: function (args) {
console.log("");
console.log("베이스 주소 : " + base_address);
console.log("후킹 타겟 주소 : " + target_address);
console.log("[+] 타겟 명령어 실행");
},
onLeave: function (retval) {
console.log("리턴 값 : " + retval);
retval.replace(ptr("0x1"));
console.log("변환된 리턴 값 : " + retval);
}
});
}
catch(err){
console.log("[!] Error: " + err.message);
}
}
else {
console.log("Objective-C Runtime is not available!");
}
리턴값을 변경하는 코드를 추가하여 재 실행한다.
앱에서 Login Method 1을 터치하면 성공적으로 인증을 우회할 수 있었다.
다음으로 ...loginMethod2Tapped... 메소드를 확인해보면 조금 다른 모습을 확인할 수가 있다.
이번에는 Login Method 1 처럼 isLoginValidated 와 같이 검증 후 리턴되는 값을 확인하는 로직이 보이지 않아, 분기할 때 레지스터 값을 변경하는 방식으로 우회해보았다.
var module_base = Module.findBaseAddress('DVIA-v2');
console.log("베이스 주소 : " + module_base);
var offset = "0x1bded4";
var jailbreak_address = module_base.add(offset);
console.log("후킹 타겟 주소 : " + jailbreak_address);
Interceptor.attach(jailbreak_address, {
onEnter: function (args) {
console.log("");
console.log("베이스주소:" + module_base);
console.log("서브루틴 주소:" + jailbreak_address);
console.log("[+] 사용자함수 호출");
this.context.x8 = 0x1;
},
onLeave: function (retval) {
}
});
TBZ 지시어가 사용하는 w8(x8) 레지스터 값을 확인했을 때 0이었기 때문에 이를 1로 변경하는 frida 코드를 생성하여 실행해준다.
Login Method 2를 터치하면 성공적으로 우회할 수 있었다.
4자리 코드 입력 후 인증하는 로직인데, 잘못된 코드 입력 시 출력되는 메시지를 확인한다.
해당 메시지를 사용하는 로직을 찾아보니 CMP 지시어의 결과에 따라 분기해서 메시지를 출력하는 것을 알 수 있다.
var module_base = Module.findBaseAddress('DVIA-v2');
console.log("베이스 주소 : " + module_base);
var offset = "0x15E3E0";
var jailbreak_address = module_base.add(offset);
console.log("후킹 타겟 주소 : " + jailbreak_address);
Interceptor.attach(jailbreak_address, {
onEnter: function (args) {
console.log("");
console.log("베이스주소:" + module_base);
console.log("서브루틴 주소:" + jailbreak_address);
console.log("[+] 타겟 호출");
console.log("x9 : " + this.context.x9);
console.log("x8 : " + this.context.x8);
},
onLeave: function (retval) {
}
});
CMP 지시어에서 x8, x9 레지스터의 값을 서로 비교하는 것으로 보아 둘 중 하나는 정답 코드일 것으로 예상되므로 이를 출력하는 frida 코드를 작성한다.
frida 코드를 실행하면 Validate code를 터치했을 때 x8, x9의 값이 출력된다.
0x457의 값이 바로 입력했던 1111이므로, 0x2290이 바로 맞는 코드인 것을 알 수 있다.
그렇다면 x9의 값을 0x2290으로 바꿔도 되고, x8, x9 둘 다 같은 값으로 변경하는 방법이 있을 수 있는데, 후자의 방법으로 코드를 작성해보았다.
var module_base = Module.findBaseAddress('DVIA-v2');
console.log("베이스 주소 : " + module_base);
var offset = "0x15E3E0";
var jailbreak_address = module_base.add(offset);
console.log("후킹 타겟 주소 : " + jailbreak_address);
Interceptor.attach(jailbreak_address, {
onEnter: function (args) {
console.log("");
console.log("베이스주소:" + module_base);
console.log("서브루틴 주소:" + jailbreak_address);
console.log("[+] 타겟 호출");
this.context.x8 = 0x1;
this.context.x9 = 0x1;
},
onLeave: function (retval) {
}
});
x8, x9 레지스터의 값을 0x1로 똑같이 변경하는 코드를 작성후 실행한다.
다시 무작위 코드 입력 후 validate code를 터치하면 성공적으로 인증할 수 있었다.