본문 바로가기

High Level Technique/Reversing

API Hooking - IAT Hooking

API Hooking - IAT Hooking


Windows의 계산기에 DLL 파일을 삽입하여 IAT의 user32.SetWindowsTextW() API를 후킹하는 것을 해보도록 하겠습니다.


PEViewer를 이용하여 IAT를 확인합니다. 대부분 많이 사용되는 PEView 프로그램은 64bit를 지원하지 않기 때문에 64비트 프로그램을 분석할 수가 없습니다.

그래서 64비트를 지원하는 PEBrowse를 이용합니다.



PEBrowseV10_1_5.zip



PEView 프로그램을 이용해서 IAT를 확인해 보면 windows 10의 계산기 프로그램에서는 SetWindowTextW() API가 나타나지 않았습니다.

그래서 혹시나 해서 디버거를 이용해서 확인해보니 user32.dll이 로딩이 되었고, SetWindowTextW가 존재했습니다.



SetwindowTextW에 BreakPoint를 걸고 실행을 시켰는데, 디버거는 종료가되고 계산기는 실행이 되었습니다.


그래서 계산기를 켜두고 Attach를 이용해서 확인해 보았는데, system32의 calc.exe와 다른 주소인 WindowsApp에서 실행되었습니다.


Attach를 한 상태에서 SetWindowTextW에 BreakPoint를 걸고 실행시켜보았지만 이 또한 해당 주소에 멈추지 않았습니다.



좀 더 분석을 해봤는데, CreateString 이라는 함수가 존재했고 해당 영역에 BreakPoint를 걸고 분석을 했는데, 값이 나타나긴 했습니다.

해당 값을 한글로 변경을 시도했지만 되지 않았고, DisplayValue라는 곳을 찾기도 했지만 정확한 위치를 찾지는 못했습니다.











그래서 일단 Windows 7에서 시도해 보겠습니다.


Windows 7 calc.exe 프로그램에 USER32.dll에 SetwindowsTextW가 존재합니다. 해당 부분에 BreakPoint를 걸어두고 분석을 해보겠습니다.




위 사진처럼 SetWindowTextW에 BreakPoint가 걸려있고, 오른쪽 하단을 확인해 보면 Text = "4"라고 나타나 있습니다. (제가 입력한 값이 4입니다.)


이걸 한글 "사"로 바꿔 보도록 하겠습니다. 유니코드로 0xC0AC 입니다.



한글로 4가 출력된 것을 볼 수 있습니다.





hookiat.dll 만들기




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
 
typedef BOOL (WINAPI *PFSETWINDOWTEXTW)(HWND hWnd, LPWSTR lpString);
 
FARPROC g_pOrgFunc = NULL;
 
// SetWindowTextW Hooking
BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString)
{
    wchar_t* pNum = L"영일이삼사오육칠팔구";
    wchar_t temp[2= {0,};
    int i = 0, nLen = 0, nIndex = 0;
 
    nLen = wcslen(lpString);
    for(i = 0; i < nLen; i++)
    {
        // 숫자를 한글로 변환
        //   lpString 은 wide-character (2 byte) 문자열
        if( L'0' <= lpString[i] && lpString[i] <= L'9' )
        {
            temp[0= lpString[i];
            nIndex = _wtoi(temp);
            lpString[i] = pNum[nIndex];
        }
    }
 
    // user32!SetWindowTextW() API 호출
    //   (위에서 lpString 버퍼 내용을 변경하였음)
    return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);
}
 
BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew)
{
    HMODULE hMod;
    LPCSTR szLibName;
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc; 
    PIMAGE_THUNK_DATA pThunk;
    DWORD dwOldProtect, dwRVA;
    PBYTE pAddr;
 
    hMod = GetModuleHandle(NULL); // ImageBase
    pAddr = (PBYTE)hMod; // ImageBase
 
    pAddr += *((DWORD*)&pAddr[0x3C]); // PE Signature
 
    dwRVA = *((DWORD*)&pAddr[0x80]); //RVA to IMAGE_IMPORT_DESCRIPTOR Table
 
    pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod+dwRVA); // VA to IMAGE_IMPORT_DESCRIPTOR Table
 
    for( ; pImportDesc->Name; pImportDesc++ )
    {
        /*     Windows 7 x86 Ent Calc.exe IDT INFO
            VA            Data        Description
            1051BC4        51FC8        Import Name Table RVA
            1051BC8        FFFFFFFF    Time Data Stamp
            1051BCC        FFFFFFFF    Forwarder Chain
            1051BD0        51C8C        Name RVA
            1051BD4        12A8        Import Address Table RVA
        */
 
        // szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name
        szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name); // pImportDesc == 1051BD4
        if!_stricmp(szLibName, szDllName) )
        {
            // pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk
            //        = VA to IAT(Import Address Table)
            pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod + pImportDesc->FirstThunk);
 
            // pThunk->u1.Function = VA to API
            for( ; pThunk->u1.Function; pThunk++ )
            {
                if( pThunk->u1.Function == (DWORD)pfnOrg )
                {
                    // 메모리 속성을 E/R/W 로 변경
                    VirtualProtect((LPVOID)&pThunk->u1.Function, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect);
 
                    // IAT 값을 변경
                    pThunk->u1.Function = (DWORD)pfnNew;
                    
                    // 메모리 속성 복원
                    VirtualProtect((LPVOID)&pThunk->u1.Function, 4, dwOldProtect, &dwOldProtect);                        
 
                    return TRUE;
                }
            }
        }
    }
 
    return FALSE;
}
 
 
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH : 
            // user32.dll SetWindowTextW 주소를 가져와 g_pOrgFunc에 저장.
            // 계산기는 user32.dll이 로딩되있다는 것을 알기 때문에 GetProcAddress()를 바로 사용.
            // 만약 다른 프로그램을 후킹하는 경우 해당 DLL이 로딩되어있는지 확인해야 한다.
            // 후킹 직전까지 로딩되어 있지 않다면, LoadLibrary()를 이용하여 직접 로딩하면 된다.
               g_pOrgFunc = GetProcAddress(GetModuleHandle(L"user32.dll"), "SetWindowTextW");
 
            //   user32!SetWindowTextW() 를 hookiat!MySetWindowText() 로 후킹
            // SetWindowTextW()주소를 MySetWindowText()로 변경.
            hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW);
            break;
 
        case DLL_PROCESS_DETACH :
            // calc.exe 의 IAT 를 원래대로 복원
            // MySetWindowText() 주소를 원래 SetWindowTextW()로 변경.
            hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc);
            break;
    }
 
    return TRUE;
}
cs











다음에는 Windows 10에서 해보는 걸로... 출력해주는 API 부터 찾는게 우선..













'High Level Technique > Reversing' 카테고리의 다른 글

64비트에서 달라진 점  (0) 2016.07.26
API Hooking - API Code Patch, Global Hooking  (0) 2016.07.25
API Hooking - Debug Technique  (0) 2016.07.19
API Hooking  (0) 2016.07.19
Code Injection  (0) 2016.07.15