ios) 안티디버깅 - sysctl
ptrace와 비슷한 맥락이다.
다만 이번에는 ptrace flag가 설정됐는지 여부를 확인하는 것.
Is_debugger_present를 알고 있다면 동일하다고 생각하면 된다.
정보 : 디버거 아래에 자식으로 생성하던, 실행중인 프로세스에 attach를 했건 P_TRACED 플래그는 Set 된다.
아래 코드는 mobile-security-testing-guide의 ios-testing-guide에서 발췌함.
#include <assert.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>
static bool AmIBeingDebugged(void)
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
{
int junk;
int mib[4];
struct kinfo_proc info;
size_t size;
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
// Call sysctl.
size = sizeof(info);
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
assert(junk == 0);
// We're being debugged if the P_TRACED flag is set.
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}
배열 설정하고 sysctl를 호출하면 결과가 info에 담긴다.
결과로 얻은 info에 P_TRACED 플래그가 있는지 없는지 확인함으로써 디버깅 여부를 판단한다.
위 소스는 딱 봐도 우회하기 좋게 생겼다.
또한 sysctl을 호출한다는 사실로 앱이 디버깅 감지를 수행한다는 판단의 지표가 될 수도 있다.
[우회]
검증 함수 패치 혹은 후킹은 여태 하던대로 하면 된다.
디버거 상에서 실시간으로 우회할 때 편하게 접근하는 방법만 다룬다.
(gdb) break sysctl if $r1==4 && *(int *)$r0==1 && *(int *)($r0+4)==14 && *(int *)($r0+8)==1
특정 인자를 가진 sysctl에서 중단점을 설정하는 명령어이다.
ios에는 $r0~$r7가 인자 전달로 쓰이며 $r0부터 순서대로 들어간다고 보면 된다.
*(int *)$r0==1 (첫번째인자[0] == 1 : CTL_KERN)
*(int *)($r0+4)==14 (첫번째인자[1] == 14 : KERN_PROC)
*(int *)($r0+8)==1 (첫번째인자[2] == 1 : KERN_PROC_PID)
$r1==4 (두번째인자 == 4)
두번째 인자는 sizeof(mib)/sizeof(*mib)으로 배열의 총 크기를 한 요소의 크기로 나누는 것이므로 배열의 개수다.
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
이렇게 총 4개를 넘기므로, 두번째 인자에 4가 담겼는지를 확인하는 것.
(gdb) set $pinfo=$r2
우회하려면 결과로 받아온 플래그에서 P_TRACED 플래그를 제거해야하므로 세번째 인자인 kinfo_proc 구조체를 담아둔다.
(gdb) finish
(gdb) break *$pc if $pinfo!=-1
finish명령으로 sysctl 호출 끝까지 실행시키고, 받아온 info에 제대로 정보가 담겼다면 finish 위치에 bp를 건다.
정보를 담아온 다음이므로 잡아서 값을 바꾸면 됨.
(gdb) set $pflag = (*(int *)($pinfo+16))
(gdb) set *(int *)($pinfo+16) = $pflag & ~0x800
플래그 부분을 가져와서 0x800(P_TRACED) 플래그만 제거해서 다시 설정한다.
(gdb) print (*(int *)($pinfo+16) & 0x800)
(gdb) continue
print 출력 결과 0으로 나온다면 제대로 P_TRACED 플래그를 제거한 것.
끝.
[자동 우회 설정]
매번 bp 걸릴 때마다 저 짓을 하기는 번거로우니, commands 명령어로 bp걸렸을 때 수행될 명령어를 등록하자.
commands 1
silent
set $pinfo=$r2
continue
end
commands 2
silent
set $pflag = (*(int *)($pinfo+16))
set *(int *)($pinfo+16) = $pflag & ~0x800
set $pinfo=-1
continue
end
'iOS 앱 점검(ObjC) > 안티디버깅' 카테고리의 다른 글
ios) 안티디버깅 - getppid() (0) | 2020.07.27 |
---|---|
ios) ptrace관련 안티디버깅 정리 (0) | 2020.07.27 |