Subversion Repositories spk

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
11 cycrow 1
/*--------------------------------------------------------------------------------------------------------
2
    APIHIJACK.CPP - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000.
3
    http://msdn.microsoft.com/library/periodic/period00/hood0200.htm
4
    Adapted by Wade Brainerd, wadeb@wadeb.com
5
--------------------------------------------------------------------------------------------------------*/
6
#define WIN32_LEAN_AND_MEAN
7
#include <windows.h>
8
#include <stdio.h>
9
#include "apihijack.h"
10
 
11
//===========================================================================
12
// Called from the DLPD_IAT_STUB stubs.  Increments "count" field of the stub
13
 
14
void __cdecl DefaultHook( PVOID dummy )
15
{
16
    __asm   pushad  // Save all general purpose registers
17
 
18
    // Get return address, then subtract 5 (size of a CALL X instruction)
19
    // The result points at a DLPD_IAT_STUB
20
 
21
    // pointer math!  &dummy-1 really subtracts sizeof(PVOID)
22
    PDWORD pRetAddr = (PDWORD)(&dummy - 1);
23
 
24
    DLPD_IAT_STUB * pDLPDStub = (DLPD_IAT_STUB *)(*pRetAddr - 5);
25
 
26
    pDLPDStub->count++;
27
 
28
    #if 0
29
    // Remove the above conditional to get a cheezy API trace from
30
    // the loader process.  It's slow!
31
    if ( !IMAGE_SNAP_BY_ORDINAL( pDLPDStub->pszNameOrOrdinal) )
32
    {
33
        OutputDebugString( "Called hooked function: " );
34
        OutputDebugString( (PSTR)pDLPDStub->pszNameOrOrdinal );
35
        OutputDebugString( "\n" );
36
    }
37
    #endif
38
 
39
    __asm   popad   // Restore all general purpose registers
40
}
41
 
42
// This function must be __cdecl!!!
43
void __cdecl DelayLoadProfileDLL_UpdateCount( PVOID dummy );
44
 
45
PIMAGE_IMPORT_DESCRIPTOR g_pFirstImportDesc;
46
 
47
//===========================================================================
48
// Given an HMODULE, returns a pointer to the PE header
49
 
50
PIMAGE_NT_HEADERS PEHeaderFromHModule(HMODULE hModule)
51
{
52
    PIMAGE_NT_HEADERS pNTHeader = 0;
53
 
54
    __try
55
    {
56
        if ( PIMAGE_DOS_HEADER(hModule)->e_magic != IMAGE_DOS_SIGNATURE )
57
            __leave;
58
 
59
        pNTHeader = PIMAGE_NT_HEADERS(PBYTE(hModule)
60
                    + PIMAGE_DOS_HEADER(hModule)->e_lfanew);
61
 
62
        if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
63
            pNTHeader = 0;
64
    }
65
    __except( EXCEPTION_EXECUTE_HANDLER )
66
    {       
67
    }
68
 
69
    return pNTHeader;
70
}
71
 
72
//===========================================================================
73
// Builds stubs for and redirects the IAT for one DLL (pImportDesc)
74
 
75
bool RedirectIAT( SDLLHook* DLLHook, PIMAGE_IMPORT_DESCRIPTOR pImportDesc, PVOID pBaseLoadAddr )
76
{
77
    PIMAGE_THUNK_DATA pIAT;     // Ptr to import address table
78
    PIMAGE_THUNK_DATA pINT;     // Ptr to import names table
79
    PIMAGE_THUNK_DATA pIteratingIAT;
80
 
81
    // Figure out which OS platform we're on
82
    OSVERSIONINFO osvi; 
83
    osvi.dwOSVersionInfoSize = sizeof(osvi);
84
    GetVersionEx( &osvi );
85
 
86
    // If no import names table, we can't redirect this, so bail
87
    if ( pImportDesc->OriginalFirstThunk == 0 )
88
        return false;
89
 
90
    pIAT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->FirstThunk );
91
    pINT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->OriginalFirstThunk );
92
 
93
    // Count how many entries there are in this IAT.  Array is 0 terminated
94
    pIteratingIAT = pIAT;
95
    unsigned cFuncs = 0;
96
    while ( pIteratingIAT->u1.Function )
97
    {
98
        cFuncs++;
99
        pIteratingIAT++;
100
    }
101
 
102
    if ( cFuncs == 0 )  // If no imported functions, we're done!
103
        return false;
104
 
105
    // These next few lines ensure that we'll be able to modify the IAT,
106
    // which is often in a read-only section in the EXE.
107
    DWORD flOldProtect, flNewProtect, flDontCare;
108
    MEMORY_BASIC_INFORMATION mbi;
109
 
110
    // Get the current protection attributes                            
111
    VirtualQuery( pIAT, &mbi, sizeof(mbi) );
112
 
113
    // remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag
114
    flNewProtect = mbi.Protect;
115
    flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ);
116
    flNewProtect |= (PAGE_READWRITE);
117
 
118
    if ( !VirtualProtect(   pIAT, sizeof(PVOID) * cFuncs,
119
                            flNewProtect, &flOldProtect) )
120
    {
121
        return false;
122
    }
123
 
124
    // If the Default hook is enabled, build an array of redirection stubs in the processes memory.
125
    DLPD_IAT_STUB * pStubs = 0;
126
    if ( DLLHook->UseDefault )
127
    {
128
        // Allocate memory for the redirection stubs.  Make one extra stub at the
129
        // end to be a sentinel
130
        pStubs = new DLPD_IAT_STUB[ cFuncs + 1];
131
        if ( !pStubs )
132
            return false;
133
    }
