DLL 인젝션을 통한 지뢰찾기 IAT 후킹 (Hooking) 구현
- 리버싱/리버싱
- 2020. 3. 24. 21:49
지뢰찾기.exe를 사용해서 단순 DLL 인젝션부터 코드 후킹 (Code Hooking), API 후킹 (API Hooking)까지 구현을 해봤는데 오늘은 마지막으로 IAT 후킹 (IAT Hooking)을 구현해보려 한다. IAT 후킹은 사실 큰개념으로 보면 API 후킹에 포함되는 개념이지만 API 후킹에서 사용했던 방식은 WinAPI의 EP 코드를 후킹하는 것이었는데 오늘할 IAT 후킹에서는 코드가 아닌 IAT 영역을 변경한다는 것이 다르다.
IAT 후킹을 위해선, 핸들값을 얻은 후에 내가 후킹할 함수의 IAT 위치를 알아내는 것이 필요하기 때문에 PE구조를 어느정도 알 필요가 있다.
- 빌드 : VisualStudio 2015
- 환경 : Windows10 x64
타겟 API 선정
타겟 API는 아래 링크에 있는 'DLL 인젝션을 통한 지뢰찾기 API 후킹'에서 후킹한 함수와 동일하게 'SetCapture'로 진행할 예정이다. SetCapture는 마우스 움직임을 감지?하는 함수로 클릭시 호출되는 클릭 이벤트핸들러 내부에서 처음 호출된다.
SetCapture를 후킹해서 게임 종료 직전에 실행되는 지뢰를 보여주는 함수가 실행되게 하면 지뢰가 보여진 채로 게임을 진행하는 것이 가능했는데 오늘은 DLL 함수에 ShowMessage라는 함수를 작성하고 SetCapture 대신 DLL 내부의 해당 함수가 실행되도록 해볼 것이다.
관련포스팅
DLL 인젝션을 통한 지뢰찾기 API 후킹 (Hooking) 구현
DLL 인젝션을 통한 지뢰찾기 코드 후킹 (Code Hooking) 구현
IAT(Import Address Table) 접근
IAT에 접근하려면 먼저 IMPORT Directory Table(IMAGE_IMPORT_DESCRIPTOR 구조체 배열)에서 내가 찾으려고 하는 DLL을 Name 변수를 사용해서 찾아야 한다. 그리고 Import Name Table의 시작주소가 저장되어 있는 OriginalFirstThunk 값을 구하거나 Import Address Table의 시작주소가 저장되어 있는 FirstThunk 값을 구한다.
여기서 내가 찾으려고 하는 함수의 IAT 위치를 구하는 방법이 2개가 있는데, Name Table에서 함수 이름이 일치하는지의 여부로 찾을 수도 있고 Addrss Table에서 함수 주소가 일치하는지의 여부로 찾을 수도 있다. 여기서 함수 주소가 일치하는지의 여부를 알려면 사전에 GetModulHandle, GetProcAddress를 사용해서 미리 주소값을 얻어놔야 하긴 하다.
DLL 인젝션 코드
DLL 인젝션 코드는 아래 포스팅에서 제작한 코드와 동일한 코드를 사용했다. 인젝션 관련 내용은 아래 포스팅을 참고하길 바란다.
2020/03/18 - [리버싱/리버싱] - CreateRemoteThread를 사용한 DLL 인젝션 구현
IAT 후킹을 수행하는 DLL 코드
그럼 이제, 위에서 살펴본 IAT에 접근하는 방식을 그대로 사용해서 DLL 코드를 짜보자. DLLMain에서는 DLL이 로딩될 시 CreateThread를 사용해 IATHooking 스레드를 실행시킨다.
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
HANDLE hThread = NULL;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
hThread = CreateThread(NULL, 0, IATHooking, NULL, 0, NULL);
}
return TRUE;
}
IATHooking 코드는 아래와 같다. 사실 나중에 참고하기 위해 주석을 많이 써놔서 그렇치 코드 자체는 엄청 짧다. 먼저 IMAGE_OPTIONAL_HEADER의 DataDircetory[1].VirtualAddress 값을 통해 IMPORT Directory Table의 위치를 구한다. 그리고 해당 테이블에서 후킹하려는 함수의 DLL을 찾은 후 OriginalFirstThunk 값으로 IMPORT Name Table의 위치를 얻어 후킹 함수를 찾으면, 해당 위치에서의 IAT 주소가 API 주소가 저장되어 있는 위치이다. 사실 굳이 Import Name Table을 사용할 필요도 없이 주석에서 구한 TargetAddr을 사용하면 Import Address Table만으로도 SetCapture의 IAT 위치를 구할수는 있는데 코드에서 최대한 많이 사용..? 해보기 위해 둘다 사용해보았다.
후킹할 API가 저장되어있는 IAT 위치를 찾았으면 VirtualProtect를 사용해 WIRTE 권한을 추가해준다. 그리고나서 IAT 후킹을 진행하기 위해 'AddrTable->ul.Function' 값을 ShowMessage 함수로 변경해준다. ShowMessage 함수는 IAT 후킹 성공 여부를 판별하기 위해 메시지박스를 띄우는 함수이다.
DWORD WINAPI ShowMessage(LPVOID lParam)
{
MessageBox(NULL, TEXT("IAT Hooking Success"), TEXT("Live Your IT"), MB_OK);
return 0;
}
DWORD WINAPI IATHooking(LPVOID lParam)
{
PBYTE hMod, TargetAddr, HookingAddr;
DWORD OldProtect = 0;
PCSTR IIDName;
// 현재 프로세스의 핸들값 얻어오기
hMod = GetModuleHandle(NULL);
// 후킹할 API의 주소값 얻어오기
//TargetAddr = GetProcAddress(GetModuleHandle(TEXT("win32u.dll")), "NtUserSetCapture");
//printf("%x\n\n", GetModuleHandle(TEXT("win32u.dll")));
// IMPORT Directory Table (IMAGE_IMPORT_DESCRIPTOR) 접근
PIMAGE_DOS_HEADER idh = hMod;
PIMAGE_OPTIONAL_HEADER ioh = hMod + (idh->e_lfanew) + 24;
PIMAGE_IMPORT_DESCRIPTOR iid = hMod + ioh->DataDirectory[1].VirtualAddress;
PIMAGE_THUNK_DATA32 AddrTable; // IAT 파싱 구조체
PIMAGE_THUNK_DATA32 NameTable; // INT 파싱 구조체
for (; iid->Name; iid++)
{
IIDName = (PCSTR)(hMod + iid->Name);
// IID에서 후킹할 API의 DLL과 일치하는 DLL 찾기
if (!(_stricmp(IIDName, (PCSTR)"USER32.dll")))
{
MessageBox(NULL, TEXT("Found USER32.dll in Import Directory Table"), TEXT("Live Your IT"), MB_OK);
AddrTable = hMod + iid->FirstThunk;
NameTable = hMod + iid->OriginalFirstThunk;
for (; AddrTable->u1.Function; AddrTable++)
{
PIMAGE_IMPORT_BY_NAME iibn = hMod + (NameTable->u1.AddressOfData);
//printf("\%s\n", (char*)iibn->Name); // (char *)필요함
// INT에서 후킹할 API의 이름과 일치하는지 확인
// if(TargetAddr == AddrTable->u1.Function) 로 해도됨
if (!_stricmp((char*)iibn->Name, "SetCapture"))
{
//HookingAddr = (PBYTE)AddrTable->u1.Function;
//VirtualProtect(&HookingAddr, 4, PAGE_READWRITE, &OldProtect);
MessageBox(NULL, TEXT("Found SetCapture IAT Address"), TEXT("Live Your IT"), MB_OK);
// WIRTE 권한 추가
VirtualProtect(&(AddrTable->u1.Function), 4, PAGE_READWRITE, &OldProtect);
// IAT 후킹 수행
AddrTable->u1.Function = (DWORD)ShowMessage;
// 페이지 권한 복구
VirtualProtect(&(AddrTable->u1.Function), 4, OldProtect, &OldProtect);
}
NameTable++;
}
}
}
return 0;
}
참고로 WinDbg로 지뢰찾기에 붙어서 실제 IAT를 봐보면, 0x10010e4가 SetCapture API 주소값 0x761e5890이 저장되어 있는 IAT 위치이고 VirtualProtect로 WRITE 권한을 추가하기 전이기 때문에 페이지 권한이 PAGE_EXECUTE_READ인 것을 볼 수 있다.
그리고 IAT 후킹 후에는 아래와 같이 SetCapture 함수가 저장되어 있던 위치에 MessageBoxW를 호출하는 함수 0x5391000이 저장되어 있는 것을 볼 수 있다.
DLL 인젝션을 활용한 IAT 후킹 결과
SetCapture 함수 주소가 저장되어야 할 IAT 위치에 ShowMessage 함수주소가 저장되어있기 때문에 마우스 클릭 이벤트를 발생시키면, 아래와 같이 IAT 후킹 결과가 성공했음을 메시지창으로 확인할 수 있다.
'리버싱 > 리버싱' 카테고리의 다른 글
C++ 리버싱을 위한 vtable 분석 (2) | 2020.03.27 |
---|---|
[크래쉬 분석] Access violation - code c0000005 (오디오편집 프로그램) (0) | 2020.03.25 |
DLL 인젝션을 통한 지뢰찾기 API 후킹 (Hooking) 구현 (4) | 2020.03.22 |
DLL 인젝션을 통한 지뢰찾기 코드 후킹 (Code Hooking) 구현 (2) | 2020.03.21 |
CreateRemoteThread를 사용한 DLL 인젝션 구현 (10) | 2020.03.18 |