티스토리 뷰

보안/App

[Android] Anti-Debugging bypass

damti 2023. 7. 14. 13:49

실습 앱은 다음과 같음

anti_debug_ptrace1.apk
1.73MB

 

IDA dynamic debugging

adb push "android_x86_server경로" /data/local/tmp

- IDA 폴더 > dbgsrv에서 android_x86_server 파일 -> /data/local/tmp 폴더로 이동 

- 윈도우에서 구동하는 에뮬레이터여서, x86 아키텍처의 IDA 서버를 설치함 

  (안드로이드 루팅 단말기의 경우 ARM 아키텍처의 android_server)

 

adb forward tcp:23946 tcp:23946

- adb를 통해 윈도우 IDA와 통신하기 위해 포트 포워딩 설정

- IDA 기본 서버 포트 : 23946

 

adb shell
cd /data/local/tmp
chmod 755 android_x86_server

- adb shell로 에뮬레이터의 쉘 실행

- /data/local/tmp 폴더로 이동

- chmod 명령어로 실행 권한 변경 시킴

 

./android_x86_server &

- IDA 서버를 백그라운드로 실행시킴

 

- IDA > Debugger > Attach > Remote Linux debugger

- 에뮬레이터 -> Remote Linux debugger, 단말기일 시 -> Remote ARM Linux/Android debugger 연결

 

- OK

 

- ps 명령어로 부모 프로세스의 pid 확인

 

- 부모 프로세스의 pid 선택 후 OK -> Attach 됨

  (여러번 시도해서 pid값 바뀜)

 

- ptrace 선점 안티 디버깅이 적용되어 있을 시, Attach를 할 수 없다고 메시지 뜸

 

 

Anti-Debugging bypass

Anti-Debugging 소스 코드

__int64 __fastcall readStatus(__int64 a1)
{
  unsigned __int64 v1; // x26
  __int64 v2; // ST08_8
  unsigned int v3; // w19
  __int64 v4; // x0
  __int64 v5; // x0
  __int64 result; // x0
  int v7; // w20
  int v8; // w23
  int v9; // w23
  int v10; // w25
  __int64 v11; // x24
  int v12; // [xsp+14h] [xbp-25Ch]
  __int64 v13; // [xsp+18h] [xbp-258h]
  _BYTE v14[6]; // [xsp+22h] [xbp-24Eh]
  char v15; // [xsp+118h] [xbp-158h]

  v1 = _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
  v2 = *(_QWORD *)(v1 + 40);
  v3 = getpid(a1);
  prctl(4LL, 1LL, 0LL);
  v4 = sprintf(&v15, "/proc/%d/status", v3);
  v5 = fork(v4);
  v12 = v5;
  if ( (_DWORD)v5 )
  {
    result = pthread_create(&v13, 0LL, checkChildProcess, &v12);
    if ( !(_DWORD)result )
      result = pthread_detach(v13);
  }
  else
  {
    v7 = getpid(v5);
    if ( (unsigned int)ptrace(16LL, v3, 0LL, 0LL) == -1 )
    {
      do
      {
        __android_log_print(6LL, "LIN_FORUM", "PTRACE ERROR - [%d] [%d]");
        v8 = ptrace(16LL, v3, 0LL, 0LL);
        usleep(10LL);
      }
      while ( v8 == -1 );
    }
    if ( (unsigned int)ptrace(7LL, v3, 0LL, 0LL) == -1 )
    {
      do
      {
        __android_log_print(6LL, "LIN_FORUM", "PTRACE ERROR - [%d] [%d]", 7LL, v3);
        v9 = ptrace(7LL, v3, 0LL, 0LL);
        usleep(10LL);
      }
      while ( v9 == -1 );
    }
    usleep(100000LL);
LABEL_11:
    v11 = fopen(&v15, "r");
    do
    {
      if ( !fgets(&v13, 128LL, v11) )
      {
LABEL_10:
        usleep(200000LL);
        goto LABEL_11;
      }
    }
    while ( (unsigned int)strncmp(&v13, "TracerPid", 9LL) );
    v10 = atoi(v14);
    fclose(v11);
    if ( v10 == v7 )
      goto LABEL_10;
    __android_log_print(6LL, "LIN_FORUM", "DETECTED DEBUGGER");
    result = kill(v3, 9LL);
  }
  *(_QWORD *)(v1 + 40);
  return result;
}

 

- ptrace 함수를 사용하여 디버깅을 시작함

- ptrace(16, pid, 0, 0)은 PTRACE_ATTACH를 의미하며, 프로세스에 디버거를 연결함
  => /proc/<pid>/status 파일을 사용해 프로세스의 디버깅 여부를 확인하고, 디버거가 감지되면 프로세스를 종료시킴

 

 

 

frida를 이용해

fopen 함수 호출을 후킹하고,

파일 경로를 조작하여 디버거 감지 패턴을 우회할 예정

 

후킹 코드는 Koo00님의 블로그를 참고했음

(https://blog.naver.com/koo__oo/222005876208)

Java.perform(function() {
	console.error('\n[!] Let\'s Koo00 !\n')

	Interceptor.attach(Module.findExportByName(null, "fopen"), {
		onEnter: function(args) {
			// console.warn("[*] fopen() called !")
			var path = Memory.readUtf8String(args[0])
			if((path.indexOf("/proc/") !== -1) && (path.indexOf("/status") !== -1)) {
				console.warn("[!] Debug Detection Pattern Found !")
				console.log("\t[+] fopen : " + path)
				Memory.writeUtf8String(args[0], "Koooo")
				// console.log("\t\t[+] new fopen : " + Memory.readUtf8String(args[0]))
			}
		},
		onLeave: function(retval) {
		}
	})
})

 

- Interceptor.attach 함수를 사용하여 fopen 함수를 후킹함

  -> Module.findExportByName(null, "fopen")은 fopen 함수의 주소를 찾음
- Memory.readUtf8String(args[0])를 사용하여 fopen 함수의 첫 번째 인자인 파일 경로를 읽어옴
- 경로가 "/proc/"과 "/status"를 포함하는지 확인함
  -> 안티디버깅 소스 코드에서 디버거 탐지를 수행하는 부분과 동일한 파일 경로 패턴을 검사하는 것

- 경로에 디버거 탐지 패턴이 포함되어 있다면, "[!] Debug Detection Pattern Found !" 메시지를 출력하고,

  원래의 파일 경로를 "Koooo"로 변경

  => 코드에서 파일을 읽을 때 디버거 탐지를 우회할 수 있음

 

 

fopen() : 파일 스트림을 여는 함수
- 입력 매개 변수 리스트
  >path 절대 경로 혹은 상대 경로
  >mode rwba+의 조합 문자열
- 반환 값
  >성공 시 파일 스트림 포인터, 실패 시 NULL 포인터

 

 

frida -U -f kr.linforum.anti_debug_crack_me -l fopen.js

fopen이 후킹된 것을 볼 수 있음

 

IDA에서 Attach할 프로세스를 확인

 

실행 중인 프로세스에 디버깅을 잡을 수 있음

 

 

 

참고 출처

https://linears.tistory.com/entry/%EC%95%88%ED%8B%B0%EB%94%94%EB%B2%84%EA%B9%85-%EC%9A%B0%ED%9A%8C-%EC%8B%A4%EC%8A%B5-1

https://blog.naver.com/PostView.naver?blogId=koo__oo&logNo=222005876208&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView