공부해요/리버싱_핵심원리

45. TLS 콜백 함수

yenas0 2025. 1. 2. 08:26
반응형

TLS 콜백 함수란?

EP 코드보다 먼저 실행됨

 

EP코드보다 먼저 실행된다는 특징때문에 안티 디버깅에 사용할 수 있다.

 

실습..

https://github.com/reversecore/book/tree/master/%EC%8B%A4%EC%8A%B5%EC%98%88%EC%A0%9C/06_%EA%B3%A0%EA%B8%89_%EB%A6%AC%EB%B2%84%EC%8B%B1/45_TLS_Callback_Function/bin

 

book/실습예제/06_고급_리버싱/45_TLS_Callback_Function/bin at master · reversecore/book

리버싱 핵심원리 - 소스 코드 및 실습 예제. Contribute to reversecore/book development by creating an account on GitHub.

github.com

다우ㄴ받아서.

 

HelloTls.exe파일을 실행시켜보자.

일케 나옴

올리디버거에 올려보자

올리면 이렇게 나옴

 

확인 누르고 나면 이렇게 종료된걸로 확인할 수 있다..

일반실행과 다른 이유는 EP 코드보다 먼저 실행되는 TLS 콜백함수에서 안티 디버깅 코드를 실행시ㅕㅆ기 때문에 디버깅이 안된것이다.

 

 

TLS란?

스레드별로 독립된 데이터 저장 공간

스레드 내에서 프로세스의 전역 데이터나 정적 데이터를 마치 지역데이터처럼 독립적으로 취급하고 싶을 때 사용한다.

 

IMAGE_TLS_DIRECTORY

#ifdef _WIN64
typedef struct _IMAGE_TLS_DIRECTORY64 {
    ULONGLONG StartAddressOfRawData;
    ULONGLONG EndAddressOfRawData;
    ULONGLONG AddressOfIndex;      // PDWORD
    ULONGLONG AddressOfCallBacks;  // PIMAGE_TLS_CALLBACK *
    DWORD SizeOfZeroFill;
    DWORD Characteristics;
} IMAGE_TLS_DIRECTORY64;
typedef IMAGE_TLS_DIRECTORY64 * PIMAGE_TLS_DIRECTORY64;

typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY;
typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY;

#else

typedef struct _IMAGE_TLS_DIRECTORY32 {
    DWORD StartAddressOfRawData;
    DWORD EndAddressOfRawData;
    DWORD AddressOfIndex;       // PDWORD
    DWORD AddressOfCallBacks;   // PIMAGE_TLS_CALLBACK *
    DWORD SizeOfZeroFill;
    DWORD Characteristics;
} IMAGE_TLS_DIRECTORY32;
typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;

typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY;
typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY;

#endif

이 구조체는 32비트랑 64비트 두개로 준비되어 있다.

 

리버싱에서 중요학 다루는 멤버는 AddressOfCallbacks

이 값은 TLS 콜백 함수 주소(VA 형태) 배열을 가리킨다 즉 TLS 콜백 함수를 여러개 등록 할 수 있다는 것

 

콜백함수 주소 배열에서 보면 배열에 실제 TLS 콜백 함수들의 주소가 들어있는데 프로세스 시작될 때 시스템에서 배열에 저장된 함수를 하나씩 호출한다.

 

TLS 콜백 함수란?

프로세스의 스레드가 생성/종료될 때마다 자동으로 호출되는 콜백 함수

메일 스레드 생성시에도 이 콜백함수가 호출됨(EP 코드보다 먼저..)

-> 이걸로 안티 디버깅

 

IMAGE_TLS_CALLBACK

typedef VOID 
(NTAPI *PIMAGE_TLS_CALLBACK) (
    PVOID DllHandle,
    DWORD Reason,
    PVOID Reserved
);

 DllMain과 비슷함

파라미터의 순서와 의미가 동일..

 

TLS 콜백 함수의 동작 원리 이해하기 위해 TlsTest.exe 실습진행

https://github.com/reversecore/book/blob/master/%EC%8B%A4%EC%8A%B5%EC%98%88%EC%A0%9C/06_%EA%B3%A0%EA%B8%89_%EB%A6%AC%EB%B2%84%EC%8B%B1/45_TLS_Callback_Function/bin/TlsTest.exe

 

book/실습예제/06_고급_리버싱/45_TLS_Callback_Function/bin/TlsTest.exe at master · reversecore/book

리버싱 핵심원리 - 소스 코드 및 실습 예제. Contribute to reversecore/book development by creating an account on GitHub.

github.com

 

 

#include <windows.h>

#pragma comment(linker, "/INCLUDE:__tls_used")

void print_console(char* szMsg)
{
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    WriteConsoleA(hStdout, szMsg, strlen(szMsg), NULL, NULL);
}

