티스토리 뷰

카테고리 없음

Anti-Debugging Tech - 1

mhibio 2021. 2. 13. 13:08

Anti Debug

https://www.apriorit.com/dev-blog/367-anti-reverse-engineering-protection-techniques-to-use-before-releasing-software

해당 안티 디버깅 관련 자료들을 읽고 한글로 번역하고 도움될만한 내용들 끄적여본다.

 

Who this article is intended for

안티 리버싱 기술과 안티 디버깅 기술에 관심있는 소프트웨어 개발자, 리버스 엔지니어들을 위한 자료.

어셈 지식, windbg 사용법, api를 이용한 윈도우 개발 경험이 필요할 수 도있다.

 

explanatory notes

잘 알지못하는 개념들을 적어두었다.

 

PEB (Process Environment Block)

PEBWindows operating system 내부에서 사용되는 구조체이다.

x64 / x32에 따라 구조체 포인터를 가져오는 방법이 다르다.

// Current PEB for 64bit and 32bit processes accordingly
PVOID GetPEB()
{
#ifdef _WIN64
    return (PVOID)__readgsqword(0x0C * sizeof(PVOID));
#else
    return (PVOID)__readfsdword(0x0C * sizeof(PVOID));
#endif
}

 

WOW64

WOW64Windows on Windows 64-bit. 즉 운영체제의 하위시스템으로, 모든 64bit버전의 Windows에서 32bit 응용 프로그램들이 돌아가도록 도와주는 매커니즘?? 이다.

 

 

Anti-debugging method introduction

안티디버깅에 관한 다양한 기술들을 설명.

소프트웨어를 reverse engineering으로부터 완전히 보호하는것은 불가능.

안티리버싱의 목표는 가능한 다양한 작업, 프로세스들을 최대한 복잡하게 만드는것.

 

 

IsDebuggerPresent

가장 간단한 안티디버깅 기법으로는 IsDebuggerPresent함수를 호출하는 것.

해당 함수는 함수를 호출하는 프로세스가 user-mode디버거에 의해 디버깅 되고있다면 보호하는 역할을 함.

 

Example

int main()
{
    if (IsDebuggerPresent())
    {
        std::cout << "Stop debugging program!" << std::endl;
        exit(-1);
    }
    return 0;
}

 

IsDebuggerPresent함수안에는 다음과 같은 루틴이 존재하는데, PEB (Process Environment Block)구조체에서 BeingDebugged필드 ( offset +2 )를 검사한다. ( debugged : 1 / not : 0 )

#######################################################################################################
# x32
0:000< u kernelbase!IsDebuggerPresent L3
KERNELBASE!IsDebuggerPresent:
751ca8d0 64a130000000    mov     eax,dword ptr fs:[00000030h]
751ca8d6 0fb64002        movzx   eax,byte ptr [eax+2]
751ca8da c3              ret

#######################################################################################################
# x64
0:000< u kernelbase!IsDebuggerPresent L3
KERNELBASE!IsDebuggerPresent:
00007ffc ab6c1aa0 65488b042560000000 mov   rax,qword ptr gs:[60h]
00007ffc ab6c1aa9 0fb64002           movzx eax,byte ptr [rax+2]
00007ffc ab6c1aad c3                 ret

 

PEB structure

0:000< dt _PEB
ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar

 

How to bypass the IsDebuggerPresent check

단순하게 BeingDebugged 검사코드가 실행되기전에 return값을 0으로 설정하도록 함.

DLL주입을 통해서도 가능함.

  • 그냥 직접 분기문 가기전에 패치해서 우회하면 될듯?

 

TLS Callback

main 함수에 안티 디버깅 루틴을 작성하는 것은 좋지 않음. 우회하기 매우 쉽기 때문임.

CRT Library를 사용한다면 main Threadmain 함수를 실행하기전에 특정 Call Stack을 형성하기때문에

TLS callback안에서 디버깅 체크를 하는것이 매우 좋음.

 

Example

#pragma section(".CRT$XLY", long, read)
__declspec(thread) int var = 0xDEADBEEF;
VOID NTAnopPI TlsCallback(PVOID DllHandle, DWORD Reason, VOID Reserved)
{
    var = 0xB15BADB0; // Required for TLS Callback call
    if (IsDebuggerPresent())
    {
        MessageBoxA(NULL, "Stop debugging program!", "Error", MB_OK | MB_ICONERROR);
        TerminateProcess(GetCurrentProcess(), 0xBABEFACE);
    }
}
__declspec(allocate(".CRT$XLY"))PIMAGE_TLS_CALLBACK g_tlsCallback = TlsCallback;

