Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

549 lines
17 KiB

#include "cap.h"
#if defined(MIPS) && !defined(MIPS_VC40_INTERFACE)
static BOOL fPenterFound;
ULONG ulPenterAddress;
static BOOL __stdcall FindPenterCallback(LPSTR, ULONG, ULONG, PVOID);
#endif
static PSYMINFO pProfSymb;
static PTCHAR pcProfSymbName;
static ULONG ulMaxSymbAddr;
static BOOL __stdcall SymbolEnumCallback(LPSTR, ULONG, ULONG, PVOID);
PPROFBLK SetupProfiling(LPCTSTR ptchFileName)
{
PVOID ImageBase;
PPROFBLK pProfBlk;
PPROFBLK pPrevProfBlk;
ULONG ulBlkOff;
LPCSTR ptchImageName;
TCHAR atchImageName [256];
PIMAGE_NT_HEADERS pImageNtHeader;
IMAGEHLP_MODULE ModuleInfo;
// Skip directory name
if ( (ptchImageName = strrchr(ptchFileName, '\\')) )
ptchImageName++;
else
ptchImageName = (PTCHAR)ptchFileName;
// Make uppercase copy
_strupr (strcpy (atchImageName, ptchImageName));
// Don't profile CAP
if ( !strcmp (atchImageName, CAPDLL) )
return NULL;
// Search prof blk list for matching image name
pPrevProfBlk = NULL;
ulBlkOff = ulLocProfBlkOff;
while (ulBlkOff != 0)
{
pPrevProfBlk = MKPPROFBLK(ulBlkOff);
// If found image, no need to set up new block
if (!strcmp((PCHAR)pPrevProfBlk->atchImageName, atchImageName))
return FALSE;
ulBlkOff = pPrevProfBlk->ulNxtBlk;
}
try // Accessing new block can cause an access fault
// which will extend the allocation
{
// Place block at next available offset
pProfBlk = MKPPROFBLK(*pulProfBlkBase);
// Fill in initial values
pProfBlk->ImageBase =0;
pProfBlk->CodeStart = 0;
pProfBlk->CodeLength = 0;
pProfBlk->iSymCnt = 0;
pProfBlk->State = BLKSTATE_ASSIGNED;
pProfBlk->ulNxtBlk = 0;
strcpy ((TCHAR *) pProfBlk->atchImageName, atchImageName);
// Link to previous block or initial block offset
if (pPrevProfBlk)
pPrevProfBlk->ulNxtBlk = *pulProfBlkBase;
else
ulLocProfBlkOff = *pulProfBlkBase;
// Load module symbols
ImageBase = GetModuleHandle(ptchImageName);
SymLoadModule(hThisProcess, NULL, (LPSTR)ptchFileName,
(LPSTR)ptchImageName, (DWORD)ImageBase, 0);
if (ImageBase != NULL)
{
pProfBlk->ImageBase = ImageBase;
// Get code start address
if ((pImageNtHeader = ImageNtHeader(ImageBase)) != NULL)
{
pProfBlk->CodeStart = (PULONG)((TCHAR *)ImageBase +
pImageNtHeader->OptionalHeader.BaseOfCode);
}
else
{
// If can't get code start, use imagebase as next best guess
pProfBlk->CodeStart = ImageBase;
}
#if defined(MIPS) && !defined(MIPS_VC40_INTERFACE)
// Enumerate symbols to find adress of _penter
fPenterFound = FALSE;
SymEnumerateSymbols(hThisProcess, (DWORD)ImageBase,
FindPenterCallback, (PVOID)pProfBlk);
#endif // MIPS && !MIPS_VC40_INTERFACE
// Get module info for symbols count
SymGetModuleInfo(hThisProcess, (DWORD)ImageBase, &ModuleInfo);
pProfBlk->iSymCnt = ModuleInfo.NumSyms;
// Determine location for symbols and symbol names
pProfSymb = (PSYMINFO)(&pProfBlk->atchImageName[strlen(atchImageName) + 1]);
pProfBlk->ulSym = (PTCHAR)pProfSymb - (PTCHAR)pulProfBlkBase;
pcProfSymbName = (PTCHAR)&pProfSymb[ModuleInfo.NumSyms];
// Now enumerate symbols to build up symbol table
ulMaxSymbAddr = (ULONG)pProfBlk->CodeStart;
SymEnumerateSymbols(hThisProcess, (DWORD)ImageBase,
SymbolEnumCallback, (PVOID)pProfBlk);
// Set symbol range based on max symbol address encountered
if (ulMaxSymbAddr > (ULONG)pProfBlk->CodeStart)
pProfBlk->CodeLength = ulMaxSymbAddr - (ULONG)pProfBlk->CodeStart;
// Update pointer to available space
*pulProfBlkBase = (ULONG)(pcProfSymbName - (PTCHAR)pulProfBlkBase);
// Unload the module
SymUnloadModule(hThisProcess, (DWORD)ImageBase);
// Do any requested import/export patching
PatchDll (ptchPatchImports, ptchPatchCallers, bCallersToPatch,
atchImageName, ImageBase);
}
else
{
// No symbols - Update offset to next free space
*pulProfBlkBase = (ULONG)&pProfBlk->atchImageName[strlen(atchImageName) + 1]
-(ULONG)pulProfBlkBase;
} // ImageBase != NULL
}
//
// + : 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
return pProfBlk;
}
void SetupLibProfiling (LPCSTR ImageName, BOOL fFirstLevelCall)
{
BOOL fStat;
PPROFBLK pProfBlk;
ULONG ulImportSize;
PIMAGE_IMPORT_DESCRIPTOR pImports;
if (fFirstLevelCall)
{
// Get the GLOBAL semaphore... (valid accross all process contexts)
// Prevents anyone else from updating profile block data
if (WAIT_FAILED == WaitForSingleObject (hGlobalSem, INFINITE))
{
CapDbgPrint ("CAP: CAP_GetLibSyms() - ERROR - "
"Wait for GLOBAL semaphore failed - 0x%lx\n",
GetLastError());
return;
}
}
// Setup profiling block for the module
pProfBlk = SetupProfiling(ImageName);
// If successfully loaded
if (pProfBlk != NULL && pProfBlk->ImageBase != NULL)
{
// Locate the import array for this image/dll
pImports = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(pProfBlk->ImageBase,
TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulImportSize);
// Recursively call SetupLibProfiling on each imported dll
for (;pImports; pImports++)
{
if (!pImports->Name)
break;
SetupLibProfiling((PTCHAR)((ULONG)pProfBlk->ImageBase + pImports->Name), FALSE);
}
}
if (fFirstLevelCall)
{
// Release the GLOBAL semaphore
fStat = ReleaseSemaphore (hGlobalSem, 1, NULL);
if (!fStat)
{
CapDbgPrint ("CAP: CAP_GetLibSyms() - "
"Error releasing GLOBAL semaphore - 0x%lx\n", GetLastError());
}
}
return;
}
//********************* FindPenterCallback *********************************
#if defined(MIPS) && !defined(MIPS_VC40_INTERFACE)
BOOL __stdcall FindPenterCallback( LPSTR psSymbName, ULONG ulSymbAddr,
ULONG ulSymbSize, PVOID dummy )
{
if (strcmp(psSymbName, "_penter") == 0)
{
ulPenterAddress = ulSymbAddr;
fPenterFound = TRUE;
return FALSE;
}
return TRUE;
}
#endif
//********************* SymbolEnumCallback *********************************
BOOL __stdcall SymbolEnumCallback( LPSTR psSymbName, ULONG ulSymbAddr,
ULONG ulSymbSize, PPROFBLK pProfBlk )
{
PTCHAR ptchExcludeModule;
PTCHAR ptchExcludeFuncName;
PBYTE pbPenterCode;
PULONG pulPenterCode;
PULONG pulLockAddress;
ULONG ulRegionSize;
ULONG ulOldProtect;
NTSTATUS Status;
char aszDebugString[256];
ULONG ulNewProtect = PAGE_READWRITE;
BOOL fExcludeFunc = FALSE;
BOOL fModuleFound = FALSE;
static PPROFBLK pProfBlkNotFound = NULL; // Pointer cache to avoid redundant searches // appear in the excluded list
// Check if this is an excluded function
// (Don't know the purpose of the fDllInit flag, but leaving it to be safe.)
if (fDllInit && (ptchExcludeFuncs[0] != EMPTY_STRING) && pProfBlk != pProfBlkNotFound)
{
ptchExcludeModule = (PTCHAR) ptchExcludeFuncs;
// Search for match with excluded names
while (* ptchExcludeModule != '\0')
{
ptchExcludeFuncName = strchr(ptchExcludeModule,
INI_DELIM) + 1;
*(ptchExcludeFuncName - 1) = '\0';
if (strstr(pProfBlk->atchImageName, _strupr(ptchExcludeModule)))
{
fModuleFound = TRUE;
// We have matched the module, now try to match
// the func name
if (strstr(psSymbName, ptchExcludeFuncName))
{
*(ptchExcludeFuncName - 1) = INI_DELIM;
fExcludeFunc = TRUE;
// If we have matched the module & func
// then just break out
break;
}
}
// Bump to next Exclude func
*(ptchExcludeFuncName - 1) = INI_DELIM;
ptchExcludeModule += strlen(ptchExcludeModule) + 1;
}
// If module doesn't appear in the excluded list,
// skip the search for the rest of its symbols
if (!fModuleFound)
pProfBlkNotFound = pProfBlk;
}
// If function is to be excluded
if (fExcludeFunc)
{
#if defined(MIPS) && !defined(MIPS_VC40_INTERFACE)
if (fPenterFound && ((ulSymbAddr & 3) == 0))
PatchEntryRoutine(ulSymbAddr, (PVOID)0, ulPenterAddress, TRUE);
#elif defined(MIPS) || defined(i386)
// Setup address of _penter call
#ifdef i386
pbPenterCode = (PBYTE)ulSymbAddr;
ulRegionSize = 5;
#elif MIPS
pbPenterCode = (PBYTE)(ulSymbAddr + 4);
ulRegionSize = 4;
#endif
// Change the protection of this page
if (VirtualProtect((PVOID)pbPenterCode,
ulRegionSize, ulNewProtect, &ulOldProtect))
{
#ifdef i386
if (CALL_OPCODE == *pbPenterCode)
{
// Nop the call to _penter
*(pbPenterCode) = (BYTE) NOP_OPCODE;
*(pbPenterCode + 1) = (BYTE) NOP_OPCODE;
*(pbPenterCode + 2) = (BYTE) NOP_OPCODE;
*(pbPenterCode + 3) = (BYTE) NOP_OPCODE;
*(pbPenterCode + 4) = (BYTE) NOP_OPCODE;
sprintf(aszDebugString,
"CAP: NOPing [%s:%s] @ [%08lx]\n",
pProfBlk->atchImageName,
psSymbName,
(ULONG) pbPenterCode);
SETUPPrint((aszDebugString));
}
#elif MIPS
pulPenterCode = (PULONG)pbPenterCode;
if ((*pulPenterCode & 0xfc000000) == JAL_INSTR)
*pulPenterCode = NOP;
#endif
// BUGBUG: We do not change back since it could
// affect data areas which should retain
// their READWRITE access.
//
// Reset the protection of this page
if (!VirtualProtect((PVOID)pbPenterCode,
ulRegionSize,
ulOldProtect,
&ulNewProtect))
{
INFOPrint(("CAP: GetSymbols: Reset VirtualProtect FAILED @(%08lx)\n",
pbPenterCode));
OutputCapDebugString("CAP: GetSymbols: Reset VirtualProtect FAILED\n");
}
}
else
{
INFOPrint(("CAP: GetSymbols: VirtualProtect FAILED @ [%08lx]\n",
pbPenterCode));
OutputCapDebugString("CAP: GetSymbols: VirtualProtect FAILED\n");
}
#endif // MIPS && !MIPS_VC40_INTERFACE
}
else
{
// Add symbol to prof blk
pProfSymb->ulAddr = ulSymbAddr;
pProfSymb->ulSymOff = (ULONG)(pcProfSymbName - (PTCHAR)pulProfBlkBase);
strcpy(pcProfSymbName,psSymbName);
// Update pointers
pcProfSymbName += strlen(psSymbName) + 1;
pProfSymb++;
if (ulSymbAddr > ulMaxSymbAddr)
ulMaxSymbAddr = ulSymbAddr;
#if defined(MIPS) && !defined(MIPS_VC40_INTERFACE)
if (fPenterFound && ((ulSymbAddr & 3) == 0))
PatchEntryRoutine(ulSymbAddr, (PVOID)0, ulPenterAddress, FALSE);
#endif // MIPS && !MIPS_VC40_INTERFACE
} // end if (fExcludeFunc)
return TRUE;
}
#if defined(MIPS) && !defined(MIPS_VC40_INTERFACE)
/********************** P a t c h E n t r y R o u t i n e ******************
*
* PatchEntryRoutine () -
* Patch all [jal _penter] to be above the instr [sw ra, ...]
* and right after [addiu sp,sp,xx]
* This is neccessary because the MIPS support for CAP is rather
* minimal.
*
* ENTRY ulAddr - Address of Symbol
* ImageBase - Base address of image
* ulPenterAddress - Address of the _penter routine thunk
* fDisablePenter - TRUE: Nop [jal _penter] instruction
* FALSE: Set Offset of $ra in NOP after
* [jal _penter] instruction
*
* EXIT -none-
*
* RETURN TRUE/FALSE
*
* WARNING:
* -none-
*
* COMMENT:
* -none-
*
*/
BOOL PatchEntryRoutine (ULONG ulAddr,
PVOID ImageBase,
ULONG ulPenterAddress,
BOOL fDisablePenter)
{
PULONG pulRoutineAddr = (PULONG) (ulAddr + (ULONG) ImageBase);
PULONG pulLockAddress;
int InstOfs = 0;
ULONG ulRegionSize;
NTSTATUS Status;
ULONG ulOldProtect;
ULONG ulJalDestOffset;
ULONG ulSwRaOfs;
BOOL fFoundJalPenter = FALSE;
char pszDebString[100];
// If first instruction is not ADDIU SP,SP,<Frame size>
// this is not a routine entry point
if ( (CURRENT_INST(0) & 0xffff0000) != ADDIU_SP )
{
return (FALSE);
}
// We only search MAX_INST_SEARCH instructions !
while ( (InstOfs < MAX_INST_SEARCH) &&
((CURRENT_INST(InstOfs) & 0xffff0000) != SW_RA) )
{
InstOfs++; // Bump to next instruction
}
// We have found SW $RA,xx($SP)
ulSwRaOfs = CURRENT_INST(InstOfs) & 0x0000ffff;
// Now search for our Jal _penter instruction
do
{
InstOfs++;
if ( ((CURRENT_INST(InstOfs) & 0xfc000000) == JAL_INSTR) )
{
// Check if we have the correct [jal _penter] instruction
ulJalDestOffset = CURRENT_INST(InstOfs) & 0x03ffffff;
ulJalDestOffset <<= 2; // Shift left 2 bits
ulJalDestOffset |= (((ULONG) pulRoutineAddr + InstOfs + 2) &
0xf0000000);
if (ulJalDestOffset == (ulPenterAddress + (ULONG) ImageBase))
{
fFoundJalPenter = TRUE;
break;
}
}
}
while ( (CURRENT_INST(InstOfs) != JR_RA) &&
(InstOfs < MAX_INST_SEARCH) );
if (fFoundJalPenter)
{
if (fDisablePenter)
{
sprintf(pszDebString,
"CAP: NOPing Penter @ [%lx] - ",
ulAddr + (ULONG)ImageBase);
OutputCapDebugString (pszDebString);
}
else if (CURRENT_INST(InstOfs + 1) == NOP)
{
sprintf(pszDebString,
"CAP: Patching @ [%lx] - ",
ulAddr + (ULONG)ImageBase);
OutputCapDebugString (pszDebString);
}
else
{
sprintf(pszDebString,
"CAP: Jal penter without NOP @ [%lx] - ",
ulAddr + (ULONG)ImageBase);
OutputCapDebugString (pszDebString);
}
pulLockAddress = pulRoutineAddr;
ulRegionSize = INST_SIZE * (InstOfs + 2); // Enough for [jal _penter] & [nop]
// Change the protection of this page
if (!VirtualProtect((PVOID) pulLockAddress, ulRegionSize,
PAGE_READWRITE, &ulOldProtect))
{
INFOPrint(("CAP: PatchEntry(Mips) : VirtualProtect FAILED @(%08lx)\n",
pulLockAddress));
OutputCapDebugString("CAP: PatchEntry(Mips) : VirtualProtect FAILED\n");
DebugBreak();
}
if (fDisablePenter)
{
// Nop the [jal _penter]
CURRENT_INST(InstOfs) = NOP;
}
else if (CURRENT_INST(InstOfs + 1) == NOP)
{
// Set offset in the NOP instruction
ulSwRaOfs |= (((InstOfs + 2) * INST_SIZE) << 8);
CURRENT_INST(InstOfs + 1) = (ULONG) (ulSwRaOfs | 0x24000000);
}
else
{
// jal _penter without following NOP !!!!!
CURRENT_INST(InstOfs) = NOP;
}
// Reset the protection for the code we just changed
pulLockAddress = pulRoutineAddr;
ulRegionSize = INST_SIZE * (InstOfs + 2); // Enough for [jal _penter] & [nop]
// Reset the protection of this page
if (!VirtualProtect((PVOID) pulLockAddress, ulRegionSize,
ulOldProtect, &ulOldProtect))
{
INFOPrint(("CAP: PatchEntry(Mips) : Reset VirtualProtect FAILED "
"@(%08lx)\n", pulLockAddress));
OutputCapDebugString("CAP: PatchEntry(Mips) : Reset VirtualProtect "
"FAILED\n");
}
return (TRUE);
}
else
{
return (FALSE);
}
}
#endif // MIPS && !MIPS_VC40_INTERFACE