TracerPid 검사를 통한 동적 디버깅 탐지 방안과 우회 기법
들어가기 앞서
디버깅 개요 및 동적 디버깅 사용을 위한 사전 조건
들어가기 앞서 '안드로이드/루팅 탐지 및 우회' 카테고리의 글 목록 모바일 분석 글을 주로 포스팅 합니다. naro-security.tistory.com 루팅 탐지 및 우회 기법에 대한 주제에 이어서 이번 시간에는 디버
naro-security.tistory.com
이전 "디버깅 개요 및 동적 디버깅 사용을 위한 사전 조건" 포스팅에 이어서 실행 중인 프로세스의 상태 필드 정보인 TracerPid 값을 검사하여 동적 디버깅을 탐지하는 방법과 또 이를 우회하는 기법을 다뤄보도록 하겠다.
실습 진행에 사용되는 ANDITER 앱은 아래의 GitHub에서 다운로드 가능하다.
GitHub - naroSEC/Anditer
Contribute to naroSEC/Anditer development by creating an account on GitHub.
github.com
개요
TracerPid는 실해 중인 프로세스의 상태 정보를 나타내는 상태 필드 중 하나로 해당 프로세스를 디버깅하고 있는 프로세스의 아이디(Pid)를 표시한다. 만약 디버깅하고 있는 프로세스가 존재하지 않는다면 0으로 표기된다.
[그림 2]는 애플리케이션이 디버그 되고 있지 않을 때의 모습으로 TracertPid 값이 0으로 표기된다. 반면, 디버그 중일 때는 [그림 3]과 같이 디버그 하고 있는 프로세스의 아이디 값을 표시한다. 동작 중인 프로세스 정보는 /proc 디렉터리에 저장되며, 디바이스 콘솔에서 “cat /proc/[PID]/status” 명령으로 확인하고자 하는 애플리케이션에 관한 프로세스 상태 정보 열람이 가능하다.
Bypass TracerPID 탐지 항목은 이와 같은 특징을 이용해 실행중인 애플리케이션의 TracerPid 값을 확인해 0이 아닌 경우 디버그가 동작인 것으로 판단해 탐지하게 된다.
실습 진행을 위한 사전 준비
원활한 실습 진행을 위해 탐지를 원하는 경우 IDA, GDA, Ghidra와 같은 디버그를 지원하는 도구를 사용하여 TracerPid 값을 변형시킬 수 있다. 다만, 이러한 도구들은 별도의 설치가 필요하고 추가적인 설정을 해줘야 하기 때문에, 해당 포스팅에서는 디바이스 콘솔에서 바로 사용이 가능한 strace 도구를 사용해 TracerPid 값을 변형시켜 보겠다.
strace 명령어가 본인의 디바이스에 설치되어 있지 않다면 아래의 Github 링크에서 "strace"를 다운로드 받아 디바이스로 이동시킨 후 사용하면 된다.
https://github.com/andrew-d/static-binaries/blob/master/binaries/linux/arm/strace
strace는 애플리케이션이 실행될 동안 시스템 콜 함수들과 시그널 처리를 추적할 수 있는 디버그 도구로 [그림 4]와 같이 실행중인 애플리케이션 대상으로 사용이 가능하며, 사용 시 [그림 5]처럼 TracerPid 값이 strace 프로세스 Pid 값으로 변경된 것을 확인할 수 있다.
분석
[그림 3-9]의 isCheckDebggerState() 함수는 Bypass TracerPID 탐지 결과를 반환해주는 역할을 한다. 코드를 살펴보면 ①에서 File 클래스를 사용해 TracerPid 상태 필드가 저장되어 있는 /proc/self/status 파일 객체를 생성한다.
② ①에서 생성한 파일 객체를 읽어와 contains() 함수를 사용해 TracerPid 문자열이 포함되어 있는지 확인한다.
③ 해당 문자열이 포함되어 있다면 split() 함수를 통해 TracerPid 값을 가져와 0과 비교해 Pid 값이 0이 아니라면 디버그가 동작 중인 것으로 판단해 탐지하게 된다.
Bypass TracerPID 탐지를 우회하기 위한 후킹 포인트는 세 가지가 있다. 첫 번째는 함수 결과와 상관없이 무조건 false를 반환하도록 isCheckDebggerState() 함수를 재 작성하는 방법이고 두 번째는 File 클래스가 객체를 생성할 때 인자로 전달하는 문자열을 더미 값으로 변조하는 방법과 exists() 함수를 후킹하는 방법이다. 마지막 세 번째는 contains() 함수의 인자 값을 변조하는 방법이다. 여기서는 두 번째 방법을 사용해 탐지를 우회해 보겠다.
우회 실습
[그림 3-10]은 File 클래스 생성자를 후킹하기 위해 필자가 작성한 Frida 스크립트이다.
코드를 보면 ①에서 File 클래스 사용을 위해 클래스 객체를 반환 받고 File 클래스 생성자를 오버로딩으로 구현한다.
②에서는 File 클래스 객체 생성 시 인자로 전달되는 문자열을 검사해 들어오는 매개 변수 값이 /proc/self/status일 경우 더미 값으로 변조하고 변조한 더미 값을 인자로 File 클래스 객체를 생성해 반환한다.
Frida를 통해 작성한 스크립트를 ADITER 애플리케이션에 어태치 하고 Bypass TracerPID 탐지 항목을 체크하면 Success! 가 출력되며 탐지가 우회된 것을 볼 수 있다.
마무리
지금까지 앱 프로세스의 상태 필드 중 하나인 TracerPid 값을 검사하여 동적 디버깅을 탐지하는 방법과 또 이를 공격자의 관점에서 어떻게 우회할 수 있는지 살펴봤다. 다음 포스팅에는 안드로이드 OS의 시스템 속성인 ro.debuggable 값을 검사하여 동적 디버깅을 탐지하는 방안에 대해서 다뤄보도록 하겠다.