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.
2513 lines
84 KiB
2513 lines
84 KiB
/*++
|
|
|
|
Module Description:
|
|
|
|
init.c
|
|
|
|
Contains the profiling initialization routines for CAP.DLL
|
|
|
|
|
|
Revision History:
|
|
|
|
2-Feb-95 a-robw (Bob Watson)
|
|
Added this header
|
|
Made the following changes for Windows95 compatibility:
|
|
Replaced OutputDebugString w/ OutputCapDebugString macro
|
|
Replaced image & module scanning functions with those
|
|
supported by PSAPI.DLL
|
|
Replaced KdPrint & DbgPrint with CapDbgPrint function
|
|
|
|
10-Feb-95 a-robw (Bob Watson)
|
|
added support for loading symbols from a .SYM file if no
|
|
COFF symbols are found in the module.
|
|
|
|
--*/
|
|
|
|
#include "cap.h"
|
|
//#include "symfile.h"
|
|
|
|
PSYMINFO pProfSymb;
|
|
PTCHAR pcProfSymbName;
|
|
ULONG ulMinSymb,ulMaxSymb;
|
|
ULONG ulSymbCnt;
|
|
BOOL __stdcall SymbolEnumCallback(LPSTR, ULONG, ULONG, PVOID);
|
|
|
|
#ifdef MIPS
|
|
ULONG ulPenterAddress;
|
|
BOOL fPenterFound = FALSE;
|
|
|
|
BOOL __stdcall FindPenterCallback(LPSTR, ULONG, ULONG, PVOID);
|
|
#endif
|
|
|
|
|
|
/************************** C a l l P r o f M a i n ************************
|
|
*
|
|
* DllMain () -
|
|
* This is call profiler DLL entry routine. It performs
|
|
* DLL's initializations and cleanup.
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN TRUE
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
BOOL WINAPI DllMain (IN HANDLE DllHandle,
|
|
ULONG Reason,
|
|
IN PCONTEXT Context OPTIONAL)
|
|
|
|
{
|
|
DllHandle; // avoid compiler warnings
|
|
Context; // avoid compiler warnings
|
|
|
|
|
|
if (Reason == DLL_PROCESS_ATTACH)
|
|
{
|
|
gfGlobalDebFlag = SETUP_FLAG + INFO_FLAG;
|
|
//gfGlobalDebFlag = 0;
|
|
|
|
//
|
|
// Initialize the DLL data
|
|
//
|
|
OutputCapDebugString("CAP: DLL Process Attach\n");
|
|
SETUPPrint (("Process attaching..\n"));
|
|
if (DoDllInitializations ())
|
|
{
|
|
OutputCapDebugString("CAP: Initialization Successful!\n");
|
|
gfInitializationOK = TRUE;
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
OutputCapDebugString("CAP: Initialization FAILED!\n");
|
|
gfInitializationOK = FALSE;
|
|
return (TRUE);
|
|
// Return FALSE will hang up NT --- HWC 11/12/93
|
|
// return(FALSE);
|
|
}
|
|
}
|
|
|
|
// If fail Init., no need to proceed -- HWC 11/12/93
|
|
// if (gfInitializationOK == FALSE)
|
|
// return (TRUE);
|
|
else if (Reason == DLL_THREAD_ATTACH)
|
|
{
|
|
//
|
|
// Thread is attaching.
|
|
//
|
|
OutputCapDebugString("CAP: DLL Thread Attach\n");
|
|
SETUPPrint (("Thread attaching..\n"));
|
|
RESETCLIENT();
|
|
}
|
|
else if (Reason == DLL_THREAD_DETACH)
|
|
{
|
|
//
|
|
// Thread is detaching, cleanup reserved TEB stuff
|
|
//
|
|
SETCAPINUSE(); // don't done any more data collection
|
|
OutputCapDebugString("CAP: DLL Thread Detach\n");
|
|
SETUPPrint (("Thread detaching..\n"));
|
|
#ifdef KERNEL32_IMPORTS_HACK
|
|
SETCURTHDBLK(NULL);
|
|
RESETCLIENT();
|
|
#endif // KERNEL32_IMPORTS_HACK
|
|
}
|
|
else if (Reason == DLL_PROCESS_DETACH)
|
|
{
|
|
//
|
|
// Cleanup time
|
|
//
|
|
SETCAPINUSE(); // don't done any more data collection
|
|
OutputCapDebugString("CAP: DLL Process Detach\n");
|
|
SETUPPrint (("Process detaching..\n"));
|
|
DoDllCleanups();
|
|
#ifdef KERNEL32_IMPORTS_HACK
|
|
SETCURTHDBLK(NULL);
|
|
RESETCLIENT();
|
|
#endif // KERNEL32_IMPORTS_HACK
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
} /* CallProfMain() */
|
|
|
|
|
|
|
|
|
|
/****************** D o D l l I n i t i a l i z a t i o n s ****************
|
|
*
|
|
* DoDllInitializations () -
|
|
* Performs the following initializations:
|
|
*
|
|
* o Create LOCAL semaphore (not named)
|
|
* o Create named GLOBAL semaphore
|
|
* o Create named DUMP event
|
|
* o Create named CLEAR event
|
|
* o Create named PAUSE event
|
|
* o Initialize timer (QueryPerformanceCounter)
|
|
* o Create/Open global storage for profile object blocks
|
|
* o Locate all the executables/DLLs in the address and
|
|
* create a seperate profile object for each one.
|
|
* o Do the timer calibrations
|
|
* o Allocate virtiual memory for data
|
|
* o Start the DUMP monitor thread
|
|
* o Start the CLEAR monitor thread
|
|
* o Start the PAUSE monitor thread
|
|
* o Set the profiling flag to TRUE
|
|
*
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN TRUE/FALSE
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
|
|
BOOL DoDllInitializations ()
|
|
{
|
|
NTSTATUS Status;
|
|
ANSI_STRING ObjName;
|
|
UNICODE_STRING UnicodeName;
|
|
OBJECT_ATTRIBUTES ObjAttributes;
|
|
PVOID ImageBase;
|
|
ULONG CodeLength;
|
|
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
|
|
ULONG ExportSize;
|
|
PIMAGE_COFF_SYMBOLS_HEADER DebugInfo;
|
|
STRING ImageStringName;
|
|
LARGE_INTEGER AllocationSize;
|
|
ULONG ulViewSize;
|
|
PPROFBLK pTmpProfBlk;
|
|
DWORD BytesRead;
|
|
HANDLE hPatchFile;
|
|
TCHAR atchTmpImageName [MAX_PATH];
|
|
PIMAGE_NT_HEADERS pImageNtHeader;
|
|
HANDLE hLib;
|
|
PTCHAR ptchEntry;
|
|
PIMAGE_SECTION_HEADER pSections;
|
|
PIMAGE_SECTION_HEADER pSectionTmp;
|
|
USHORT NumberOfSections;
|
|
USHORT i;
|
|
PTCHAR ptchTemp;
|
|
ULONG ulRegionSize;
|
|
ULONG ulOldProtect;
|
|
PIMAGE_DEBUG_INFORMATION pImageDbgInfo = NULL;
|
|
BOOLEAN fFoundSymbols = FALSE;
|
|
INT iDir;
|
|
TCHAR szCurrentDirectory[MAX_PATH];
|
|
TCHAR aszCapIniFile[FILENAMELENGTH];
|
|
PTCHAR ptchCurrentString;
|
|
PTCHAR ptchChronoList;
|
|
PTCHAR ptchProfilingStat;
|
|
PTCHAR ptchExcludeList;
|
|
PTCHAR ptchOutputFileList;
|
|
BOOL fSymbolsPresent = FALSE;
|
|
BOOL fProfilingStat = TRUE;
|
|
LARGE_INTEGER liTemp;
|
|
|
|
// new for PSAPI
|
|
//HANDLE hThisProcess; // moved to cap.h
|
|
HMODULE hImageModule;
|
|
MODULEINFO miData;
|
|
HMODULE *hmArray;
|
|
DWORD dwReqdSize;
|
|
DWORD dwTemp;
|
|
DWORD dwModuleIndex;
|
|
DWORD dwLastModule;
|
|
TCHAR ImageName[MAX_PATH];
|
|
TCHAR ImageFullName[MAX_PATH];
|
|
|
|
IMAGEHLP_MODULE ModuleInfo;
|
|
|
|
TlsThdBlk = TlsAlloc();
|
|
|
|
TlsClient = TlsAlloc();
|
|
TlsCapInUse = TlsAlloc();
|
|
if ((TlsThdBlk == 0xffffffff) ||
|
|
(TlsClient == 0xffffffff) ||
|
|
(TlsCapInUse == 0xffffffff))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"TlsAlloc failed - 0x%lx\n",
|
|
GetLastError());
|
|
OutputCapDebugString("CAP: TlsAlloc FAILED!\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
SetSymbolSearchPath();
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
// Create public share security descriptor for all the named objects
|
|
//
|
|
|
|
SecAttributes.nLength = sizeof(SecAttributes);
|
|
SecAttributes.lpSecurityDescriptor = &SecDescriptor;
|
|
SecAttributes.bInheritHandle = FALSE;
|
|
if (!InitializeSecurityDescriptor(&SecDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION1))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"InitializeSecurityDescriptor failed - 0x%lx\n",
|
|
GetLastError());
|
|
OutputCapDebugString("CAP: InitializeSecurityDescriptor FAILED!\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
if (!SetSecurityDescriptorDacl(
|
|
&SecDescriptor, // SecurityDescriptor
|
|
TRUE, // DaclPresent
|
|
NULL, // Dacl
|
|
FALSE // DaclDefaulted
|
|
))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"SetSecurityDescriptorDacl failed - 0x%lx\n",
|
|
GetLastError());
|
|
OutputCapDebugString("CAP: SetSecurityDescriptorDacl FAILED!\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
// Create LOCAL semaphore (not named - only for this process context)
|
|
//
|
|
hLocalSem = CreateSemaphore (&SecAttributes, 1L, 1L, NULL);
|
|
if (hLocalSem == NULL)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"LOCAL semaphore creation failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: CreateSemaphore FAILED!\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Create GLOBAL semaphore creation (named)
|
|
//
|
|
hGlobalSem = CreateSemaphore (&SecAttributes, 1L, 1L, GLOBALSEMNAME);
|
|
if (hGlobalSem == NULL)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"GLOBAL semaphore creation failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: CreateSem GlobalSem FAILED!\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
//
|
|
// Create DONE event
|
|
//
|
|
hDoneEvent = CreateEvent (&SecAttributes, TRUE, FALSE, DONEEVENTNAME);
|
|
if (hDoneEvent == NULL)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"DONE event creation failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: CreateEvent DoneEvent FAILED!\n");
|
|
return (FALSE);
|
|
} else {
|
|
INFOPrint(("CAP: Event Created: %s\n", DONEEVENTNAME));
|
|
}
|
|
|
|
//
|
|
// Create DUMP event
|
|
//
|
|
hDumpEvent = CreateEvent (&SecAttributes, TRUE, FALSE, DUMPEVENTNAME);
|
|
if (hDumpEvent == NULL)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"DUMP event creation failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: CreateEvent DumpEvent FAILED!\n");
|
|
return (FALSE);
|
|
} else {
|
|
INFOPrint(("CAP: Event Created: %s\n", DUMPEVENTNAME));
|
|
}
|
|
|
|
//
|
|
// Create CLEAR event
|
|
//
|
|
hClearEvent = CreateEvent (&SecAttributes, TRUE, FALSE, CLEAREVENTNAME);
|
|
if (hClearEvent == NULL)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"CLEAR event creation failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: CreateEvent ClearEvent FAILED!\n");
|
|
return (FALSE);
|
|
} else {
|
|
INFOPrint(("CAP: Event Created: %s\n", CLEAREVENTNAME));
|
|
}
|
|
|
|
//
|
|
// Create PAUSE event
|
|
//
|
|
hPauseEvent = CreateEvent (&SecAttributes, TRUE, FALSE, PAUSEEVENTNAME);
|
|
if (hPauseEvent == NULL)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"PAUSE event creation failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: CreateEvent PauseEvent FAILED!\n");
|
|
return (FALSE);
|
|
} else {
|
|
INFOPrint(("CAP: Event Created: %s\n", PAUSEEVENTNAME));
|
|
}
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
//
|
|
// Initialize timer
|
|
// frequency of zero implies timer not available - shouldn't happen
|
|
//
|
|
if (!QueryPerformanceFrequency(&liTemp))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"Error getting timer frequency - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: QueryPerformanceFrequency FAILED!\n");
|
|
return (FALSE);
|
|
}
|
|
liTimerFreq = liTemp.QuadPart;
|
|
if (liTimerFreq == (LONGLONG)0)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"Timer frequency is zero - Timer not available!\n");
|
|
OutputCapDebugString("CAP: Timer Frequency ZERO!\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
// Look for CAP.INI file
|
|
hPatchFile = INVALID_HANDLE_VALUE;
|
|
iDir = 0;
|
|
|
|
while (hPatchFile == INVALID_HANDLE_VALUE && iDir < 4)
|
|
{
|
|
// Try four directories in priority order
|
|
switch (iDir)
|
|
{
|
|
case 0:
|
|
// [current directory]
|
|
GetCurrentDirectory(MAX_PATH, szCurrentDirectory);
|
|
break;
|
|
|
|
case 1:
|
|
// [windows_dir]
|
|
GetWindowsDirectory(szCurrentDirectory, MAX_PATH);
|
|
break;
|
|
|
|
case 2:
|
|
// [\]
|
|
szCurrentDirectory[0] = 0;
|
|
break;
|
|
|
|
case 3:
|
|
// [C:\]
|
|
sprintf(szCurrentDirectory, "C:", CAPINI);
|
|
}
|
|
|
|
// Add CAP.INI file name
|
|
sprintf(aszCapIniFile, "%s%s", szCurrentDirectory, CAPINI);
|
|
|
|
// Try to open file for reading
|
|
hPatchFile = CreateFile (
|
|
aszCapIniFile, // The filename
|
|
GENERIC_READ, // Desired access
|
|
FILE_SHARE_READ, // Shared Access
|
|
NULL, // Security Access
|
|
OPEN_EXISTING, // Read share access
|
|
FILE_ATTRIBUTE_NORMAL, // Open option
|
|
NULL); // No template file
|
|
|
|
if (hPatchFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - Error opening %s - "
|
|
"0x%lx\n", aszCapIniFile, GetLastError());
|
|
}
|
|
|
|
iDir++;
|
|
}
|
|
|
|
if (hPatchFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
CapDbgPrint ("CAP: No CAP.INI file found - Terminating...\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
// Read contents of CAP.INI file
|
|
if (!ReadFile (hPatchFile, // DLL patch file handle
|
|
(PVOID)atchPatchBuffer, // Buffer to receive data
|
|
PATCHFILESZ, // Bytes to read
|
|
&BytesRead, // Byte offset
|
|
NULL)) // Target process
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"Error reading %s - 0x%lx\n", aszCapIniFile,
|
|
GetLastError());
|
|
OutputCapDebugString("CAP: ReadFile CAP.ini FAILED!\n");
|
|
return (FALSE);
|
|
}
|
|
else if (BytesRead >= PATCHFILESZ)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"DLL patch buffer too small (%lu)\n", PATCHFILESZ);
|
|
OutputCapDebugString("CAP: PatchBuffer too small to read CAP.INI!\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
atchPatchBuffer [BytesRead] = '\0';
|
|
_strupr (atchPatchBuffer);
|
|
SETUPPrint (("CAP: DoDllInitializations() - atchPatchBuffer "
|
|
"(%lu):\n", BytesRead));
|
|
|
|
ptchCurrentString = atchPatchBuffer;
|
|
|
|
// **** [EXES] section
|
|
if ((ptchPatchExes = strstr (ptchCurrentString, PATCHEXELIST)) == NULL)
|
|
{
|
|
ptchPatchExes = "";
|
|
}
|
|
|
|
// **** [PATCH IMPORTS] section
|
|
if (ptchPatchImports = strstr(ptchCurrentString, PATCHIMPORTLIST))
|
|
{
|
|
*(ptchPatchImports-1) = '\0';
|
|
ptchCurrentString = ptchPatchImports;
|
|
}
|
|
else
|
|
{
|
|
ptchPatchImports = "";
|
|
}
|
|
|
|
// **** [PATCH CALLERS] section
|
|
if (ptchPatchCallers = strstr(ptchCurrentString, PATCHCALLERLIST))
|
|
{
|
|
*(ptchPatchCallers - 1) = '\0';
|
|
ptchCurrentString = ptchPatchCallers;
|
|
|
|
//
|
|
// It's expensive to search through ptchPatchCallers all the time in
|
|
// PatchDll so check up front to see if it's empty.
|
|
//
|
|
// Start at the end ] and see if there is any thing but white space.
|
|
// Unfortunately there doesn't seem to be a str* C runtime to do this.
|
|
//
|
|
ptchTemp = strchr(ptchPatchCallers, ']');
|
|
ptchTemp++;
|
|
bCallersToPatch = FALSE;
|
|
while (*ptchTemp != '\0')
|
|
{
|
|
while (*ptchTemp != '\0' && isspace(*ptchTemp))
|
|
ptchTemp++;
|
|
|
|
if (*ptchTemp == COMMENT_CHAR) // skip to end of line
|
|
{
|
|
while (*ptchTemp != '\0' && *ptchTemp != '\n')
|
|
ptchTemp++;
|
|
}
|
|
else if (*ptchTemp == '[')
|
|
{
|
|
break; // reached start of next section
|
|
}
|
|
else if (*ptchTemp != '\0')
|
|
{
|
|
bCallersToPatch = TRUE;
|
|
break; // There's a dll for which to patch callers
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptchPatchCallers = "";
|
|
bCallersToPatch = FALSE;
|
|
}
|
|
|
|
// **** [NAME LENGTH] section ****
|
|
if (ptchNameLength = strstr (ptchCurrentString, NAMELENGTH) )
|
|
{
|
|
*(ptchNameLength - 1) = '\0';
|
|
ptchCurrentString = ptchNameLength;
|
|
}
|
|
else
|
|
{
|
|
ptchNameLength = "";
|
|
}
|
|
|
|
// **** Check out [CHRONO FUNCS] section
|
|
|
|
if (ptchChronoList = strstr(ptchCurrentString, CHRONO_SECTION))
|
|
{
|
|
//
|
|
// We minus 2 since CHRONO_SECTION does not
|
|
// include the '[' & ']' of "[CHRONO FUNCS]"
|
|
//
|
|
*(ptchChronoList - 2) = '\0';
|
|
ptchCurrentString = ptchChronoList;
|
|
|
|
if (GetPrivateProfileSection(
|
|
CHRONO_SECTION,
|
|
ptchChronoFuncs,
|
|
CHRONO_FUNCS_SIZE,
|
|
aszCapIniFile) == 0)
|
|
{
|
|
ptchChronoFuncs[0] = EMPTY_STRING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptchChronoFuncs[0] = EMPTY_STRING;
|
|
}
|
|
|
|
// **** Check out [EXCLUDE FUNCS] section
|
|
|
|
if (ptchExcludeList = strstr(ptchCurrentString, EXCLUDE_SECTION))
|
|
{
|
|
//
|
|
// We minus 2 since EXCLUDE_SECTION does not
|
|
// include the '[' & ']' of "[EXCLUDE FUNCS]"
|
|
//
|
|
*(ptchExcludeList - 2) = '\0';
|
|
ptchCurrentString = ptchExcludeList;
|
|
|
|
if (GetPrivateProfileSection(
|
|
EXCLUDE_SECTION,
|
|
ptchExcludeFuncs,
|
|
EXCLUDE_FUNCS_SIZE,
|
|
aszCapIniFile) == 0)
|
|
{
|
|
ptchExcludeFuncs[0] = EMPTY_STRING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptchExcludeFuncs[0] = EMPTY_STRING;
|
|
}
|
|
|
|
// **** Check out [OUTPUT FILE] section
|
|
if (ptchOutputFileList = strstr(ptchCurrentString, OUTPUTFILE_SECTION))
|
|
{
|
|
//
|
|
// We minus 2 since OUTPUTFILE_SECTION does not
|
|
// include the '[' & ']' of "[OUTPUT FILE]"
|
|
//
|
|
*(ptchOutputFileList - 2) = '\0';
|
|
ptchCurrentString = ptchOutputFileList;
|
|
|
|
if (GetPrivateProfileSection(
|
|
OUTPUTFILE_SECTION,
|
|
ptchOutputFile,
|
|
FILENAMELENGTH,
|
|
aszCapIniFile) == 0)
|
|
{
|
|
ptchOutputFile[0] = EMPTY_STRING;
|
|
}
|
|
else
|
|
{
|
|
strcpy(ptchOutputFile, (strchr(ptchOutputFile, '=') +
|
|
sizeof(TCHAR)));
|
|
if (ptchOutputFile[0] == '\n')
|
|
{
|
|
ptchOutputFile[0] = EMPTY_STRING;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptchOutputFile[0] = EMPTY_STRING;
|
|
}
|
|
|
|
|
|
// **** Check out [CAP FLAGS] section
|
|
if (ptchProfilingStat = strstr(ptchCurrentString, CAP_FLAGS))
|
|
{
|
|
*(ptchProfilingStat - 1) = '\0';
|
|
ptchProfilingStat += sizeof(CAP_FLAGS);
|
|
|
|
// + 1 to bump past the 0ah
|
|
_strupr(ptchProfilingStat + 1);
|
|
ptchEntry = strstr (ptchProfilingStat + 1, PROFILE_OFF);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fProfilingStat = FALSE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, DUMPBINARY_ON);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fDumpBinary = TRUE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, CAPTHREAD_OFF);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fCapThreadOn = FALSE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, SETJUMP_ON);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fSetJumpOn = TRUE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, LOADLIBRARY_ON);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fLoadLibraryOn = TRUE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, UNDECORATE_OFF);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fUndecorateName = FALSE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, EXCEL_ON);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
cExcelDelimiter = EXCEL_DELIM;
|
|
}
|
|
else
|
|
{
|
|
cExcelDelimiter = ' ';
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, REGULARDUMP_OFF);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fRegularDump = FALSE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, CHRONOCOLLECT_ON);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fChronoCollect = TRUE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, CHRONODUMP_ON);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fChronoDump = TRUE;
|
|
}
|
|
}
|
|
|
|
ptchEntry = strstr (ptchProfilingStat + 1, SLOWSYMBOLS_OFF);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
fSecondChanceTranslation = FALSE;
|
|
}
|
|
}
|
|
ptchEntry = strstr (ptchProfilingStat + 1, PER_THREAD_MEMORY);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry -1) != COMMENT_CHAR)
|
|
{
|
|
ulPerThdAllocSize =
|
|
atoi(ptchEntry+PER_THREAD_MEMORY_CHAR);
|
|
}
|
|
}
|
|
}
|
|
|
|
CloseHandle (hPatchFile);
|
|
|
|
SETUPPrint (("CAP: DoDllInitializations() - Patching info:\n"));
|
|
SETUPPrint (("CAP: -- %s\n", ptchPatchExes));
|
|
SETUPPrint (("CAP: -- %s\n", ptchPatchImports));
|
|
SETUPPrint (("CAP: -- %s\n", ptchPatchCallers));
|
|
SETUPPrint (("CAP: -- %s\n", ptchNameLength));
|
|
|
|
if (ptchNameLength[0] != '\0')
|
|
{
|
|
ptchNameLength += (sizeof(NAMELENGTH));
|
|
iNameLength = atoi (ptchNameLength);
|
|
}
|
|
|
|
if (iNameLength <= 0)
|
|
{
|
|
iNameLength = DEFNAMELENGTH;
|
|
}
|
|
else if (iNameLength < MINNAMELENGTH)
|
|
{
|
|
iNameLength = MINNAMELENGTH;
|
|
}
|
|
else if (iNameLength > MAXNAMELENGTH)
|
|
{
|
|
iNameLength = MAXNAMELENGTH;
|
|
}
|
|
|
|
SETUPPrint (("CAP: -- %d\n", iNameLength));
|
|
|
|
SETUPPrint (("CAP: -- %s\n", ptchChronoList));
|
|
|
|
// BUGBUG This could cause major problem for CapDbgPrint The
|
|
// printing is all garbage... Commented out for now!
|
|
// SETUPPrint (("CAP: -- %s\n", ptchExcludeList);
|
|
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
#ifdef i386
|
|
|
|
if (fSetJumpOn)
|
|
{
|
|
OutputCapDebugString("CAP: SetJmp code activated\n");
|
|
|
|
hLib = LoadLibrary((LPCSTR)CRTDLL);
|
|
if (hLib) {
|
|
longjmpaddr = GetProcAddress(hLib,(LPCSTR)"longjmp");
|
|
if (!longjmpaddr)
|
|
{
|
|
CapDbgPrint ("CAP: [longjmp] GetProcAddress() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
setjmpaddr = GetProcAddress(hLib,(LPCSTR)"_setjmp");
|
|
if (!setjmpaddr)
|
|
{
|
|
CapDbgPrint ("CAP: [_setjmp] GetProcAddress() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
FreeLibrary(hLib);
|
|
}
|
|
else
|
|
{
|
|
CapDbgPrint ("CAP: [crtdll.dll] LoadLibrary() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
#endif // ifdef i386
|
|
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
hLib = LoadLibrary((LPCSTR)KERNEL32);
|
|
if (hLib)
|
|
{
|
|
GetLastErrorAddr = GetProcAddress(hLib,(LPCSTR)"GetLastError");
|
|
if (!GetLastErrorAddr)
|
|
{
|
|
CapDbgPrint ("CAP: [GetLastError] GetProcAddress() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
if (fLoadLibraryOn)
|
|
{
|
|
|
|
loadlibAaddr = GetProcAddress(hLib,(LPCSTR)"LoadLibraryA");
|
|
if (!loadlibAaddr)
|
|
{
|
|
CapDbgPrint ("CAP: [LoadLibraryA] GetProcAddress() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
loadlibExAaddr = GetProcAddress(hLib,(LPCSTR)"LoadLibraryExA");
|
|
if (!loadlibExAaddr)
|
|
{
|
|
CapDbgPrint ("CAP: [LoadLibraryExA] GetProcAddress() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
#ifndef _CHICAGO_
|
|
loadlibWaddr = GetProcAddress(hLib,(LPCSTR)"LoadLibraryW");
|
|
if (!loadlibWaddr)
|
|
{
|
|
CapDbgPrint ("CAP: [LoadLibraryW] GetProcAddress() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
loadlibExWaddr = GetProcAddress(hLib,(LPCSTR)"LoadLibraryExW");
|
|
if (!loadlibExWaddr)
|
|
{
|
|
CapDbgPrint ("CAP: [LoadLibraryExW] GetProcAddress() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
#endif // _CHICAGO_
|
|
}
|
|
FreeLibrary(hLib);
|
|
}
|
|
else {
|
|
CapDbgPrint ("CAP: [kernel32.dll] LoadLibrary() Error: %0lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
try // EXCEPT - to handle access violation exception.
|
|
{ // Access violation might happen since same section is being openned
|
|
// and used by different processes. Each process adds new profile block
|
|
// info to to globally alocated section.
|
|
|
|
//
|
|
// Locate all the executables/DLLs in the address and create a
|
|
// seperate profile object for each one.
|
|
//
|
|
|
|
iPatchCnt = 0;
|
|
hThisProcess = GetCurrentCapProcess();
|
|
hImageModule = GetModuleHandle(NULL);
|
|
|
|
//
|
|
// set image names
|
|
//
|
|
GetModuleBaseName(hThisProcess, hImageModule, ImageName,
|
|
sizeof(ImageName) / sizeof(TCHAR));
|
|
|
|
GetModuleFileNameEx(hThisProcess, hImageModule, ImageFullName,
|
|
sizeof(ImageFullName) / sizeof(TCHAR));
|
|
|
|
ptchBaseAppImageName = GlobalAlloc(GPTR, MAX_PATH*sizeof(TCHAR));
|
|
ptchFullAppImageName = GlobalAlloc(GPTR, MAX_PATH*sizeof(TCHAR));
|
|
|
|
if (ptchBaseAppImageName != 0) {
|
|
lstrcpy(ptchBaseAppImageName, ImageName); // copy image name
|
|
_strupr(ptchBaseAppImageName);
|
|
}
|
|
//
|
|
// Skip the object directory name (if any)
|
|
//
|
|
if (ptchFullAppImageName != NULL) {
|
|
if (strchr(ImageFullName, ':') != NULL)
|
|
{
|
|
lstrcpy (ptchFullAppImageName, (strchr(ImageFullName, ':')-1));
|
|
}
|
|
else
|
|
{
|
|
lstrcpy (ptchFullAppImageName, ImageFullName);
|
|
}
|
|
_strupr(ptchFullAppImageName);
|
|
}
|
|
ptchEntry = strstr (ptchPatchExes, ptchBaseAppImageName);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry - 1) != COMMENT_CHAR)
|
|
{
|
|
// This image is one specified under [EXES]
|
|
fPatchImage = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fPatchImage) // Image is being patched ?
|
|
{
|
|
//
|
|
// Allocate global storage for profile objects' info
|
|
//
|
|
hProfMapObject = CreateFileMapping((HANDLE)0xFFFFFFFF,
|
|
&SecAttributes,
|
|
PAGE_READWRITE | SEC_RESERVE,
|
|
0,
|
|
MEMSIZE,
|
|
PROFOBJSNAME);
|
|
|
|
if (NULL == hProfMapObject)
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"CreateFileMapping() failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: CreateFileMapping CAPProfObjs FAILED!\n");
|
|
}
|
|
|
|
//
|
|
// Map the section - commit the first 4 * COMMIT_SIZE pages
|
|
//
|
|
pulProfBlkShared = MapViewOfFile(hProfMapObject, FILE_MAP_WRITE, 0, 0,
|
|
ulPerThdAllocSize);
|
|
|
|
if (NULL == pulProfBlkShared )
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"MapViewOfFile() failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: MapViewOfFile hProfMapObject FAILED!\n");
|
|
}
|
|
//
|
|
// Commit the first 4*COMMIT_SIZE pages
|
|
//
|
|
if (!VirtualAlloc(pulProfBlkShared , 4*COMMIT_SIZE, MEM_COMMIT,
|
|
PAGE_READWRITE))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"VirtualAlloc() commit failed - 0x%lx\n", GetLastError());
|
|
}
|
|
|
|
// Get the GLOBAL semaphore... (valid accross all process contexts)
|
|
// Prevents anyone else from updating profile block data
|
|
// We only wait for 10secs - If the semaphore is taken we just leave
|
|
// very frustrated.
|
|
//
|
|
if (WAIT_FAILED == WaitForSingleObject (hGlobalSem, INFINITE))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - ERROR - "
|
|
"Wait for GLOBAL semaphore failed - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: DoDllInit - Wait for GLOBAL sem failed\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// 1st ULONG (*pulProfBlkShared) is used by clear/dump/pause threads.
|
|
// 2nd ULONG (*pulProfBlkBase) offset to the first profile block cell
|
|
// followed by actual profile block cells. Please read CAP.H to see
|
|
// structure of profile blocks
|
|
//
|
|
pulProfBlkBase = pulProfBlkShared + 1;
|
|
if (*pulProfBlkBase == 0L)
|
|
{
|
|
*pulProfBlkBase = sizeof(pulProfBlkBase);
|
|
}
|
|
|
|
// get module List
|
|
|
|
dwReqdSize = 1024 * sizeof(HMODULE); // initial size good for 1K modules
|
|
|
|
hmArray = (HMODULE * ) GlobalAlloc (GPTR, dwReqdSize);
|
|
|
|
// Get Process's module list now
|
|
EnumProcessModules (
|
|
hThisProcess,
|
|
hmArray,
|
|
dwReqdSize,
|
|
&dwReqdSize);
|
|
|
|
dwLastModule = dwReqdSize / sizeof(HMODULE);
|
|
|
|
// Init imagehelp symbol handler
|
|
SymInitialize(hThisProcess, NULL, FALSE);
|
|
|
|
if (fUndecorateName == FALSE)
|
|
SymSetOptions(SymGetOptions() & ~SYMOPT_UNDNAME);
|
|
|
|
// Create profile block for each module
|
|
for (dwModuleIndex = 0; dwModuleIndex < dwLastModule; dwModuleIndex++) {
|
|
|
|
GetModuleFileNameEx (
|
|
hThisProcess,
|
|
hmArray[dwModuleIndex],
|
|
ImageFullName,
|
|
sizeof(ImageFullName) / sizeof(TCHAR));
|
|
|
|
SetupProfiling(ImageFullName);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// + : transfer control to the handler (EXCEPTION_EXECUTE_HANDLER)
|
|
// 0 : continue search (EXCEPTION_CONTINUE_SEARCH)
|
|
// - : dismiss exception & continue (EXCEPTION_CONTINUE_EXECUTION)
|
|
//
|
|
except ( AccessXcptFilter (GetExceptionCode(),
|
|
GetExceptionInformation(),
|
|
COMMIT_SIZE) )
|
|
{
|
|
//
|
|
// Should never get here since filter never returns
|
|
// EXCEPTION_EXECUTE_HANDLER.
|
|
//
|
|
CapDbgPrint ("CAP: DoDllInitializations() - *LOGIC ERROR* - "
|
|
"Inside the EXCEPT: (xcpt=0x%lx)\n", GetExceptionCode());
|
|
|
|
} // end of TRY/EXCEPT -------------------------------------------------
|
|
|
|
|
|
/*
|
|
*******************************************************************
|
|
*/
|
|
|
|
if (fPatchImage)
|
|
{
|
|
//
|
|
// Release the GLOBAL semaphore
|
|
//
|
|
if (!ReleaseSemaphore (hGlobalSem, 1, NULL))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllInitializations() - "
|
|
"Error releasing GLOBAL semaphore - 0x%lx\n", GetLastError());
|
|
OutputCapDebugString("CAP: Error Releasing Global Sem\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Do the calibrations
|
|
//
|
|
DoCalibrations ();
|
|
|
|
// Setup initial thread information block count
|
|
//
|
|
iThdCnt = 0;
|
|
|
|
// Start monitor threads
|
|
//
|
|
|
|
if (fCapThreadOn)
|
|
{
|
|
DWORD ThreadId;
|
|
|
|
hDumpThread = CreateThread (
|
|
NULL, // no security attribute
|
|
(DWORD)1024L, // initial stack size
|
|
(LPTHREAD_START_ROUTINE)DumpThread, // thread starting address
|
|
NULL, // no argument for the thread
|
|
(DWORD)0, // no creation flag
|
|
&ThreadId); // address for thread id
|
|
DumpClientId.UniqueThread = (HANDLE)ThreadId;
|
|
|
|
hClearThread = CreateThread (
|
|
NULL, // no security attribute
|
|
(DWORD)1024L, // initial stack size
|
|
(LPTHREAD_START_ROUTINE)ClearThread, // thread starting address
|
|
NULL, // no argument for the thread
|
|
(DWORD)0, // no creation flag
|
|
&ThreadId); // address for thread id
|
|
ClearClientId.UniqueThread = (HANDLE)ThreadId;
|
|
|
|
hPauseThread = CreateThread (
|
|
NULL, // no security attribute
|
|
(DWORD)1024L, // initial stack size
|
|
(LPTHREAD_START_ROUTINE)PauseThread, // thread starting address
|
|
NULL, // no argument for the thread
|
|
(DWORD)0, // no creation flag
|
|
&ThreadId); // address for thread id
|
|
PauseClientId.UniqueThread = (HANDLE)ThreadId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fDllInit = FALSE;
|
|
|
|
SETUPPrint (("CAP: DoDllInitializations() - fProfiling=%s\n",
|
|
fProfilingStat ? "ON" : "OFF"));
|
|
|
|
SETUPPrint (("CAP: DoDllInitializations() - fUndecorateName=%s\n",
|
|
fUndecorateName ? "ON" : "OFF"));
|
|
|
|
if (fPatchImage)
|
|
{
|
|
// Set profiling status to whatever was set in [PROFILING STATUS]
|
|
fProfiling = fProfilingStat;
|
|
// 060494 davidfie -- State is now consistent with StartCAP checks
|
|
fPaused = !fProfiling;
|
|
}
|
|
return (TRUE);
|
|
|
|
} /* DoDllInitializations () */
|
|
|
|
|
|
|
|
|
|
/************************ D o D l l C l e a n u p s ************************
|
|
*
|
|
* DoDllCleanups () -
|
|
* Dumps the end data, closes all semaphores and events, and
|
|
* closes DUMP, CLEAR & PAUSE thread handles.
|
|
*
|
|
* ENTRY -none-
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN -none-
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* DUMP, CLEAR & PAUSE threads are terminated during DLL detaching
|
|
* process, before this cleanup routine is called.
|
|
*
|
|
*/
|
|
|
|
void DoDllCleanups (void)
|
|
{
|
|
NTSTATUS Status;
|
|
int i;
|
|
|
|
|
|
//
|
|
// Dump the profiled info
|
|
//
|
|
if (fProfiling || fPaused)
|
|
{
|
|
fProfiling = FALSE;
|
|
fPaused = FALSE;
|
|
INFOPrint (("CAP: ***** DLL cleanup & data dump started...\n"));
|
|
if (!fDumpBinary)
|
|
{
|
|
DumpProfiledInfo (".END");
|
|
}
|
|
else
|
|
{
|
|
DumpProfiledBinary (".BIN");
|
|
}
|
|
}
|
|
|
|
if (fInThread)
|
|
{
|
|
(*pulProfBlkShared)--;
|
|
fInThread = FALSE;
|
|
if ( *pulProfBlkShared == 0L )
|
|
{
|
|
if (!SetEvent (hDoneEvent))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Setting DONE event failed - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the virtual memory
|
|
//
|
|
|
|
// Unmap and close profile objects block sections
|
|
//
|
|
|
|
#ifdef KERNEL32_IMPORTS_HACK
|
|
// Free patch dll memory
|
|
//
|
|
for (i=0; i<iPatchCnt; i++)
|
|
{
|
|
if (!VirtualFree((PVOID)aPatchDllSec[i].pSec, 0, MEM_RELEASE))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - VirtualFree() - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
// Unmap and close data sections
|
|
//
|
|
for (i=0; i<iThdCnt; i++)
|
|
{
|
|
if (fChronoCollect)
|
|
{
|
|
|
|
if (!UnmapViewOfFile((PVOID)((aSecInfo[i].pthdblk)->pChronoHeadCell)))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - ChronoSec"
|
|
"ERROR - UnmapViewOfFile() - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
if (!CloseHandle(aSecInfo[i].hChronoMapObject))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - hChronoSec"
|
|
"ERROR - CloseHandle() - 0x%lx\n", GetLastError());
|
|
}
|
|
}
|
|
|
|
if (!UnmapViewOfFile((PVOID)aSecInfo[i].pthdblk))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - UnmapViewOfFile() - 0x%lx\n", GetLastError());
|
|
}
|
|
|
|
if (!CloseHandle(aSecInfo[i].hMapObject))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - CloseHandle() section - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
#endif // KERNEL32_IMPORTS_HACK
|
|
|
|
//
|
|
// Close LOCAL semaphore
|
|
//
|
|
if (!CloseHandle (hLocalSem))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"Could not close the LOCAL semaphore - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
//
|
|
// Close GLOBAL semaphore
|
|
//
|
|
if (!CloseHandle (hGlobalSem))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Could not close the GLOBAL semaphore - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
//
|
|
// Close DONE event
|
|
//
|
|
if (!CloseHandle (hDoneEvent))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Could not close the Done event - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
//
|
|
// Close DUMP event
|
|
//
|
|
if (!CloseHandle (hDumpEvent))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Could not close the DUMP event - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
//
|
|
// Close CLEAR event
|
|
//
|
|
if (!CloseHandle (hClearEvent))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Could not close the CLEAR event - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
//
|
|
// Close PAUSE event
|
|
//
|
|
if (!CloseHandle (hPauseEvent))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Could not close the PAUSE event - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
if (fPatchImage)
|
|
{
|
|
// Unmap and close profile objects block sections
|
|
//
|
|
if (!UnmapViewOfFile((PVOID)pulProfBlkShared))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - UnmapViewOfFile() - 0x%lx\n", GetLastError());
|
|
}
|
|
|
|
if (!CloseHandle(hProfMapObject))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - CloseHandle() - 0x%lx\n", GetLastError());
|
|
}
|
|
|
|
//
|
|
// Close thread handles - threads are terminated during DLL detaching
|
|
// process.
|
|
//
|
|
if (!CloseHandle(hDumpThread))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Could not close DUMP thd handle - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
if (!CloseHandle(hClearThread))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Could not close CLEAR thd handle - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
|
|
if (!CloseHandle(hPauseThread))
|
|
{
|
|
CapDbgPrint ("CAP: DoDllCleanups() - "
|
|
"ERROR - Could not close PAUSE thd handle - 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
if (strstr(atchOutFileName, ".END"))
|
|
{
|
|
INFOPrint (("CAP: ...DLL cleanup done & data dumped to %s *****\n",
|
|
atchOutFileName));
|
|
}
|
|
|
|
} /* DoDllCleanups () */
|
|
|
|
|
|
|
|
/****************************** P a t c h D l l ******************************
|
|
*
|
|
* PatchDll (ptchPatchImports, ptchPatchCallers, bCallersToPatch, ptchDllName, pvImageBase) -
|
|
* Patches all the imported entry points for the specified dll.
|
|
*
|
|
* ENTRY ptchPatchImports - list of DLLs to patch all their imports
|
|
* ptchPatchCallers - list of DLLs to patch all their callers
|
|
* bCallersToPatch - true if there are items in the PatchCallers list
|
|
* ptchDllName - name of dll to be patched
|
|
* pvImageBase - image base address
|
|
*
|
|
* EXIT -none-
|
|
*
|
|
* RETURN TRUE/FALSE
|
|
*
|
|
* WARNING:
|
|
* -none-
|
|
*
|
|
* COMMENT:
|
|
* -none-
|
|
*
|
|
*/
|
|
BOOL PatchDll (PTCHAR ptchPatchImports,
|
|
PTCHAR ptchPatchCallers,
|
|
BOOL bCallersToPatch,
|
|
PTCHAR ptchDllName,
|
|
PVOID pvImageBase)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjAttributes;
|
|
LARGE_INTEGER AllocationSize;
|
|
ULONG ulViewSize;
|
|
ULONG ulImportSize;
|
|
PIMAGE_IMPORT_DESCRIPTOR pImports;
|
|
PIMAGE_IMPORT_DESCRIPTOR pImportsTmp;
|
|
PIMAGE_THUNK_DATA ThunkNames;
|
|
ULONG ulNumThunks;
|
|
PVOID pvPatchSec;
|
|
PVOID pvPatchSecThunk;
|
|
BOOL bAllImports = FALSE;
|
|
|
|
BOOL bPatchAllImports = FALSE;
|
|
PTCHAR ptchName;
|
|
|
|
BOOL fPatchDlls = FALSE;
|
|
int iInterceptedCalls = 0;
|
|
BOOL fCrtDllPatched = FALSE;
|
|
BOOL fKernel32Patched = FALSE;
|
|
BOOL fKernel32Import = FALSE;
|
|
BOOL fCrtDll = FALSE;
|
|
BOOL fKernel32 = FALSE;
|
|
BOOL fAlreadyPatched = FALSE;
|
|
PTCHAR ptchEntry;
|
|
|
|
PIMAGE_SECTION_HEADER pSections;
|
|
int cNumberOfSections;
|
|
PVOID pvCalleeImageBase;
|
|
BOOL bCodeImport;
|
|
|
|
#ifdef i386
|
|
PBYTE pbAddr;
|
|
#elif defined(MIPS) || defined(ALPHA) || defined(_PPC_)
|
|
PULONG pulAddr;
|
|
PPATCHCODE pPatchStub;
|
|
ULONG ThunkAddress; // $%^& For ThunkAddress who
|
|
// are not aligned at all
|
|
// (ntimage.h - IMAGE_THUNK_DATA)
|
|
#endif
|
|
|
|
TCHAR atchTmpImageName [256];
|
|
|
|
#ifdef SPEEDUP_INIT
|
|
return(fPatchDlls);
|
|
#endif
|
|
|
|
SETUPPrint(("CAP: PatchDLL (%s) - ImageBase[%lx]\n",
|
|
ptchDllName, pvImageBase));
|
|
|
|
#ifdef MIPS // this is only to fix the problem when
|
|
// KERNEL32.DLL is in [PATCH CALLERS]
|
|
// and CAIROCRT is messing us up
|
|
if ( (lstrcmpi(ptchDllName, CAIROCRT) == 0) ||
|
|
(lstrcmpi(ptchDllName, CRTDLL) == 0) )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
if ( !lstrcmpi (ptchDllName, KERNEL32) )
|
|
{
|
|
fKernel32 = TRUE;
|
|
}
|
|
if ( !lstrcmpi (ptchDllName, CRTDLL) )
|
|
{
|
|
fCrtDll = TRUE;
|
|
}
|
|
|
|
//
|
|
// Patch all the imports?
|
|
//
|
|
ptchEntry = strstr (ptchPatchImports, ptchDllName);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry - 1) != COMMENT_CHAR)
|
|
{
|
|
bPatchAllImports = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!(bPatchAllImports || bCallersToPatch))
|
|
return(FALSE);
|
|
|
|
if (iPatchCnt >= MAX_PATCHES)
|
|
return(FALSE);
|
|
|
|
//
|
|
// Locate the import array for this image/dll
|
|
//
|
|
pImports = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData (
|
|
pvImageBase,
|
|
TRUE,
|
|
IMAGE_DIRECTORY_ENTRY_IMPORT,
|
|
&ulImportSize);
|
|
ulNumThunks = 0L;
|
|
pImportsTmp = pImports;
|
|
for ( ; pImportsTmp && pImportsTmp->Name ; pImportsTmp++)
|
|
{
|
|
strcpy (atchTmpImageName,
|
|
(PTCHAR) ((ULONG)pvImageBase + pImportsTmp->Name));
|
|
ptchName = _strupr (atchTmpImageName);
|
|
|
|
if (!bPatchAllImports) // don't waste time if we're patching everything
|
|
{
|
|
ptchEntry = strstr (ptchPatchCallers, ptchName);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry-1) == COMMENT_CHAR)
|
|
{
|
|
ptchEntry = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( lstrcmpi(ptchName, CAPDLL) &&
|
|
(bPatchAllImports || ptchEntry))
|
|
{
|
|
SETUPPrint(("CAP: PatchDll (%s) - ImportThunk[%s]\n",
|
|
ptchDllName, ptchName));
|
|
|
|
ThunkNames = (PIMAGE_THUNK_DATA) ((ULONG)pvImageBase +
|
|
(ULONG)pImportsTmp->FirstThunk);
|
|
if ( !strcmp (ptchName, KERNEL32))
|
|
{
|
|
fKernel32Import = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fKernel32Import = FALSE;
|
|
}
|
|
//
|
|
// We need to check every thunk to see if it's a data or code
|
|
// import. We do this by getting the section list for the
|
|
// image we are thunking too and then checking the sections
|
|
// to see if they have the exe bit set.
|
|
//
|
|
pSections = NULL;
|
|
while (ThunkNames->u1.Function) // Could happen for imports
|
|
{ // that are optimized away
|
|
//
|
|
// Don't patch GetLastError as cap will set the error value
|
|
//
|
|
if (fKernel32Import &&
|
|
(GetLastErrorAddr == (FARPROC)ThunkNames->u1.Function)) {
|
|
ThunkNames++;
|
|
continue;
|
|
}
|
|
if (pSections == NULL) {
|
|
// see if this function points inside a module, if it
|
|
// does, then a section list for that module will
|
|
// be returned
|
|
|
|
pSections = GetSectionListFromAddress(
|
|
ThunkNames->u1.Function,
|
|
&cNumberOfSections, &pvCalleeImageBase);
|
|
}
|
|
//
|
|
// As long as Function is not NULL, a thunk contains
|
|
// valid data. If Function is NULL, it indicates
|
|
// the previous entry is the last valid thunk.
|
|
//
|
|
if (IsCodeAddress(ThunkNames->u1.Function, pSections,
|
|
cNumberOfSections, pvCalleeImageBase)) {
|
|
ulNumThunks++; // count code imports
|
|
}
|
|
#if defined(i386) && defined(_CHICAGO)
|
|
else {
|
|
// the thunk did not point inside a valid code section
|
|
// of a module in the image. as a last chance, see if
|
|
// it's a push instruction, if so assume it's a
|
|
// part of a push & call/jump instruction
|
|
// see if this is a Push Immediate Longword or Byte
|
|
// instruction
|
|
if ((*(BYTE *)(ThunkNames->u1.Function) == 0x6A) ||
|
|
(*(BYTE *)(ThunkNames->u1.Function) == 0x68)) {
|
|
// then we'll assume this is really code and
|
|
// not data
|
|
ulNumThunks++; // count code imports
|
|
} else {
|
|
INFOPrint (("CAP: Unknown Thunk type found at address 0x%8.8x (Data: 0x%8.8x)",
|
|
(ThunkNames->u1.Function),
|
|
*(ULONG *)(ThunkNames->u1.Function)));
|
|
}
|
|
}
|
|
#endif
|
|
// Bump to next thunk
|
|
ThunkNames++;
|
|
} // end list of valid thunks
|
|
}
|
|
} // for (;pImportsTmp; pImportsTmp++)
|
|
|
|
|
|
if (ulNumThunks == 0L)
|
|
{
|
|
fPatchDlls = FALSE;
|
|
INFOPrint (("\n"));
|
|
}
|
|
else
|
|
{
|
|
fPatchDlls = TRUE;
|
|
INFOPrint (("(patched)\n"));
|
|
|
|
//
|
|
// Allocate storage for patch code for the current image
|
|
//
|
|
(PVOID)aPatchDllSec[iPatchCnt].pSec = VirtualAlloc(0,
|
|
ulNumThunks * sizeof(PATCHCODE),
|
|
MEM_COMMIT,
|
|
PAGE_EXECUTE_READWRITE);
|
|
|
|
if (aPatchDllSec[iPatchCnt].pSec == NULL)
|
|
{
|
|
CapDbgPrint ("CAP: PatchDll() - "
|
|
"VirtualAlloc() failed - 0x%lx\n", GetLastError());
|
|
}
|
|
|
|
//
|
|
// Initialization of structures which contain the patched
|
|
// thunk templates
|
|
//
|
|
#if defined(MIPS)
|
|
|
|
#ifdef MIPS_VC40_INTERFACE
|
|
PatchStub.Or_t9_ra = 0x03e0c825;
|
|
PatchStub.Lui_t0_penter = 0x3c080000 | (((ULONG)&penter & 0xffff0000) >> 16);
|
|
PatchStub.Ori_t0_penter = 0x35080000 | ((ULONG)&penter & 0x0000ffff);
|
|
PatchStub.Jalr_t0 = 0x0100f809;
|
|
PatchStub.Nop_1 = 0x00000000;
|
|
PatchStub.Or_ra_t9 = 0x0320f825;
|
|
PatchStub.Lui_t0 = 0x3c080000;
|
|
PatchStub.Ori_t0 = 0x35080000;
|
|
PatchStub.Jr_t0 = 0x01000008;
|
|
PatchStub.Nop_2 = 0x00000000;
|
|
PatchStub.OurSignature = STUB_SIGNATURE;
|
|
#else
|
|
PatchStub.Addiu_sp_sp_imm = 0x27bdfff8;
|
|
PatchStub.Sw_ra_sp = 0xafbf0004;
|
|
PatchStub.Lui_t0_ra = 0x3c080000 | (((ULONG)&penter & 0xffff0000) >> 16);
|
|
PatchStub.Ori_t0_ra = 0x35080000 | ((ULONG)&penter & 0x0000ffff);
|
|
PatchStub.Jalr_t0 = 0x0100f809;
|
|
PatchStub.Addiu_r0_r0 = 0x24001804;
|
|
PatchStub.Lw_ra_sp = 0x8fbf0004;
|
|
PatchStub.Lui_t0 = 0x3c080000;
|
|
PatchStub.Ori_t0 = 0x35080000;
|
|
PatchStub.Jr_t0 = 0x01000008;
|
|
PatchStub.Delay_Inst = 0x27bd0008;
|
|
PatchStub.OurSignature = STUB_SIGNATURE;
|
|
#endif //MIPS_VC40_INTERFACE
|
|
|
|
#elif defined(ALPHA)
|
|
|
|
PatchStub.Lda_sp_sp_imm = 0x23defff0;
|
|
PatchStub.Stq_v0_sp = 0xb41e0000;
|
|
PatchStub.Ldah_t12_ra = (((ULONG) &penter) & 0xffff0000) >> 16;
|
|
PatchStub.Ldah_t12_ra |= 0x277f0000;
|
|
|
|
if (((ULONG) &penter) & 0x00008000)
|
|
{
|
|
// need to add one to the upper address because Lda
|
|
// will substract one from it.
|
|
PatchStub.Ldah_t12_ra += 1;
|
|
}
|
|
|
|
PatchStub.Lda_t12_ra = ((ULONG) &penter) & 0x0000ffff;
|
|
PatchStub.Lda_t12_ra |= 0x237b0000;
|
|
PatchStub.Jsr_t12 = 0x681b4000;
|
|
PatchStub.Ldq_v0_sp = 0xa41e0000;
|
|
PatchStub.Lda_sp_sp = 0x23de0010;
|
|
PatchStub.Ldah_t12 = 0x277f0000;
|
|
PatchStub.Lda_t12 = 0x237b0000;
|
|
PatchStub.Jmp_t12 = 0x6bfb0000;
|
|
PatchStub.Bis_0 = 0x47ff041f;
|
|
PatchStub.OurSignature = STUB_SIGNATURE;
|
|
|
|
#elif defined(_PPC_)
|
|
|
|
// For PPC Stub in *** LittleEndian *** order
|
|
PatchStub.TOC = GetTOC();
|
|
|
|
PatchStub.addis_UH_penter = 0x3D600000 |
|
|
(((ULONG )&penter & 0xFFFF0000) >> 16);
|
|
PatchStub.ori_LH_penter = 0x616C0000 |
|
|
(((ULONG )&penter & 0x0000FFFF));
|
|
PatchStub.lwz_r11_0r12 = 0x816C0000;
|
|
PatchStub.mtctr_r11 = 0x7D6903A6;
|
|
PatchStub.mflr_r0 = 0x7C0802A6;
|
|
PatchStub.bctrl = 0x4E800421;
|
|
PatchStub.mtlr_r0 = 0x7C0803A6;
|
|
PatchStub.addis_UH_ep = 0x3D600000;
|
|
PatchStub.ori_LH_ep = 0x616C0000;
|
|
PatchStub.lwz_r11_0r12_ = 0x816C0000;
|
|
PatchStub.mtctr_r11_ = 0x7D6903A6;
|
|
PatchStub.lwz_r2_4r12 = 0x804C0004;
|
|
PatchStub.bctr = 0x4E800420;
|
|
PatchStub.OurSignature = STUB_SIGNATURE;
|
|
#endif // MIPS || ALPHA || _PPC_
|
|
|
|
//
|
|
// Munge the section and tables
|
|
//
|
|
pvPatchSec = aPatchDllSec[iPatchCnt].pSec;
|
|
pImportsTmp = pImports;
|
|
for ( ; pImportsTmp && pImportsTmp->Name ; pImportsTmp++)
|
|
{
|
|
strcpy (atchTmpImageName,
|
|
(PTCHAR) ((ULONG)pvImageBase + pImportsTmp->Name));
|
|
ptchName = _strupr (atchTmpImageName);
|
|
|
|
if (!bPatchAllImports) // don't waste time if we're patching everything
|
|
{
|
|
ptchEntry = strstr (ptchPatchCallers, ptchName);
|
|
if (ptchEntry)
|
|
{
|
|
if (*(ptchEntry - 1) == COMMENT_CHAR)
|
|
{
|
|
ptchEntry = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( lstrcmpi (ptchName, CAPDLL) &&
|
|
(bPatchAllImports || ptchEntry) )
|
|
{
|
|
INFOPrint (("CAP: -- %s\n", ptchName));
|
|
ThunkNames = (PIMAGE_THUNK_DATA)
|
|
((ULONG)pvImageBase +
|
|
(ULONG)pImportsTmp->FirstThunk);
|
|
|
|
if (!ThunkNames->u1.Function) // Could happen for imports
|
|
{ // that are optimized away
|
|
continue;
|
|
}
|
|
|
|
if ( !strcmp (ptchName, KERNEL32))
|
|
{
|
|
fKernel32Patched = TRUE;
|
|
fKernel32Import = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fKernel32Import = FALSE;
|
|
}
|
|
pSections = GetSectionListFromAddress(ThunkNames->u1.Function,
|
|
&cNumberOfSections, &pvCalleeImageBase);
|
|
|
|
// Find the first code import
|
|
while (ThunkNames->u1.Function)
|
|
{
|
|
//
|
|
// Don't patch GetLastError as cap will set the error value
|
|
//
|
|
if (fKernel32Import &&
|
|
(GetLastErrorAddr == (FARPROC)ThunkNames->u1.Function)) {
|
|
}
|
|
else if (IsCodeAddress(ThunkNames->u1.Function, pSections,
|
|
cNumberOfSections, pvCalleeImageBase)) {
|
|
// a code thunk was found so bail out of the loop now
|
|
break;
|
|
}
|
|
#if defined(i386) && defined(_CHICAGO)
|
|
else {
|
|
// not a code address, so see if it points to a
|
|
// thunk "signature" (i.e. a push immediate inst.)
|
|
if ((*(BYTE *)(ThunkNames->u1.Function) == 0x6A) ||
|
|
(*(BYTE *)(ThunkNames->u1.Function) == 0x68)) {
|
|
// then we'll assume this is really code and
|
|
// not data and exit the loop
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
// try the next one
|
|
ThunkNames++;
|
|
}
|
|
//
|
|
// Check for no imports (they may have been optimized
|
|
// away and the dll dependencies not cleaned up)
|
|
//
|
|
#ifdef i386
|
|
pbAddr = (PBYTE)(ThunkNames->u1.Function);
|
|
if (!pbAddr)
|
|
|
|
#elif defined(MIPS) || defined(ALPHA) || defined(_PPC_)
|
|
pulAddr = (PULONG ) (ThunkNames->u1.Function);
|
|
if (!pulAddr)
|
|
#endif
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Are we already patched? If so set a flag.
|
|
// Check for our signature:
|
|
//
|
|
#ifdef i386
|
|
// call CAP!_penter 0xe8 _penter
|
|
//
|
|
// mov eax, Function 0xb8 dwAddr
|
|
// jmp eax 0xe0ff
|
|
//
|
|
//
|
|
if ((*pbAddr == 0xe8) &&
|
|
(*(pbAddr + 5) == 0xb8) &&
|
|
(*( PWORD)(pbAddr + 10) == 0xe0ff) &&
|
|
(*(PDWORD)(pbAddr + 14) == STUB_SIGNATURE))
|
|
{
|
|
fAlreadyPatched = TRUE;
|
|
}
|
|
#elif defined(MIPS)
|
|
|
|
#ifdef MIPS_VC40_INTERFACE
|
|
// or t9, ra, zero (+ 0) 0x03e0c825
|
|
// lui t0, xxxx (+ 1) 0x3c08----
|
|
// ori t0, xxxx (+ 2) 0x3508----
|
|
// jalr t0 (+ 3) 0x0100f809
|
|
// nop (+ 4) 0x00000000
|
|
// or ra, t9, zero (+ 5) 0x0320f825
|
|
// lui t0, xxxx (+ 6) 0x3c08----
|
|
// ori t0, xxxx (+ 7) 0x3508----
|
|
// jr t0 (+ 8) 0x01000008
|
|
// nop (+ 9) 0x00000000
|
|
// $(FEFE55AA) (+10) STUB_SIGNATURE
|
|
|
|
if ( (*pulAddr == 0x03e0c825) &&
|
|
((*(pulAddr + 1) & 0xffff0000) == 0x3c080000) &&
|
|
((*(pulAddr + 2) & 0xffff0000) == 0x35080000) &&
|
|
(*(pulAddr + 3) == 0x0100f809) &&
|
|
(*(pulAddr + 4) == 0x00000000) &&
|
|
(*(pulAddr + 5) == 0x0320f825) &&
|
|
((*(pulAddr + 6) & 0xffff0000) == 0x3c080000) &&
|
|
((*(pulAddr + 7) & 0xffff0000) == 0x35080000) &&
|
|
(*(pulAddr + 8) == 0x01000008) &&
|
|
(*(pulAddr + 9) == 0x00000000) &&
|
|
(*(pulAddr +10) == STUB_SIGNATURE) )
|
|
{
|
|
fAlreadyPatched = TRUE;
|
|
}
|
|
#else
|
|
// addiu sp, sp, -8 (+ 0) 0x27bdfff8
|
|
// sw ra, 4(sp) (+ 1) 0xafbf0004
|
|
// lui t0, xxxx (+ 2) 0x3c08----
|
|
// ori t0, xxxx (+ 3) 0x3508----
|
|
// jalr t0 (+ 4) 0x0100f809
|
|
// addiu $0, $0, 0x1804 (+ 5) 0x24001804
|
|
// lw ra, 4(sp) (+ 6) 0x8fbf0004
|
|
// lui t0, xxxx (+ 7) 0x3c08----
|
|
// ori t0, t0, xxxx (+ 8) 0x3508----
|
|
// jr t0 (+ 9) 0x01000008
|
|
// addiu sp, sp, 8 (+ A) 0x27bd0008
|
|
// $(FEFE55AA) (+ B) STUB_SIGNATURE
|
|
|
|
if ( (*pulAddr == 0x27bdfff8) &&
|
|
(*(pulAddr + 1) == 0xafbf0004) &&
|
|
((*(pulAddr + 2) & 0xffff0000) == 0x3c080000) &&
|
|
((*(pulAddr + 3) & 0xffff0000) == 0x35080000) &&
|
|
(*(pulAddr + 4) == 0x0100f809) &&
|
|
(*(pulAddr + 5) == 0x24001804) &&
|
|
(*(pulAddr + 6) == 0x8fbf0004) &&
|
|
((*(pulAddr + 7) & 0xffff0000) == 0x3c080000) &&
|
|
((*(pulAddr + 8) & 0xffff0000) == 0x35080000) &&
|
|
(*(pulAddr + 9) == 0x01000008) &&
|
|
(*(pulAddr + 10) == 0x27bd0008) &&
|
|
(*(pulAddr + 11) == STUB_SIGNATURE) )
|
|
{
|
|
fAlreadyPatched = TRUE;
|
|
}
|
|
#endif //MIPS_VC40_INTERFACE
|
|
|
|
#elif defined (ALPHA)
|
|
if ( (*pulAddr == 0x23defff0) &&
|
|
(*(pulAddr + 1) == 0xb41e0000) &&
|
|
((*(pulAddr + 2) & 0xffff0000) == 0x277f0000) &&
|
|
((*(pulAddr + 3) & 0xffff0000) == 0x237b0000) &&
|
|
(*(pulAddr + 4) == 0x681b4000) &&
|
|
(*(pulAddr + 5) == 0xa41e0000) &&
|
|
(*(pulAddr + 6) == 0x23de0010) &&
|
|
((*(pulAddr + 7) & 0xffff0000) == 0x277f0000) &&
|
|
((*(pulAddr + 8) & 0xffff0000) == 0x237b0000) &&
|
|
(*(pulAddr + 9) == 0x6bfb0000) &&
|
|
(*(pulAddr + 10) == 0x47ff041f) &&
|
|
(*(pulAddr + 11) == STUB_SIGNATURE) )
|
|
{
|
|
fAlreadyPatched = TRUE;
|
|
}
|
|
#elif defined(_PPC_)
|
|
if ( (*pulAddr + 15 == STUB_SIGNATURE))
|
|
fAlreadyPatched = TRUE;
|
|
#endif
|
|
if ( !fAlreadyPatched )
|
|
{
|
|
while (ThunkNames->u1.Function)
|
|
{
|
|
|
|
//
|
|
// Don't patch GetLastError as cap will set the error value
|
|
//
|
|
if (fKernel32Import &&
|
|
(GetLastErrorAddr == (FARPROC)ThunkNames->u1.Function)) {
|
|
ThunkNames++;
|
|
continue;
|
|
}
|
|
bCodeImport = IsCodeAddress(ThunkNames->u1.Function,
|
|
pSections,
|
|
cNumberOfSections,
|
|
pvCalleeImageBase);
|
|
|
|
#if defined(i386) && defined(_CHICAGO)
|
|
if (!bCodeImport)
|
|
{
|
|
// see if this is a pointer to a table outside
|
|
// the module by checking whats at the address
|
|
if ((*(BYTE *)(ThunkNames->u1.Function) == 0x6A) ||
|
|
(*(BYTE *)(ThunkNames->u1.Function) == 0x68))
|
|
// then we'll assume this is really code and
|
|
// not data
|
|
bCodeImport = TRUE;
|
|
}
|
|
#endif //defined(i386) && defined(_CHICAGO)
|
|
|
|
if (!bCodeImport)
|
|
{
|
|
// no code to patch so go to next thunk
|
|
ThunkNames++;
|
|
continue;
|
|
}
|
|
|
|
pvPatchSecThunk = pvPatchSec;
|
|
|
|
//
|
|
// The goal here is to correctly emulate the same
|
|
// environment as what the compiler emits for
|
|
// every function call. The scenario for DLL is
|
|
// a little different than calling an internal
|
|
// function:
|
|
#ifdef i386
|
|
//
|
|
// a. Call Commnot!MemAlloc
|
|
// RetAddrX:
|
|
//
|
|
// b. The thunk will jump to the code so by the
|
|
// time we get to the code, only RetAddrX is
|
|
// on the stack. This will cause penter to
|
|
// fail. Therefore, the following code
|
|
// emulates the same settings that exist in
|
|
// the code generated by the compiler.
|
|
//
|
|
// mov eax, OFFSET _penter
|
|
// call eax
|
|
// mov eax, OFFSET Function
|
|
// jmp eax
|
|
//
|
|
// This way, by the time we enter _penter,
|
|
// the stack looks like this:
|
|
//
|
|
// +----------------+
|
|
// | RetAddrX | <--- Real Addr to return
|
|
// +----------------+
|
|
// | RealAddrOfFunc | <--- Func to profile
|
|
// +----------------+
|
|
// | ... |
|
|
//
|
|
//
|
|
|
|
|
|
//
|
|
// mov eax, OFFSET _penter
|
|
// call eax
|
|
//
|
|
*(PBYTE)pvPatchSec = 0xe8;
|
|
((PBYTE)pvPatchSec)++;
|
|
*(PDWORD)pvPatchSec = (DWORD)_penter -
|
|
(DWORD)((PBYTE)pvPatchSec + 4);
|
|
((PDWORD)pvPatchSec)++;
|
|
|
|
//
|
|
// mov eax, OFFSET Function ; Jmp to thunk
|
|
// jmp eax
|
|
//
|
|
*(PBYTE)pvPatchSec = 0xb8;
|
|
((PBYTE)pvPatchSec)++;
|
|
*(PDWORD)pvPatchSec = (DWORD)ThunkNames->u1.Function;
|
|
((PDWORD)pvPatchSec)++;
|
|
*(PWORD)pvPatchSec = 0xe0ff;
|
|
((PWORD)pvPatchSec)++;
|
|
|
|
*(PDWORD)pvPatchSec = (DWORD)STUB_SIGNATURE;
|
|
((PDWORD)pvPatchSec)++;
|
|
#elif defined(MIPS)
|
|
//
|
|
// a. jal Commnot!MemAlloc
|
|
// RetAddrX:
|
|
//
|
|
// b. The thunk will jump to the code so by the
|
|
// time we get to the code, only RetAddrX is
|
|
// set in $ra. _penter will not even be in
|
|
// the picture since the DLL was not compiled
|
|
// with -Gh.
|
|
//
|
|
// Therefore, the following code emulates the
|
|
// same code that get generated by the compiler.
|
|
//
|
|
// addiu sp, sp, -0x..
|
|
// sw ra, 4(sp)
|
|
// ... ...
|
|
// jal _penter <---- inserted code
|
|
// addiu $0, $0, 0x.. by -Gh
|
|
// ... ...
|
|
//
|
|
// This way by the time we enter the MemAlloc
|
|
// routine, $ra is set to somewhere in _penter
|
|
//
|
|
|
|
SETUPPrint(("CAP: Patching [%s] Imports of [%s]\n",
|
|
ptchName,
|
|
ptchDllName));
|
|
|
|
{ // Move the stub into the shared memory
|
|
int i;
|
|
pPatchStub = &PatchStub;
|
|
for (i = 0; i < sizeof(PATCHCODE); i++)
|
|
{
|
|
(BYTE) *((PBYTE)pvPatchSec + i) =
|
|
*((PBYTE)pPatchStub + i);
|
|
}
|
|
}
|
|
|
|
pPatchStub = (PPATCHCODE) pvPatchSec;
|
|
(PBYTE) pvPatchSec += sizeof(PATCHCODE);
|
|
|
|
pPatchStub->Lui_t0 |=
|
|
((DWORD)ThunkNames->u1.Function & 0xffff0000) >> 16;
|
|
pPatchStub->Ori_t0 |=
|
|
(DWORD)ThunkNames->u1.Function & 0x0000ffff;
|
|
#elif defined (ALPHA)
|
|
|
|
SETUPPrint(("CAP: Patching [%s] Imports of [%s]\n", ptchName, ptchDllName));
|
|
|
|
{ // Move the stub into the shared memory
|
|
int i;
|
|
pPatchStub = &PatchStub;
|
|
for (i = 0; i < sizeof(PATCHCODE); i++)
|
|
{
|
|
(BYTE) *((PBYTE)pvPatchSec + i) =
|
|
*((PBYTE)pPatchStub + i);
|
|
}
|
|
}
|
|
|
|
pPatchStub = (PPATCHCODE) pvPatchSec;
|
|
(PBYTE) pvPatchSec += sizeof(PATCHCODE);
|
|
|
|
// now move in the actual thunk address
|
|
pPatchStub->Ldah_t12 |= ((DWORD) ThunkNames->u1.Function
|
|
& 0xffff0000) >> 16;
|
|
if ((DWORD)ThunkNames->u1.Function & 0x000008000)
|
|
{
|
|
pPatchStub->Ldah_t12 += 1;
|
|
}
|
|
|
|
pPatchStub->Lda_t12 |=
|
|
(DWORD)ThunkNames->u1.Function & 0x0000ffff;
|
|
#elif defined(_PPC_)
|
|
|
|
SETUPPrint(("CAP: Patching [%s] Imports of [%s]\n", ptchName, ptchDllName));
|
|
{ // Move the stub into the shared memory
|
|
int i;
|
|
|
|
pPatchStub = &PatchStub;
|
|
|
|
for (i = 0; i < sizeof(PATCHCODE); i++)
|
|
{
|
|
(BYTE) *((PBYTE)pvPatchSec + i) =
|
|
*((PBYTE)pPatchStub + i);
|
|
}
|
|
}
|
|
|
|
pPatchStub = (PPATCHCODE) pvPatchSec;
|
|
(PBYTE) pvPatchSec += sizeof(PATCHCODE);
|
|
|
|
// now move in the actual thunk address
|
|
|
|
pPatchStub->EntryPoint = (PVOID )
|
|
&(pPatchStub->addis_UH_penter);
|
|
pPatchStub->addis_UH_ep |=
|
|
(((DWORD) ThunkNames->u1.Function
|
|
& 0xffff0000) >> 16);
|
|
pPatchStub->ori_LH_ep |=
|
|
((DWORD) ThunkNames->u1.Function
|
|
& 0x0000ffff);
|
|
|
|
#endif // ifdef i386 || MIPS || ALPHA || PPC
|
|
|
|
// Point the thunk to the PatchSec
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = pvPatchSecThunk;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
ThunkNames++;
|
|
} // while (ThunkNames->u1.Function)
|
|
} // if ( !fAlreadyPatched )
|
|
if ( fAlreadyPatched )
|
|
{
|
|
INFOPrint (("CAP: -- %s\n", ptchName));
|
|
}
|
|
else
|
|
{
|
|
INFOPrint (("CAP: ++ %s\n", ptchName));
|
|
}
|
|
} // if ( lstrcmpi (ptchName, CAPDLL) && ...
|
|
} // for (;pImportsTmp; pImportsTmp++)
|
|
}
|
|
|
|
//
|
|
// Are we already patched? If so abandon operation.
|
|
//
|
|
if (fAlreadyPatched)
|
|
{
|
|
if (VirtualFree(aPatchDllSec[iPatchCnt].pSec, 0, MEM_RELEASE))
|
|
{
|
|
CapDbgPrint ("CAP: PatchDll() - "
|
|
"ERROR - VirtualFree() - 0x%lx\n", GetLastError());
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Now take care of intercepted calls: setjmp, longjmp, LoadLibrary calls
|
|
//
|
|
if ( (!fCrtDll) &&
|
|
(!fKernel32) &&
|
|
(
|
|
#ifdef i386
|
|
(setjmpaddr) ||
|
|
(longjmpaddr) ||
|
|
#endif
|
|
(loadlibAaddr) ||
|
|
(loadlibExAaddr)
|
|
#ifndef _CHICAGO_
|
|
|| (loadlibWaddr)
|
|
|| (loadlibExWaddr)
|
|
#endif // _CHICAGO_
|
|
))
|
|
{
|
|
for ( ; pImports && pImports->Name ; pImports++)
|
|
{
|
|
strcpy (atchTmpImageName,
|
|
(PTCHAR)((ULONG)pvImageBase + pImports->Name));
|
|
ptchName = _strupr (atchTmpImageName);
|
|
|
|
#ifdef i386
|
|
|
|
if ( !strcmp (ptchName, CRTDLL) )
|
|
{
|
|
iInterceptedCalls = 0;
|
|
ThunkNames = (PIMAGE_THUNK_DATA)
|
|
((ULONG) pvImageBase +
|
|
(ULONG) pImports->FirstThunk);
|
|
|
|
while (ThunkNames->u1.Function)
|
|
{
|
|
if (fCrtDllPatched)
|
|
{
|
|
//
|
|
// The thunk has been patched but we can get the orignal address
|
|
// by looking in the stub. See the stub generation above.
|
|
//
|
|
ULONG *FuncAddress = (ULONG *)(((PBYTE)ThunkNames->u1.Function) + 6);
|
|
|
|
if (*FuncAddress == (ULONG)setjmpaddr)
|
|
{
|
|
*FuncAddress = (ULONG)CAP_SetJmp;
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) setjmp() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (*FuncAddress == (ULONG)longjmpaddr)
|
|
{
|
|
*FuncAddress = (ULONG)CAP_LongJmp;
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) longjmp() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ThunkNames->u1.Function == (PULONG)setjmpaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_SetJmp;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"setjmp() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkNames->u1.Function == (PULONG)longjmpaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LongJmp;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"longjmp() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
}
|
|
|
|
if (iInterceptedCalls == 2)
|
|
{
|
|
break;
|
|
}
|
|
ThunkNames++;
|
|
}
|
|
}
|
|
|
|
#endif // ifdef i386
|
|
|
|
if ( !strcmp (ptchName, KERNEL32) )
|
|
{
|
|
iInterceptedCalls = 0;
|
|
ThunkNames = (PIMAGE_THUNK_DATA)
|
|
((ULONG)pvImageBase+(ULONG)pImports->FirstThunk);
|
|
|
|
while (ThunkNames->u1.Function)
|
|
{
|
|
#ifdef i386
|
|
if (fKernel32Patched)
|
|
{
|
|
//
|
|
// The thunk has been patched but we can get the orignal address
|
|
// by looking in the stub. See the stub generation above.
|
|
//
|
|
ULONG *FuncAddress = (ULONG *)(((PBYTE)ThunkNames->u1.Function) + 6);
|
|
|
|
if (*FuncAddress == (ULONG)loadlibAaddr)
|
|
{
|
|
(*FuncAddress) = (ULONG)CAP_LoadLibraryA;
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) LoadLibraryA() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (*FuncAddress == (ULONG)loadlibExAaddr)
|
|
{
|
|
(*FuncAddress) = (ULONG) CAP_LoadLibraryExA;
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) LoadLibraryExA() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
#ifndef _CHICAGO_
|
|
else if (*FuncAddress == (ULONG)loadlibWaddr)
|
|
{
|
|
(*FuncAddress) = (ULONG)CAP_LoadLibraryW;
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) LoadLibraryW() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (*FuncAddress == (ULONG)loadlibExWaddr)
|
|
{
|
|
(*FuncAddress) = (ULONG)CAP_LoadLibraryExW;
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) LoadLibraryExW() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
#endif // !_CHICAGO_
|
|
}
|
|
else
|
|
{
|
|
if (ThunkNames->u1.Function == (PULONG)loadlibAaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LoadLibraryA;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"LoadLibraryA() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkNames->u1.Function == (PULONG)loadlibExAaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LoadLibraryExA;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"LoadLibraryExA() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
#ifndef _CHICAGO_
|
|
else if (ThunkNames->u1.Function == (PULONG)loadlibWaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LoadLibraryW;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"LoadLibraryW() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkNames->u1.Function == (PULONG)loadlibExWaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LoadLibraryExW;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"LoadLibraryExW() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
#endif // !_CHICAGO_
|
|
} // end if (fKernelPatched)
|
|
|
|
#endif
|
|
|
|
#if defined(MIPS) || defined(_PPC_)
|
|
// BUGBUG
|
|
// How about ALPHA?
|
|
// Why is this done this way? Shouldn't the addresses be aligned?
|
|
//
|
|
if (fKernel32Patched)
|
|
{
|
|
((PBYTE)ThunkNames->u1.Function)++;
|
|
memmove(&ThunkAddress, ThunkNames->u1.Function,
|
|
sizeof(ULONG));
|
|
if (ThunkAddress == (ULONG)loadlibAaddr)
|
|
{
|
|
memmove(ThunkNames->u1.Function, &CAP_LoadLibraryA,
|
|
sizeof(ULONG));
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) LoadLibraryA() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkAddress == (ULONG)loadlibExAaddr)
|
|
{
|
|
memmove(ThunkNames->u1.Function,
|
|
&CAP_LoadLibraryExA,
|
|
sizeof(ULONG));
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) LoadLibraryExA() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkAddress == (ULONG)loadlibWaddr)
|
|
{
|
|
memmove(ThunkNames->u1.Function, &CAP_LoadLibraryW,
|
|
sizeof(ULONG));
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) LoadLibraryW() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkAddress == (ULONG)loadlibExWaddr)
|
|
{
|
|
memmove(ThunkNames->u1.Function,
|
|
&CAP_LoadLibraryExW,
|
|
sizeof(ULONG));
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"(P) LoadLibraryExW() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
((PBYTE)ThunkNames->u1.Function)--;
|
|
}
|
|
else
|
|
{
|
|
if (ThunkNames->u1.Function == (PULONG)loadlibAaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LoadLibraryA;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"LoadLibraryA() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkNames->u1.Function == (PULONG)loadlibExAaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LoadLibraryExA;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"LoadLibraryExA() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkNames->u1.Function == (PULONG)loadlibWaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LoadLibraryW;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"LoadLibraryW() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
else if (ThunkNames->u1.Function == (PULONG)loadlibExWaddr)
|
|
{
|
|
try
|
|
{
|
|
ThunkNames->u1.Function = (PULONG)CAP_LoadLibraryExW;
|
|
}
|
|
except (UnprotectThunkFilter (
|
|
&(ThunkNames->u1.Function),
|
|
GetExceptionInformation()))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
SETUPPrint (("CAP: PatchDll() - "
|
|
"LoadLibraryExW() intercepted\n"));
|
|
iInterceptedCalls++;
|
|
}
|
|
} // end if (fKernelPatched)
|
|
|
|
#endif
|
|
if (iInterceptedCalls == 4)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ThunkNames++;
|
|
|
|
} // end while (ThunkNames->u1.Function)
|
|
|
|
} // end if ( !strcmp (ptchName, KERNEL32) )
|
|
|
|
} // end for (;pImports; pImports++)
|
|
|
|
} // end if ( (!fCrtDll) && (!fKernel32) && setjmpaddr && longjmpaddr &&
|
|
|
|
FlushInstructionCache(GetCurrentProcess(), NULL, 0);
|
|
|
|
if (fPatchDlls) iPatchCnt++;
|
|
|
|
return (fPatchDlls);
|
|
|
|
} /* PatchDll () */
|
|
|
|
|