참고사이트
: https://iforint.tistory.com/52
19번은 윈도우 api를 사용하여 디버깅을 체킹하는 예제이다.
총 두가지 방식을 보여준다. isdebugging 함수와 findwindow를 통해서 프로세스상 디버깅 이름을 비교하는 방시이다.
하지만 이외에도 안티디버깅은 여러가지 기법이 존재한다.
https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-isdebuggerpresent
앞선 예제에서 살펴본, 가장 간단한 디버거 탐지 윈도우 API 함수이다.
이 함수는 PEB 구조에서 IsDebugged 필드를 찾아 디버그가 동작 중인지 판단하여 동작 중이 아니라면 0을, 동작 중이라면 0이 아닌 값을 반환한다.
** PEB 는 FS 레지스터를 통해 접근 가능. TEB 의 0x30 이 PEB 를 가리킴
--> FS:[0x30] 이라 되어있으면 PEB 를 가리키는 것
** TEB, PEB 란?
닫기
: win32 의 자료 구조로서, 현재 실행 중인 스레드에 대한 정보를 저장하고 있다.
다양한 윈도우 DLL 에 대한 컨텍스트 정보를 담고 있다.
이 요소들이 유저 모드에서 구동되므로 유저 모드에서 쓰기가 가능한 구조체가 필요했다.
그래서 이 구조체는 커널 모드에서만 쓰기가 가능한 시스템 주소 공간이 아닌 프로세스 주소 공간에 위치한다.
: 윈도우 NT 에서의 데이터 구조체.
운영체제 내부에서 사용하는 구조체로, 이미지 로더, 힘 관리자, 윈도우 시스템 DLL 등 유저 모드 상에서 접근할 필요가 있는 정보를 가지고 있다.
: 커널 모드에서는 KPCR(Kernel's Processor Control Region) 구조체를,
유저 모드에서는 TEB 구조체를 가리키고 있다.
따라서
FS:[0] 은 TEB 의 시작 위치,
FS:[0x30] 은 PEB 의 시작 위치를 의미
실제로 함수 실행에 들어가보면 FS:[30] 으로 PEB 구조체에서 +2 를 하여 BeingDebugged 를 확인하는 것을 볼 수 있다.
https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-checkremotedebuggerpresent
PEB 구조의 IsDebugged 필드를 확인하며 IsDebuggerPresent 와 거의 동일한 기능을 한다.
다만 자신이나 로컬 컴퓨터의 프로세스에 대해서만 검사할 수 있다.
파라미터로 프로세스 헨들을 받아 프로세스가 디버거 환경에서 실행 중인지를 판단한다.
Use the IsDebuggerPresent function to detect whether the calling process is running under the debugger.
https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
첫 번쨰 파라미터로 프로세스 헨들을, 두 번째 파라미터로 얻고자 하는 프로세스 정보의 타입을 요구한다.
두 번째 파라미터인 ProcessInformationClass 에 ProcessDebugPort(0x7) 을 준다면 해당 프로세스가 디버깅 중인지에 대한 여부를 반환한다.
디버깅 중이라면 0, 아니면 디버거 포트 번호를 반환한다.
(NT ZW ?? -> https://blog.naver.com/stgavriel/80044878343)
https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-outputdebugstringw
디버거에 출력할 문자열을 전달하는 데 사용되는 함수이므로 디버거의 존재를 탐지하는 데 사용할 수 있다.
이 함수를 실행했는데 오류가 발생하지 않는다면 디버거로 실행중이라는 의미이다.
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowa
특정 프로그램(디버그)가 실행되고 있는지 검색할 수 있다.
첫번째 파라미터로 검색할 프로그램(디버그) 이름을 주고, 만일 해당 프로그램이 실행 중이라면 그 헨들을, 실행하고 있지 않다면 NULL 값을 반환한다.
ex. FindWindow("OllyDbg", NULL)
PEB 구조체에서 디버거가 존재하는지에 대한 정보를 제공한다.
운영 체제는 실행 중인 각 프로세스에 대해 윈도우 PEB 구조체를 관리한다.
환경 변수 값, 로드된 모듈 목록, 메모리 주소, 디버거 상태 등의 프로세스 환경 데이터를 포함한다.
프로세스 실행 중에 FS:[0x30] 으로 PEB 를 접근할 수 있다.
https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
이 플래그는 PEB 구조체의 오프셋 2에 있다. (0x2) (향후 윈도우 버전에 따라 변경 가능)
이 플래그 값이 0 이면 디버거가 동작하고 있지 않다는 것이고, 1 이면 디버거가 동작하고 있다는 뜻이다.
그리고 다른 플래그들이 존재하지만, 향후 윈도우 버전에 의해 구조가 달라질 수 있으므로 해당 문서를 참조하길 바란다.
INT 3 는 소프트웨어 BP 를 설정하는 기본 메커니즘이다.
INT 3 의 OPCODE 는 0xCC 로, 이 OPCODE 를 검색하여 본래의 코드가 INT 3 로 변경되었는지 프로세스를 스캔한다.
0xCC 가 발견되면 디버거가 존재한다는 뜻이다.
혹은 코드에 INT 3 구문이 있을 때, 디버거로 실행하면 오류가 나지 않지만 그냥 실행하면 해당 구문은 오류를 뱉는다. 오류를 뱉는지에 대한 여부로도 디버그의 존재 여부를 파악할 수 있다.
이를 우회하기 위해서는 소프트웨어 BP 대신 하드웨어 BP 를 설정하면 된다.
3.2 Checksums
특정 코드 영역의 CheckSum 값을 구하고, 원본 CheckSum 과 비교하여 BP 설정 혹은 각종 코드 패치 여부를 검사할 수 있다.
그 중 Hash Checking 기법은 함수 코드들의 Hash 값을 미리 구해 둔 다음, 그 값과 실행 중간에 호가인한 Hash 값이 같은지 확인하여 패치 여부를 탐지하는 것이다.
디버거로 프로세스를 실행하면 그냥 프로세스를 실행했을 때보다 속도가 현저히 느려진다.
이런 시간 차이를 탐지하는 몇 가지 기술이 존재한다.
특정 동작 수행 전후에 타임 스탬프를 기록하고 비교한다.
혹은 예외 발생 전후의 타임 스탬프를 가져와서 비교한다. 디버거가 예외를 처리하는 경우 상당한 지연이 발생하기 때문에 구분할 수 있다. (예외를 무시하거나 지나치게 하는 기능을 제공하는 디버거들도 있지만, 그럼에도 차이가 발생한다.)
가장 일반적인 시간 검사 방법이다.
가장 최근에 시스템이 리부팅한 이후 흐른 시간 값을 저장한 64비트를 반환한다.
이 명령어를 실행한 후 두 값의 차가 특정한 정도를 넘으면 디버거가 실행 중임으로 판단할 수 있다.
https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter
https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount
rdtsc 와 같이 시간차를 분석할 수 있는 윈도우 API 함수이다.
일반적으로 대다수 디버거는 PE 헤더에서 정의한 프로그램 지입점에서 시작한다.
그런데 TLS(Thread Local Storage) Callback 은 진입점 전에 실행되는 코드로, 디버거 몰래 실행할 수 있다.
즉, TLS Callback 에 악성 코드 기능을 삽입한다면 디버거로는 감지하지 못한다.
일반적인 프로그램은 .tls 섹션을 사용하지 않기 때문에 .tls 섹션이 있는 경우 가장 먼저 안티 디버깅을 의심해야 한다.