|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
WoWTask.cpp
Abstract:
Functions that retrieve process-history related information from 16-bit environment. This includes the retrieval of the correct __PROCESS_HISTORY that was passed in from the parent (32-bit)process and tracing the process history through WOW
Notes:
History:
10/26/00 VadimB Created
--*/
#include "precomp.h"
IMPLEMENT_SHIM_BEGIN(Win2kPropagateLayer) #include "ShimHookMacro.h"
#include "Win2kPropagateLayer.h"
typedef struct tagFINDWOWTASKDATA { BOOL bFound; DWORD dwProcessId; DWORD dwThreadId; WORD hMod16; WORD hTask16;
} FINDWOWTASKDATA, *PFINDWOWTASKDATA;
//
// Dynamically Linked apis
//
// from WOW32.dll
//
typedef LPVOID (WINAPI *PFNWOWGetVDMPointer)(DWORD vp, DWORD dwBytes, BOOL fProtectedMode);
//
// from vdmdbg.dll - defined in the header file
//
//
typedef INT (WINAPI *PFNVDMEnumTaskWOW)(DWORD dwProcessId, TASKENUMPROC fp, LPARAM lparam);
//
// Api importing -- modules
//
WCHAR g_wszWOW32ModName[] = L"wow32.dll"; WCHAR g_wszVdmDbgModName[] = L"VdmDbg.dll";
//
// Api importing - module handles and function pointers
//
HMODULE g_hWow32; HMODULE g_hVdmDbg; BOOL g_bInitialized; // set to true when imports are initialized
PFNWOWGetVDMPointer g_pfnWOWGetVDMPointer; PFNVDMEnumTaskWOW g_pfnVDMEnumTaskWOW;
extern BOOL* g_pSeparateWow;
//
// function in this module to import apis
//
BOOL ImportWowApis(VOID);
//
// Marcro to access 16-bit memory
//
#define SEGPTR(seg,off) ((g_pfnWOWGetVDMPointer)((((ULONG)seg) << 16) | (off), 0, TRUE))
//
// task enum proc, called back from vdmdbg
//
BOOL WINAPI MyTaskEnumProc( DWORD dwThreadId, WORD hMod16, WORD hTask16, LPARAM lParam ) { PFINDWOWTASKDATA pFindData = (PFINDWOWTASKDATA)lParam;
if (dwThreadId == pFindData->dwThreadId) { pFindData->hMod16 = hMod16; pFindData->hTask16 = hTask16; pFindData->bFound = TRUE; return TRUE; }
return FALSE; }
BOOL FindWowTask( DWORD dwProcessId, DWORD dwThreadId, PFINDWOWTASKDATA pFindData ) { RtlZeroMemory(pFindData, sizeof(*pFindData));
pFindData->dwProcessId = dwProcessId; pFindData->dwThreadId = dwThreadId;
g_pfnVDMEnumTaskWOW(dwProcessId, (TASKENUMPROC)MyTaskEnumProc, (LPARAM)pFindData);
return pFindData->bFound; }
//
// get the pointer to task database block from hTask
//
PTDB GetTDB( WORD wTDB ) { PTDB pTDB;
pTDB = (PTDB)SEGPTR(wTDB, 0); if (NULL == pTDB || TDB_SIGNATURE != pTDB->TDB_sig) { LOGN( eDbgLevelError, "[GetTDB] TDB is invalid for task 0x%x", (DWORD)wTDB); return NULL; }
return pTDB; }
//
// GetModName
// wTDB - TDB entry
// szModName - pointer to the buffer that receives module name
// buffer should be at least 9 characters long
//
// returns FALSE if the entry is invalid
BOOL GetModName( WORD wTDB, PCH szModName ) { PTDB pTDB; PCH pch;
pTDB = GetTDB(wTDB); if (NULL == pTDB) { return FALSE; }
RtlCopyMemory(szModName, pTDB->TDB_ModName, 8 * sizeof(CHAR)); // we have modname now
szModName[8] = '\0';
pch = &szModName[8]; while (--pch >= szModName && *pch == ' ') { *pch = 0; }
if( pch < szModName ) { return FALSE; }
return TRUE; }
//
// ShimGetTaskFileName
// IN wTask - 16-bit task handle
// Returns:
// Fully qualified exe that is running in this task's context
//
PSZ ShimGetTaskFileName( WORD wTask ) { PSZ pszFileName = NULL; PTDB pTDB;
pTDB = GetTDB(wTask); if (NULL == pTDB) { // this is really bad -- the module is invalid, debug output is generated by GetTDB
return pszFileName; }
if (NULL == pTDB->TDB_pModule) { LOGN( eDbgLevelError, "[ShimGetTaskFileName] module pointer is NULL for 0x%x", (DWORD)wTask); return pszFileName; }
pszFileName = (PSZ)SEGPTR(pTDB->TDB_pModule, (*(WORD *)SEGPTR(pTDB->TDB_pModule, 10)) + 8); return pszFileName; }
PSZ ShimGetTaskEnvptr( WORD hTask16 ) { PTDB pTDB = GetTDB(hTask16); PSZ pszEnv = NULL; PDOSPDB pPSP;
if (NULL == pTDB) { LOGN( eDbgLevelError, "[ShimGetTaskEnvptr] Bad TDB entry 0x%x", hTask16); return NULL; } //
// Prepare environment data - this buffer is used when we're starting a new task from the
// root of the chain (as opposed to spawning from an existing 16-bit task)
//
pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
if (pPSP != NULL) { pszEnv = (PCH)SEGPTR(pPSP->PDB_environ, 0); }
return pszEnv; }
// IsWowExec
// IN wTDB - entry into the task database
// Returns:
// TRUE if this particular entry points to WOWEXEC
//
// Note:
// WOWEXEC is a special stub module that always runs on NTVDM
// new tasks are spawned by wowexec (in the most typical case)
// it is therefore the "root" module and it's environment's contents
// should not be counted, since we don't know what was ntvdm's parent process
//
BOOL IsWOWExec( WORD wTDB ) { PTDB pTDB; CHAR szModName[9];
pTDB = GetTDB(wTDB); if (NULL == pTDB) { LOGN( eDbgLevelError, "[IsWOWExec] Bad TDB entry 0x%x", (DWORD)wTDB); return FALSE; }
if (!GetModName(wTDB, szModName)) { // can we get modname ?
LOGN( eDbgLevelError, "[IsWOWExec] GetModName failed."); return FALSE; }
return (0 == _strcmpi(szModName, "wowexec")); // is the module named WOWEXEC ?
}
//
// ImportWowApis
// Function imports necessary apis from wow32.dll and vdmdbg.dll
//
//
BOOL ImportWowApis( VOID ) { g_hWow32 = LoadLibraryW(g_wszWOW32ModName); if (g_hWow32 == NULL) { LOGN( eDbgLevelError, "[ImportWowApis] Failed to load wow32.dll Error 0x%x", GetLastError()); goto Fail; }
g_pfnWOWGetVDMPointer = (PFNWOWGetVDMPointer)GetProcAddress(g_hWow32, "WOWGetVDMPointer"); if (g_pfnWOWGetVDMPointer == NULL) { LOGN( eDbgLevelError, "[ImportWowApis] Failed to get address of WOWGetVDMPointer Error 0x%x", GetLastError()); goto Fail; }
g_hVdmDbg = LoadLibraryW(g_wszVdmDbgModName); if (g_hVdmDbg == NULL) { LOGN( eDbgLevelError, "[ImportWowApis] Failed to load vdmdbg.dll Error 0x%x", GetLastError()); goto Fail; }
g_pfnVDMEnumTaskWOW = (PFNVDMEnumTaskWOW)GetProcAddress(g_hVdmDbg, "VDMEnumTaskWOW"); if (g_pfnVDMEnumTaskWOW == NULL) { LOGN( eDbgLevelError, "[ImportWowApis] Failed to get address of VDMEnumTaskWOW Error 0x%x", GetLastError()); goto Fail; }
g_bInitialized = TRUE;
return TRUE;
Fail:
if (g_hWow32) { FreeLibrary(g_hWow32); g_hWow32 = NULL; } if (g_hVdmDbg) { FreeLibrary(g_hVdmDbg); g_hVdmDbg = NULL; } g_pfnWOWGetVDMPointer = NULL; g_pfnVDMEnumTaskWOW = NULL;
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////////////////////
//
//
// WOWTaskList
//
// We maintain a shadow list of running wow tasks complete with respective process history and
// inherited process history
//
//
typedef struct tagWOWTASKLISTITEM* PWOWTASKLISTITEM;
typedef struct tagWOWTASKLISTITEM {
WORD hTask16; // 16-bit tdb entry
DWORD dwThreadId; // thread id of the task
WOWENVDATA EnvData; // environment data (process history, compat layer, etc)
PWOWTASKLISTITEM pTaskNext;
} WOWTASKLISTITEM;
PWOWTASKLISTITEM g_pWowTaskList;
/*++
FindWowTaskInfo
IN hTask16 16-bit task's handle IN dwThreadId OPTIONAL 32-bit thread id of the task, might be 0
Returns: pointer to the task information structure
--*/
PWOWTASKLISTITEM FindWowTaskInfo( WORD hTask16, DWORD dwThreadId ) { PWOWTASKLISTITEM pTask = g_pWowTaskList;
while (NULL != pTask) {
if (hTask16 == pTask->hTask16) {
if (dwThreadId == 0 || dwThreadId == pTask->dwThreadId) { break; } }
pTask = pTask->pTaskNext; }
return pTask; }
/*++
UpdateWowTaskList
IN hTask16 16-bit task's handle
Returns: True if the task was added successfully Note: wowexec is not among the "legitimate" tasks
--*/
BOOL UpdateWowTaskList( WORD hTask16 ) { PTDB pTDB; WORD wTaskParent; PWOWTASKLISTITEM pTaskParent = NULL; LPSTR lpszFileName; PSZ pszEnv; WOWENVDATA EnvData; PWOWENVDATA pData = NULL; DWORD dwLength; PWOWTASKLISTITEM pTaskNew; PCH pBuffer; PDOSPDB pPSP; BOOL bSuccess;
//
// see that we are initialized, import apis
//
if (!g_bInitialized) { // first call, link apis
bSuccess = ImportWowApis(); if (!bSuccess) { LOGN( eDbgLevelError, "[UpdateWowTaskList] Failed to import apis."); return FALSE; } }
//
// If this task is WOWEXEC -- just return, it's not an error condition, but we don't need
// wowexec in our list
//
if (IsWOWExec(hTask16)) { // this is ok, we don't want wowexec
return FALSE; }
//
// next, see what the parent item is, to do so -- access it through TDB
//
pTDB = GetTDB(hTask16); if (NULL == pTDB) { LOGN( eDbgLevelError, "[UpdateWowTaskList] Bad TDB entry 0x%x", hTask16); return FALSE; }
//
// Prepare environment data - this buffer is used when we're starting a new task from the
// root of the chain (as opposed to spawning from an existing 16-bit task)
//
RtlZeroMemory(&EnvData, sizeof(EnvData)); pData = &EnvData;
wTaskParent = pTDB->TDB_Parent; if (IsWOWExec(wTaskParent) || GetTDB(wTaskParent) == NULL) { //
// Root task, extract process history, compat layer, etc
//
pszEnv = NULL; pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
if (pPSP != NULL) { pszEnv = (PCH)SEGPTR(pPSP->PDB_environ, 0); }
//
// we have a pointer to the current environment here, pData is initialized
//
if (pszEnv != NULL) { pData->pszProcessHistory = ShimFindEnvironmentVar(g_szProcessHistoryVar, pszEnv, &pData->pszProcessHistoryVal); pData->pszCompatLayer = ShimFindEnvironmentVar(g_szCompatLayerVar, pszEnv, &pData->pszCompatLayerVal); pData->pszShimFileLog = ShimFindEnvironmentVar(g_szShimFileLogVar, pszEnv, &pData->pszShimFileLogVal); }
} else { //
// Not a root task, find parent process
//
pTaskParent = FindWowTaskInfo(wTaskParent, 0); // we can't determine which thread owns the task
if (pTaskParent == NULL) { //
// something is very wrong
// we can't inherit
//
LOGN( eDbgLevelError, "[UpdateWowTaskList] Task 0x%x is not root but parent not listed 0x%x", (DWORD)hTask16, (DWORD)wTaskParent); //
// we still allow building up process history. The initial variables will be empty
//
} else { //
// inherit everything from the parent and add it's module name (later)
//
pData = &pTaskParent->EnvData; } }
//
// Get the filename involved
//
//
lpszFileName = ShimGetTaskFileName(hTask16);
//
// now calculate how much space is required to hold all of the data
//
dwLength = sizeof(WOWTASKLISTITEM) + (NULL == pData->pszProcessHistory ? 0 : (strlen(pData->pszProcessHistory) + 1) * sizeof(CHAR)) + (NULL == pData->pszCompatLayer ? 0 : (strlen(pData->pszCompatLayer) + 1) * sizeof(CHAR)) + (NULL == pData->pszShimFileLog ? 0 : (strlen(pData->pszShimFileLog) + 1) * sizeof(CHAR)) + (NULL == pData->pszCurrentProcessHistory ? 0 : (strlen(pData->pszCurrentProcessHistory) + 2) * sizeof(CHAR)) + (NULL == lpszFileName ? 0 : (strlen(lpszFileName) + 1) * sizeof(CHAR));
pTaskNew = (PWOWTASKLISTITEM)ShimMalloc(dwLength); if (pTaskNew == NULL) { LOGN( eDbgLevelError, "[UpdateWowTaskList] failed to allocate 0x%x bytes", dwLength); return FALSE; }
RtlZeroMemory(pTaskNew, dwLength);
//
// now this entry has to be setup
// process history is first
//
pBuffer = (PCH)(pTaskNew + 1); // Keep track of how much of the buffer is left.
size_t cchRemaining = dwLength - sizeof(WOWTASKLISTITEM);
pTaskNew->hTask16 = hTask16; pTaskNew->dwThreadId = GetCurrentThreadId();
if (pData->pszProcessHistory != NULL) {
//
// Copy process history. The processHistoryVal is a pointer into the buffer
// pointed to by pszProcessHistory: __PROCESS_HISTORY=c:\foo;c:\docs~1\install
// then pszProcessHistoryVal will point here ---------^
//
// we are copying the data and moving the pointer using the calculated offset
pTaskNew->EnvData.pszProcessHistory = pBuffer; StringCchCopyExA(pTaskNew->EnvData.pszProcessHistory, cchRemaining, pData->pszProcessHistory, NULL, &cchRemaining, 0); pTaskNew->EnvData.pszProcessHistoryVal = pTaskNew->EnvData.pszProcessHistory + (INT)(pData->pszProcessHistoryVal - pData->pszProcessHistory); //
// There is enough space in the buffer to accomodate all the strings, so
// move pointer past current string to point at the "empty" space
//
pBuffer += strlen(pData->pszProcessHistory) + 1; }
if (pData->pszCompatLayer != NULL) { pTaskNew->EnvData.pszCompatLayer = pBuffer; StringCchCopyExA(pTaskNew->EnvData.pszCompatLayer, cchRemaining, pData->pszCompatLayer, NULL, &cchRemaining, 0); pTaskNew->EnvData.pszCompatLayerVal = pTaskNew->EnvData.pszCompatLayer + (INT)(pData->pszCompatLayerVal - pData->pszCompatLayer); pBuffer += strlen(pData->pszCompatLayer) + 1; }
if (pData->pszShimFileLog != NULL) { pTaskNew->EnvData.pszShimFileLog = pBuffer; StringCchCopyExA(pTaskNew->EnvData.pszShimFileLog, cchRemaining, pData->pszShimFileLog, NULL, &cchRemaining, 0); pTaskNew->EnvData.pszShimFileLogVal = pTaskNew->EnvData.pszShimFileLog + (INT)(pData->pszShimFileLogVal - pData->pszShimFileLog); pBuffer += strlen(pData->pszShimFileLog) + 1; }
if (pData->pszCurrentProcessHistory != NULL || lpszFileName != NULL) { //
// Now process history
//
pTaskNew->EnvData.pszCurrentProcessHistory = pBuffer; if (pData->pszCurrentProcessHistory != NULL) { StringCchCopyExA(pTaskNew->EnvData.pszCurrentProcessHistory, cchRemaining, pData->pszCurrentProcessHistory, NULL, &cchRemaining, 0); if (lpszFileName != NULL ) { StringCchCatExA(pTaskNew->EnvData.pszCurrentProcessHistory, cchRemaining, ";", NULL, &cchRemaining, 0); } } if (lpszFileName != NULL) { StringCchCatA(pTaskNew->EnvData.pszCurrentProcessHistory, cchRemaining, lpszFileName); } }
LOGN( eDbgLevelInfo, "[UpdateWowTaskList] Running : \"%s\"", lpszFileName); LOGN( eDbgLevelInfo, "[UpdateWowTaskList] ProcessHistory : \"%s\"", pTaskNew->EnvData.pszCurrentProcessHistory); LOGN( eDbgLevelInfo, "[UpdateWowTaskList] BaseProcessHistory: \"%s\"", pTaskNew->EnvData.pszProcessHistory); LOGN( eDbgLevelInfo, "[UpdateWowTaskList] CompatLayer : \"%s\"", pTaskNew->EnvData.pszCompatLayer);
//
// We are done, link the entry into the list
//
pTaskNew->pTaskNext = g_pWowTaskList;
g_pWowTaskList = pTaskNew;
return TRUE; }
/*++
CleanupWowTaskList
IN hTask16 16-bit task handle that is to be removed from the list of running tasks
Returns : TRUE if the function succeeds
--*/
BOOL CleanupWowTaskList( WORD hTask16 ) { PWOWTASKLISTITEM pTask = g_pWowTaskList; PWOWTASKLISTITEM pTaskPrev = NULL;
while (pTask != NULL) {
if (pTask->hTask16 == hTask16) { // this is the item
break; }
pTaskPrev = pTask; pTask = pTask->pTaskNext; }
if (pTask == NULL) { LOGN( eDbgLevelError, "[CleanupWowTaskList] Failed to locate task information for 0x%x", (DWORD)hTask16); return FALSE; }
if (pTaskPrev == NULL) {
g_pWowTaskList = pTask->pTaskNext;
} else {
pTaskPrev->pTaskNext = pTask->pTaskNext;
}
ShimFree(pTask);
return TRUE;
}
/*++
ShimRetrieveVariablesEx
IN pData Structure that receives pointers to all the relevant environment information for the calling thread. The threads are scheduled non-preemptively by user and threadid is used to identify the calling 16-bit task All the real work on information retrieval is done in UpdateWowTaskList
Returns: TRUE if success --*/
BOOL ShimRetrieveVariablesEx( PWOWENVDATA pData ) { DWORD dwProcessId = GetCurrentProcessId(); DWORD dwThreadId = GetCurrentThreadId(); PWOWTASKLISTITEM pTask; FINDWOWTASKDATA FindData; WORD hTask; BOOL bSuccess;
RtlZeroMemory(pData, sizeof(*pData));
if (!g_bInitialized) { // first call, link apis
bSuccess = ImportWowApis(); if (!bSuccess) { LOGN( eDbgLevelError, "[ShimRetrieveVariablesEx] Failed to import apis."); return FALSE; } }
if (!FindWowTask(dwProcessId, dwThreadId, &FindData)) { LOGN( eDbgLevelError, "[ShimRetrieveVariablesEx] Task not found ProcessId 0x%x ThreadId 0x%x", dwProcessId, dwThreadId); return FALSE; }
hTask = FindData.hTask16;
pTask = FindWowTaskInfo(hTask, dwThreadId); if (pTask == NULL) { LOGN( eDbgLevelError, "[ShimRetrieveVariablesEx] Failed to locate wow task."); return FALSE; }
//
// Found this one. Copy the info.
//
RtlMoveMemory(pData, &pTask->EnvData, sizeof(*pData));
return TRUE; }
/*++
ShimThisProcess
Function invokes Shim Engine for dynamic shimming of the current process Which happens to be ntvdm, naturally. This ntvdm is a separate ntvdm (which is insured through various checks in CheckAndShimNTVDM)
--*/
BOOL ShimThisProcess( HMODULE hModShimEngine, HSDB hSDB, SDBQUERYRESULT* pQueryResult ) { typedef BOOL (WINAPI *PFNDynamicShim)(LPCWSTR , HSDB , SDBQUERYRESULT*, LPCSTR, LPDWORD); PFNDynamicShim pfnDynamicShim = NULL; WCHAR wszFileName[MAX_PATH]; DWORD dwLength; DWORD dwDynamicToken = 0;
pfnDynamicShim = (PFNDynamicShim) GetProcAddress(hModShimEngine, "SE_DynamicShim"); if (NULL == pfnDynamicShim) { LOGN( eDbgLevelError, "[ShimThisProcess] failed to obtain dynamic shim proc address\n"); return FALSE; }
dwLength = GetModuleFileNameW(GetModuleHandle(NULL), wszFileName, CHARCOUNT(wszFileName)); if (!dwLength || dwLength == CHARCOUNT(wszFileName)) { LOGN( eDbgLevelError, "[ShimThisProcess] failed to obtain module file name\n"); return FALSE; }
return pfnDynamicShim(wszFileName, hSDB, pQueryResult, NULL, &dwDynamicToken); }
/*++
CheckAndShimNTVDM Procedure checks ntvdm application for having to be shimmed. If an application is located in appcompat database, this ntvdm would have to be running as a separate ntvdm (explorer is shimmed as well, as a result it will have checked the binary first and set the separate vdm flag in CreateProcess)
Further, this call comes through InitTask (intercepted between ntvdm and user32) -- as a parameter it takes hTask16 - which we're able to use to retrieve application's environment and other important information. --*/
BOOL CheckAndShimNTVDM( WORD hTask16 ) { HMODULE hModShimEngine; CString csTaskFileName; PSZ pszEnv = NULL; PTDB pTDB = NULL; PVOID pEnvNew = NULL; BOOL bSuccess = FALSE; BOOL bMatch; BOOL bNewEnv = FALSE; HSDB hSDB; NTSTATUS Status; SDBQUERYRESULT QueryResult; DWORD dwFlags;
hModShimEngine = GetModuleHandle(TEXT("shim.dll")); if (hModShimEngine == NULL) { // impossible -- shim.dll is not injected!!!
return FALSE; } if (g_pSeparateWow != NULL && *g_pSeparateWow == FALSE) { //
// not a separate wow
//
LOGN( eDbgLevelError, "[CheckAndShimNTVDM] running in shared wow, no shimming\n"); return FALSE; }
if (!g_bInitialized) { // first call, link apis
bSuccess = ImportWowApis(); if (!bSuccess) { LOGN( eDbgLevelError, "[CheckAndShimNTVDM] Failed to import apis.\n"); return FALSE; } }
if (IsWOWExec(hTask16)) { LOGN( eDbgLevelError, "[CheckAndShimNTVDM] not touching wowexec\n"); return FALSE; }
csTaskFileName = ShimGetTaskFileName(hTask16); if (csTaskFileName.IsEmpty()) { LOGN( eDbgLevelError, "[CheckAndShimNTVDM] failed to get the filename for task 0x%lx\n", hTask16); return FALSE; } //
// init database
//
hSDB = SdbInitDatabase(0, NULL);
if (hSDB == NULL) { LOGN( eDbgLevelError, "[CheckAndShimNTVDM] failed to init shim database\n"); return FALSE; }
//
// process history please --
// if we end up here, we are a separate ntvdm
// running with a process history in the env, was retrieved in init
//
pTDB = GetTDB(hTask16); if (NULL == pTDB) { LOGN( eDbgLevelError, "[UpdateWowTaskList] Bad TDB entry 0x%x", hTask16); return FALSE; }
//
// Prepare environment data - this buffer is used when we're starting a new task from the
// root of the chain (as opposed to spawning from an existing 16-bit task)
//
pszEnv = ShimGetTaskEnvptr(hTask16); if (NULL != pszEnv) { Status = ShimCloneEnvironment(&pEnvNew, (LPVOID)pszEnv, FALSE); if (!NT_SUCCESS(Status)) { LOGN( eDbgLevelError, "[CheckAndShimNTVDM] cannot clone environment 0x%lx\n", Status); pEnvNew = NULL; bNewEnv = TRUE; }
//
// if this call has come the way of VDM - we need to carry over our environment stuff
// which is stored separately in this shim
//
// should the call to ShimCloneEnvironment fail, we will have pEnvNew == NULL
// and bNewEnv = TRUE, as a result, we shall try again to clone the environment
dwFlags = CREATE_UNICODE_ENVIRONMENT; pEnvNew = ShimCreateWowEnvironment_U(pEnvNew, &dwFlags, bNewEnv); } //
// run detection please
//
bMatch = SdbGetMatchingExe(hSDB, (LPCWSTR)csTaskFileName, NULL, // we can give out module name as well -- but WHY?
(LPCWSTR)pEnvNew, 0, &QueryResult); if (bMatch) { bSuccess = ShimThisProcess(hModShimEngine, hSDB, &QueryResult); } if (pEnvNew != NULL) { ShimFreeEnvironment(pEnvNew); } return bSuccess; }
IMPLEMENT_SHIM_END
|