TLS callback위치에서 디버깅 체크를 하는 예제이다.

 

 

NtGlobalFlag

Windows NT에서, 전역변수 NtGlobalFLag에 플래그집합이 위치해있다.

부팅시, NtGlobalFlag 전역 시스템변수는 시스템 레지스트리 키값으로 초기화된다.

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\GlobalFlag]

 

이 변수값은 System Trace, Debugging그리고 제어에 사용된다.

SDK에는 전역 플래그 값을 편집 할 수 있는 gflags 유틸리티가 포함되어 있다.

PEB 구조체 또한 NtGlobalFlag 영역을 포함하는데, 해당 비트 구조는 NtGlobalFlag 전역변수에 해당하지 않는다.

 

  • 쉽게말해서, 기본적으로 NtGlobalFlagwindows NT에서 사용되는 플래그 집합이며.
  • PEB구조체 또한 NtGlobalFLag필드가 존재하지만 필드값은 해당 프로세스에만 영향을 줄뿐, 윈도우 전역에는 영향 X
  • 디버깅 중이라면 NtFlobalFlag필드에 필드갑이 설정되고,
  • SDK 에서 해당 플래그 값을 편집할 수 있는 gflags 유틸리티가 포함되어 있다.

틀린 내용이 있을 수 도있습니다. 지적 환영입니다 :)

 

즉 디버깅중에는, NtGlobalFlag필드에 플래그가 설정된다

FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
FLG_HEAP_ENABLE_FREE_CHECK (0x20)
FLG_HEAP_VALIDATE_PARAMETERS (0x40)

NtGlobalFlag필드를 확인하면 디버깅중인지 확인할 수 있다.

 

오프셋은 다음과 같다.

#######################################################################################################
# x32
0:000> dt _PEB NtGlobalFlag @$peb 
ntdll!_PEB
   +0x068 NtGlobalFlag : 0x70 

#######################################################################################################
# x64
0:000> dt _PEB NtGlobalFlag @$peb
ntdll!_PEB
   +0x0bc NtGlobalFlag : 0x70

 

Example

#define FLG_HEAP_ENABLE_TAIL_CHECK   0x10
#define FLG_HEAP_ENABLE_FREE_CHECK   0x20
#define FLG_HEAP_VALIDATE_PARAMETERS 0x40
#define NT_GLOBAL_FLAG_DEBUGGED (FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS)
void CheckNtGlobalFlag()
{
    PVOID pPeb = GetPEB();
    PVOID pPeb64 = GetPEB64();
    DWORD offsetNtGlobalFlag = 0;
#ifdef _WIN64
    offsetNtGlobalFlag = 0xBC;
#else
    offsetNtGlobalFlag = 0x68;
#endif
    DWORD NtGlobalFlag = *(PDWORD)((PBYTE)pPeb + offsetNtGlobalFlag);
    if (NtGlobalFlag & NT_GLOBAL_FLAG_DEBUGGED)
    {
        std::cout << "Stop debugging program!" << std::endl;
        exit(-1);
    }
    if (pPeb64)
    {
        DWORD NtGlobalFlagWow64 = *(PDWORD)((PBYTE)pPeb64 + 0xBC);
        if (NtGlobalFlagWow64 & NT_GLOBAL_FLAG_DEBUGGED)
        {
            std::cout << "Stop debugging program!" << std::endl;
            exit(-1);
        }
    }
}

NtGlobalFlag를 검사해서 안티디버깅을 하는 예제이다.

 

How to bypass the NtGlobalFlag check

이거도 마찬가지로 안티디버깅 루틴을 거치기전에 PEB 구조필드를 0으로 설정하면 된다.

 

 

 

Heap Flags and ForceFlags

Check RemoteDebuggerPresent and NtQueryInformationProcess

Breakpoints: Software and Hardware

NtSetInformationThread - hiding thread from debugger

NtCreateThreadEx

Handle Tracing

Stack Segment Manipulation

Debugging Messages

댓글
댓글쓰기 폼
공지사항
Total
7,553
Today
0
Yesterday
4
TAG
more
«   2022/01   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
글 보관함