모바일/보안
Frida : 안티디버깅 우회
parktest0325
2019. 8. 13. 19:27
ptrace
lib.so에서 export하고 리눅스, 유닉스 환경에서 프로세스 디버깅에 사용되는 함수이다. (gdb도 ptrace 이용함)
ptrace라는 이름의 26번 커널 시스템콜이 내부적으로 사용된다.
# cat /usr/include/asm/unistd.h | grep ptrace
#define __NR_ptrace 26
ptrace(PTRACE_ATTACH, ... ); // process에 Attach해서 작업. Dettach 하기 전까진 타겟은 STOP 상태이다.
ptrace(PTRACE_GETREGS, ... ); // 대상 process의 레지스터 목록 가져오기 return 값은
ptrace(PTRACE_PEEKDATA, ... ); // 데이터 쓰기 (레지스터 크기만큼씩 읽고 쓰기가 가능하다)
ptrace(PTRACE_POPEDATA, ... ); // 데이터 읽기
ptrace를 이용한 안티디버깅 예시
void anti_debug() {
child_pid = fork();
if (child_pid == 0)
{
int ppid = getppid();
int status;
if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0)
{
waitpid(ppid, &status, 0);
ptrace(PTRACE_CONT, ppid, NULL, NULL);
while (waitpid(ppid, &status, 0)) {
if (WIFSTOPPED(status)) {
ptrace(PTRACE_CONT, ppid, NULL, NULL);
} else {
// Process has exited for some reason
_exit(0);
}
}
}
}
}
fork()로 자식프로세스를 생성하고 부모프로세스를 ptrace하여 점유하게되면 다른 프로세스에서 ptrace시도 시 이미 점유되어 attach가 불가능하다.
1. 프리다를 이용한 안티디버깅 우회
import sys
import frida
def on_message(message,data):
print "[%s] -> %s" % (message, data)
PACKAGE_NAME = sys.argv[1]
jscode = """
/// Inject_Jscode
"""
try:
device = frida.get_usb_device(timeout=10)
pid = device.spawn([PACKAGE_NAME])
print("App is starting ... pid : {}".format(pid))
process = device.attach(pid)
device.resume(pid)
script = process.create_script(jscode)
script.on('message',on_message)
print('[*] Running Frida')
script.load()
sys.stdin.read()
except Exception as e:
print(e)
frida의 device.spawn을 이용해서 앱 실행 전에 프리다가 후킹을 시도하여 안티디버깅을 우회
또는
frida -U -f <Package_name> --no-pause 명령어를 이용
2. 안티디버깅 로직의 smali를 변조하여 리빌드
무결성 체크로직도 함께 우회해야 한다.