리버싱핵심원리

Reverse Engineering Chap 45

지환태 2016. 1. 30. 21:27

TLS 콜백은 프로세스에서 스레드가 생성되기 전, 스레드가 종료된 후 자동으로 실행되는 함수 들이다 . 메인 함수가 실행되는 스레드도 예외가 아니기 때문에 메인함수 시작 전에도 TLS 콜백이 실행된다. 메인의 엔트리 포인트 이전에 실행되기 때문에 안티 디버깅을 위한 용도로 쓰이기도 한다.


TLS TLS 콜백을 등록하기 위해서는 아래와 같은 형태의 함수를 사용해야한다.이 형태는 DLL에서 쓰이는 것과 같다.


예제 코드


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

#pragma data_seg(".CRT$XLX")

PIMAGE_TLS_CALLBACK TLS_CALLBACk[] = { tlsCallback, 0 };

#pragma data_seg()


위의 코드가 TLS를 사용하기 위해 필요하다. .CRT$XLX 영역에 PIMAGE_TLS_CALLBACK 변수 또는 배열을 이용하여 TLS 콜백 함수들을 등록한다.

위의 코드를 실행하면 아래와 같은 결과를 볼 수 있다.

메인 함수가 실행되기 전 TLS 콜백이 실행되어 문자열 TLS가 출력된다.

스레드 실행 전 후로 TLS 콜백이 실행되는 것을 확인할 수 있다.

디버깅을 해보면 메인 함수 종료 후에도 TLS 콜백이 실행되나 printf 함수가 제대로 동작하지 않아 실제로 출력은 되지 않는다.


PE 내부 TLS의 위치와 구조

TLS를 사용하면 IMAGE_NT_HEADER.IMAGE_OPTIONAL_HEADER.IMAGE_DATA_DIRECTORY[9]에 TLS 테이블의 크기와 RVA가 기록된다.


PEview로 확인하면 TLS table에 대한 정보가 있는 것을 확인할 수 있다.

RVA 0x176EC에 해당하는 RAW인 0x68EC에는 IMAGE_TLS_DIRECTORY가 있다.


IMAGE_TLS_DIRECTORY 구조체 중 Address of Callbacks에 TLS 콜백 함수들의 주소(VA)가 저장되어있다.

00416720에 해당하는 곳은 아래 그림에서 볼 수 있다.


Address of Callbacks에 해당하는 곳인 0x00416720의 모습이다. 콜백 함수들의 주소가 저장되고 마지막은 NULL로 끝난다. 우리가 정의한 함수의 주소인 0x004110EB는 아래의 그림에 있다.


0x004110EB의 값을 보면 E9로 시작한다. E9 XXXXXXXX는 점프문에 해당하기 때문에 점프 주소를 쉽게 확인하기 위해 올리 디버거로 확인해보았다.


올리 디버거로 확인해보면 VA 0x004110EB에는 JMP 007316E0 명령어가 있고, 이 점프문을 따라가면 우리가 정의했던 TLS 콜백 함수가 나타난다.


문자열 TLS를 스택에 넣고 출력하는 것으로 보아 우리가 정의했던 TLS 콜백 함수임을 알 수 있다.