/*++ Copyright (c) 2000 Microsoft Corporation Module Name: Settlers3.cpp Abstract: The app has a protection system that sets the CPU direction flag and expects it to be maintained through calls to WaitForSingleObject, SetEvent and ResetEvent. We have to patch the import tables manually and pretend to be kernel32 so the protection system doesn't fail elsewhere. Notes: This is an app specific shim. History: 07/05/2001 linstev Created --*/ #include "precomp.h" #include "LegalStr.h" IMPLEMENT_SHIM_BEGIN(Settlers3) #include "ShimHookMacro.h" APIHOOK_ENUM_BEGIN APIHOOK_ENUM_END // // The real kernel32 handle // HINSTANCE g_hinstKernel; // Functions to hook imports BOOL HookImports(HMODULE hModule); // // List of hooks we'll be patching // FARPROC _GetProcAddress(HMODULE hModule, LPCSTR lpProcName); HINSTANCE _LoadLibraryA(LPCSTR lpLibFileName); HMODULE _GetModuleHandleA(LPCSTR lpModuleName); BOOL _ResetEvent(HANDLE hEvent); BOOL _SetEvent(HANDLE hEvent); DWORD _WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); struct AHOOK { LPSTR szName; PVOID pfnOld; PVOID pfnNew; }; AHOOK g_HookArray[] = { { "LoadLibraryA" , 0, _LoadLibraryA }, { "GetProcAddress" , 0, _GetProcAddress }, { "GetModuleHandleA" , 0, _GetModuleHandleA }, { "ResetEvent" , 0, _ResetEvent }, { "SetEvent" , 0, _SetEvent }, { "WaitForSingleObject" , 0, _WaitForSingleObject } }; DWORD g_dwHookCount = sizeof(g_HookArray) / sizeof(AHOOK); /*++ Hooks section: each designed to spoof the app into thinking this shim is kernel32.dll. --*/ HINSTANCE _LoadLibraryA( LPCSTR lpLibFileName ) { if (lpLibFileName && stristr(lpLibFileName, "kernel32")) { return g_hinstDll; } else { HINSTANCE hRet = LoadLibraryA(lpLibFileName); HookImports(GetModuleHandleW(0)); return hRet; } } FARPROC _GetProcAddress( HMODULE hModule, LPCSTR lpProcName ) { if (hModule == g_hinstDll) { hModule = g_hinstKernel; } FARPROC lpRet = GetProcAddress(hModule, lpProcName); // // Run the list of our hooks to see if we need to spoof them // if (lpRet) { for (UINT i=0; ie_lfanew); dwImportTableOffset = pINTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; if (dwImportTableOffset == 0) { // // No import table found. This is probably ntdll.dll // return TRUE; } pIID = (PIMAGE_IMPORT_DESCRIPTOR)(pDllBase + dwImportTableOffset); // // Loop through the import table and search for the APIs that we want to patch // while (TRUE) { LPSTR pszImportEntryModule; PIMAGE_THUNK_DATA pITDA; // // Return if no first thunk (terminating condition). // if (pIID->FirstThunk == 0) { break; } pszImportEntryModule = (LPSTR)(pDllBase + pIID->Name); // // We have APIs to hook for this module! // pITDA = (PIMAGE_THUNK_DATA)(pDllBase + (DWORD)pIID->FirstThunk); while (TRUE) { SIZE_T dwFuncAddr; AHOOK *pHook = NULL; pfnOld = (PVOID)pITDA->u1.Function; // // Done with all the imports from this module? (terminating condition) // if (pITDA->u1.Ordinal == 0) { break; } for (i=0; iu1.Function; status = VirtualProtect((PVOID)dwFuncAddr, dwProtectSize, PAGE_READWRITE, &dwOldProtect); if (NT_SUCCESS(status)) { pITDA->u1.Function = (SIZE_T)pHook->pfnNew; dwProtectSize = sizeof(DWORD); status = VirtualProtect((PVOID)dwFuncAddr, dwProtectSize, dwOldProtect, &dwOldProtect2); if (!NT_SUCCESS(status)) { DPFN(eDbgLevelError, "[HookImports] Failed to change back the protection"); } } else { DPFN(eDbgLevelError, "[HookImports] Failed 0x%X to change protection to PAGE_READWRITE." " Addr 0x%p\n", status, &pITDA->u1.Function); } pITDA++; } pIID++; } return TRUE; } /*++ Register hooked functions --*/ BOOL NOTIFY_FUNCTION( DWORD fdwReason ) { if (fdwReason == DLL_PROCESS_ATTACH) { // // Patch all the import tables of everyone with this module // g_hinstKernel = GetModuleHandleW(L"kernel32"); for (UINT i=0; i