153 lines
3.5 KiB
C++
153 lines
3.5 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
SpecOps2.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
App does too much within a DLLMain and hangs because dinput is waiting on
|
||
|
a thread it just created.
|
||
|
|
||
|
The fix is to prevent the DllMain from running during the loader lock. The
|
||
|
only way to do this seems to be to hook an API that's called really early
|
||
|
during the DllMain and jump back to the loader.
|
||
|
|
||
|
The catch is that we still need to call the DllMain after the LoadLibrary
|
||
|
has completed.
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
This is an app specific shim.
|
||
|
|
||
|
History:
|
||
|
|
||
|
05/01/2001 linstev Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
IMPLEMENT_SHIM_BEGIN(SpecOps2)
|
||
|
#include "ShimHookMacro.h"
|
||
|
|
||
|
APIHOOK_ENUM_BEGIN
|
||
|
APIHOOK_ENUM_ENTRY(GetVersion)
|
||
|
APIHOOK_ENUM_ENTRY(LoadLibraryA)
|
||
|
APIHOOK_ENUM_END
|
||
|
|
||
|
// Global state used to determine what to do for a particular call
|
||
|
BOOL g_bState = FALSE;
|
||
|
|
||
|
// The thread handle for matching synchronization logic
|
||
|
HANDLE g_hThread = NULL;
|
||
|
|
||
|
/*++
|
||
|
|
||
|
This is the first API that the DllMain calls, so we're going to back out
|
||
|
jump straight out of it, back into loader code as if it completed normally.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
__declspec(naked)
|
||
|
DWORD
|
||
|
APIHOOK(GetVersion)(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
__asm {
|
||
|
//
|
||
|
// Make sure we're on the right thread so we don't have to synchronize
|
||
|
//
|
||
|
call dword ptr [GetCurrentThread]
|
||
|
cmp eax, g_hThread
|
||
|
jne Exit
|
||
|
|
||
|
// test for the right dll
|
||
|
cmp g_bState, 1
|
||
|
jne Exit
|
||
|
|
||
|
// we're done
|
||
|
mov g_bState, 0
|
||
|
|
||
|
// leave the stack and registers as they were before
|
||
|
add esp, 20
|
||
|
pop edi
|
||
|
pop esi
|
||
|
pop ebx
|
||
|
pop ebp
|
||
|
ret 12
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
// original api
|
||
|
call dword ptr [GetVersion]
|
||
|
ret
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
When "SO Menu.dll" is loaded, we start the sequence which prevents the DllMain
|
||
|
from crashing, but it means we have to run the entry point after the load.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
HINSTANCE
|
||
|
APIHOOK(LoadLibraryA)(
|
||
|
LPCSTR lpLibFileName
|
||
|
)
|
||
|
{
|
||
|
BOOL bCheck = FALSE;
|
||
|
if (_stricmp(lpLibFileName, "menu\\SO Menu.dll") == 0) {
|
||
|
//
|
||
|
// We assume *only* the main thread tries to load this library, so
|
||
|
// we don't synchronize multiple threads trying to load this same dll
|
||
|
//
|
||
|
g_hThread = GetCurrentThread();
|
||
|
bCheck = TRUE;
|
||
|
g_bState = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load the library, if it's "SO Menu", we'll catch the GetVersion called
|
||
|
// by its DllMain
|
||
|
//
|
||
|
|
||
|
HMODULE hMod = ORIGINAL_API(LoadLibraryA)(lpLibFileName);
|
||
|
|
||
|
if (hMod && bCheck) {
|
||
|
//
|
||
|
// Run the DllMain
|
||
|
//
|
||
|
typedef BOOL (WINAPI *_pfn_DllMain)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
|
||
|
|
||
|
PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER) hMod;
|
||
|
PIMAGE_NT_HEADERS pINTH = (PIMAGE_NT_HEADERS)((LPBYTE)hMod + pIDH->e_lfanew);
|
||
|
_pfn_DllMain pfnMain = (_pfn_DllMain)((LPBYTE)hMod + pINTH->OptionalHeader.AddressOfEntryPoint);
|
||
|
|
||
|
// Call the startup routine
|
||
|
(*pfnMain)(hMod, DLL_PROCESS_ATTACH, NULL);
|
||
|
}
|
||
|
|
||
|
return hMod;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Register hooked functions
|
||
|
|
||
|
--*/
|
||
|
|
||
|
HOOK_BEGIN
|
||
|
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, GetVersion)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, LoadLibraryA)
|
||
|
|
||
|
HOOK_END
|
||
|
|
||
|
IMPLEMENT_SHIM_END
|
||
|
|