50. 안티 디버깅
디버깅 -> 프로그램의 코드 흐름과 데이터 구조를 쉽게 파악 가능
안티 디버깅을 통해 이를 방지
안티 안티 디버깅 : 리버서들이 안티 디버깅을 상대하는 방법을 일컫는다.
static
디버깅을 시작할 때 한번만 해체해주면 되는 기법
이 기법이 적용된 파일은 RUN조차 되지 않음.
static 기법을 해제해줘야 실행 가능
dynamic
만날 때마다 해결해줘야함.
RUN은 되지만 TRACING은 방해하여 원본 프로그램의 코드와 데이터를 확인할 수 없게 만든다.
run : 디버기 프로세스를 실행시키는 것
trace : 디버기의 내부 Instruction 을 하나씩 실행하면서 레지스터, 메모리(스택) 등을 실시간으로 확인하는 것
51. Static Anti Debugging
51.1. 목적
디버깅중이라고 판단되면 일반 실행과는 다른 코드를 실행
구현 방법 : 디버거 탐지 / 디버깅 환경 탐지 / 디버거 강제 분리
회피 방법 : 탐지 코드에서 얻어오는 정보를 파악하여 그 정보 자체를 변경
51.2. PEB
Process Environment Block : 프로세스 환경 정보가 담겨져 있다.
신용 가능하고, 사용또한 쉽기 대문에 가장 널리 사용되는 안티 디버깅 기법
Windows XP SP3의 PEB 구조체에서 안티 디버깅을 위해 사용되는 멤버는 아래와 같다
+0x002 BeingDebugged : UChar
+0x00c Ldr : Ptr32_PEB_LDR_DATA
+0x018 ProcessHeap : Ptr32_Void
+0x068 NtGlobalFlag : Uint4B
PEB 구하는법 : 올리디버거로 해당 디버기 불러왔을 때, EBX에 저장된 값이 PEB의 시작주소
51.2.1. BeingDebugged (+0x2)
디버깅 중이면 1, 일반 실행이면 0
IsDebuggerPresent()를 통해 이 값을 가져오고, 이로써 디버깅 여부를 판별한다.
회피방법 : 0으로 변경
51.2.2. Ldr (+0xC)
디버깅 프로세스는 힙 메모리 영역에 자신이 디버깅 당하는 프로세스라는 표시를 한다. 그 중 가장 큰 특징은 사용되지 않는 역역은 0xFEEEFEEE 로 채운다는 것이다. 이를 통해 디버깅 여부 판별 가능하다.
Ldr 주소로 가면 0xFEEEFEEE를 찾을 수 있다.
회피방법 : NULL로 덮어씌우면 된다.
XP 이하에서만 동작하고 Vista 이후부터는 동작하지 않는다.
51.2.3. Process Heap (+0x18)
heap 구조체를 가리키는 포인터이다.
heap 구조체 중 Flags(+0xC) 와 Force Flags(+0x10) 멤버는 디버깅 중 특정한 값으로 세팅된다.
일반 실행시 Flags는 0x2 이고, ForceFlags는 0x0 이다.
디버깅 중에는 이 값들이 변경된다.
회피방법 : 정상 값으로 변경.
XP에서만 효과가 있다.
51.2.4. NtGlobaIFlag (+0x68)
디버깅 중일때는 이 값이 0x70으로 세팅된다.
회피방법 : 0x0으로 세팅
51.3. NtQueryInformationProcess()
ntdll!NtQueryInformationProcess() API를 사용하여 프로세스의 정보를 가져온 후, 이 중 디버깅 관련 정보를 통해 안티 디버깅을 수행한다.
3번째 파라미터인 PVOID ProcessInformation에 해당 정보가 세팅되는데 이 정보 중, ProcessDebugPort(0x7), Process DebugObjectHandle(0x1E), ProcessDebugFlags(0x1F) 가 사용된다.
51.3.1. ProcessDebugPort(0x7)
프로세스가 디버깅 중일 때 Debug Port가 할당된다.
디버깅 중이 아니라면 0이 세팅되지만
디버깅중이라면 0xFFFFFFFF 가 세팅된다.
CheckRemoteDebuggerPresent()를 통해 이 값을 가져오고, 이로써 디버깅 여부를 판별한다.
51.3.2. ProcessDebugObjectHandle(0x1E)
프로세스가 디버깅될 때 Debug Object가 생성된다.
디버깅 중이라면 Handle 값이 존재하고, 디버깅중이 아니라면 Handle은 NULL이다.
51.3.3. ProcessDebugFlags(0x1F)
0이면 디버깅 상태이고, 1이면 디버깅이 아니다.
51.3.4. 회피방법
API 후킹을 통해 특정 파라미터일 때 무조건 정상 값을 반환하도록 조작함.
51.4. NtQuerySystemInformation()
디버깅 환경을 체크하는 안티 디버깅 기법
OS가 Debug Mode로 부팅되었는지를 판단하는 안티 디버깅 기법
ntdll!NtQuerySystemInformation() API 를 통해 현재 동작 중인 OS 시스템에 대한 다양한 정보를 구할 수 있다.
첫번째 파라미터인 SYSTEM_INFORMATION_CLASS SystemInformationClass 에 SystemKernelDebuggerlnformation(0x23) 을 입력하면 현재 OS 시스템이 디버그 모드로 부팅되었는지 알 수 있다.
디버그 모드인 경우 SYSTEM_KERNEL_DEBUGGER_INFORMATION.DebuggerEnabled는 1에 세팅된다.
[회피]
xp의 경우, boot.ini를 편집하고 ‘/debugport=com1 /bandrate=115200 /Debug’ 값을 제거한다.
7의 경우, cmd 창에서 ‘bcdedit /debug off’ 명령을 내리고 재부팅하면 일반모드로 부팅된다.
51.5. NtQueryObject()
프로세스가 디버깅될 때 Debug Object가 생성되는데 이 존재를 확인하는 방법이다.
ntdll!NtQueryObject()는 시스템의 다양한 종류의 커널 객체 정보를 구해오는 함수이다.
두번째 파라미터에 원하는 값을 입력하고 API를 호출하면 세번째 파라미터에 관련 정보의 구조체 포인터를 리턴한다.
ObjectAllTypesInformaion 항목을 이용하여 시스템의 모든 객체 정보를 구한 다음 그 중에 DebugObject가 있는지 확인한다.
회피방법 : 이 함수가 호출될 때 breakpoint를 걸어 두번째 파라미터에 3(ObjectAllTypesInformaion)이 아닌 0(ObjecBasicTypesInformaion)이 들어가게 한다.
51.6. ZwSetInformationThread()
디버기에서 강제로 디버거를 떼어내는 기법이다.
이 함수는 스레드에게 정보를 세팅하는 System Native API이다.
첫번째 파라미터에 현재 스레드의 핸들을 넘겨주고
두번째 파라미터에 ThreadHideFromDebugger(Ox11) 값을 입력하면 디버거 프로세스가 분리된다.
회피방법 : breakpoint 를 걸어 두번째 파라미터에 0x11이 들어가 있다면 0으로 변경한다.
51.7. TLS
45장 참고
51.8. ETC
- 디버거 창 검색
- 디버거 프로세스 검색
- 컴퓨터 이름 확인 (TEST, ANALYSIS)
- 프로그램 실행 경로 검사 (TEST, SAMPLE)
- 가상 머신 실행 중인지 확인
회피방법 : 반환되는 문자열을 NULL로 세팅
'리버싱핵심원리' 카테고리의 다른 글
Reverse Engineering Chap 47 (0) | 2016.02.03 |
---|---|
Reverse Engineering Chap 46 (0) | 2016.02.03 |
Reverse Engineering Chap 21-22 (0) | 2016.02.03 |
Reverse Engineering Chap 45 (0) | 2016.01.30 |
Reverse Engineering Chap 34 (0) | 2016.01.27 |