Disable Debugging을 터치하면 디버깅 방지 로직이 적용됐다는 메시지가 출력된다.
lldb로 디버깅 하려 했으나 attach 실패 메시지를 출력한다.
디버깅 방지 메시지를 검색하여 어떤 로직에서 사용되는 지 확인했다.
해당 메소드 로직을 살펴보았을 때, 중간에 _disable_gdb 로 분기하는 부분이 확인되었다.
더블 클릭하여 해당 메소드로 진입해보았다.
메소드 내부 로직에서 ptrace 라는 문자열을 확인할 수 있었다.
이 ptrace는 iOS에서 안티 디버깅 방법 중 가장 기본적인 방법으로, PT_DENY_ATTACH flag를 사용하여 프로세스에 접근하지 못하도록 막는 것이라고 한다.
앱을 재실행 후에 lldb를 통해 ptrace에 breakpoint를 설정한다.
그리고 Disable Debugging을 터치했을 때 프로세스가 일시 중지되는데, 이 때 모든 레지스터의 내용을 살펴보았다.
x0 레지스터의 값이 0x1f 인데, PT_DENY_ATTACH flag 값을 의미한다.
이 상태에서 c로 resume 하면 디버깅이 종료 된다.
앱을 재실행하여 ptrace break point 설정 후, x0 레지스터의 값을 0으로 수정했는데, 이 때는 c로 resume해도 디버깅이 종료되지 않고 정상적으로 디버깅 진행이 가능해진다.
이제 ptrace에 frida로 후킹해서 PT_DENY_ATTACH flag를 수정하는 코드를 작성해보자.
Interceptor.attach(Module.findExportByName(null, "ptrace"), {
onEnter: function (args) {
console.log("[ptrace] " + args[0] + " " + args[1] + " " + args[2] + " " + args[3]);
if (args[0] == 0x1f) {
args[0] = ptr("0xa");
}
},
onLeave: function (retval) {
console.log("[return] " + retval);
}
});
ptrace 호출될 때 인자가 4개가 있는데 그 중 첫번째가 flag 값으로, 이를 0xa로 수정했다.
이유는 ptrace에서 사용하는 flag 값 정의를 보면 PT_ATTACH 가 10(0xa)이기 때문이다.
이제 frida로 앱 실행 후 Disable Debugging 터치해도 lldb로 디버깅이 가능해진다.