[Reversing] Windows 10 Anti-Reversing 기법 2

Preview

Windows 환경 리버싱 공부 중 안티 리버싱 기법들이 오래된 OS 버전을 기준으로 하고 있어서 Windows 10 x64에도 가능한 기법을 새로 조사, 실습하여 정리한다.

 

이 포스트는 이전 포스트에서 이어지는 글이다.  https://gomguk.tistory.com/45

 

[분석환경]
Windows 10 x64 1903

[개발 & 분석도구]
Visual Studio 2012(v110), OllyDbg, IDA Pro

CheckRemoteDebuggerPresent()

Windows XP 이상부터 꾸준히 사용되는 기법. ZwQueryInformation()을 사용하여 Debug Port 정보를 얻는다.

MSDN에서 제공하는 정보는 다음과 같다.

프로세스 핸들과 디버그된 상태를 알려줄 변수 포인터를 인자로 전달하면, 성공 시 0이 아닌 값, 실패 시 0을 반환한다.

[EBP-8] = bDebugged

CheckRemotePresent 함수는 내부적으로 ZwQueryInformationProcess의 ProcessDebugPort를 사용하는 것을 알 수 있다.

 

ntdll!ZwQueryInformationProcess()

현재 동작 중인 프로세스에 대한 다양한 정보를 구할 수 있는 시스템 함수이다. 정보를 얻을 프로세스 핸들, 디버그 포트 등 원하는 시스템 정보를 주고 호출하면 디버깅여부를 확인할 수 있는 리턴값을 반환한다. 이 반환값을 0으로 변경을 통해서도 안티 디버깅의 우회가 가능하다.

코드 패치JE(74) -> JMP(EB)로 분기문 우회

FindWindow()

특정 윈도우 이름이나 클래스 이름을 찾아주는 함수이다. lpClassName은 찾을 윈도우의 클래스 이름, lpWindowName은 찾을 윈도우의 창 제목을 인자로 한다. 디버거 문자열을 미리 준비한 후 일치여부를 판단하여 디버깅 여부를 판단할 수 있다.

SEH(Structured Exception Handling)

예외(exception)를 이용하는 안티디버깅 기법이다. 프로세스에서 예외가 발생하면 OS가 예외를 받아서 프로세스에 등록된 SEH를 호출한다. 하지만 디버기에서 예외가 발생하면 디버거에서 예외를 처리한다는 점을 이용한다.

예외처리 구조

예외 종류(Winnt.h)

다양한 예외들이 미리 선언되어 있다. 목록은 다음과 같다.

0으로 나누기 연산을 하여 예외를 의도적으로 발생시킨다.

  • EXCEPTION_EXECUTE_HANDLER : 예외 처리 루틴 수행
  • EXCEPTION_CONTINUE_EXECUTION : 예외가 발생한 라인부터 다시 실행(무한루프 가능성 있음)
  • EXCEPTION_CONTINUE_SEARCH : 가장 가까운 catch 문 찾기

나눗셈(IDIV)을 하는 과정에서 예외가 발생
EXCEPTION_INT_DIVIDE_BY_ZERO 예외 발생

예외가 발생하게 되면 SEH_FLAG가 세팅된다. 기법의 우회는 올리디버거에서 Shift+F7/F8/F9를 통해 예외의 처리를 시스템에 넘겨주거나 함수가 참조하는 구조체의 값을 직접 변경한다.

Single Step-Trap Flag

Trap-Flag

  • The trap interupt flag bit(TF)
  • TrapFlag는 CPU의 동작을 제어하는 Control Flag중 하나
  • 예외를 발생하고 제어권이 SEH로 넘어감
  • 이러한 예외처리 유무로 디버거를 감지
  • PUSHFD를 이용하는데 'push flags double-word'의 약자로 플래그를 더블 워드로 스택에 넣음
  • 실제로 스택에 들어가는 값은 EFL의 값이 들어감

EFLAGS의 9번째 비트 = TF

EFLAGS를 바로 변경하는 명령어는 없기 때문에 PUSHFD를 통해 모든 플래그를 PUSH 한후 0x100을 xor연산한다. 이는 9번째 비트를 SET 시키기 위함이다. 연산 완료 후 POPFD를 통해 TF 값을 다시 EFLAGS에 저장한다.

연산 전 Trap Flag
연산 후 Trap Flag

Timing Check

디버거를 이용해 코드를 한줄 씩 트레이싱하면 정상 실행보다 오랜 시간 소요된다. 이 시간차이를 측정하여 디버깅 여부를 판별하는 기법이다.

시간 측정 방법

1. Counter based method(CPU의 카운터 이용)

  • RDTSC
  • kernel32!QueryPerformanceCounter()
  • kernel32!GetTickCount()

2. Time based method(시스템의 실제 시간)

  • timeGetTime()
  • _ftime()

RDTSC

CPU 내에는 TSC(Time Stamp Counter)가 존재한다. CPU는 매 순간 Clock Cycle을 카운트하여 TSC에 저장한다. RDTSC는 TSC 값을 EDX:EAX 형식으로 읽어오는 어셈블리 명령어이다.

RDTSC
MOV DWORD PTR SS:[EBP-C], EAX
처음 나온 RDTSC 값을 EBP-C에 넣고 Stack에 넣는다.
RDTSC
SUB EAX, DWORD PTR SS:[EBP-C]
두번째 RDTSC를 사용하여 걸린 시간을 체크한다.
시간 차이를 EAX에 저장한다.

시간 경과 비교 함수를 분기조작하여 넘어가거나 시간 측정 부분을 RUN하여 Skip하는 방법으로 우회한다.

 

이외의 기법들

가비지 코드

코드 중간중간 쓰레기 코드를 넣어 분석에 오랜 시간이 걸리게 한다.

Breaking Code Alignment

디버거의 코드 해석을 방해하여 실제 수행되는 명령어가 아닌 다른 어셈블리어로 보이도록 한다.

코드 암/복호화

랜섬웨어나 악성코드에서 주로 사용된다.

API Redirection

디버깅 시 프로그램에 사용되는 API 주소에 BP를 걸어 특정 행위가 발생하는 시점의 핵심코드에 접근한다.

API의 코드 전체 또는 일부를 다른 메모리 영역에 복사한 후 코드를 실행하는 기법이다.

 


Review

포스트에서 설명한 것 이외에도 다양한 안티 디버깅 기법이 존재한다. 더 많은 기법은 아래의 사이트에서 확인이 가능하다.

http://www.openrce.org/reference_library/anti_reversing

 

OpenRCE

The Anti Reverse Engineering Database provides the analysis and desription for a number of various anti debugging, disassembly and dumping tricks. This resource aims to help reverse engineers locate, identify and bypass such techniques. If anyone would lik

www.openrce.org

 

반응형

'Reversing' 카테고리의 다른 글

[Frida] Binary Hooking 2  (0) 2022.05.03
[Frida] Binary Hooking 1  (1) 2022.04.28
DLL Injection 실습  (0) 2020.12.14
[Reversing] Windows 10 Anti-Reversing 기법 1  (0) 2020.12.09
[Binary] PETya 랜섬웨어 분석  (0) 2020.11.27