134
 
135
    // Scan through the IAT, completing the stubs and redirecting the IAT
136
    // entries to point to the stubs
137
    pIteratingIAT = pIAT;
138
 
139
    while ( pIteratingIAT->u1.Function )
140
    {
141
        void* HookFn = 0;  // Set to either the SFunctionHook or pStubs.
142
 
143
        if ( !IMAGE_SNAP_BY_ORDINAL( pINT->u1.Ordinal ) )  // import by name
144
        {
145
            PIMAGE_IMPORT_BY_NAME pImportName = MakePtr( PIMAGE_IMPORT_BY_NAME, pBaseLoadAddr, pINT->u1.AddressOfData );
146
 
147
            // Iterate through the hook functions, searching for this import.
148
            SFunctionHook* FHook = DLLHook->Functions;
149
            while ( FHook->Name )
150
            {
151
                if ( lstrcmpi( FHook->Name, (char*)pImportName->Name ) == 0 )
152
                {
153
                    OutputDebugString( "Hooked function: " );
154
                    OutputDebugString( (char*)pImportName->Name );
155
                    OutputDebugString( "\n" );
156
 
157
                    // Save the old function in the SFunctionHook structure and get the new one.
158
                    FHook->OrigFn = reinterpret_cast<void*>(pIteratingIAT->u1.Function);
159
                    HookFn = FHook->HookFn;
160
                    break;
161
                }
162
 
163
                FHook++;
164
            }
165
 
166
            // If the default function is enabled, store the name for the user.
167
            if ( DLLHook->UseDefault )
168
                pStubs->pszNameOrOrdinal = (DWORD)&pImportName->Name;
169
        }
170
        else
171
        {
172
            // If the default function is enabled, store the ordinal for the user.
173
            if ( DLLHook->UseDefault )
174
                pStubs->pszNameOrOrdinal = pINT->u1.Ordinal;
175
        }
176
 
177
        // If the default function is enabled, fill in the fields to the stub code.
178
        if ( DLLHook->UseDefault )
179
        {
180
            pStubs->data_call = (DWORD)(PDWORD)DLLHook->DefaultFn
181
                                - (DWORD)(PDWORD)&pStubs->instr_JMP;
182
            pStubs->data_JMP = *(PDWORD)pIteratingIAT - (DWORD)(PDWORD)&pStubs->count;
183
 
184
            // If it wasn't manually hooked, use the Stub function.
185
            if ( !HookFn )
186
                HookFn = (void*)pStubs;
187
        }
188
 
189
        // Replace the IAT function pointer if we have a hook.
190
        if ( HookFn )
191
        {
192
            // Cheez-o hack to see if what we're importing is code or data.
193
            // If it's code, we shouldn't be able to write to it
194
            if ( IsBadWritePtr( (PVOID)pIteratingIAT->u1.Function, 1 ) )
195
            {
196
                pIteratingIAT->u1.Function = reinterpret_cast<DWORD>(HookFn);
197
            }
198
            else if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
199
            {
200
                // Special hack for Win9X, which builds stubs for imported
201
                // functions in system DLLs (Loaded above 2GB).  These stubs are
202
                // writeable, so we have to explicitly check for this case
203
                if ( pIteratingIAT->u1.Function > 0x80000000 )
204
                    pIteratingIAT->u1.Function = reinterpret_cast<DWORD>(HookFn);
205
            }
206
        }
207
 
208
        if ( DLLHook->UseDefault )
209
            pStubs++;           // Advance to next stub
210
 
211
        pIteratingIAT++;    // Advance to next IAT entry
212
        pINT++;             // Advance to next INT entry
213
    }
214
 
215
    if ( DLLHook->UseDefault )
216
        pStubs->pszNameOrOrdinal = 0;   // Final stub is a sentinel
217
 
218
    // Put the page attributes back the way they were.
219
    VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flOldProtect, &flDontCare);
220
 
221
    return true;
222
}
223
 
224
//===========================================================================
225
// Top level routine to find the EXE's imports, and redirect them
226
bool HookAPICalls( SDLLHook* Hook )
227
{
228
    if ( !Hook )
229
        return false;
230
 
231
    HMODULE hModEXE = GetModuleHandle( 0 );
232
 
233
    PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule( hModEXE );
234
 
235
    if ( !pExeNTHdr )
236
        return false;
237
 
238
    DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
239
                        [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
240
    if ( !importRVA )
241
        return false;
242
 
243
    // Convert imports RVA to a usable pointer
244
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr( PIMAGE_IMPORT_DESCRIPTOR,
245
                                                    hModEXE, importRVA );
246
 
247
    // Save off imports address in a global for later use
248
    g_pFirstImportDesc = pImportDesc;   
249
 
250
    // Iterate through each import descriptor, and redirect if appropriate
251
    while ( pImportDesc->FirstThunk )
252
    {
253
        PSTR pszImportModuleName = MakePtr( PSTR, hModEXE, pImportDesc->Name);
254
 
255
        if ( lstrcmpi( pszImportModuleName, Hook->Name ) == 0 )
256
        {
257
            OutputDebugString( "Found " );
258
            OutputDebugString( Hook->Name );
259
            OutputDebugString( "...\n" );
260
 
261
            RedirectIAT( Hook, pImportDesc, (PVOID)hModEXE );
262
        }
263
 
264
        pImportDesc++;  // Advance to next import descriptor
265
    }
266
 
267
    return true;
268
}
269