1004 lines
26 KiB
C++
1004 lines
26 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
EmulateMissingEXE.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Win9x had scandskw.exe and defrag.exe in %windir%, NT does not.
|
||
|
Whistler has a hack in the shell32 for scandisk for app compatability
|
||
|
purposes. Whistler can also invoke defrag via
|
||
|
"%windir%\system32\mmc.exe %windir%\system32\dfrg.msc".
|
||
|
|
||
|
This shim redirects CreateProcess and Winexec to execute these two
|
||
|
substitutes, as well as FindFile to indicate their presence.
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
This is a general purpose shim.
|
||
|
|
||
|
History:
|
||
|
|
||
|
01/02/2001 prashkud Created
|
||
|
02/18/2001 prashkud Merged HandleStartKeyword SHIM with this.
|
||
|
02/21/2001 prashkud Replaced most strings with CString class.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
IMPLEMENT_SHIM_BEGIN(EmulateMissingEXE)
|
||
|
#include "ShimHookMacro.h"
|
||
|
|
||
|
APIHOOK_ENUM_BEGIN
|
||
|
APIHOOK_ENUM_ENTRY(CreateProcessA)
|
||
|
APIHOOK_ENUM_ENTRY(CreateProcessW)
|
||
|
APIHOOK_ENUM_ENTRY(WinExec)
|
||
|
APIHOOK_ENUM_ENTRY(FindFirstFileA)
|
||
|
APIHOOK_ENUM_ENTRY(FindFirstFileW)
|
||
|
APIHOOK_ENUM_ENTRY_COMSERVER(SHELL32)
|
||
|
APIHOOK_ENUM_END
|
||
|
|
||
|
IMPLEMENT_COMSERVER_HOOK(SHELL32)
|
||
|
|
||
|
// Type for the functions that builds the New EXES
|
||
|
typedef BOOL (*_pfn_STUBFUNC)(CString&, CString&, BOOL);
|
||
|
|
||
|
// Main Data structure to hold the New strings
|
||
|
struct REPLACEENTRY {
|
||
|
WCHAR *OrigExeName; // original EXE to be replaced
|
||
|
_pfn_STUBFUNC pfnFuncName; // function to call to correct the name
|
||
|
};
|
||
|
|
||
|
CRITICAL_SECTION g_CritSec;
|
||
|
WCHAR *g_szSysDir = NULL; // system directory for stubs to use
|
||
|
|
||
|
BOOL StubScandisk(CString&, CString&, BOOL);
|
||
|
BOOL StubDefrag(CString&, CString&, BOOL);
|
||
|
BOOL StubStart(CString&, CString&, BOOL);
|
||
|
BOOL StubControl(CString&, CString&, BOOL);
|
||
|
BOOL StubDxDiag(CString&, CString&, BOOL);
|
||
|
BOOL StubWinhlp(CString&, CString&, BOOL);
|
||
|
BOOL StubRundll(CString&, CString&, BOOL);
|
||
|
BOOL StubPbrush(CString&, CString&, BOOL);
|
||
|
|
||
|
// Add variations of these missing Exes like in HandleStartKeyword
|
||
|
// Start has been put at the top of the list as there seem to be more apps
|
||
|
// that need the SHIM for this EXE than others. In fact there was a
|
||
|
// seperate SHIM HandleStartKeyword that was merged with this.
|
||
|
REPLACEENTRY g_ReplList[] = {
|
||
|
{L"start", StubStart },
|
||
|
{L"start.exe", StubStart },
|
||
|
{L"scandskw", StubScandisk },
|
||
|
{L"scandskw.exe", StubScandisk },
|
||
|
{L"defrag", StubDefrag },
|
||
|
{L"defrag.exe", StubDefrag },
|
||
|
{L"control", StubControl },
|
||
|
{L"control.exe", StubControl },
|
||
|
{L"dxdiag", StubDxDiag },
|
||
|
{L"dxdiag.exe", StubDxDiag },
|
||
|
{L"winhelp", StubWinhlp },
|
||
|
{L"winhelp.exe", StubWinhlp },
|
||
|
{L"rundll", StubRundll },
|
||
|
{L"rundll.exe", StubRundll },
|
||
|
{L"Pbrush", StubPbrush },
|
||
|
{L"Pbrush.exe", StubPbrush },
|
||
|
// Always the last one
|
||
|
{L"", NULL }
|
||
|
};
|
||
|
|
||
|
// Added to merge HandleStartKeyword
|
||
|
// Link list of shell link object this pointers.
|
||
|
struct THISPOINTER
|
||
|
{
|
||
|
THISPOINTER *next;
|
||
|
LPCVOID pThisPointer;
|
||
|
};
|
||
|
|
||
|
THISPOINTER *g_pThisPointerList;
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function Description:
|
||
|
|
||
|
Add a this pointer to the linked list of pointers. Does not add if the
|
||
|
pointer is NULL or a duplicate.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
IN pThisPointer - the pointer to add.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
History:
|
||
|
|
||
|
12/14/2000 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
AddThisPointer(
|
||
|
IN LPCVOID pThisPointer
|
||
|
)
|
||
|
{
|
||
|
EnterCriticalSection(&g_CritSec);
|
||
|
|
||
|
if (pThisPointer)
|
||
|
{
|
||
|
THISPOINTER *pPointer = g_pThisPointerList;
|
||
|
while (pPointer)
|
||
|
{
|
||
|
if (pPointer->pThisPointer == pThisPointer)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
pPointer = pPointer->next;
|
||
|
}
|
||
|
|
||
|
pPointer = (THISPOINTER *) malloc(sizeof THISPOINTER);
|
||
|
|
||
|
if (pPointer)
|
||
|
{
|
||
|
pPointer->pThisPointer = pThisPointer;
|
||
|
pPointer->next = g_pThisPointerList;
|
||
|
g_pThisPointerList = pPointer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&g_CritSec);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function Description:
|
||
|
|
||
|
Remove a this pointer if it can be found in the linked list of pointers.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
IN pThisPointer - the pointer to remove.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if the pointer is found.
|
||
|
FALSE if the pointer is not found.
|
||
|
|
||
|
History:
|
||
|
|
||
|
12/14/2000 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
RemoveThisPointer(
|
||
|
IN LPCVOID pThisPointer
|
||
|
)
|
||
|
{
|
||
|
THISPOINTER *pPointer = g_pThisPointerList;
|
||
|
THISPOINTER *last = NULL;
|
||
|
BOOL lRet = FALSE;
|
||
|
|
||
|
EnterCriticalSection(&g_CritSec);
|
||
|
|
||
|
while (pPointer)
|
||
|
{
|
||
|
if (pPointer->pThisPointer == pThisPointer)
|
||
|
{
|
||
|
if (last)
|
||
|
{
|
||
|
last->next = pPointer->next;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_pThisPointerList = pPointer->next;
|
||
|
}
|
||
|
|
||
|
free(pPointer);
|
||
|
lRet = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
last = pPointer;
|
||
|
pPointer = pPointer->next;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&g_CritSec);
|
||
|
return lRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
|
||
|
We are here because the application name: scandskw.exe, matches the one in the
|
||
|
static array. Fill the News for scandskw.exe as:
|
||
|
|
||
|
rundll32.exe shell32.dll,AppCompat_RunDLL SCANDSKW
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
StubScandisk(
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL /*bExists*/
|
||
|
)
|
||
|
{
|
||
|
csNewApplicationName = g_szSysDir;
|
||
|
csNewApplicationName += L"\\rundll32.exe";
|
||
|
csNewCommandLine = L"shell32.dll,AppCompat_RunDLL SCANDSKW";
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
We are here because the application name: defrag.exe, matches the one in the
|
||
|
static array. Fill the News for .exe as:
|
||
|
|
||
|
%windir%\\system32\\mmc.exe %windir%\\system32\\dfrg.msc
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
StubDefrag(
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL /*bExists*/
|
||
|
)
|
||
|
{
|
||
|
csNewApplicationName = g_szSysDir;
|
||
|
csNewApplicationName += L"\\mmc.exe";
|
||
|
|
||
|
csNewCommandLine = g_szSysDir;
|
||
|
csNewCommandLine += L"\\dfrg.msc";
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
We are here because the application name: start.exe, matches the one in the
|
||
|
static array. Fill the News for .exe as:
|
||
|
|
||
|
%windir%\\system32\\cmd.exe" "/c start"
|
||
|
|
||
|
Many applications have a "start.exe" in their current working directories
|
||
|
which needs to take precendence over any New we make.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
StubStart(
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL bExists
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// First check the current working directory for start.exe
|
||
|
//
|
||
|
|
||
|
if (bExists) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// There is no start.exe in the current working directory
|
||
|
//
|
||
|
csNewApplicationName = g_szSysDir;
|
||
|
csNewApplicationName += L"\\cmd.exe";
|
||
|
csNewCommandLine = L"/d /c start \"\"";
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
We are here because the application name: control.exe, matches the one in the
|
||
|
static array. Fill the News for .exe as:
|
||
|
|
||
|
%windir%\\system32\\control.exe
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
StubControl(
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL /*bExists*/
|
||
|
)
|
||
|
{
|
||
|
csNewApplicationName = g_szSysDir;
|
||
|
csNewApplicationName += L"\\control.exe";
|
||
|
csNewCommandLine = L"";
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
We are here because the application name: dxdiag.exe, matches the one in the
|
||
|
static array. Fill the News for .exe as:
|
||
|
|
||
|
%windir%\system32\dxdiag.exe
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
StubDxDiag(
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL /*bExists*/
|
||
|
)
|
||
|
{
|
||
|
csNewApplicationName = g_szSysDir;
|
||
|
csNewApplicationName += L"\\dxdiag.exe";
|
||
|
csNewCommandLine = L"";
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
We are here because the application name: Winhlp.exe, matches the one in the
|
||
|
static array. Fill the News for .exe as:
|
||
|
|
||
|
%windir%\system32\winhlp32.exe
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
StubWinhlp(
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL /*bExists*/
|
||
|
)
|
||
|
{
|
||
|
csNewApplicationName = g_szSysDir;
|
||
|
csNewApplicationName += L"\\winhlp32.exe";
|
||
|
// Winhlp32.exe needs the app name to be in the commandline.
|
||
|
csNewCommandLine = csNewApplicationName;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
We are here because the application name: rundll.exe matches the one in the
|
||
|
static array. Fill the News for .exe as:
|
||
|
|
||
|
%windir%\system32\rundll32.exe
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
StubRundll(
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL /*bExists*/
|
||
|
)
|
||
|
{
|
||
|
csNewApplicationName = g_szSysDir;
|
||
|
csNewApplicationName += L"\\rundll32.exe";
|
||
|
csNewCommandLine = L"";
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
We are here because the application name: Pbrush.exe matches the one in the
|
||
|
static array. Fill the New for .exe as:
|
||
|
|
||
|
%windir%\system32\mspaint.exe
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
StubPbrush(
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL /*bExists*/
|
||
|
)
|
||
|
{
|
||
|
csNewApplicationName = g_szSysDir;
|
||
|
csNewApplicationName += L"\\mspaint.exe";
|
||
|
csNewCommandLine = L"";
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
GetTitle takes the app path and returns just the EXE name.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
GetTitle(CString& csAppName,CString& csAppTitle)
|
||
|
{
|
||
|
csAppTitle = csAppName;
|
||
|
int len = csAppName.ReverseFind(L'\\');
|
||
|
if (len)
|
||
|
{
|
||
|
csAppTitle.Delete(0, len+1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
This is the main function where the New logic happens. This function
|
||
|
goes through the static array and fills the suitable New appname and
|
||
|
the commandline.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
Redirect(
|
||
|
const CString& csApplicationName,
|
||
|
const CString& csCommandLine,
|
||
|
CString& csNewApplicationName,
|
||
|
CString& csNewCommandLine,
|
||
|
BOOL bJustCheckExePresence
|
||
|
)
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
|
||
|
CString csOrigAppName;
|
||
|
CString csOrigCommandLine;
|
||
|
BOOL bExists = FALSE;
|
||
|
|
||
|
AppAndCommandLine AppObj(csApplicationName, csCommandLine);
|
||
|
csOrigAppName = AppObj.GetApplicationName();
|
||
|
csOrigCommandLine = AppObj.GetCommandlineNoAppName();
|
||
|
|
||
|
if (csOrigAppName.IsEmpty())
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Loop through the list of redirectors
|
||
|
//
|
||
|
|
||
|
REPLACEENTRY *rEntry = &g_ReplList[0];
|
||
|
CString csAppTitle;
|
||
|
GetTitle(csOrigAppName, csAppTitle);
|
||
|
|
||
|
while (rEntry && rEntry->OrigExeName[0])
|
||
|
{
|
||
|
if (_wcsicmp(rEntry->OrigExeName, csAppTitle) == 0)
|
||
|
{
|
||
|
//
|
||
|
// This final parameter has been added for the merger
|
||
|
// of HandleStartKeyword Shim. If this is TRUE, we don't
|
||
|
// go any further but just return.
|
||
|
//
|
||
|
if (bJustCheckExePresence)
|
||
|
{
|
||
|
bRet = TRUE;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check if the current working directory contains the exe in question
|
||
|
//
|
||
|
WCHAR *szCurrentDirectory = NULL;
|
||
|
DWORD dwLen = GetCurrentDirectoryW(0, NULL); // Just to get the length
|
||
|
// The dwLen got includes the terminating NULL too.
|
||
|
szCurrentDirectory = (WCHAR*)malloc(dwLen * sizeof(WCHAR));
|
||
|
|
||
|
if (szCurrentDirectory &&
|
||
|
GetCurrentDirectoryW(dwLen, szCurrentDirectory))
|
||
|
{
|
||
|
CString csFullAppName(szCurrentDirectory);
|
||
|
csFullAppName += L"\\";
|
||
|
csFullAppName += csAppTitle;
|
||
|
|
||
|
// Check if the file exists and is not a directory
|
||
|
DWORD dwAttr = GetFileAttributesW(csFullAppName);
|
||
|
if ((dwAttr != INVALID_FILE_ATTRIBUTES) &&
|
||
|
!(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
|
||
|
{
|
||
|
DPFN( eDbgLevelInfo,
|
||
|
"[Redirect] %s found in current working directory");
|
||
|
bExists = TRUE;
|
||
|
}
|
||
|
free(szCurrentDirectory);
|
||
|
}
|
||
|
else if(szCurrentDirectory)
|
||
|
{
|
||
|
free(szCurrentDirectory);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We have a match, so call the corresponding function
|
||
|
//
|
||
|
|
||
|
bRet = (*(rEntry->pfnFuncName))(csNewApplicationName,
|
||
|
csNewCommandLine, bExists);
|
||
|
if (bRet)
|
||
|
{
|
||
|
//
|
||
|
// Append the original command line
|
||
|
//
|
||
|
csNewCommandLine += L" ";
|
||
|
csNewCommandLine += csOrigCommandLine;
|
||
|
}
|
||
|
|
||
|
// We matched an EXE, so we're done
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
rEntry++;
|
||
|
}
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
DPFN( eDbgLevelWarning, "Redirected:");
|
||
|
DPFN( eDbgLevelWarning, "\tFrom: %S %S", csApplicationName, csCommandLine);
|
||
|
DPFN( eDbgLevelWarning, "\tTo: %S %S", csNewApplicationName, csNewCommandLine);
|
||
|
}
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "Not Redirecting: Exception encountered");
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hooks the CreateProcessA function to see if any News need to be
|
||
|
substituted.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
APIHOOK(CreateProcessA)(
|
||
|
LPCSTR lpApplicationName,
|
||
|
LPSTR lpCommandLine,
|
||
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||
|
BOOL bInheritHandles,
|
||
|
DWORD dwCreationFlags,
|
||
|
LPVOID lpEnvironment,
|
||
|
LPCSTR lpCurrentDirectory,
|
||
|
LPSTARTUPINFOA lpStartupInfo,
|
||
|
LPPROCESS_INFORMATION lpProcessInformation
|
||
|
)
|
||
|
{
|
||
|
if ((NULL == lpApplicationName) &&
|
||
|
(NULL == lpCommandLine))
|
||
|
{
|
||
|
// If both are NULL, return FALSE.
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csNewApplicationName;
|
||
|
CString csNewCommandLine;
|
||
|
CString csPassedAppName(lpApplicationName);
|
||
|
CString csPassedCommandLine(lpCommandLine);
|
||
|
|
||
|
if ((csPassedAppName.IsEmpty()) &&
|
||
|
(csPassedCommandLine.IsEmpty()))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Run the list of New stubs: call to the main New routine
|
||
|
//
|
||
|
if (Redirect(csPassedAppName, csPassedCommandLine, csNewApplicationName,
|
||
|
csNewCommandLine, FALSE))
|
||
|
{
|
||
|
LOGN(
|
||
|
eDbgLevelWarning,
|
||
|
"[CreateProcessA] \" %s %s \": changed to \" %s %s \"",
|
||
|
lpApplicationName, lpCommandLine,
|
||
|
csNewApplicationName.GetAnsi(), csNewCommandLine.GetAnsi());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
csNewApplicationName = lpApplicationName;
|
||
|
csNewCommandLine = lpCommandLine;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Convert back to ANSI using the GetAnsi() method exposed by the CString class.
|
||
|
return ORIGINAL_API(CreateProcessA)(
|
||
|
csNewApplicationName.IsEmpty() ? NULL : csNewApplicationName.GetAnsi(),
|
||
|
csNewCommandLine.IsEmpty() ? NULL : csNewCommandLine.GetAnsi(),
|
||
|
lpProcessAttributes, lpThreadAttributes, bInheritHandles,
|
||
|
dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
|
||
|
lpProcessInformation);
|
||
|
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "[CreateProcessA]:Original API called.Exception occured!");
|
||
|
|
||
|
}
|
||
|
|
||
|
exit:
|
||
|
return ORIGINAL_API(CreateProcessA)(lpApplicationName, lpCommandLine,
|
||
|
lpProcessAttributes, lpThreadAttributes, bInheritHandles,
|
||
|
dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
|
||
|
lpProcessInformation);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hooks the CreateProcessW function to see if any News need to be
|
||
|
substituted.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
APIHOOK(CreateProcessW)(
|
||
|
LPCWSTR lpApplicationName,
|
||
|
LPWSTR lpCommandLine,
|
||
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||
|
BOOL bInheritHandles,
|
||
|
DWORD dwCreationFlags,
|
||
|
LPVOID lpEnvironment,
|
||
|
LPCWSTR lpCurrentDirectory,
|
||
|
LPSTARTUPINFOW lpStartupInfo,
|
||
|
LPPROCESS_INFORMATION lpProcessInformation
|
||
|
)
|
||
|
{
|
||
|
if ((NULL == lpApplicationName) &&
|
||
|
(NULL == lpCommandLine))
|
||
|
{
|
||
|
// If both are NULL, return FALSE.
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csNewApplicationName;
|
||
|
CString csNewCommandLine;
|
||
|
CString csApplicationName(lpApplicationName);
|
||
|
CString csCommandLine(lpCommandLine);
|
||
|
|
||
|
if ((csApplicationName.IsEmpty()) &&
|
||
|
(csCommandLine.IsEmpty()))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Run the list of New stubs
|
||
|
//
|
||
|
|
||
|
if (Redirect(csApplicationName, csCommandLine, csNewApplicationName,
|
||
|
csNewCommandLine, FALSE))
|
||
|
{
|
||
|
LOGN(
|
||
|
eDbgLevelWarning,
|
||
|
"[CreateProcessW] \" %S %S \": changed to \" %S %S \"",
|
||
|
lpApplicationName, lpCommandLine, csNewApplicationName, csNewCommandLine);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
csNewApplicationName = lpApplicationName;
|
||
|
csNewCommandLine = lpCommandLine;
|
||
|
}
|
||
|
|
||
|
|
||
|
return ORIGINAL_API(CreateProcessW)(
|
||
|
csNewApplicationName.IsEmpty() ? NULL : csNewApplicationName.Get(),
|
||
|
csNewCommandLine.IsEmpty() ? NULL : (LPWSTR)csNewCommandLine.Get(),
|
||
|
lpProcessAttributes, lpThreadAttributes, bInheritHandles,
|
||
|
dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
|
||
|
lpProcessInformation);
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "[CreateProcessW] Original API called. Exception occured!");
|
||
|
}
|
||
|
|
||
|
exit:
|
||
|
return ORIGINAL_API(CreateProcessW)(lpApplicationName, lpCommandLine,
|
||
|
lpProcessAttributes, lpThreadAttributes, bInheritHandles,
|
||
|
dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
|
||
|
lpProcessInformation);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hooks WinExec to redirect if necessary.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
UINT
|
||
|
APIHOOK(WinExec)(
|
||
|
LPCSTR lpCmdLine,
|
||
|
UINT uCmdShow
|
||
|
)
|
||
|
{
|
||
|
if (NULL == lpCmdLine)
|
||
|
{
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return ERROR_PATH_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csNewApplicationName;
|
||
|
CString csNewCommandLine;
|
||
|
CString csAppName;
|
||
|
CString csNewCmdLine;
|
||
|
CString csCommandLine(lpCmdLine);
|
||
|
|
||
|
if (csCommandLine.IsEmpty())
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
// Check for redirection
|
||
|
if (Redirect(csAppName, csCommandLine, csNewApplicationName,
|
||
|
csNewCommandLine, FALSE))
|
||
|
{
|
||
|
// Modification for the WinHlp32 strange behaviour
|
||
|
if (csNewCommandLine.Find(csNewApplicationName.Get()) == -1)
|
||
|
{
|
||
|
// If the new Command line does not contain the new application
|
||
|
// name as the substring, we are here.
|
||
|
csNewCmdLine = csNewApplicationName;
|
||
|
csNewCmdLine += L" ";
|
||
|
}
|
||
|
csNewCmdLine += csNewCommandLine;
|
||
|
|
||
|
// Assign to csCommandLine as this can be commonly used
|
||
|
csCommandLine = csNewCmdLine;
|
||
|
|
||
|
LOGN(
|
||
|
eDbgLevelInfo,
|
||
|
"[WinExec] \" %s \": changed to \" %s \"",
|
||
|
lpCmdLine, csCommandLine.GetAnsi());
|
||
|
}
|
||
|
|
||
|
return ORIGINAL_API(WinExec)(csCommandLine.GetAnsi(), uCmdShow);
|
||
|
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "[WinExec]:Original API called.Exception occured!");
|
||
|
}
|
||
|
|
||
|
exit:
|
||
|
return ORIGINAL_API(WinExec)(lpCmdLine, uCmdShow);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hooks the FindFirstFileA function to see if any replacements need to be
|
||
|
substituted. This is a requirement for cmd.exe.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
HANDLE
|
||
|
APIHOOK(FindFirstFileA)(
|
||
|
LPCSTR lpFileName,
|
||
|
LPWIN32_FIND_DATAA lpFindFileData
|
||
|
)
|
||
|
{
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csNewApplicationName;
|
||
|
CString csNewCommandLine;
|
||
|
CString csFileName(lpFileName);
|
||
|
CString csAppName;
|
||
|
|
||
|
// Call the main replacement routine.
|
||
|
if (Redirect(csFileName, csAppName, csNewApplicationName, csNewCommandLine, FALSE))
|
||
|
{
|
||
|
// Assign to csFileName
|
||
|
csFileName = csNewApplicationName;
|
||
|
LOGN(
|
||
|
eDbgLevelInfo,
|
||
|
"[FindFirstFileA] \" %s \": changed to \" %s \"",
|
||
|
lpFileName, csFileName.GetAnsi());
|
||
|
}
|
||
|
|
||
|
return ORIGINAL_API(FindFirstFileA)(csFileName.GetAnsi(), lpFindFileData);
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "[FindFirstFileA]:Original API called.Exception occured!");
|
||
|
return ORIGINAL_API(FindFirstFileA)(lpFileName, lpFindFileData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hooks the FindFirstFileW function to see if any replacements need to be
|
||
|
substituted. This is a requirement for cmd.exe.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
HANDLE
|
||
|
APIHOOK(FindFirstFileW)(
|
||
|
LPCWSTR lpFileName,
|
||
|
LPWIN32_FIND_DATAW lpFindFileData
|
||
|
)
|
||
|
{
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csNewApplicationName(lpFileName);
|
||
|
CString csNewCommandLine;
|
||
|
CString csFileName(lpFileName);
|
||
|
CString csAppName;
|
||
|
|
||
|
// Call the main replacement routine.
|
||
|
if (Redirect(csFileName, csAppName, csNewApplicationName,
|
||
|
csNewCommandLine, FALSE))
|
||
|
{
|
||
|
LOGN(
|
||
|
eDbgLevelInfo,
|
||
|
"[FindFirstFileW] \" %S \": changed to \" %S \"",
|
||
|
lpFileName, (const WCHAR*)csNewApplicationName);
|
||
|
}
|
||
|
|
||
|
return ORIGINAL_API(FindFirstFileW)(csNewApplicationName, lpFindFileData);
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "[FindFirstFileW]:Original API called.Exception occured!");
|
||
|
return ORIGINAL_API(FindFirstFileW)(lpFileName, lpFindFileData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Added for the merge of HandleStartKeyword
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hook IShellLinkA::SetPath - check if it's start, if so change it to cmd and add the
|
||
|
this pointer to the list.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
COMHOOK(IShellLinkA, SetPath)(
|
||
|
PVOID pThis,
|
||
|
LPCSTR pszFile
|
||
|
)
|
||
|
{
|
||
|
_pfn_IShellLinkA_SetPath pfnSetPath = ORIGINAL_COM( IShellLinkA, SetPath, pThis);
|
||
|
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csExeName;
|
||
|
CString csCmdLine;
|
||
|
CString csNewAppName;
|
||
|
CString csNewCmdLine;
|
||
|
CString cscmdCommandLine(pszFile);
|
||
|
|
||
|
// Assign the ANSI string to the WCHAR CString
|
||
|
csExeName = pszFile;
|
||
|
csExeName.TrimLeft();
|
||
|
|
||
|
// Check to see whether the Filename conatains the "Start" keyword.
|
||
|
// The last parameter to the Rediect function controls this.
|
||
|
if (Redirect(csExeName, csCmdLine, csNewAppName, csNewCmdLine, TRUE))
|
||
|
{
|
||
|
// Found a match. We add the this pointer to the list.
|
||
|
AddThisPointer(pThis);
|
||
|
DPFN( eDbgLevelInfo, "[SetPath] Changing start.exe to cmd.exe\n");
|
||
|
|
||
|
// Prefix of new "start" command line, use full path to CMD.EXE
|
||
|
// Append the WCHAR global system directory path to ANSI CString
|
||
|
cscmdCommandLine = g_szSysDir;
|
||
|
cscmdCommandLine += L"\\cmd.exe";
|
||
|
}
|
||
|
|
||
|
return (*pfnSetPath)(pThis, cscmdCommandLine.GetAnsi());
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "[SetPath] Original API called. Exception occured!");
|
||
|
return (*pfnSetPath)(pThis, pszFile);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Hook IShellLinkA::SetArguments - if the this pointer can be found in the list, remove it
|
||
|
from the list and add "/d /c start" in front of the original argument list.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE
|
||
|
COMHOOK(IShellLinkA, SetArguments)(
|
||
|
PVOID pThis,
|
||
|
LPCSTR pszFile
|
||
|
)
|
||
|
{
|
||
|
_pfn_IShellLinkA_SetArguments pfnSetArguments = ORIGINAL_COM(IShellLinkA, SetArguments, pThis);
|
||
|
|
||
|
CSTRING_TRY
|
||
|
{
|
||
|
CString csNewFile(pszFile);
|
||
|
if (RemoveThisPointer(pThis))
|
||
|
{
|
||
|
csNewFile = "/d /c start \"\" ";
|
||
|
csNewFile += pszFile;
|
||
|
|
||
|
DPFN( eDbgLevelInfo, "[SetArguments] Arg list is now %S", csNewFile);
|
||
|
}
|
||
|
|
||
|
return (*pfnSetArguments)( pThis, csNewFile.GetAnsi());
|
||
|
}
|
||
|
CSTRING_CATCH
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "[SetArguments]:Original API called.Exception occured!");
|
||
|
return (*pfnSetArguments)( pThis, pszFile );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Register hooked functions
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
NOTIFY_FUNCTION(
|
||
|
DWORD fdwReason
|
||
|
)
|
||
|
{
|
||
|
if (fdwReason == DLL_PROCESS_ATTACH)
|
||
|
{
|
||
|
UINT uiLen = GetSystemDirectory(NULL, 0);
|
||
|
g_szSysDir = (WCHAR*)malloc(uiLen * sizeof(WCHAR)); // This won't be deallocated..
|
||
|
if (g_szSysDir && !GetSystemDirectory(g_szSysDir, uiLen))
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "[Notify] GetSystemDirectory failed");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (InitializeCriticalSectionAndSpinCount(&g_CritSec, 0x80000000) == FALSE)
|
||
|
{
|
||
|
DPFN( eDbgLevelError, "Failed to initialize critical section");
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
HOOK_BEGIN
|
||
|
|
||
|
CALL_NOTIFY_FUNCTION
|
||
|
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, CreateProcessA)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, CreateProcessW)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, WinExec)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, FindFirstFileA)
|
||
|
APIHOOK_ENTRY(KERNEL32.DLL, FindFirstFileW)
|
||
|
APIHOOK_ENTRY_COMSERVER(SHELL32)
|
||
|
COMHOOK_ENTRY(ShellLink, IShellLinkA, SetPath, 20)
|
||
|
COMHOOK_ENTRY(ShellLink, IShellLinkA, SetArguments, 11)
|
||
|
|
||
|
HOOK_END
|
||
|
|
||
|
IMPLEMENT_SHIM_END
|
||
|
|
||
|
|