mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
611 lines
13 KiB
611 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
hookproc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains hooker management code for the Winsock 2 to
|
|
Winsock 1.1 Mapper Service Provider.
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 29-May-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
PHOOKER_INFORMATION
|
|
SockFindAndReferenceHooker(
|
|
IN LPGUID ProviderId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine maps the given provider GUID to the corresponding
|
|
HOOKER_INFORMATION structure. If the specified hooker has already
|
|
been loaded (and therefore has an entry in the global list) its
|
|
structure pointer is simply returned. Otherwise, an attempt is made
|
|
to load the necessary information from the registry.
|
|
|
|
Arguments:
|
|
|
|
ProviderId - A pointer to the GUID identifying a hooker.
|
|
|
|
Return Value:
|
|
|
|
PHOOKER_INFORMATION - Pointer to the hooker structure if successful,
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PLIST_ENTRY listEntry;
|
|
PHOOKER_INFORMATION hookerInfo;
|
|
RPC_STATUS status;
|
|
UCHAR * str;
|
|
LONG err;
|
|
DWORD type;
|
|
DWORD length;
|
|
HINSTANCE dllHandle;
|
|
CHAR dllPath[MAX_PATH];
|
|
CHAR expandedDllPath[MAX_PATH];
|
|
WSADATA wsaData;
|
|
INT result;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
SOCK_ASSERT( ProviderId != NULL );
|
|
|
|
//
|
|
// Setup locals so we know how to cleanup on exit.
|
|
//
|
|
|
|
str = NULL;
|
|
dllHandle = NULL;
|
|
|
|
//
|
|
// Scan the in-memory hooker list.
|
|
//
|
|
|
|
SockAcquireGlobalLock();
|
|
|
|
for( listEntry = SockHookerListHead.Flink ;
|
|
listEntry != &SockHookerListHead ;
|
|
listEntry = listEntry->Flink ) {
|
|
|
|
hookerInfo = CONTAINING_RECORD(
|
|
listEntry,
|
|
HOOKER_INFORMATION,
|
|
HookerListEntry
|
|
);
|
|
|
|
if( GUIDS_ARE_EQUAL( ProviderId, &hookerInfo->ProviderId ) ) {
|
|
|
|
if( hookerInfo->Initialized ) {
|
|
|
|
hookerInfo->ReferenceCount++;
|
|
|
|
} else {
|
|
|
|
hookerInfo = NULL;
|
|
|
|
}
|
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Not found in memory, try to load it from the registry.
|
|
//
|
|
|
|
//
|
|
// Prepare for early exit.
|
|
//
|
|
|
|
hookerInfo = NULL;
|
|
|
|
//
|
|
// Open the registry key if not already open.
|
|
//
|
|
|
|
if( SockHookerRegistryKey == NULL ) {
|
|
|
|
err = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
SOCK_HOOKER_GUID_MAPPER_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&SockHookerRegistryKey
|
|
);
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SOCK_PRINT((
|
|
"SockFindAndReferenceHooker: cannot open %s, error %ld\n",
|
|
SOCK_HOOKER_GUID_MAPPER_KEY,
|
|
err
|
|
));
|
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Map the GUID to a string.
|
|
//
|
|
|
|
status = UuidToString( ProviderId, &str );
|
|
|
|
if( status != RPC_S_OK ) {
|
|
|
|
SOCK_PRINT((
|
|
"SockFindAndReferenceHooker: cannot map GUID to string, error %d\n",
|
|
status
|
|
));
|
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
//
|
|
// Try to load the DLL path from the registry.
|
|
//
|
|
|
|
length = sizeof(dllPath);
|
|
|
|
err = RegQueryValueEx(
|
|
SockHookerRegistryKey,
|
|
str,
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)dllPath,
|
|
&length
|
|
);
|
|
|
|
if( err != NO_ERROR ) {
|
|
|
|
SOCK_PRINT((
|
|
"SockFindAndReferenceHooker: cannot query %s, error %ld\n",
|
|
str,
|
|
err
|
|
));
|
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
//
|
|
// Expand any embedded environment strings.
|
|
//
|
|
|
|
length = ExpandEnvironmentStrings(
|
|
dllPath,
|
|
expandedDllPath,
|
|
sizeof(expandedDllPath)
|
|
);
|
|
|
|
if( length == 0 ) {
|
|
|
|
err = GetLastError();
|
|
|
|
SOCK_PRINT((
|
|
"SockFindAndReferenceHooker: cannot expand %s, error %ld\n",
|
|
dllPath,
|
|
err
|
|
));
|
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
//
|
|
// Load the DLL.
|
|
//
|
|
|
|
dllHandle = LoadLibrary( expandedDllPath );
|
|
|
|
if( dllHandle == NULL ) {
|
|
|
|
err = GetLastError();
|
|
|
|
SOCK_PRINT((
|
|
"SockFindAndReferenceHooker: cannot load %s, error %ld\n",
|
|
expandedDllPath,
|
|
err
|
|
));
|
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate a new hooker.
|
|
//
|
|
|
|
hookerInfo = SOCK_ALLOCATE_HEAP( sizeof(*hookerInfo) );
|
|
|
|
if( hookerInfo == NULL ) {
|
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
ZeroMemory(
|
|
hookerInfo,
|
|
sizeof(*hookerInfo)
|
|
);
|
|
|
|
//
|
|
// Find the entrypoints.
|
|
//
|
|
|
|
hookerInfo->accept = (PVOID)GetProcAddress( dllHandle, "accept" );
|
|
hookerInfo->bind = (PVOID)GetProcAddress( dllHandle, "bind" );
|
|
hookerInfo->closesocket = (PVOID)GetProcAddress( dllHandle, "closesocket" );
|
|
hookerInfo->connect = (PVOID)GetProcAddress( dllHandle, "connect" );
|
|
hookerInfo->ioctlsocket = (PVOID)GetProcAddress( dllHandle, "ioctlsocket" );
|
|
hookerInfo->getpeername = (PVOID)GetProcAddress( dllHandle, "getpeername" );
|
|
hookerInfo->getsockname = (PVOID)GetProcAddress( dllHandle, "getsockname" );
|
|
hookerInfo->getsockopt = (PVOID)GetProcAddress( dllHandle, "getsockopt" );
|
|
hookerInfo->listen = (PVOID)GetProcAddress( dllHandle, "listen" );
|
|
hookerInfo->recv = (PVOID)GetProcAddress( dllHandle, "recv" );
|
|
hookerInfo->recvfrom = (PVOID)GetProcAddress( dllHandle, "recvfrom" );
|
|
hookerInfo->select = (PVOID)GetProcAddress( dllHandle, "select" );
|
|
hookerInfo->send = (PVOID)GetProcAddress( dllHandle, "send" );
|
|
hookerInfo->sendto = (PVOID)GetProcAddress( dllHandle, "sendto" );
|
|
hookerInfo->setsockopt = (PVOID)GetProcAddress( dllHandle, "setsockopt" );
|
|
hookerInfo->shutdown = (PVOID)GetProcAddress( dllHandle, "shutdown" );
|
|
hookerInfo->socket = (PVOID)GetProcAddress( dllHandle, "socket" );
|
|
hookerInfo->WSAStartup = (PVOID)GetProcAddress( dllHandle, "WSAStartup" );
|
|
hookerInfo->WSACleanup = (PVOID)GetProcAddress( dllHandle, "WSACleanup" );
|
|
hookerInfo->WSAGetLastError = (PVOID)GetProcAddress( dllHandle, "WSAGetLastError" );
|
|
hookerInfo->WSAIsBlocking = (PVOID)GetProcAddress( dllHandle, "WSAIsBlocking" );
|
|
hookerInfo->WSAUnhookBlockingHook = (PVOID)GetProcAddress( dllHandle, "WSAUnhookBlockingHook" );
|
|
hookerInfo->WSASetBlockingHook = (PVOID)GetProcAddress( dllHandle, "WSASetBlockingHook" );
|
|
hookerInfo->WSACancelBlockingCall = (PVOID)GetProcAddress( dllHandle, "WSACancelBlockingCall" );
|
|
hookerInfo->WSAAsyncSelect = (PVOID)GetProcAddress( dllHandle, "WSAAsyncSelect" );
|
|
|
|
hookerInfo->gethostname = (PVOID)GetProcAddress( dllHandle, "gethostname" );
|
|
hookerInfo->gethostbyname = (PVOID)GetProcAddress( dllHandle, "gethostbyname" );
|
|
hookerInfo->gethostbyaddr = (PVOID)GetProcAddress( dllHandle, "gethostbyaddr" );
|
|
hookerInfo->getservbyname = (PVOID)GetProcAddress( dllHandle, "getservbyname" );
|
|
hookerInfo->getservbyport = (PVOID)GetProcAddress( dllHandle, "getservbyport" );
|
|
|
|
if( hookerInfo->accept == NULL ||
|
|
hookerInfo->bind == NULL ||
|
|
hookerInfo->closesocket == NULL ||
|
|
hookerInfo->connect == NULL ||
|
|
hookerInfo->ioctlsocket == NULL ||
|
|
hookerInfo->getpeername == NULL ||
|
|
hookerInfo->getsockname == NULL ||
|
|
hookerInfo->getsockopt == NULL ||
|
|
hookerInfo->listen == NULL ||
|
|
hookerInfo->recv == NULL ||
|
|
hookerInfo->recvfrom == NULL ||
|
|
hookerInfo->select == NULL ||
|
|
hookerInfo->send == NULL ||
|
|
hookerInfo->sendto == NULL ||
|
|
hookerInfo->setsockopt == NULL ||
|
|
hookerInfo->shutdown == NULL ||
|
|
hookerInfo->socket == NULL ||
|
|
hookerInfo->WSAStartup == NULL ||
|
|
hookerInfo->WSACleanup == NULL ||
|
|
hookerInfo->WSAGetLastError == NULL ||
|
|
hookerInfo->WSAIsBlocking == NULL ||
|
|
hookerInfo->WSAUnhookBlockingHook == NULL ||
|
|
hookerInfo->WSASetBlockingHook == NULL ||
|
|
hookerInfo->WSACancelBlockingCall == NULL ||
|
|
hookerInfo->WSAAsyncSelect == NULL ||
|
|
hookerInfo->gethostname == NULL ||
|
|
hookerInfo->gethostbyname == NULL ||
|
|
hookerInfo->gethostbyaddr == NULL ||
|
|
hookerInfo->getservbyname == NULL ||
|
|
hookerInfo->getservbyname == NULL
|
|
) {
|
|
|
|
SOCK_PRINT((
|
|
"SockFindAndReferenceHooker: cannot find entrypoints in %s\n",
|
|
expandedDllPath
|
|
));
|
|
|
|
SOCK_FREE_HEAP( hookerInfo );
|
|
hookerInfo = NULL;
|
|
goto complete;
|
|
|
|
}
|
|
|
|
//
|
|
// Go ahead and put it on the global list, but with the "Initialized"
|
|
// flag set to FALSE. We don't set this to TRUE until after we've
|
|
// completed the hooker's WSAStartup().
|
|
//
|
|
|
|
hookerInfo->ProviderId = *ProviderId;
|
|
SOCK_ASSERT( !hookerInfo->Initialized );
|
|
|
|
InsertHeadList(
|
|
&SockHookerListHead,
|
|
&hookerInfo->HookerListEntry
|
|
);
|
|
|
|
//
|
|
// Initialize it.
|
|
//
|
|
// Note that the hooker starts out with a reference count of two;
|
|
// one for the "active" reference, and one for the reference added
|
|
// by this routine.
|
|
//
|
|
|
|
SockPreApiCallout();
|
|
|
|
result = hookerInfo->WSAStartup( 0x0101, &wsaData );
|
|
|
|
SockPostApiCallout();
|
|
|
|
if( result != NO_ERROR ) {
|
|
|
|
SOCK_PRINT((
|
|
"SockFindAndReferenceHooker: %s:WSAStartup() failed, error %d\n",
|
|
expandedDllPath,
|
|
result
|
|
));
|
|
|
|
RemoveEntryList(
|
|
&hookerInfo->HookerListEntry
|
|
);
|
|
|
|
SOCK_FREE_HEAP( hookerInfo );
|
|
hookerInfo = NULL;
|
|
goto complete;
|
|
|
|
}
|
|
|
|
//
|
|
// Finish initializing the hooker.
|
|
//
|
|
|
|
hookerInfo->DllHandle = dllHandle;
|
|
hookerInfo->ReferenceCount = 2;
|
|
hookerInfo->Initialized = TRUE;
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
IF_DEBUG(HOOKER) {
|
|
|
|
SOCK_PRINT((
|
|
"SockFindAndReferenceHooker: loaded %s [%s] @ %08lx\n",
|
|
str,
|
|
dllPath,
|
|
hookerInfo
|
|
));
|
|
|
|
}
|
|
|
|
complete:
|
|
|
|
SockReleaseGlobalLock();
|
|
|
|
if( str != NULL ) {
|
|
|
|
RpcStringFree( &str );
|
|
|
|
}
|
|
|
|
if( hookerInfo == NULL && dllHandle != NULL ) {
|
|
|
|
FreeLibrary( dllHandle );
|
|
|
|
}
|
|
|
|
return hookerInfo;
|
|
|
|
} // SockFindAndReferenceHooker
|
|
|
|
|
|
|
|
VOID
|
|
SockDereferenceHooker(
|
|
IN PHOOKER_INFORMATION HookerInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dereferences the given HOOKER_INFORMATION structure.
|
|
If the reference count drops to zero, all resources associated with
|
|
the structure are released.
|
|
|
|
Arguments:
|
|
|
|
HookerInfo - A pointer to the HOOKER_INFORMATION structure to
|
|
dereference.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
INT result;
|
|
INT err;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
SOCK_ASSERT( HookerInfo != NULL );
|
|
|
|
//
|
|
// Dereference the hooker, protected by a lock.
|
|
//
|
|
|
|
SockAcquireGlobalLock();
|
|
|
|
if( HookerInfo->ReferenceCount-- == 0 ) {
|
|
|
|
//
|
|
// Shut 'er down, Scotty.
|
|
//
|
|
|
|
result = HookerInfo->WSACleanup();
|
|
|
|
if( result == SOCKET_ERROR ) {
|
|
|
|
err = HookerInfo->WSAGetLastError();
|
|
|
|
SOCK_PRINT((
|
|
"SockDereferenceHooker: WSACleanup() failed, error %d\n",
|
|
err
|
|
));
|
|
|
|
//
|
|
// Press on regardless...
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Free the hooker's DLL.
|
|
//
|
|
|
|
FreeLibrary( HookerInfo->DllHandle );
|
|
|
|
//
|
|
// Remove the hooker from the global list.
|
|
//
|
|
|
|
RemoveEntryList( &HookerInfo->HookerListEntry );
|
|
|
|
//
|
|
// Free the hooker itself.
|
|
//
|
|
|
|
SOCK_FREE_HEAP( HookerInfo );
|
|
|
|
}
|
|
|
|
SockReleaseGlobalLock();
|
|
|
|
} // SockDereferenceHooker
|
|
|
|
|
|
|
|
VOID
|
|
SockReferenceHooker(
|
|
IN PHOOKER_INFORMATION HookerInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine references the given HOOKER_INFORMATION structure.
|
|
|
|
Arguments:
|
|
|
|
HookerInfo - A pointer to the HOOKER_INFORMATION structure to
|
|
reference.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
SOCK_ASSERT( HookerInfo != NULL );
|
|
|
|
//
|
|
// Reference the hooker, protected by a lock.
|
|
//
|
|
|
|
SockAcquireGlobalLock();
|
|
|
|
HookerInfo->ReferenceCount++;
|
|
SOCK_ASSERT( HookerInfo->ReferenceCount != 0 );
|
|
|
|
SockReleaseGlobalLock();
|
|
|
|
} // SockReferenceHooker
|
|
|
|
|
|
|
|
VOID
|
|
SockFreeAllHookers(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees all allocated HOOKER_INFORMATION structures
|
|
and closes the hooker registry key.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PLIST_ENTRY listEntry;
|
|
PHOOKER_INFORMATION hookerInfo;
|
|
|
|
//
|
|
// Scan the in-memory hooker list and free 'em.
|
|
//
|
|
|
|
SockAcquireGlobalLock();
|
|
|
|
for( listEntry = SockHookerListHead.Flink ;
|
|
listEntry != &SockHookerListHead ; ) {
|
|
|
|
hookerInfo = CONTAINING_RECORD(
|
|
listEntry,
|
|
HOOKER_INFORMATION,
|
|
HookerListEntry
|
|
);
|
|
|
|
//
|
|
// Dereference the hooker.
|
|
//
|
|
|
|
SockDereferenceHooker( hookerInfo );
|
|
|
|
}
|
|
|
|
//
|
|
// Close the registry key if necessary.
|
|
//
|
|
|
|
if( SockHookerRegistryKey != NULL ) {
|
|
|
|
RegCloseKey( SockHookerRegistryKey );
|
|
SockHookerRegistryKey = NULL;
|
|
|
|
}
|
|
|
|
SockReleaseGlobalLock();
|
|
|
|
} // SockFreeAllHookers
|
|
|