1. 목적
본 문서는 Anti-Debugging 기능 중 Attach 선점을 이용한 구현 방법에 대해서 설명합니다.
2. 원리
A 프로세스가 B프로세스를 Attach를 먼저 수행하였다면 Detach되기 전까지, C프로세스는 B프로세스를 Attach 할 수 없다.
3. Self Attach
ptrace 함수 호출 시 PTRACE_TRACEME를 전달하여 자기 자신한테 Attach를 적용
A. 필요조건
- 부모프로세스와 동일한 UID, GID를 가지고 있을 경우
- 부모프로세스가 CAP_SYS_PTRACE를 가지고 있을 경우
B. 예시코드
void anti_debug() { long ptrace_status = ptrace(PTRACE_TRACEME, 0, 0, 0); } |
C. Android에서 사용불가능한 이유
Android는 zygote가 루트가 아닌 unconfined로 실행되며 CAP_SYS_PTRACE가 설정되어 있습니다.
그래서 Android 4.3까지는 zygote의 하위 프로세스가 Self Attach가 가능했었으나,
Android 4.4부터는 SELinux가 적용되면서 CAP_SYS_PTRACE 기능이 제한되어 Self Attach를 할 수 없습니다.
4. Attach from child
자식프로세스를 생성 후 자식프로세스가 부모프로세스에게 Attach를 적용
A. 필요조건
- 부모프로세스가 디버깅 가능한 상태일 경우
- 앱 Release 빌드의 경우 : 기본값이 Debuggable이 false로 셋팅되므로, ptrace 호출 전 prctl 함수를 이용하여 덤프가능한 상태로 변경 필요.
- 앱 Debug 빌드의 경우 : 기본값이 Debuggable이 true로 셋팅되므로 추가 작업은 필요없으나, JDWP이 가능한 상태로 권장하지 않음.
B. 예시코드
#include <jni.h> #include <string> #include <unistd.h> #include <sys/ptrace.h> #include <sys/prctl.h> #include <sys/types.h> #include <pthread.h> #include <sys/wait.h> #include <android/log.h> #define LOG_TAG "LEE_NDK" #define LOGUNK(...) __android_log_print(ANDROID_LOG_UNKNOWN,LOG_TAG,__VA_ARGS__) #define LOGDEF(...) __android_log_print(ANDROID_LOG_DEFAULT,LOG_TAG,__VA_ARGS__) #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) #define LOGF(...) __android_log_print(ANDROID_FATAL_ERROR,LOG_TAG,__VA_ARGS__) #define LOGS(...) __android_log_print(ANDROID_SILENT_ERROR,LOG_TAG,__VA_ARGS__) static int child_pid = -2; static int ptrace_status; //c++11에서는 void *monitor_pid(void *args) void *monitor_pid(void *) { int status; waitpid(child_pid, &status, 0); /* Child status should never change. */ _exit(0); } int anti_debug() { if (child_pid == -2) { int status_prctl = prctl(PR_SET_DUMPABLE, 1); LOGI("status_prctl 상태: %d", status_prctl); child_pid = fork(); } if (child_pid == 0) { int status; pid_t ppid = getppid(); ptrace_status = ptrace(PTRACE_ATTACH, ppid, 0, 0); LOGI("ptrace_status 상태: %d", ptrace_status); if (ptrace_status == 0) { // 로그 변경 해야함. // LOGI("부모프로세스 Attach 성공"); int waitpid_status = waitpid(ppid, &status, 0); LOGI("waitpid : %d", waitpid_status); ptrace(PTRACE_CONT, ppid, NULL, NULL); while (waitpid(ppid, &status, 0)) { if (WIFSTOPPED(status)) { ptrace(PTRACE_CONT, ppid, NULL, NULL); } else { LOGI("Ptrace Exit"); _exit(0); } } } else { // ptrace 실패 시 처리 코드 삽입 // } } else { pthread_t t; pthread_create(&t, NULL, monitor_pid, (void *) NULL); } if ((child_pid > 0) && (ptrace_status == 0)) return 0; return -1; } extern "C" JNIEXPORT void JNICALL Java_kamos_kakao_com_antidebugging_MainActivity_antidebug (JNIEnv *env, jobject /* this */) { anti_debug(); } |
- 성능 : 디바이스의 성능에 따라 다를 수 있으나, 빠른 응답이 필요한 서비스의 경우 속도 하향이 발생할 수 있음.
5. ToDO
- 다른 프로세스가 선점했을 때 처리 부분 반영 필요
- 단순히 libc.so에 내장된 ptrace 함수를 사용할 경우 비교적 우호
- so 파일을 디컴파일 했을 때 쉬운 코드 분석이 가능한 점
6. REF
- http://www.vantagepoint.sg/blog/89-more-android-anti-debugging-fun
- http://man7.org/linux/man-pages/man2/ptrace.2.html
- http://man7.org/linux/man-pages/man2/prctl.2.html
- http://www.debugme.co.kr/2017/05/ptrace-anti-debugging.html
- https://github.com/wariua/manpages-ko/wiki/ptrace(2)
- https://android.googlesource.com/kernel/common/+/android-trusty-3.10/Documentation/security/Yama.txt
- https://stackoverflow.com/questions/21337923/why-ptrace-doesnt-attach-to-process-after-setuid
- http://elenoa.tistory.com/115
'Security > Mobile' 카테고리의 다른 글
안드로이드 7.0이상 버프 인증서 디바이스 설치 (0) | 2023.04.04 |
---|---|
[iPhone/iOS] [더한섬닷컴] 탈옥안했는데 탈옥알림 (2) | 2022.02.14 |
Android WebView 디버깅 (0) | 2020.02.25 |