블로그 > BIT Inside http://blog.naver.com/hch0808/100013839465
어떤 프로그램 작동방식이 궁금해 이것 저것 뒤져 보던중 detour 라는 MS Research 팀에서 만드는 툴에 대해 알게 되었다. 이 툴엔 여러가지 기능이 있는데 Dll Injection 툴, Api Trace 툴, Memory Allocation Trace 툴 등등.. 무엇 보다 좋았던건 소스도 포함되어 있거니와 PPT 파일로 작동 방식도 설명 해주고 있다.
이 중 가장 애용(?) 했던 것이 API 함수가 호출 되는 것을 Trace 로그로 남겨 주는 traceapi 툴이다. 이를 이용해 특정 프로그램을 실행 하면 이 프로그램이 로더에 의해 로드 되어 쓰레드가 시작 될 때 부터의 모든 API를 로그로 찍어 준다.(모든 API는 아니고 거의 모든. 이에 대해서는 다시 설명 한다.) 몇 십초만 실행 시켜도 로그 파일이 몇 메가 단위로 생긴다. (요즘 CPU 참 빠르다...)
detour를 다운로드 받을 수 있는 경로는 http://research.microsoft.com/sn/detours/#pubs
다운로드 받고 나서 압축을 풀면 몇개의 폴더안의 소스코드와 Readme 파일과 설명 ppt, pdf 파일, 그리고 make 파일이 나온다. 그런데 실행 파일은 하나도 없다. 직접 빌드 해야 한다. 그러나 Visual Studio 용 프로젝트 파일 같은건 없기 때문에 makefile을 이용해 직접 빌드를 해야 한다. 빌드를 위해서는 detour가 위치한 경로에서 command 창으로
nmake
를 가볍게 쳐준다.(VC 환경 변수 세팅이 되어 있다고 가정 한다.) 그럼 자동으로 빌드가 되고 bin 폴더 안에 모든 실행 파일들이 들어간다. (간혹, pdb 파일이 뭐라 뭐라 하면서 빌드 중간에 종료 되는 경우가 있는데 이런 경우엔 lib 폴더에 detour.pdb 파일을 삭제 하고 다시 빌드 하면 된다.) 이렇게 빌드가 끝나면 각 툴들의 폴더 안에 가면 test.bat 가 있는데 이를 간단히 실행 해 봄으로써 테스트를 해 볼 수 있다.
우선 TraceApi를 보자. traceapi 폴더 내에 보면 cpp 파일 몇개와 makefile 그리고 test.bat 파일이 하나 있다. 그럼 먼저 test.bat 파일을 열어 보자.
start ..\bin\syelogd.exe
..\bin\withdll -d:traceapi.dll ..\bin\sleepold.exe
열어 보면 위와 같이 두개의 커맨드 명령이 있다. 첫째 라인은 syelogd.exe 라는 로그 프로그램을 띄우는 것이고 두번째 라인은 withdll 이라는 프로그램으로 sleepold.exe라는 프로그램을 띄우는데 이 프로세스에 traceapi.dll을 삽입 시켜 실행 하라는 명령이다. 이 batch 파일을 커맨드 콘솔에서 실행 시켜 보면 두개의 콘솔이 뜨고 하나는 로그창 다른 하나는 withdll를 이용한 sleepold.exe의 실행화면이 뜬다. 그러나 로그가 너무 빨리 지나가기 때문에 분석하기에 힘들다. 그래서 다음과 같이 커맨드 콘솔을 두개 띄우고 한개의 콘솔에는
..\bin\syelogd.exe >> trace.txt
다른 콘솔에는
..\bin\withdll -d:traceapi.dll ..\bin\someprogram.exe
이렇게 해주면 someprogram.exe가 실행되는 동안 로그는 trace.txt에 들어가게 된다. 물론 로그가 파일로 가기 때문에 someprogram.exe 가 실행 되는 동안에는 약간의 성능 저하가 있다. 그리고 로그가 금방 쌓이기 때문에 몇십초만 실행 해도 로그 파일의 크기는 메가 단위로 커진다. 우선 사용 방법은 됐는데 내가 원하는 API가 호출 되는 것에 대한 로그가 안찍히는 경우엔? traceapi 폴더 안에 보면 무려 1메가가 넘는 cpp 파일 하나가 있다. 이 _win32.cpp 파일을 보면 traceapi 툴이 훅킹 하는 모든 API 함수들의 stub을 볼 수 있는데 이 툴이 배포용으로 만들어 졌을 당시의 API 함수들만이 들어 있기 때문에 XP 나 2003 Server에 새로 추가된 함수들은 없다. 앞에서 거의 모든 API 함수들에 대한 로그라고 한 이유가 여기 있다. 그럼 여기에 내가 원하는 API 함수를 추가 해 보자.
예로 SetLayeredWindowAttributes() 함수를 추가 해 보자. 우선 함수의 prototype을 선언 해준다.
extern "C"
BOOL WINAPI SetLayeredWindowAttributes(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);
그리고
DETOUR_TRAMPOLINE(int __stdcall Real_SetLayeredWindowAttributes(HWND a0, COLORREF a1, BYTE a2, DWORD a3), SetLayeredWindowAttributes);
와 같이 DETOUR_TRAMPOLINE 매크로를 이용해 훅킹거는 대상의 함수와 stub 함수를 연결 시켜 준다. 그리고 나서
int __stdcall Mine_SetLayeredWindowAttributes(HWND a0, COLORREF a1, BYTE a2, DWORD a3)
{
_PrintEnter("SetLayeredWindowAttributes(%lx,%lx,%lx,%lx)\n", a0, a1, a2, a3);
int rv = 0;
__try {
rv = Real_SetLayeredWindowAttributes(a0, a1, a2, a3);
} __finally {
_PrintExit("SetLayeredWindowAttributes() -> %lx\n", rv);
};
return rv;
}
를 추가 해준다. 여기서 _PrintEnter()를 보면 이 함수가 호출 되었을 때 찍히는 로그 형식을 볼 수 있는데 이를 적절히 고치면 로그의 형식을 내가 원하는 방식으로 변경이 가능 하다. 그리고 나서 VOID TrampolineWith(VOID) 함수 안에
DetourFunctionWithTrampoline((PBYTE)Real_SetLayeredWindowAttributes, (PBYTE)Mine_SetLayeredWindowAttributes);
를 추가 해준다. 이 과정은 _win32.cpp 파일의 코드를 조금만 들여다 보면 금방 알 수 있으니 직접 코드를 보면서 하면 쉽다. 이 과정이 모두 끝났으면 다시 한번 nmake를 이용해 빌드 해주고 나서 다시 실행 하면 추가한 API 함수가 로그에 찍힌다.
이제 할일은... 수만 라인의 로그를 분석 하는 일만.. ㅜ.ㅜ
< 출처 : http://krispy.onblog.com >