void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
    char szMsg[80] = {0,};
    wsprintfA(szMsg, "TLS_CALLBACK1() : DllHandle = %X, Reason = %d\n", DllHandle, Reason);
    print_console(szMsg);
}

void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
    char szMsg[80] = {0,};
    wsprintfA(szMsg, "TLS_CALLBACK2() : DllHandle = %X, Reason = %d\n", DllHandle, Reason);
    print_console(szMsg);
}

#pragma data_seg(".CRT$XLX")
    PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, 0 };
#pragma data_seg()

DWORD WINAPI ThreadProc(LPVOID lParam)
{
    print_console("ThreadProc() start\n");

    print_console("ThreadProc() end\n");

    return 0;
}

int main(void)
{
    HANDLE hThread = NULL;

    print_console("main() start\n");

    hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
    WaitForSingleObject(hThread, 60*1000);
    CloseHandle(hThread);

    print_console("main() end\n");

    return 0;
}

 

 

  • TlsTest.cpp
    • 두 개의 TLS 콜백 함수(TLS_CALLBACK1, TLS_CALLBACK2)를 등록
    • 각 콜백 함수는 DllHandle과 Reason 파라미터 값을 출력한 후 종료
  • main() 함수
    • ThreadProc 사용자 스레드를 생성
    • 함수 시작과 종료 시 로그를 출력
  • ThreadProc() 함수
    • 함수 시작과 종료 시 로그를 출력

 

각 함수의 호출 순서

 

1. DLL_PROCESS_ATTACH

TLS 콜백 함수가 main호출전 호출된다.

이때 Reason 값은 1(DLL_PROCESS_ATTACH)임

 

2. DLL_THREAD_ATTACH

TLS 콜백 함수 종료 시 main 실행

사용자 스레드 생성순간 Reason은 2

 

3. DLL_THREAD_DETACH

Tls 콜백 함수 모두 종료되면 TreadProc()스레드 함수 실행됨 이때 Reason은 3

 

4. DLL_PROCESS_DETACH

ThreadProc()스레드가 종료되면 스레드의 종료를 기다리던 메인함수도 종료된 이때 Reason은 0

 

 

TLS 콜백 디버깅

그냥 디버거로 열면 아까처럼 되니까올리디버거의 설정을 바꿔줘야된다.

옵션 - events 드가서 일케 해주면 된다.

 

 

 

책이랑 다른디 머..

암튼 여기서 잡히는게 System startup BP위치

 

 

수작업으로 TLS 콜백 함수 추가하기https://github.com/reversecore/book/blob/master/%EC%8B%A4%EC%8A%B5%EC%98%88%EC%A0%9C/06_%EA%B3%A0%EA%B8%89_%EB%A6%AC%EB%B2%84%EC%8B%B1/45_TLS_Callback_Function/bin/Hello.exe

 

book/실습예제/06_고급_리버싱/45_TLS_Callback_Function/bin/Hello.exe at master · reversecore/book

리버싱 핵심원리 - 소스 코드 및 실습 예제. Contribute to reversecore/book development by creating an account on GitHub.

github.com

 

이 실습파일로 시작한다.

 

그냥 실행시키면 이렇게 나온다

 

TLS 안티디버깅

  1. 목적
    • PE 파일에 TLS 콜백 함수를 추가하여 안티디버깅 기능을 구현하려고 한다..
  2. 섹션 확장 방식 선택
    • PE 파일 수정 시 마지막 섹션(.rsrc)의 크기 확장 방법을 사용함
  3. 섹션 확장 단계
    • .rsrc 섹션의 Pointer to Raw Data: 9000
    • Size of Raw Data: 200 → 400으로 확장
    • 파일 크기: 9200 → 9400으로 증가
    • Characteristics 플래그에 IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_WRITE 속성 추가
  4. IMAGE_DATA_DIRECTORY[9] (TLS Table) 설정
    • TLS Table의 RVA: C200, Size: 18
    • 옵셋 9200에 IMAGE_TLS_DIRECTORY 구조체를 만듦
  5. IMAGE_TLS_DIRECTORY 구성
    • AddressOfCallbacks: VA 40C224 (파일 옵셋 9224)
    • Array of TLS Callback Function에 콜백 함수 주소 (40C230) 추가
  6. TLS 콜백 함수
    • TLS 콜백 함수는 처음에 RETN 0C 명령어로 설정되어, 아무 작업 없이 리턴하도록 구성
  7. 안티디버깅 코드 작성
    • OllyDbg를 사용하여 40C230 주소부터 안티디버깅 코드를 작성

 

하고나면 이렇게 나오게 된다.

 

반응형

'공부해요 > 리버싱_핵심원리' 카테고리의 다른 글

47. PEB  (1) 2025.01.02
46. TEB  (1) 2025.01.02
44. InjDll.exe-DLL 인젝션 전용 도구  (0) 2024.12.26
43. DLL Injection in Kernel 6  (0) 2024.12.26
42. Session in Kernel 6  (0) 2024.12.26