최근에 EasyHook 라이브러리를 이용해서 후킹을 할 일이 있어서 코드를 작성했는데
explorer.exe 프로세스에 injection 을 할 때 크래시가 발생하더군요. >.<
이리저리 살펴본 결과 EasyHook 라이브러리 내에 문제의 소지가 있는 코드조각이 좀 있었습니다.
thread.c 파일의 RhInjectLibrary( ) 함수와 entry.cpp 파일의 HookCompleteInjection() 함수를 살펴보면 아래와 같은 내용이 있습니다.
Info->LoadLibraryW = (PVOID)GetProcAddress(hKernel32, "LoadLibraryW");
Info->FreeLibrary = (PVOID)GetProcAddress(hKernel32, "FreeLibrary");
Info->GetProcAddress = (PVOID)GetProcAddress(hKernel32, "GetProcAddress");
Info->VirtualFree = (PVOID)GetProcAddress(hKernel32, "VirtualFree");
Info->VirtualProtect = (PVOID)GetProcAddress(hKernel32, "VirtualProtect");
Info->ExitThread = (PVOID)GetProcAddress(hKernel32, "ExitThread");
Info->GetLastError = (PVOID)GetProcAddress(hKernel32, "GetLastError");
Info 구조체는 리모트 프로세스에 생성한 스레드의 파라미터로 넘어가는 파라미터 블럭인데요.
hook 코드를 담고있는 dll 을 로드등의 작업을 위한 함수 포인터들이 저장됩니다.
단순히 GetProcAddress() 함수를 이용해서 함수들의 포인터를 얻어옵니다.
문제는 만일 현재 프로세스가 로드한 kernel32.dll 의 EAT 가 후킹되어있는 경우입니다.
제 테스트 머신 (windows xp sp3) 의 explorer.exe 의 경우 GetProcAddress() 함수가 ShimEng!StubGetProcAddress() 함수로 바뀌어있더군요. (이런 젠장... )
해결방법은 아래와 같습니다.
1. 디스크상의 kernel32.dll 를 오픈한다.
2. PE 를 분석해서 Export table 에 기록된 함수들의 RVA 를 구한다.
3. 2번에서 구한 RVA + 현재 메모리상의 kernel32.dll 의 베이스 주소를 더한다.
PE 구조에 대해서 알고계신다면 구현하는데 크게 어려움은 없을것 같습니다. :-)
(사실은 구현한 코드의 양이 좀 많아서 올리기 귀찮아서.....)
덧글
부자되세요~ :-)