4574 lines
		
	
	
		
			129 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			4574 lines
		
	
	
		
			129 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | /////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | //  Detours Test Program (trcbld.cpp of trcbld.dll)
 | ||
|  | //
 | ||
|  | //  Microsoft Research Detours Package
 | ||
|  | //
 | ||
|  | //  Copyright (c) Microsoft Corporation.  All rights reserved.
 | ||
|  | //
 | ||
|  | 
 | ||
|  | #define _WIN32_WINNT        0x0500
 | ||
|  | #define WIN32
 | ||
|  | #define NT
 | ||
|  | 
 | ||
|  | #define DBG_TRACE   0
 | ||
|  | 
 | ||
|  | #include <windows.h>
 | ||
|  | #include <stdio.h>
 | ||
|  | #pragma warning(push)
 | ||
|  | #if _MSC_VER > 1400
 | ||
|  | #pragma warning(disable:6102 6103) // /analyze warnings
 | ||
|  | #endif
 | ||
|  | #include <strsafe.h>
 | ||
|  | #pragma warning(pop)
 | ||
|  | #include "detours.h"
 | ||
|  | #include "tracebld.h"
 | ||
|  | 
 | ||
|  | #define PULONG_PTR          PVOID
 | ||
|  | #define PLONG_PTR           PVOID
 | ||
|  | #define ULONG_PTR           PVOID
 | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | 
 | ||
|  | #pragma warning(disable:4127)   // Many of our asserts are constants.
 | ||
|  | 
 | ||
|  | #define DEBUG_BREAK() DebugBreak()
 | ||
|  | 
 | ||
|  | #define ASSERT_ALWAYS(x)   \
 | ||
|  |     do {                                                        \ | ||
|  |         if (!(x)) {                                             \ | ||
|  |             AssertFailed(#x, __FILE__, __LINE__);               \ | ||
|  |             DebugBreak();                                       \ | ||
|  |         }                                                       \ | ||
|  |     } while (0) | ||
|  | 
 | ||
|  | #ifndef NDEBUG
 | ||
|  | #define ASSERT(x)           ASSERT_ALWAYS(x)
 | ||
|  | #else
 | ||
|  | #define ASSERT(x)
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #define UNUSED(c)       (c) = (c)
 | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | static HMODULE s_hInst = NULL; | ||
|  | static HMODULE s_hKernel32 = NULL; | ||
|  | static CHAR s_szDllPath[MAX_PATH]; | ||
|  | static TBLOG_PAYLOAD s_Payload; | ||
|  | static TBLOG_PAYLOAD s_ChildPayload; | ||
|  | static CRITICAL_SECTION s_csChildPayload; | ||
|  | static DWORD s_nTraceProcessId = 0; | ||
|  | static LONG s_nChildCnt = 0; | ||
|  | 
 | ||
|  | static CRITICAL_SECTION s_csPipe;                       // Guards access to hPipe.
 | ||
|  | static HANDLE           s_hPipe = INVALID_HANDLE_VALUE; | ||
|  | static TBLOG_MESSAGE    s_rMessage; | ||
|  | 
 | ||
|  | // Logging Functions.
 | ||
|  | //
 | ||
|  | VOID Tblog(PCSTR pszMsgf, ...); | ||
|  | VOID TblogV(PCSTR pszMsgf, va_list args); | ||
|  | 
 | ||
|  | VOID VSafePrintf(PCSTR pszMsg, va_list args, PCHAR pszBuffer, LONG cbBuffer); | ||
|  | PCHAR SafePrintf(PCHAR pszBuffer, LONG cbBuffer, PCSTR pszMsg, ...); | ||
|  | 
 | ||
|  | LONG EnterFunc(); | ||
|  | VOID ExitFunc(); | ||
|  | VOID Print(PCSTR psz, ...); | ||
|  | VOID NoteRead(PCSTR psz); | ||
|  | VOID NoteRead(PCWSTR pwz); | ||
|  | VOID NoteWrite(PCSTR psz); | ||
|  | VOID NoteWrite(PCWSTR pwz); | ||
|  | VOID NoteDelete(PCSTR psz); | ||
|  | VOID NoteDelete(PCWSTR pwz); | ||
|  | VOID NoteCleanup(PCSTR psz); | ||
|  | VOID NoteCleanup(PCWSTR pwz); | ||
|  | 
 | ||
|  | PBYTE LoadFile(HANDLE hFile, DWORD cbFile); | ||
|  | static PCHAR RemoveReturns(PCHAR pszBuffer); | ||
|  | static PWCHAR RemoveReturns(PWCHAR pwzBuffer); | ||
|  | 
 | ||
|  | VOID AssertFailed(CONST PCHAR pszMsg, CONST PCHAR pszFile, ULONG nLine); | ||
|  | 
 | ||
|  | int WINAPI Mine_EntryPoint(VOID); | ||
|  | VOID WINAPI Mine_ExitProcess(UINT a0); | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | int (WINAPI * Real_EntryPoint)(VOID) | ||
|  |     = NULL; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CreateDirectoryW)(LPCWSTR a0, | ||
|  |                                       LPSECURITY_ATTRIBUTES a1) | ||
|  |     = CreateDirectoryW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CreateDirectoryExW)(LPCWSTR a0, | ||
|  |                                         LPCWSTR a1, | ||
|  |                                         LPSECURITY_ATTRIBUTES a2) | ||
|  |     = CreateDirectoryExW; | ||
|  | 
 | ||
|  | HANDLE (WINAPI * Real_CreateFileW)(LPCWSTR a0, | ||
|  |                                    DWORD a1, | ||
|  |                                    DWORD a2, | ||
|  |                                    LPSECURITY_ATTRIBUTES a3, | ||
|  |                                    DWORD a4, | ||
|  |                                    DWORD a5, | ||
|  |                                    HANDLE a6) | ||
|  |     = CreateFileW; | ||
|  | 
 | ||
|  | HANDLE (WINAPI * Real_CreateFileMappingW)(HANDLE hFile, | ||
|  |                                          LPSECURITY_ATTRIBUTES lpAttributes, | ||
|  |                                          DWORD flProtect, | ||
|  |                                          DWORD dwMaximumSizeHigh, | ||
|  |                                          DWORD dwMaximumSizeLow, | ||
|  |                                          LPCWSTR lpName | ||
|  |                                         ) | ||
|  |     = CreateFileMappingW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CreatePipe)(PHANDLE hReadPipe, | ||
|  |                                 PHANDLE hWritePipe, | ||
|  |                                 LPSECURITY_ATTRIBUTES lpPipeAttributes, | ||
|  |                                 DWORD nSize) | ||
|  |     = CreatePipe; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CloseHandle)(HANDLE a0) | ||
|  |     = CloseHandle; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_DuplicateHandle)(HANDLE hSourceProcessHandle, | ||
|  |                                      HANDLE hSourceHandle, | ||
|  |                                      HANDLE hTargetProcessHandle, | ||
|  |                                      LPHANDLE lpTargetHandle, | ||
|  |                                      DWORD dwDesiredAccess, | ||
|  |                                      BOOL bInheritHandle, | ||
|  |                                      DWORD dwOptions) | ||
|  |     = DuplicateHandle; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CreateProcessW)(LPCWSTR lpApplicationName, | ||
|  |                                     LPWSTR lpCommandLine, | ||
|  |                                     LPSECURITY_ATTRIBUTES lpProcessAttributes, | ||
|  |                                     LPSECURITY_ATTRIBUTES lpThreadAttributes, | ||
|  |                                     BOOL bInheritHandles, | ||
|  |                                     DWORD dwCreationFlags, | ||
|  |                                     LPVOID lpEnvironment, | ||
|  |                                     LPCWSTR lpCurrentDirectory, | ||
|  |                                     LPSTARTUPINFOW lpStartupInfo, | ||
|  |                                     LPPROCESS_INFORMATION lpProcessInformation) | ||
|  |     = CreateProcessW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CreateProcessA)(LPCSTR lpApplicationName, | ||
|  |                                     LPSTR lpCommandLine, | ||
|  |                                     LPSECURITY_ATTRIBUTES lpProcessAttributes, | ||
|  |                                     LPSECURITY_ATTRIBUTES lpThreadAttributes, | ||
|  |                                     BOOL bInheritHandles, | ||
|  |                                     DWORD dwCreationFlags, | ||
|  |                                     LPVOID lpEnvironment, | ||
|  |                                     LPCSTR lpCurrentDirectory, | ||
|  |                                     LPSTARTUPINFOA lpStartupInfo, | ||
|  |                                     LPPROCESS_INFORMATION lpProcessInformation) | ||
|  |     = CreateProcessA; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_DeleteFileW)(LPCWSTR a0) | ||
|  |     = DeleteFileW; | ||
|  | BOOL (WINAPI * Real_DeviceIoControl)(HANDLE a0, | ||
|  |                                      DWORD dwIoControlCode, | ||
|  |                                      LPVOID lpInBuffer, | ||
|  |                                      DWORD nInBufferSize, | ||
|  |                                      LPVOID lpOutBuffer, | ||
|  |                                      DWORD nOutBufferSize, | ||
|  |                                      LPDWORD lpBytesReturned, | ||
|  |                                      LPOVERLAPPED lpOverlapped) | ||
|  |     = DeviceIoControl; | ||
|  | 
 | ||
|  | DWORD (WINAPI * Real_GetFileAttributesW)(LPCWSTR a0) | ||
|  |     = GetFileAttributesW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_MoveFileWithProgressW)(LPCWSTR lpExistingFileName, | ||
|  |                                            LPCWSTR lpNewFileName, | ||
|  |                                            LPPROGRESS_ROUTINE lpProgressRoutine, | ||
|  |                                            LPVOID lpData, | ||
|  |                                            DWORD dwFlags) | ||
|  |     = MoveFileWithProgressW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_MoveFileA)(LPCSTR a0, | ||
|  |                                LPCSTR a1) | ||
|  |     = MoveFileA; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_MoveFileW)(LPCWSTR a0, | ||
|  |                                LPCWSTR a12) | ||
|  |     = MoveFileW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_MoveFileExA)(LPCSTR a0, | ||
|  |                                  LPCSTR a1, | ||
|  |                                  DWORD a2) | ||
|  |     = MoveFileExA; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_MoveFileExW)(LPCWSTR a0, | ||
|  |                                  LPCWSTR a1, | ||
|  |                                  DWORD a2) | ||
|  |     = MoveFileExW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CopyFileExA)(LPCSTR a0, | ||
|  |                                  LPCSTR a1, | ||
|  |                                  LPPROGRESS_ROUTINE a2, | ||
|  |                                  LPVOID a4, | ||
|  |                                  LPBOOL a5, | ||
|  |                                  DWORD a6) | ||
|  |     = CopyFileExA; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CopyFileExW)(LPCWSTR a0, | ||
|  |                                  LPCWSTR a1, | ||
|  |                                  LPPROGRESS_ROUTINE a2, | ||
|  |                                  LPVOID a4, | ||
|  |                                  LPBOOL a5, | ||
|  |                                  DWORD a6) | ||
|  |     = CopyFileExW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_PrivCopyFileExW)(LPCWSTR  lpExistingFileName, | ||
|  |                                      LPCWSTR  lpNewFileName, | ||
|  |                                      LPPROGRESS_ROUTINE  lpProgressRoutine, | ||
|  |                                      LPVOID  lpData, | ||
|  |                                      LPBOOL  pbCancel, | ||
|  |                                      DWORD  dwCopyFlags) | ||
|  |     = NULL; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CreateHardLinkA)(LPCSTR a0, | ||
|  |                                      LPCSTR a1, | ||
|  |                                      LPSECURITY_ATTRIBUTES a2) | ||
|  |     = CreateHardLinkA; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_CreateHardLinkW)(LPCWSTR a0, | ||
|  |                                      LPCWSTR a1, | ||
|  |                                      LPSECURITY_ATTRIBUTES a2) | ||
|  |     = CreateHardLinkW; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_SetStdHandle)(DWORD a0, | ||
|  |                                   HANDLE a1) | ||
|  |     = SetStdHandle; | ||
|  | 
 | ||
|  | HMODULE (WINAPI * Real_LoadLibraryA)(LPCSTR a0) | ||
|  |     = LoadLibraryA; | ||
|  | 
 | ||
|  | HMODULE (WINAPI * Real_LoadLibraryW)(LPCWSTR a0) | ||
|  |     = LoadLibraryW; | ||
|  | 
 | ||
|  | HMODULE (WINAPI * Real_LoadLibraryExA)(LPCSTR a0, | ||
|  |                                        HANDLE a1, | ||
|  |                                        DWORD a2) | ||
|  |     = LoadLibraryExA; | ||
|  | 
 | ||
|  | HMODULE (WINAPI * Real_LoadLibraryExW)(LPCWSTR a0, | ||
|  |                                        HANDLE a1, | ||
|  |                                        DWORD a2) | ||
|  |     = LoadLibraryExW; | ||
|  | 
 | ||
|  | DWORD (WINAPI * Real_SetFilePointer)(HANDLE hFile, | ||
|  |                                      LONG lDistanceToMove, | ||
|  |                                      PLONG lpDistanceToMoveHigh, | ||
|  |                                      DWORD dwMoveMethod) | ||
|  |     = SetFilePointer; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_SetFilePointerEx)(HANDLE hFile, | ||
|  |                                       LARGE_INTEGER liDistanceToMove, | ||
|  |                                       PLARGE_INTEGER lpNewFilePointer, | ||
|  |                                       DWORD dwMoveMethod) | ||
|  |     = SetFilePointerEx; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_ReadFile)(HANDLE a0, | ||
|  |                                  LPVOID a1, | ||
|  |                                  DWORD a2, | ||
|  |                                  LPDWORD a3, | ||
|  |                                  LPOVERLAPPED a4) | ||
|  |     = ReadFile; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_ReadFileEx)(HANDLE a0, | ||
|  |                                    LPVOID a1, | ||
|  |                                    DWORD a2, | ||
|  |                                    LPOVERLAPPED a3, | ||
|  |                                    LPOVERLAPPED_COMPLETION_ROUTINE a4) | ||
|  |     = ReadFileEx; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_WriteFile)(HANDLE a0, | ||
|  |                                   LPCVOID a1, | ||
|  |                                   DWORD a2, | ||
|  |                                   LPDWORD a3, | ||
|  |                                   LPOVERLAPPED a4) | ||
|  |     = WriteFile; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_WriteFileEx)(HANDLE a0, | ||
|  |                                     LPCVOID a1, | ||
|  |                                     DWORD a2, | ||
|  |                                     LPOVERLAPPED a3, | ||
|  |                                     LPOVERLAPPED_COMPLETION_ROUTINE a4) | ||
|  |     = WriteFileEx; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_WriteConsoleA)(HANDLE a0, | ||
|  |                                       const VOID* a1, | ||
|  |                                       DWORD a2, | ||
|  |                                       LPDWORD a3, | ||
|  |                                       LPVOID a4) | ||
|  |     = WriteConsoleA; | ||
|  | 
 | ||
|  | BOOL (WINAPI * Real_WriteConsoleW)(HANDLE a0, | ||
|  |                                       const VOID* a1, | ||
|  |                                       DWORD a2, | ||
|  |                                       LPDWORD a3, | ||
|  |                                       LPVOID a4) | ||
|  |     = WriteConsoleW; | ||
|  | 
 | ||
|  | VOID (WINAPI * Real_ExitProcess)(UINT a0) | ||
|  |     = ExitProcess; | ||
|  | 
 | ||
|  | DWORD (WINAPI * Real_ExpandEnvironmentStringsA)(PCSTR lpSrc, PCHAR lpDst, DWORD nSize) | ||
|  |     = ExpandEnvironmentStringsA; | ||
|  | 
 | ||
|  | DWORD (WINAPI * Real_ExpandEnvironmentStringsW)(PCWSTR lpSrc, PWCHAR lpDst, DWORD nSize) | ||
|  |     = ExpandEnvironmentStringsW; | ||
|  | 
 | ||
|  | DWORD (WINAPI * Real_GetEnvironmentVariableA)(PCSTR lpName, PCHAR lpBuffer, DWORD nSize) | ||
|  |     = GetEnvironmentVariableA; | ||
|  | 
 | ||
|  | DWORD (WINAPI * Real_GetEnvironmentVariableW)(PCWSTR lpName, PWCHAR lpBuffer, DWORD nSize) | ||
|  |     = GetEnvironmentVariableW; | ||
|  | 
 | ||
|  | PCWSTR (CDECL * Real_wgetenv)(PCWSTR var) = NULL; | ||
|  | PCSTR (CDECL * Real_getenv)(PCSTR var) = NULL; | ||
|  | DWORD (CDECL * Real_getenv_s)(DWORD *pValue, PCHAR pBuffer, DWORD cBuffer, PCSTR varname) = NULL; | ||
|  | DWORD (CDECL * Real_wgetenv_s)(DWORD *pValue, PWCHAR pBuffer, DWORD cBuffer, PCWSTR varname) = NULL; | ||
|  | DWORD (CDECL * Real_dupenv_s)(PCHAR *ppBuffer, DWORD *pcBuffer, PCSTR varname) = NULL; | ||
|  | DWORD (CDECL * Real_wdupenv_s)(PWCHAR *ppBuffer, DWORD *pcBuffer, PCWSTR varname) = NULL; | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | static VOID Copy(PWCHAR pwzDst, PCWSTR pwzSrc) | ||
|  | { | ||
|  |     while (*pwzSrc) { | ||
|  |         *pwzDst++ = *pwzSrc++; | ||
|  |     } | ||
|  |     *pwzDst = '\0'; | ||
|  | } | ||
|  | 
 | ||
|  | static DWORD Size(PCWSTR pwzSrc) | ||
|  | { | ||
|  |     DWORD c = 0; | ||
|  |     while (pwzSrc[c]) { | ||
|  |         c++; | ||
|  |     } | ||
|  |     return c; | ||
|  | } | ||
|  | 
 | ||
|  | static PCWSTR Save(PCWSTR pwzSrc) | ||
|  | { | ||
|  |     DWORD c = (Size(pwzSrc) + 1) * sizeof(WCHAR); | ||
|  |     PWCHAR pwzDst = (PWCHAR)GlobalAlloc(GPTR, c); | ||
|  |     CopyMemory(pwzDst, pwzSrc, c); | ||
|  | 
 | ||
|  |     return pwzDst; | ||
|  | } | ||
|  | 
 | ||
|  | static BOOL HasSpace(PCWSTR pwz) | ||
|  | { | ||
|  |     for (; *pwz; pwz++) { | ||
|  |         if (*pwz == ' ' || *pwz == '\t' || *pwz == '\r' || *pwz == '\n') { | ||
|  |             return TRUE; | ||
|  |         } | ||
|  |     } | ||
|  |     return FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | static BOOL HasChar(PCWSTR pwz, WCHAR w) | ||
|  | { | ||
|  |     for (; *pwz; pwz++) { | ||
|  |         if (*pwz == w) { | ||
|  |             return TRUE; | ||
|  |         } | ||
|  |     } | ||
|  |     return FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | static DWORD Compare(PCWSTR pwzA, PCWSTR pwzB) | ||
|  | { | ||
|  |     for (;;) { | ||
|  |         WCHAR cA = *pwzA++; | ||
|  |         WCHAR cB = *pwzB++; | ||
|  | 
 | ||
|  |         if (cA >= 'A' && cA <= 'Z') { | ||
|  |             cA += ('a' - 'A'); | ||
|  |         } | ||
|  |         if (cB >= 'A' && cB <= 'Z') { | ||
|  |             cB += ('a' - 'A'); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (cA == 0 && cB == 0) { | ||
|  |             return 0; | ||
|  |         } | ||
|  |         if (cA != cB) { | ||
|  |             return cA - cB; | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | static DWORD Compare(PCWSTR pwzA, PCSTR pszB) | ||
|  | { | ||
|  |     for (;;) { | ||
|  |         WCHAR cA = *pwzA++; | ||
|  |         WCHAR cB = *pszB++; | ||
|  | 
 | ||
|  |         if (cA >= 'A' && cA <= 'Z') { | ||
|  |             cA += ('a' - 'A'); | ||
|  |         } | ||
|  |         if (cB >= 'A' && cB <= 'Z') { | ||
|  |             cB += ('a' - 'A'); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (cA == 0 && cB == 0) { | ||
|  |             return 0; | ||
|  |         } | ||
|  |         if (cA != cB) { | ||
|  |             return cA - cB; | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | static DWORD Compare(PCSTR pszA, PCSTR pszB) | ||
|  | { | ||
|  |     for (;;) { | ||
|  |         CHAR cA = *pszA++; | ||
|  |         CHAR cB = *pszB++; | ||
|  | 
 | ||
|  |         if (cA >= 'A' && cA <= 'Z') { | ||
|  |             cA += ('a' - 'A'); | ||
|  |         } | ||
|  |         if (cB >= 'A' && cB <= 'Z') { | ||
|  |             cB += ('a' - 'A'); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (cA == 0 && cB == 0) { | ||
|  |             return 0; | ||
|  |         } | ||
|  |         if (cA != cB) { | ||
|  |             return cA - cB; | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | 
 | ||
|  | static PCSTR s_rpszMsvcrNames[] = { | ||
|  |     "msvcr80.dll", | ||
|  |     "msvcr80d.dll", | ||
|  |     "msvcr71.dll", | ||
|  |     "msvcr71d.dll", | ||
|  |     "msvcr70.dll", | ||
|  |     "msvcr70d.dll", | ||
|  |     NULL | ||
|  | }; | ||
|  | 
 | ||
|  | HMODULE s_hMsvcr = NULL; | ||
|  | PCSTR s_pszMsvcr = NULL; | ||
|  | 
 | ||
|  | static BOOL WINAPI ImportFileCallback(PVOID pContext, HMODULE hFile, PCSTR pszFile) | ||
|  | { | ||
|  |     UNUSED(pContext); | ||
|  | 
 | ||
|  |     if (pszFile != NULL) { | ||
|  |         for (int i = 0; s_rpszMsvcrNames[i]; i++) { | ||
|  |             if (Compare(pszFile, s_rpszMsvcrNames[i]) == 0) { | ||
|  |                 s_hMsvcr = hFile; | ||
|  |                 s_pszMsvcr = s_rpszMsvcrNames[i]; | ||
|  |                 return FALSE; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL FindMsvcr() | ||
|  | { | ||
|  |     DetourEnumerateImports(NULL, NULL, ImportFileCallback, NULL); | ||
|  | 
 | ||
|  |     if (s_hMsvcr != NULL) { | ||
|  |         return TRUE; | ||
|  |     } | ||
|  | 
 | ||
|  |     return FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL FindProc(PVOID * ppvCode, PCSTR pwzFunc) | ||
|  | { | ||
|  |     PVOID pv = GetProcAddress(s_hMsvcr, pwzFunc); | ||
|  |     if (pv != NULL) { | ||
|  |         *ppvCode = pv; | ||
|  |         return TRUE; | ||
|  |     } | ||
|  |     else { | ||
|  |         *ppvCode = NULL; | ||
|  |         return FALSE; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | struct EnvInfo | ||
|  | { | ||
|  |     DWORD   m_nHash; | ||
|  |     DWORD   m_nIndex; | ||
|  |     PCWSTR  m_pwzVar; | ||
|  |     PCWSTR  m_pwzVal; | ||
|  |     BOOL    m_fDefined; | ||
|  |     BOOL    m_fUsed; | ||
|  |     BOOL    m_fOriginal; | ||
|  | }; | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | class EnvVars | ||
|  | { | ||
|  |   private: | ||
|  |     static CRITICAL_SECTION s_csLock; | ||
|  |     static DWORD            s_nVars; | ||
|  |     static DWORD            s_nCapacity; | ||
|  |     static EnvInfo **       s_pVars; | ||
|  | 
 | ||
|  |   private: | ||
|  |     static DWORD Hash(PCWSTR pwzVar) | ||
|  |     { | ||
|  |         DWORD hash = 5381; | ||
|  |         while (*pwzVar != 0) { | ||
|  |             WCHAR c = *pwzVar++; | ||
|  |             if (c >= 'A' && c <= 'Z') { | ||
|  |                 c += ('a' - 'A'); | ||
|  |             } | ||
|  |             hash = ((hash << 5) + hash) + c; | ||
|  |         } | ||
|  |         return hash; | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID LockAcquire() | ||
|  |     { | ||
|  |         EnterCriticalSection(&s_csLock); | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID LockRelease() | ||
|  |     { | ||
|  |         LeaveCriticalSection(&s_csLock); | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID Resize(DWORD nCapacity); | ||
|  |     static VOID Set(EnvInfo *info); | ||
|  |     static EnvInfo * Find(PCWSTR pwzVar); | ||
|  | 
 | ||
|  |   public: | ||
|  |     static BOOL Equal(PCWSTR pwzA, PCWSTR pwzB) | ||
|  |     { | ||
|  |         return (Compare(pwzA, pwzB) == 0); | ||
|  |     } | ||
|  | 
 | ||
|  |   public: | ||
|  |     static VOID Initialize(); | ||
|  |     static VOID Dump(); | ||
|  | 
 | ||
|  |     static VOID Add(PCWSTR pwzVar, PCWSTR pwzVal); | ||
|  | 
 | ||
|  |     static VOID Used(PCWSTR pwzVar); | ||
|  |     static VOID Used(PCSTR pszVar); | ||
|  | }; | ||
|  | 
 | ||
|  | CRITICAL_SECTION    EnvVars::s_csLock; | ||
|  | DWORD               EnvVars::s_nVars = 0; | ||
|  | DWORD               EnvVars::s_nCapacity = 0; | ||
|  | EnvInfo **          EnvVars::s_pVars = NULL; | ||
|  | 
 | ||
|  | VOID EnvVars::Initialize() | ||
|  | { | ||
|  |     InitializeCriticalSection(&s_csLock); | ||
|  | 
 | ||
|  |     Resize(919); | ||
|  | } | ||
|  | 
 | ||
|  | VOID EnvVars::Resize(DWORD nCapacity) | ||
|  | { | ||
|  |     if (nCapacity > s_nCapacity) { | ||
|  |         DWORD nOld = s_nCapacity; | ||
|  |         EnvInfo ** pOld = s_pVars; | ||
|  | 
 | ||
|  |         // DEBUG_BREAK();
 | ||
|  | 
 | ||
|  |         s_pVars = (EnvInfo **)GlobalAlloc(GPTR, nCapacity * sizeof(EnvInfo *)); | ||
|  |         s_nCapacity = nCapacity; | ||
|  | 
 | ||
|  |         if (pOld != NULL) { | ||
|  |             for (DWORD n = 0; n < nOld; n++) { | ||
|  |                 if (pOld[n] != NULL) { | ||
|  |                     Set(pOld[n]); | ||
|  |                 } | ||
|  |             } | ||
|  |             GlobalFree((HGLOBAL)pOld); | ||
|  |             pOld = NULL; | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID EnvVars::Set(EnvInfo *info) | ||
|  | { | ||
|  |     DWORD hash = info->m_nHash; | ||
|  |     DWORD slot = hash % s_nCapacity; | ||
|  |     DWORD death = 0; | ||
|  | 
 | ||
|  |     // Find an empty slot.
 | ||
|  |     for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) { | ||
|  |         if (++death > s_nCapacity) { | ||
|  |             // We should have dropped out at some point...
 | ||
|  |             DEBUG_BREAK(); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     s_pVars[slot] = info; | ||
|  | } | ||
|  | 
 | ||
|  | EnvInfo * EnvVars::Find(PCWSTR pwzVar) | ||
|  | { | ||
|  |     DWORD hash = Hash(pwzVar); | ||
|  |     DWORD slot = hash % s_nCapacity; | ||
|  | 
 | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     // Find the the matching slot, or an empty one.
 | ||
|  |     for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) { | ||
|  |         if (Equal(s_pVars[slot]->m_pwzVar, pwzVar)) { | ||
|  |             LockRelease(); | ||
|  |             return s_pVars[slot]; | ||
|  |         } | ||
|  |     } | ||
|  |     LockRelease(); | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | VOID EnvVars::Add(PCWSTR pwzVar, PCWSTR pwzVal) | ||
|  | { | ||
|  |     if (pwzVar == NULL) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     WCHAR wzVar[MAX_PATH]; | ||
|  |     PWCHAR pwzDst = wzVar; | ||
|  |     while (*pwzVar) { | ||
|  |         if (*pwzVar >= 'a' && *pwzVar <= 'z') { | ||
|  |             *pwzDst++ = *pwzVar - ('a' - 'A'); | ||
|  |         } | ||
|  |         else { | ||
|  |             *pwzDst++ = *pwzVar; | ||
|  |         } | ||
|  |         pwzVar++; | ||
|  |     } | ||
|  |     *pwzDst = '\0'; | ||
|  |     pwzVar = wzVar; | ||
|  | 
 | ||
|  |     WCHAR wzVal[] = L""; | ||
|  |     if (pwzVal != NULL) { | ||
|  |         while (*pwzVal == ' ' || *pwzVal == '\t') { | ||
|  |             *pwzVal++; | ||
|  |         } | ||
|  |     } | ||
|  |     else { | ||
|  |         pwzVal = wzVal; | ||
|  |     } | ||
|  | 
 | ||
|  |     // Tblog("<!-- ::Add var=[%le] val=[%le] -->\n", pwzVar, pwzVal);
 | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     // DEBUG_BREAK();
 | ||
|  | 
 | ||
|  |     DWORD hash = Hash(pwzVar); | ||
|  |     DWORD slot = hash % s_nCapacity; | ||
|  |     EnvInfo *info = NULL; | ||
|  |     DWORD death = 0; | ||
|  | 
 | ||
|  |     // Find the the matching slot, or an empty one.
 | ||
|  |     for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) { | ||
|  |         if (Equal(s_pVars[slot]->m_pwzVar, pwzVar)) { | ||
|  |             LockRelease(); | ||
|  |             return; | ||
|  |         } | ||
|  |         if (++death > s_nCapacity) { | ||
|  |             // We should have dropped out at some point...
 | ||
|  |             DEBUG_BREAK(); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     // Add the var to list of known vars.
 | ||
|  |     info = (EnvInfo *)GlobalAlloc(GPTR, sizeof(EnvInfo)); | ||
|  |     info->m_nHash = hash; | ||
|  |     info->m_nIndex = s_nVars++; | ||
|  |     info->m_pwzVar = Save(pwzVar); | ||
|  |     info->m_pwzVal = Save(pwzVal); | ||
|  |     if (pwzVal[0] == '\0') { | ||
|  |         info->m_fDefined = FALSE; | ||
|  |         info->m_fUsed = TRUE; | ||
|  |     } | ||
|  |     else { | ||
|  |         info->m_fDefined = TRUE; | ||
|  |     } | ||
|  |     s_pVars[slot] = info; | ||
|  | 
 | ||
|  |     // Check if we should grow the table.
 | ||
|  |     if (s_nVars > (s_nCapacity / 2)) { | ||
|  |         Resize(s_nCapacity * 2 - 1); | ||
|  |     } | ||
|  | 
 | ||
|  |     LockRelease(); | ||
|  | } | ||
|  | 
 | ||
|  | VOID EnvVars::Used(PCWSTR pwzVar) | ||
|  | { | ||
|  |     if (pwzVar != NULL) { | ||
|  |         // Tblog("<!-- Used [%le] -->\n", pwzVar);
 | ||
|  |         EnvInfo *pInfo = Find(pwzVar); | ||
|  |         if (pInfo) { | ||
|  |             pInfo->m_fUsed = TRUE; | ||
|  |         } | ||
|  | #if 0
 | ||
|  |         else { | ||
|  |             Add(pwzVar, NULL); | ||
|  |         } | ||
|  | #endif
 | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID EnvVars::Used(PCSTR pszVar) | ||
|  | { | ||
|  |     if (pszVar != NULL) { | ||
|  |         WCHAR wzVar[MAX_PATH]; | ||
|  |         PWCHAR pwzVar = wzVar; | ||
|  |         while (*pszVar) { | ||
|  |             *pwzVar++ = *pszVar++; | ||
|  |         } | ||
|  |         *pwzVar = '\0'; | ||
|  | 
 | ||
|  |         Used(wzVar); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID EnvVars::Dump() | ||
|  | { | ||
|  |     if (s_nVars == 0) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     Tblog("<t:Vars>\n"); | ||
|  | 
 | ||
|  |     // Remove any variables that match the original environment.
 | ||
|  |     PCWSTR pwzz = s_Payload.wzzEnvironment; | ||
|  |     while (*pwzz) { | ||
|  |         WCHAR wzVar[MAX_PATH]; | ||
|  |         PWCHAR pwzVar = wzVar; | ||
|  | 
 | ||
|  |         while (*pwzz && *pwzz != '=') { | ||
|  |             *pwzVar++ = *pwzz++; | ||
|  |         } | ||
|  |         *pwzVar = '\0'; | ||
|  |         if (*pwzz == '=') { | ||
|  |             pwzz++; | ||
|  |         } | ||
|  | 
 | ||
|  |         EnvInfo *pInfo = Find(wzVar); | ||
|  |         if (pInfo) { | ||
|  |             if (Compare(pwzz, pInfo->m_pwzVal) == 0) { | ||
|  |                 pInfo->m_fUsed = FALSE; | ||
|  |             } | ||
|  |         } | ||
|  |         pwzz += Size(pwzz) + 1; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     EnvInfo ** pSorted = (EnvInfo **)GlobalAlloc(GPTR, s_nVars * sizeof(EnvInfo *)); | ||
|  | 
 | ||
|  |     for (DWORD n = 0; n < s_nCapacity; n++) { | ||
|  |         if (s_pVars[n] != NULL) { | ||
|  |             if (s_pVars[n]->m_nIndex > s_nVars) { | ||
|  |                 DEBUG_BREAK(); | ||
|  |             } | ||
|  |             pSorted[s_pVars[n]->m_nIndex] = s_pVars[n]; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     for (DWORD n = 0; n < s_nVars; n++) { | ||
|  |         EnvInfo *pInfo = pSorted[n]; | ||
|  | 
 | ||
|  |         if (pInfo == NULL) { | ||
|  |             Print("<!-- Warning: Missing %d of %d -->\n", n, s_nVars); | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (pInfo->m_fUsed && pInfo->m_pwzVal[0]) { | ||
|  |             Print("<t:Var var=\"%le\">%le</t:Var>\n", pInfo->m_pwzVar, pInfo->m_pwzVal); | ||
|  |         } | ||
|  |     } | ||
|  |     GlobalFree((HGLOBAL)pSorted); | ||
|  | 
 | ||
|  |     Tblog("</t:Vars>\n"); | ||
|  | 
 | ||
|  |     LockRelease(); | ||
|  | } | ||
|  | 
 | ||
|  | void SaveEnvironment() | ||
|  | { | ||
|  |     LPWCH pwStrings = GetEnvironmentStringsW(); | ||
|  |     PCWSTR pwEnv = (PCWSTR)pwStrings; | ||
|  | 
 | ||
|  |     while (*pwEnv != '\0') { | ||
|  |         WCHAR wzVar[MAX_PATH]; | ||
|  |         PWCHAR pwzDst = wzVar; | ||
|  |         PCWSTR pwzVal = NULL; | ||
|  | 
 | ||
|  |         if (*pwEnv == '=') { | ||
|  |             *pwzDst++ = *pwEnv++; | ||
|  |         } | ||
|  |         while (*pwEnv != '\0' && *pwEnv != '=') { | ||
|  |             *pwzDst++ = *pwEnv++; | ||
|  |         } | ||
|  |         *pwzDst++ = '\0'; | ||
|  | 
 | ||
|  |         if (*pwEnv == '=') { | ||
|  |             pwEnv++; | ||
|  |         } | ||
|  | 
 | ||
|  |         pwzVal = pwEnv; | ||
|  |         while (*pwEnv != '\0') { | ||
|  |             pwEnv++; | ||
|  |         } | ||
|  |         if (*pwEnv == '\0') { | ||
|  |             pwEnv++; | ||
|  |         } | ||
|  |         if (wzVar[0] != '=') { | ||
|  |             EnvVars::Add(wzVar, pwzVal); | ||
|  |         } | ||
|  |     } | ||
|  |     FreeEnvironmentStringsW(pwStrings); | ||
|  | } | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | struct ProcInfo | ||
|  | { | ||
|  |     HANDLE  m_hProc; | ||
|  |     DWORD   m_nProcId; | ||
|  |     DWORD   m_nProc; | ||
|  | }; | ||
|  | 
 | ||
|  | class Procs | ||
|  | { | ||
|  |   private: | ||
|  |     static CRITICAL_SECTION s_csLock; | ||
|  |     static DWORD            s_nProcs; | ||
|  |     static ProcInfo         s_rProcs[4049]; | ||
|  | 
 | ||
|  |   private: | ||
|  |     static ProcInfo& HashToSlot(HANDLE handle) | ||
|  |     { | ||
|  |         return s_rProcs[((DWORD_PTR)handle) % ARRAYSIZE(s_rProcs)]; | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID LockAcquire() | ||
|  |     { | ||
|  |         EnterCriticalSection(&s_csLock); | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID LockRelease() | ||
|  |     { | ||
|  |         LeaveCriticalSection(&s_csLock); | ||
|  |     } | ||
|  | 
 | ||
|  |   public: | ||
|  |     static VOID Initialize(); | ||
|  |     static ProcInfo * Create(HANDLE hProc, DWORD nProcId); | ||
|  |     static BOOL Close(HANDLE hProc); | ||
|  | }; | ||
|  | 
 | ||
|  | CRITICAL_SECTION    Procs::s_csLock; | ||
|  | DWORD               Procs::s_nProcs = 0; | ||
|  | ProcInfo            Procs::s_rProcs[4049]; | ||
|  | 
 | ||
|  | VOID Procs::Initialize() | ||
|  | { | ||
|  |     InitializeCriticalSection(&s_csLock); | ||
|  |     for (DWORD i = 0; i < ARRAYSIZE(s_rProcs); i++) { | ||
|  |         s_rProcs[i].m_hProc = INVALID_HANDLE_VALUE; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | ProcInfo * Procs::Create(HANDLE hProc, DWORD nProcId) | ||
|  | { | ||
|  |     LockAcquire(); | ||
|  |     s_nProcs++; | ||
|  |     ProcInfo& slot = HashToSlot(hProc); | ||
|  |     slot.m_hProc = hProc; | ||
|  |     slot.m_nProcId = nProcId; | ||
|  |     slot.m_nProc = s_nProcs; | ||
|  |     Print("<!-- CreateProcess (%d)-->\n", slot.m_nProc); | ||
|  |     LockRelease(); | ||
|  | 
 | ||
|  |     return &slot; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL Procs::Close(HANDLE hProc) | ||
|  | { | ||
|  |     BOOL first = false; | ||
|  | 
 | ||
|  |     LockAcquire(); | ||
|  |     ProcInfo& slot = HashToSlot(hProc); | ||
|  |     if (slot.m_hProc == hProc) { | ||
|  |         first = true; | ||
|  |         Print("<!-- CloseProcess (%d)-->\n", slot.m_nProc); | ||
|  |         slot.m_hProc = INVALID_HANDLE_VALUE; | ||
|  |         slot.m_nProcId = 0; | ||
|  |         slot.m_nProc = 0; | ||
|  |         s_nProcs--; | ||
|  |     } | ||
|  |     LockRelease(); | ||
|  | 
 | ||
|  |     return first; | ||
|  | } | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | struct FileInfo | ||
|  | { | ||
|  |     DWORD   m_nHash; | ||
|  |     DWORD   m_nIndex; | ||
|  | 
 | ||
|  |     BOOL    m_fCantRead;        // Set for file that are opened Create
 | ||
|  |     BOOL    m_fRead; | ||
|  |     BOOL    m_fWrite; | ||
|  | 
 | ||
|  |     BOOL    m_fDelete; | ||
|  |     BOOL    m_fCleanup; | ||
|  |     BOOL    m_fSystemPath; | ||
|  |     BOOL    m_fTemporaryPath; | ||
|  |     BOOL    m_fTemporaryFile; | ||
|  | 
 | ||
|  |     DWORD   m_cbRead; | ||
|  |     DWORD   m_cbWrite; | ||
|  | 
 | ||
|  |     BOOL    m_fAppend; | ||
|  |     BOOL    m_fAbsorbed;        // Absorbed by TraceBld.
 | ||
|  |     BOOL    m_fDirectory; | ||
|  | 
 | ||
|  |     PCWSTR  m_pwzPath; | ||
|  |     PBYTE   m_pbContent; | ||
|  |     DWORD   m_cbContent; | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | class FileNames | ||
|  | { | ||
|  |   private: | ||
|  |     static CRITICAL_SECTION s_csLock; | ||
|  |     static DWORD            s_nFiles; | ||
|  |     static DWORD            s_nCapacity; | ||
|  |     static FileInfo **      s_pFiles; | ||
|  | 
 | ||
|  |   public: | ||
|  |     static WCHAR            s_wzSysPath[MAX_PATH]; | ||
|  |     static WCHAR            s_wzS64Path[MAX_PATH]; | ||
|  |     static WCHAR            s_wzTmpPath[MAX_PATH]; | ||
|  |     static WCHAR            s_wzExePath[MAX_PATH]; | ||
|  |     static DWORD            s_wcSysPath; | ||
|  |     static DWORD            s_wcS64Path; | ||
|  |     static DWORD            s_wcTmpPath; | ||
|  |     static DWORD            s_wcExePath; | ||
|  | 
 | ||
|  |   private: | ||
|  |     static DWORD Hash(PCWSTR pwzFile) | ||
|  |     { | ||
|  |         DWORD hash = 5381; | ||
|  |         while (*pwzFile != 0) { | ||
|  |             WCHAR c = *pwzFile++; | ||
|  |             if (c >= 'A' && c <= 'Z') { | ||
|  |                 c += ('a' - 'A'); | ||
|  |             } | ||
|  |             hash = ((hash << 5) + hash) + c; | ||
|  |         } | ||
|  |         return hash; | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID LockAcquire() | ||
|  |     { | ||
|  |         EnterCriticalSection(&s_csLock); | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID LockRelease() | ||
|  |     { | ||
|  |         LeaveCriticalSection(&s_csLock); | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID Resize(DWORD nCapacity); | ||
|  |     static VOID Set(FileInfo *info); | ||
|  |     static VOID Replace(PWCHAR pwzBuffer, PWCHAR pwzDstEnd, DWORD cwOld, PCWSTR pwzNew); | ||
|  | 
 | ||
|  |   public: | ||
|  |     static BOOL Equal(PCWSTR pwzA, PCWSTR pwzB) | ||
|  |     { | ||
|  |         return (Compare(pwzA, pwzB) == 0); | ||
|  |     } | ||
|  | 
 | ||
|  |     static BOOL PrefixMatch(PCWSTR pwzFile, PCWSTR pwzPrefix) | ||
|  |     { | ||
|  |         for (;;) { | ||
|  |             WCHAR cFile = *pwzFile++; | ||
|  |             WCHAR cPrefix = *pwzPrefix++; | ||
|  | 
 | ||
|  |             if (cFile >= 'A' && cFile <= 'Z') { | ||
|  |                 cFile += ('a' - 'A'); | ||
|  |             } | ||
|  |             if (cPrefix >= 'A' && cPrefix <= 'Z') { | ||
|  |                 cPrefix += ('a' - 'A'); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (cPrefix == 0) { | ||
|  |                 return TRUE; | ||
|  |             } | ||
|  |             if (cFile != cPrefix) { | ||
|  |                 return FALSE; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     static BOOL SuffixMatch(PCWSTR pwzFile, PCWSTR pwzSuffix) | ||
|  |     { | ||
|  |         // Move both pointers to the end of the strings.
 | ||
|  |         PCWSTR pwzFileBeg = pwzFile; | ||
|  |         while (*pwzFile) { | ||
|  |             pwzFile++; | ||
|  |         } | ||
|  | 
 | ||
|  |         PCWSTR pwzSuffixBeg = pwzSuffix; | ||
|  |         while (*pwzSuffix) { | ||
|  |             pwzSuffix++; | ||
|  |         } | ||
|  | 
 | ||
|  |         // Now walk backwards comparing strings.
 | ||
|  |         for (;;) { | ||
|  |             WCHAR cFile = (pwzFile > pwzFileBeg) ? *--pwzFile : 0; | ||
|  |             WCHAR cSuffix = (pwzSuffix > pwzSuffixBeg) ? *--pwzSuffix : 0; | ||
|  | 
 | ||
|  |             if (cFile >= 'A' && cFile <= 'Z') { | ||
|  |                 cFile += ('a' - 'A'); | ||
|  |             } | ||
|  |             if (cSuffix >= 'A' && cSuffix <= 'Z') { | ||
|  |                 cSuffix += ('a' - 'A'); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (cSuffix == 0) { | ||
|  |                 return TRUE; | ||
|  |             } | ||
|  |             if (cFile != cSuffix) { | ||
|  |                 return FALSE; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID EndInSlash(PWCHAR pwzPath) | ||
|  |     { | ||
|  |         if (*pwzPath) { | ||
|  |             while (*pwzPath) { | ||
|  |                 pwzPath++; | ||
|  |             } | ||
|  |             if (pwzPath[-1] != '\\') { | ||
|  |                 *pwzPath++ = '\\'; | ||
|  |                 *pwzPath = '\0'; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |   public: | ||
|  |     static VOID Initialize(); | ||
|  |     static VOID Dump(); | ||
|  |     static FileInfo * FindPartial(PCWSTR pwzPath); | ||
|  |     static FileInfo * FindPartial(PCSTR pszPath); | ||
|  |     static FileInfo * FindFull(PCWSTR pwzPath); | ||
|  |     static PCWSTR ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, PCWSTR pwzPath); | ||
|  |     static PCWSTR ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, FileInfo *pInfo); | ||
|  |     static VOID ParameterizeLine(PWCHAR pwzDst, PWCHAR pwzDstEnd); | ||
|  | }; | ||
|  | 
 | ||
|  | CRITICAL_SECTION    FileNames::s_csLock; | ||
|  | DWORD               FileNames::s_nFiles = 0; | ||
|  | DWORD               FileNames::s_nCapacity = 0; | ||
|  | FileInfo **         FileNames::s_pFiles; | ||
|  | WCHAR               FileNames::s_wzSysPath[MAX_PATH]; | ||
|  | WCHAR               FileNames::s_wzS64Path[MAX_PATH]; | ||
|  | WCHAR               FileNames::s_wzTmpPath[MAX_PATH]; | ||
|  | WCHAR               FileNames::s_wzExePath[MAX_PATH]; | ||
|  | DWORD               FileNames::s_wcSysPath; | ||
|  | DWORD               FileNames::s_wcS64Path; | ||
|  | DWORD               FileNames::s_wcTmpPath; | ||
|  | DWORD               FileNames::s_wcExePath; | ||
|  | 
 | ||
|  | VOID FileNames::Initialize() | ||
|  | { | ||
|  |     InitializeCriticalSection(&s_csLock); | ||
|  | 
 | ||
|  |     s_wzSysPath[0] = '\0'; | ||
|  |     GetSystemDirectoryW(s_wzSysPath, ARRAYSIZE(s_wzSysPath)); | ||
|  |     EndInSlash(s_wzSysPath); | ||
|  | 
 | ||
|  |     s_wzS64Path[0] = '\0'; | ||
|  |     GetWindowsDirectoryW(s_wzS64Path, ARRAYSIZE(s_wzS64Path)); | ||
|  |     EndInSlash(s_wzS64Path); | ||
|  |     Copy(s_wzS64Path + Size(s_wzS64Path), L"SysWOW64\\"); | ||
|  | 
 | ||
|  |     s_wzTmpPath[0] = '\0'; | ||
|  |     GetTempPathW(ARRAYSIZE(s_wzTmpPath), s_wzTmpPath); | ||
|  |     EndInSlash(s_wzTmpPath); | ||
|  | 
 | ||
|  |     s_wzExePath[0] = '\0'; | ||
|  |     GetModuleFileNameW(NULL, s_wzExePath, ARRAYSIZE(s_wzExePath)); | ||
|  |     PWCHAR pwzLast = s_wzExePath; | ||
|  |     for (PWCHAR pwz = s_wzExePath; *pwz; pwz++) { | ||
|  |         if (*pwz == '\\') { | ||
|  |             pwzLast = pwz; | ||
|  |         } | ||
|  |     } | ||
|  |     if (*pwzLast == '\\') { | ||
|  |         *++pwzLast = '\0'; | ||
|  |     } | ||
|  | 
 | ||
|  |     s_wcSysPath = Size(s_wzSysPath); | ||
|  |     s_wcS64Path = Size(s_wzS64Path); | ||
|  |     s_wcTmpPath = Size(s_wzTmpPath); | ||
|  |     s_wcExePath = Size(s_wzExePath); | ||
|  | 
 | ||
|  |     Resize(4049); | ||
|  | } | ||
|  | 
 | ||
|  | VOID FileNames::Resize(DWORD nCapacity) | ||
|  | { | ||
|  |     if (nCapacity > s_nCapacity) { | ||
|  |         DWORD nOld = s_nCapacity; | ||
|  |         FileInfo ** pOld = s_pFiles; | ||
|  | 
 | ||
|  |         s_pFiles = (FileInfo **)GlobalAlloc(GPTR, nCapacity * sizeof(FileInfo *)); | ||
|  |         s_nCapacity = nCapacity; | ||
|  | 
 | ||
|  |         if (pOld != NULL) { | ||
|  |             for (DWORD n = 0; n < nOld; n++) { | ||
|  |                 if (pOld[n] != NULL) { | ||
|  |                     Set(pOld[n]); | ||
|  |                 } | ||
|  |             } | ||
|  |             GlobalFree((HGLOBAL)pOld); | ||
|  |             pOld = NULL; | ||
|  |         } | ||
|  |         s_nCapacity = nCapacity; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID FileNames::Set(FileInfo *info) | ||
|  | { | ||
|  |     DWORD hash = info->m_nHash; | ||
|  |     DWORD slot = hash % s_nCapacity; | ||
|  |     DWORD death = 0; | ||
|  | 
 | ||
|  |     // Find an empty slot.
 | ||
|  |     for (; s_pFiles[slot] != NULL; slot = (slot + 1) % s_nCapacity) { | ||
|  |         if (++death > s_nCapacity) { | ||
|  |             // We should have dropped out at some point...
 | ||
|  |             DEBUG_BREAK(); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     s_pFiles[slot] = info; | ||
|  | } | ||
|  | 
 | ||
|  | FileInfo * FileNames::FindFull(PCWSTR pwzPath) | ||
|  | { | ||
|  |     if (pwzPath == NULL) { | ||
|  |         return NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     DWORD hash = Hash(pwzPath); | ||
|  |     DWORD slot = hash % s_nCapacity; | ||
|  |     FileInfo *info = NULL; | ||
|  |     DWORD death = 0; | ||
|  | 
 | ||
|  |     // Find the the matching slot, or an empty one.
 | ||
|  |     for (; s_pFiles[slot] != NULL; slot = (slot + 1) % s_nCapacity) { | ||
|  |         if (Equal(s_pFiles[slot]->m_pwzPath, pwzPath)) { | ||
|  |             info = s_pFiles[slot]; | ||
|  |             goto succeed; | ||
|  |         } | ||
|  |         if (++death > s_nCapacity) { | ||
|  |             // We should have dropped out at some point...
 | ||
|  |             DEBUG_BREAK(); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     // Add the file to list of known files.
 | ||
|  |     info = (FileInfo *)GlobalAlloc(GPTR, sizeof(FileInfo)); | ||
|  |     info->m_nHash = hash; | ||
|  |     info->m_nIndex = s_nFiles++; | ||
|  |     info->m_pwzPath = Save(pwzPath); | ||
|  |     info->m_fSystemPath = (PrefixMatch(info->m_pwzPath, s_wzSysPath) || | ||
|  |                            PrefixMatch(info->m_pwzPath, s_wzS64Path)); | ||
|  |     info->m_fTemporaryPath = PrefixMatch(info->m_pwzPath, s_wzTmpPath); | ||
|  |     info->m_fTemporaryFile = SuffixMatch(info->m_pwzPath, L".tmp"); | ||
|  | 
 | ||
|  |     s_pFiles[slot] = info; | ||
|  | 
 | ||
|  |     // Check if we should grow the table.
 | ||
|  |     if (s_nFiles > (s_nCapacity / 2)) { | ||
|  |         Resize(s_nCapacity * 2 - 1); | ||
|  |     } | ||
|  | 
 | ||
|  |   succeed: | ||
|  |     LockRelease(); | ||
|  | 
 | ||
|  |     return info; | ||
|  | } | ||
|  | 
 | ||
|  | FileInfo * FileNames::FindPartial(PCWSTR pwzPath) | ||
|  | { | ||
|  |     WCHAR wzPath[MAX_PATH]; | ||
|  |     PWCHAR pwzFile = NULL; | ||
|  | 
 | ||
|  |     if (!GetFullPathNameW(pwzPath, ARRAYSIZE(wzPath), wzPath, &pwzFile)) { | ||
|  |         return FindFull(pwzPath); | ||
|  |     } | ||
|  |     else { | ||
|  |         return FindFull(wzPath); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | FileInfo * FileNames::FindPartial(PCSTR pwzPath) | ||
|  | { | ||
|  |     WCHAR wzPath[MAX_PATH]; | ||
|  |     PWCHAR pwzFile = wzPath; | ||
|  | 
 | ||
|  |     while (*pwzPath) { | ||
|  |         *pwzFile++ = *pwzPath++; | ||
|  |     } | ||
|  |     *pwzFile = '\0'; | ||
|  | 
 | ||
|  |     return FindPartial(wzPath); | ||
|  | } | ||
|  | 
 | ||
|  | PCWSTR FileNames::ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, FileInfo *pInfo) | ||
|  | { | ||
|  |     return ParameterizeName(pwzDst, cMaxDst, pInfo->m_pwzPath); | ||
|  | } | ||
|  | 
 | ||
|  | PCWSTR FileNames::ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, PCWSTR pwzPath) | ||
|  | { | ||
|  |     if (PrefixMatch(pwzPath, s_wzSysPath)) { | ||
|  |         Copy(pwzDst, L"%SYSDIR%\\"); | ||
|  |         Copy(pwzDst + Size(pwzDst), pwzPath + s_wcSysPath); | ||
|  |         goto finish; | ||
|  |     } | ||
|  |     else if (PrefixMatch(pwzPath, s_wzS64Path)) { | ||
|  |         Copy(pwzDst, L"%SYSDIR%\\"); | ||
|  |         Copy(pwzDst + Size(pwzDst), pwzPath + s_wcS64Path); | ||
|  |         goto finish; | ||
|  |     } | ||
|  |     else if (PrefixMatch(pwzPath, s_wzTmpPath)) { | ||
|  |         Copy(pwzDst, L"%TMPDIR%\\"); | ||
|  |         Copy(pwzDst + Size(pwzDst), pwzPath + s_wcTmpPath); | ||
|  |         goto finish; | ||
|  |     } | ||
|  |     else { | ||
|  |         Copy(pwzDst, pwzPath); | ||
|  | 
 | ||
|  |       finish: | ||
|  | #if 0 // to convert to all lower case.
 | ||
|  |         for (PWCHAR pwz = pwzDst; *pwz && pwz < pwzDst + cMaxDst; pwz++) { | ||
|  |             if (*pwz >= 'A' && *pwz <= 'Z') { | ||
|  |                 *pwz = 'a' + (*pwz - 'A'); | ||
|  |             } | ||
|  |         } | ||
|  | #else
 | ||
|  |         (void)cMaxDst; | ||
|  | #endif
 | ||
|  |         return pwzDst; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID FileNames::Replace(PWCHAR pwzDst, PWCHAR pwzDstEnd, DWORD cwOld, PCWSTR pwzNew) | ||
|  | { | ||
|  |     DWORD cwNew = Size(pwzNew); | ||
|  |     DWORD cwDst = Size(pwzDst); | ||
|  | 
 | ||
|  |     if (cwOld < cwNew) {        // We have to insert.
 | ||
|  |         if ((cwDst + cwNew - cwOld) >= (DWORD)(pwzDstEnd - pwzDst)) { | ||
|  |             // Won't fit, so abort.
 | ||
|  |             return; | ||
|  |         } | ||
|  | 
 | ||
|  |         PWCHAR pwzTo = pwzDst + cwDst + (cwNew - cwOld); | ||
|  |         PWCHAR pwzFm = pwzDst + cwDst; | ||
|  | 
 | ||
|  |         while (pwzTo >= pwzDst) { | ||
|  |             *pwzTo-- = *pwzFm--; | ||
|  |         } | ||
|  |     } | ||
|  |     else if (cwOld > cwNew) {  // We have to remove.
 | ||
|  |         PWCHAR pwzTo = pwzDst + cwNew; | ||
|  |         PWCHAR pwzFm = pwzDst + cwOld; | ||
|  | 
 | ||
|  |         while (*pwzFm) { | ||
|  |             *pwzTo++ = *pwzFm++; | ||
|  |         } | ||
|  |         *pwzTo = '\0'; | ||
|  |     } | ||
|  | 
 | ||
|  |     // Now write the new string.
 | ||
|  |     while (*pwzNew) { | ||
|  |         *pwzDst++ = *pwzNew++; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID FileNames::ParameterizeLine(PWCHAR pwzDst, PWCHAR pwzDstEnd) | ||
|  | { | ||
|  |     for (; *pwzDst != '\0'; pwzDst++) { | ||
|  |         if (PrefixMatch(pwzDst, s_wzSysPath)) { | ||
|  |             Replace(pwzDst, pwzDstEnd, s_wcSysPath, L"%SYSDIR%\\"); | ||
|  |         } | ||
|  |         else if (PrefixMatch(pwzDst, s_wzS64Path)) { | ||
|  |             Replace(pwzDst, pwzDstEnd, s_wcS64Path, L"%SYSDIR%\\"); | ||
|  |         } | ||
|  |         else if (PrefixMatch(pwzDst, s_wzTmpPath)) { | ||
|  |             Replace(pwzDst, pwzDstEnd, s_wcTmpPath, L"%TMPDIR%\\"); | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID FileNames::Dump() | ||
|  | { | ||
|  |     WCHAR wzPath[MAX_PATH]; | ||
|  | 
 | ||
|  |     if (s_nFiles == 0) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     Tblog("<t:Files>\n"); | ||
|  | 
 | ||
|  |     FileInfo ** pSorted = (FileInfo **)GlobalAlloc(GPTR, s_nFiles * sizeof(FileInfo *)); | ||
|  | 
 | ||
|  |     for (DWORD n = 0; n < s_nCapacity; n++) { | ||
|  |         if (s_pFiles[n] != NULL) { | ||
|  |             if (s_pFiles[n]->m_nIndex > s_nFiles) { | ||
|  |                 DEBUG_BREAK(); | ||
|  |             } | ||
|  |             pSorted[s_pFiles[n]->m_nIndex] = s_pFiles[n]; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     for (DWORD n = 0; n < s_nFiles; n++) { | ||
|  |         FileInfo *pInfo = pSorted[n]; | ||
|  | 
 | ||
|  |         if (pInfo == NULL) { | ||
|  |             Print("<!-- Warning: Missing %d of %d -->\n", n, s_nFiles); | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         BOOL fRead = pInfo->m_fRead; | ||
|  |         BOOL fWrite = pInfo->m_fWrite; | ||
|  |         BOOL fDelete = (pInfo->m_fDelete); | ||
|  |         BOOL fCleanup = (pInfo->m_fCleanup); | ||
|  |         BOOL fAppend = (pInfo->m_fAppend); | ||
|  | 
 | ||
|  | #if 0
 | ||
|  |         if (fDelete && !fRead && !fWrite) { | ||
|  |             Print("<!-- Discarding: %ls -->\n", pInfo->m_pwzPath); | ||
|  |             // Discard pipe files only passed to children.
 | ||
|  |             continue; | ||
|  |         } | ||
|  | #endif
 | ||
|  |         if (pInfo->m_fAbsorbed) { | ||
|  |             // Discard response fles
 | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (PrefixMatch(pInfo->m_pwzPath, s_wzExePath) || | ||
|  |             PrefixMatch(pInfo->m_pwzPath, s_wzSysPath) || | ||
|  |             PrefixMatch(pInfo->m_pwzPath, s_wzS64Path)) { | ||
|  |             // Discard files from exec directory (because considered internal to code).
 | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  | #if 1 // Ignore PIPEs.
 | ||
|  |         if (FileNames::PrefixMatch(pInfo->m_pwzPath, L"\\\\.\\PIPE\\")) { | ||
|  |             continue; | ||
|  |         } | ||
|  | #endif
 | ||
|  |         if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conout$")) { | ||
|  |             continue; | ||
|  |         } | ||
|  |         if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conin$")) { | ||
|  |             continue; | ||
|  |         } | ||
|  |         if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\nul")) { | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo); | ||
|  | 
 | ||
|  |         if (pInfo->m_fDirectory) { | ||
|  |             Print("<t:File mkdir=\"true\">%ls</t:File>\n", wzPath); | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (!fRead && !fWrite && !fDelete && !fCleanup) { | ||
|  |             // Discard do "none" files.
 | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (pInfo->m_pbContent == NULL || | ||
|  |             pInfo->m_fDelete || | ||
|  |             pInfo->m_fCleanup || | ||
|  |             pInfo->m_fWrite) { | ||
|  | 
 | ||
|  |             Print("<t:File%s%s%s%s%s>%ls</t:File>\n", | ||
|  |                   fRead ? " read=\"true\"" : "", | ||
|  |                   fWrite ? " write=\"true\"" : "", | ||
|  |                   fDelete ? " delete=\"true\"" : "", | ||
|  |                   fCleanup ? " cleanup=\"true\"" : "", | ||
|  |                   fAppend ? " append=\"true\"" : "", | ||
|  |                   // size=\"%d\" pInfo->m_cbContent,
 | ||
|  |                   wzPath); | ||
|  |         } | ||
|  |         else if ((pInfo->m_pbContent)[0] == 0xff && (pInfo->m_pbContent)[1] == 0xfe) { | ||
|  |             // Unicode
 | ||
|  |             Print("<t:File%s%s%s%s%s>%ls<t:Data>%le</t:Data></t:File>\n", | ||
|  |                   fRead ? " read=\"true\"" : "", | ||
|  |                   fWrite ? " write=\"true\"" : "", | ||
|  |                   fDelete ? " delete=\"true\"" : "", | ||
|  |                   fCleanup ? " cleanup=\"true\"" : "", | ||
|  |                   fAppend ? " append=\"true\"" : "", | ||
|  |                   //  size=\"%d\" pInfo->m_cbContent,
 | ||
|  |                   wzPath, | ||
|  |                   RemoveReturns((PWCHAR)pInfo->m_pbContent)); | ||
|  |         } | ||
|  |         else { | ||
|  |             // Ascii
 | ||
|  |             Print("<t:File%s%s%s%s%s>%ls<t:Data>%he</t:Data></t:File>\n", | ||
|  |                   fRead ? " read=\"true\"" : "", | ||
|  |                   fWrite ? " write=\"true\"" : "", | ||
|  |                   fDelete ? " delete=\"true\"" : "", | ||
|  |                   fCleanup ? " cleanup=\"true\"" : "", | ||
|  |                   fAppend ? " append=\"true\"" : "", | ||
|  |                   //  size=\"%d\" pInfo->m_cbContent,
 | ||
|  |                   wzPath, | ||
|  |                   RemoveReturns((PCHAR)pInfo->m_pbContent)); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (pInfo->m_pbContent != NULL) { | ||
|  |             GlobalFree((HGLOBAL)pInfo->m_pbContent); | ||
|  |             pInfo->m_pbContent = NULL; | ||
|  |         } | ||
|  |     } | ||
|  |     GlobalFree((HGLOBAL)pSorted); | ||
|  | 
 | ||
|  |     Tblog("</t:Files>\n"); | ||
|  | 
 | ||
|  |     LockRelease(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | class OpenFiles | ||
|  | { | ||
|  |   private: | ||
|  |     struct SLOT | ||
|  |     { | ||
|  |         HANDLE      m_hHandle; | ||
|  |         FileInfo *  m_pFile; | ||
|  |         ProcInfo *  m_pProc; | ||
|  |     }; | ||
|  | 
 | ||
|  |   private: | ||
|  |     static CRITICAL_SECTION s_csLock; | ||
|  |     static DWORD            s_nHandles; | ||
|  |     static SLOT             s_rHandles[4049]; | ||
|  | 
 | ||
|  |   private: | ||
|  |     static SLOT& HashToSlot(HANDLE handle) | ||
|  |     { | ||
|  |         return s_rHandles[((DWORD_PTR)handle) % ARRAYSIZE(s_rHandles)]; | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID LockAcquire() | ||
|  |     { | ||
|  |         EnterCriticalSection(&s_csLock); | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID LockRelease() | ||
|  |     { | ||
|  |         LeaveCriticalSection(&s_csLock); | ||
|  |     } | ||
|  | 
 | ||
|  |   public: | ||
|  |     static VOID Initialize(); | ||
|  | 
 | ||
|  |     static VOID SetWrite(HANDLE hFile, DWORD cbData) | ||
|  |     { | ||
|  |         SLOT& slot = HashToSlot(hFile); | ||
|  |         if (slot.m_hHandle == hFile) { | ||
|  |             slot.m_pFile->m_fWrite = TRUE; | ||
|  |             slot.m_pFile->m_cbWrite += cbData; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     static VOID SetRead(HANDLE hFile, DWORD cbData) | ||
|  |     { | ||
|  |         SLOT& slot = HashToSlot(hFile); | ||
|  |         if (slot.m_hHandle == hFile) { | ||
|  |             slot.m_pFile->m_fRead = TRUE; | ||
|  |             slot.m_pFile->m_cbRead += cbData; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     static BOOL Forget(HANDLE handle); | ||
|  |     static BOOL Remember(HANDLE hFile, FileInfo *pInfo); | ||
|  |     static BOOL Remember(HANDLE hProc, ProcInfo *pInfo); | ||
|  |     static FileInfo * RecallFile(HANDLE hFile); | ||
|  |     static ProcInfo * RecallProc(HANDLE hProc); | ||
|  | }; | ||
|  | 
 | ||
|  | CRITICAL_SECTION    OpenFiles::s_csLock;  // Guards access to OpenFile stuctures.
 | ||
|  | DWORD               OpenFiles::s_nHandles = 0; | ||
|  | OpenFiles::SLOT     OpenFiles::s_rHandles[4049]; | ||
|  | 
 | ||
|  | VOID OpenFiles::Initialize() | ||
|  | { | ||
|  |     InitializeCriticalSection(&s_csLock); | ||
|  |     for (DWORD n = 0; n < ARRAYSIZE(s_rHandles); n++) { | ||
|  |         s_rHandles[n].m_hHandle = INVALID_HANDLE_VALUE; | ||
|  |         s_rHandles[n].m_pFile = NULL; | ||
|  |         s_rHandles[n].m_pProc = NULL; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | BOOL OpenFiles::Forget(HANDLE handle) | ||
|  | { | ||
|  |     LockAcquire(); | ||
|  |     OpenFiles::SLOT& slot = HashToSlot(handle); | ||
|  | 
 | ||
|  |     if (slot.m_hHandle == handle    ) { | ||
|  |         slot.m_hHandle = INVALID_HANDLE_VALUE; | ||
|  |         slot.m_pFile = NULL; | ||
|  |         slot.m_pProc = NULL; | ||
|  |         s_nHandles--; | ||
|  |     } | ||
|  |     LockRelease(); | ||
|  |     return FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL OpenFiles::Remember(HANDLE hFile, FileInfo *pFile) | ||
|  | { | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     OpenFiles::SLOT& slot = HashToSlot(hFile); | ||
|  |     if (slot.m_hHandle != hFile && slot.m_hHandle != INVALID_HANDLE_VALUE) { | ||
|  |         // hash collision
 | ||
|  |         DEBUG_BREAK(); | ||
|  |     } | ||
|  | 
 | ||
|  |     slot.m_hHandle = hFile; | ||
|  |     slot.m_pFile = pFile; | ||
|  |     slot.m_pProc = NULL; | ||
|  |     s_nHandles++; | ||
|  | 
 | ||
|  |     LockRelease(); | ||
|  | 
 | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL OpenFiles::Remember(HANDLE hProc, ProcInfo *pProc) | ||
|  | { | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     OpenFiles::SLOT& slot = HashToSlot(hProc); | ||
|  |     if (slot.m_hHandle != hProc && slot.m_hHandle != INVALID_HANDLE_VALUE) { | ||
|  |         // hash collision
 | ||
|  |         DEBUG_BREAK(); | ||
|  |     } | ||
|  | 
 | ||
|  |     slot.m_hHandle = hProc; | ||
|  |     slot.m_pProc = pProc; | ||
|  |     slot.m_pFile = NULL; | ||
|  |     s_nHandles++; | ||
|  | 
 | ||
|  |     LockRelease(); | ||
|  | 
 | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | FileInfo * OpenFiles::RecallFile(HANDLE hFile) | ||
|  | { | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     OpenFiles::SLOT& slot = HashToSlot(hFile); | ||
|  | 
 | ||
|  |     if (slot.m_hHandle == hFile) { | ||
|  |         LockRelease(); | ||
|  |         return slot.m_pFile; | ||
|  |     } | ||
|  |     LockRelease(); | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | ProcInfo * OpenFiles::RecallProc(HANDLE hProc) | ||
|  | { | ||
|  |     LockAcquire(); | ||
|  | 
 | ||
|  |     OpenFiles::SLOT& slot = HashToSlot(hProc); | ||
|  | 
 | ||
|  |     if (slot.m_hHandle == hProc) { | ||
|  |         LockRelease(); | ||
|  |         return slot.m_pProc; | ||
|  |     } | ||
|  |     LockRelease(); | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | ///////////////////////////////////////////////////////////////////// VPrintf.
 | ||
|  | //
 | ||
|  | // Completely side-effect free printf replacement (but no FP numbers).
 | ||
|  | //
 | ||
|  | static PCHAR do_base(PCHAR pszOut, UINT64 nValue, UINT nBase, PCSTR pszDigits) | ||
|  | { | ||
|  |     CHAR szTmp[96]; | ||
|  |     int nDigit = sizeof(szTmp)-2; | ||
|  |     for (; nDigit >= 0; nDigit--) { | ||
|  |         szTmp[nDigit] = pszDigits[nValue % nBase]; | ||
|  |         nValue /= nBase; | ||
|  |     } | ||
|  |     for (nDigit = 0; nDigit < sizeof(szTmp) - 2 && szTmp[nDigit] == '0'; nDigit++) { | ||
|  |         // skip leading zeros.
 | ||
|  |     } | ||
|  |     for (; nDigit < sizeof(szTmp) - 1; nDigit++) { | ||
|  |         *pszOut++ = szTmp[nDigit]; | ||
|  |     } | ||
|  |     *pszOut = '\0'; | ||
|  |     return pszOut; | ||
|  | } | ||
|  | 
 | ||
|  | static PCHAR do_str(PCHAR pszOut, PCHAR pszEnd, PCSTR pszIn) | ||
|  | { | ||
|  |     while (*pszIn && pszOut < pszEnd) { | ||
|  |         *pszOut++ = *pszIn++; | ||
|  |     } | ||
|  |     *pszOut = '\0'; | ||
|  |     return pszOut; | ||
|  | } | ||
|  | 
 | ||
|  | static PCHAR do_wstr(PCHAR pszOut, PCHAR pszEnd, PCWSTR pszIn) | ||
|  | { | ||
|  |     while (*pszIn && pszOut < pszEnd) { | ||
|  |         *pszOut++ = (CHAR)*pszIn++; | ||
|  |     } | ||
|  |     *pszOut = '\0'; | ||
|  |     return pszOut; | ||
|  | } | ||
|  | 
 | ||
|  | static PCHAR do_estr(PCHAR pszOut, PCHAR pszEnd, PCSTR pszIn) | ||
|  | { | ||
|  |     while (*pszIn && pszOut < pszEnd) { | ||
|  |         if (*pszIn == '<') { | ||
|  |             if (pszOut + 4 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'l'; | ||
|  |             *pszOut++ = 't'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn == '>') { | ||
|  |             if (pszOut + 4 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'g'; | ||
|  |             *pszOut++ = 't'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn == '&') { | ||
|  |             if (pszOut + 5 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'a'; | ||
|  |             *pszOut++ = 'm'; | ||
|  |             *pszOut++ = 'p'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn == '\"') { | ||
|  |             if (pszOut + 6 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'q'; | ||
|  |             *pszOut++ = 'u'; | ||
|  |             *pszOut++ = 'o'; | ||
|  |             *pszOut++ = 't'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn == '\'') { | ||
|  |             if (pszOut + 6 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'a'; | ||
|  |             *pszOut++ = 'p'; | ||
|  |             *pszOut++ = 'o'; | ||
|  |             *pszOut++ = 's'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn  < ' ') { | ||
|  |             BYTE c = (BYTE)(*pszIn++); | ||
|  |             if (c < 10 && pszOut + 4 <= pszEnd) { | ||
|  |                 *pszOut++ = '&'; | ||
|  |                 *pszOut++ = '#'; | ||
|  |                 *pszOut++ = '0' + (c % 10); | ||
|  |                 *pszOut++ = ';'; | ||
|  |             } | ||
|  |             else if (c < 100 && pszOut + 5 <= pszEnd) { | ||
|  |                 *pszOut++ = '&'; | ||
|  |                 *pszOut++ = '#'; | ||
|  |                 *pszOut++ = '0' + ((c / 10) % 10); | ||
|  |                 *pszOut++ = '0' + (c % 10); | ||
|  |                 *pszOut++ = ';'; | ||
|  |             } | ||
|  |             else if (c < 1000 && pszOut + 6 <= pszEnd) { | ||
|  |                 *pszOut++ = '&'; | ||
|  |                 *pszOut++ = '#'; | ||
|  |                 *pszOut++ = '0' + ((c / 100) % 10); | ||
|  |                 *pszOut++ = '0' + ((c / 10) % 10); | ||
|  |                 *pszOut++ = '0' + (c % 10); | ||
|  |                 *pszOut++ = ';'; | ||
|  |             } | ||
|  |             else { | ||
|  |                 break; | ||
|  |             } | ||
|  |         } | ||
|  |         else { | ||
|  |             *pszOut++ = *pszIn++; | ||
|  |         } | ||
|  |     } | ||
|  |     *pszOut = '\0'; | ||
|  |     return pszOut; | ||
|  | } | ||
|  | 
 | ||
|  | static PCHAR do_ewstr(PCHAR pszOut, PCHAR pszEnd, PCWSTR pszIn) | ||
|  | { | ||
|  |     while (*pszIn && pszOut < pszEnd) { | ||
|  |         if (*pszIn == '<') { | ||
|  |             if (pszOut + 4 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'l'; | ||
|  |             *pszOut++ = 't'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn == '>') { | ||
|  |             if (pszOut + 4 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'g'; | ||
|  |             *pszOut++ = 't'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn == '&') { | ||
|  |             if (pszOut + 5 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'a'; | ||
|  |             *pszOut++ = 'm'; | ||
|  |             *pszOut++ = 'p'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn == '\"') { | ||
|  |             if (pszOut + 6 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'q'; | ||
|  |             *pszOut++ = 'u'; | ||
|  |             *pszOut++ = 'o'; | ||
|  |             *pszOut++ = 't'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn == '\'') { | ||
|  |             if (pszOut + 6 > pszEnd) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             pszIn++; | ||
|  |             *pszOut++ = '&'; | ||
|  |             *pszOut++ = 'a'; | ||
|  |             *pszOut++ = 'p'; | ||
|  |             *pszOut++ = 'o'; | ||
|  |             *pszOut++ = 's'; | ||
|  |             *pszOut++ = ';'; | ||
|  |         } | ||
|  |         else if (*pszIn  < ' ' || *pszIn > 127) { | ||
|  |             WCHAR c = *pszIn++; | ||
|  |             if (c < 10 && pszOut + 4 <= pszEnd) { | ||
|  |                 *pszOut++ = '&'; | ||
|  |                 *pszOut++ = '#'; | ||
|  |                 *pszOut++ = '0' + (CHAR)(c % 10); | ||
|  |                 *pszOut++ = ';'; | ||
|  |             } | ||
|  |             else if (c < 100 && pszOut + 5 <= pszEnd) { | ||
|  |                 *pszOut++ = '&'; | ||
|  |                 *pszOut++ = '#'; | ||
|  |                 *pszOut++ = '0' + (CHAR)((c / 10) % 10); | ||
|  |                 *pszOut++ = '0' + (CHAR)(c % 10); | ||
|  |                 *pszOut++ = ';'; | ||
|  |             } | ||
|  |             else if (c < 1000 && pszOut + 6 <= pszEnd) { | ||
|  |                 *pszOut++ = '&'; | ||
|  |                 *pszOut++ = '#'; | ||
|  |                 *pszOut++ = '0' + (CHAR)((c / 100) % 10); | ||
|  |                 *pszOut++ = '0' + (CHAR)((c / 10) % 10); | ||
|  |                 *pszOut++ = '0' + (CHAR)(c % 10); | ||
|  |                 *pszOut++ = ';'; | ||
|  |             } | ||
|  |             else { | ||
|  |                 break; | ||
|  |             } | ||
|  |         } | ||
|  |         else { | ||
|  |             *pszOut++ = (CHAR)*pszIn++; | ||
|  |         } | ||
|  |     } | ||
|  |     *pszOut = '\0'; | ||
|  |     return pszOut; | ||
|  | } | ||
|  | 
 | ||
|  | #if _MSC_VER >= 1900
 | ||
|  | #pragma warning(push)
 | ||
|  | #pragma warning(disable:4456) // declaration hides previous local declaration
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | VOID VSafePrintf(PCSTR pszMsg, va_list args, PCHAR pszBuffer, LONG cbBuffer) | ||
|  | { | ||
|  |     PCHAR pszOut = pszBuffer; | ||
|  |     PCHAR pszEnd = pszBuffer + cbBuffer - 1; | ||
|  |     pszBuffer[0] = '\0'; | ||
|  | 
 | ||
|  |     __try { | ||
|  |         while (*pszMsg && pszOut < pszEnd) { | ||
|  |             if (*pszMsg == '%') { | ||
|  |                 CHAR szHead[4] = ""; | ||
|  |                 INT nLen; | ||
|  |                 INT nWidth = 0; | ||
|  |                 INT nPrecision = 0; | ||
|  |                 BOOL fLeft = FALSE; | ||
|  |                 BOOL fPositive = FALSE; | ||
|  |                 BOOL fPound = FALSE; | ||
|  |                 BOOL fBlank = FALSE; | ||
|  |                 BOOL fZero = FALSE; | ||
|  |                 BOOL fDigit = FALSE; | ||
|  |                 BOOL fSmall = FALSE; | ||
|  |                 BOOL fLarge = FALSE; | ||
|  |                 BOOL f64Bit = FALSE; | ||
|  |                 PCSTR pszArg = pszMsg; | ||
|  | 
 | ||
|  |                 pszMsg++; | ||
|  | 
 | ||
|  |                 for (; (*pszMsg == '-' || | ||
|  |                         *pszMsg == '+' || | ||
|  |                         *pszMsg == '#' || | ||
|  |                         *pszMsg == ' ' || | ||
|  |                         *pszMsg == '0'); pszMsg++) { | ||
|  |                     switch (*pszMsg) { | ||
|  |                       case '-': fLeft = TRUE; break; | ||
|  |                       case '+': fPositive = TRUE; break; | ||
|  |                       case '#': fPound = TRUE; break; | ||
|  |                       case ' ': fBlank = TRUE; break; | ||
|  |                       case '0': fZero = TRUE; break; | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (*pszMsg == '*') { | ||
|  |                     nWidth = va_arg(args, INT); | ||
|  |                     pszMsg++; | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     while (*pszMsg >= '0' && *pszMsg <= '9') { | ||
|  |                         nWidth = nWidth * 10 + (*pszMsg++ - '0'); | ||
|  |                     } | ||
|  |                 } | ||
|  |                 if (*pszMsg == '.') { | ||
|  |                     pszMsg++; | ||
|  |                     fDigit = TRUE; | ||
|  |                     if (*pszMsg == '*') { | ||
|  |                         nPrecision = va_arg(args, INT); | ||
|  |                         pszMsg++; | ||
|  |                     } | ||
|  |                     else { | ||
|  |                         while (*pszMsg >= '0' && *pszMsg <= '9') { | ||
|  |                             nPrecision = nPrecision * 10 + (*pszMsg++ - '0'); | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (*pszMsg == 'h') { | ||
|  |                     fSmall = TRUE; | ||
|  |                     pszMsg++; | ||
|  |                 } | ||
|  |                 else if (*pszMsg == 'l') { | ||
|  |                     fLarge = TRUE; | ||
|  |                     pszMsg++; | ||
|  |                 } | ||
|  |                 else if (*pszMsg == 'I' && pszMsg[1] == '6' && pszMsg[2] == '4') { | ||
|  |                     f64Bit = TRUE; | ||
|  |                     pszMsg += 3; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (*pszMsg == 's' || *pszMsg == 'e' || *pszMsg == 'c') { | ||
|  |                     // We ignore the length, precision, and alignment
 | ||
|  |                     // to avoid using a temporary buffer.
 | ||
|  | 
 | ||
|  |                     if (*pszMsg == 's') { // [GalenH] need to not use temp.
 | ||
|  |                         PVOID pvData = va_arg(args, PVOID); | ||
|  | 
 | ||
|  |                         pszMsg++; | ||
|  | 
 | ||
|  |                         if (fSmall) { | ||
|  |                             fLarge = FALSE; | ||
|  |                         } | ||
|  | 
 | ||
|  |                         __try { | ||
|  |                             if (pvData == NULL) { | ||
|  |                                 pszOut = do_str(pszOut, pszEnd, "-NULL-"); | ||
|  |                             } | ||
|  |                             else if (fLarge) { | ||
|  |                                 pszOut = do_wstr(pszOut, pszEnd, (PWCHAR)pvData); | ||
|  |                             } | ||
|  |                             else { | ||
|  |                                 pszOut = do_str(pszOut, pszEnd, (PCHAR)pvData); | ||
|  |                             } | ||
|  |                         } __except(EXCEPTION_EXECUTE_HANDLER) { | ||
|  |                             pszOut = do_str(pszOut, pszEnd, "-"); | ||
|  |                             pszOut = do_base(pszOut, (UINT64)pvData, 16, | ||
|  |                                              "0123456789ABCDEF"); | ||
|  |                             pszOut = do_str(pszOut, pszEnd, "-"); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else if (*pszMsg == 'e')    {   // Escape the string.
 | ||
|  |                         PVOID pvData = va_arg(args, PVOID); | ||
|  | 
 | ||
|  |                         pszMsg++; | ||
|  | 
 | ||
|  |                         if (fSmall) { | ||
|  |                             fLarge = FALSE; | ||
|  |                         } | ||
|  | 
 | ||
|  |                         __try { | ||
|  |                             if (pvData == NULL) { | ||
|  |                                 pszOut = do_str(pszOut, pszEnd, "-NULL-"); | ||
|  |                             } | ||
|  |                             else if (fLarge) { | ||
|  |                                 pszOut = do_ewstr(pszOut, pszEnd, (PWCHAR)pvData); | ||
|  |                             } | ||
|  |                             else { | ||
|  |                                 pszOut = do_estr(pszOut, pszEnd, (PCHAR)pvData); | ||
|  |                             } | ||
|  |                         } __except(EXCEPTION_EXECUTE_HANDLER) { | ||
|  |                             pszOut = do_str(pszOut, pszEnd, "-"); | ||
|  |                             pszOut = do_base(pszOut, (UINT64)pvData, 16, | ||
|  |                                              "0123456789ABCDEF"); | ||
|  |                             pszOut = do_str(pszOut, pszEnd, "-"); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else { | ||
|  |                         CHAR szTemp[2]; | ||
|  |                         pszMsg++; | ||
|  | 
 | ||
|  |                         szTemp[0] = (CHAR)va_arg(args, INT); | ||
|  |                         szTemp[1] = '\0'; | ||
|  |                         pszOut = do_str(pszOut, pszEnd, szTemp); | ||
|  |                     } | ||
|  |                 } | ||
|  |                 else if (*pszMsg == 'd' || *pszMsg == 'i' || *pszMsg == 'o' || | ||
|  |                          *pszMsg == 'x' || *pszMsg == 'X' || *pszMsg == 'b' || | ||
|  |                          *pszMsg == 'u') { | ||
|  |                     CHAR szTemp[128]; | ||
|  |                     UINT64 value; | ||
|  |                     if (f64Bit) { | ||
|  |                         value = va_arg(args, UINT64); | ||
|  |                     } | ||
|  |                     else { | ||
|  |                         value = va_arg(args, UINT); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     if (*pszMsg == 'x') { | ||
|  |                         pszMsg++; | ||
|  |                         nLen = (int)(do_base(szTemp, value, 16, "0123456789abcdef") - szTemp); | ||
|  |                         if (fPound && value) { | ||
|  |                             do_str(szHead, szHead + sizeof(szHead) - 1, "0x"); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else if (*pszMsg == 'X') { | ||
|  |                         pszMsg++; | ||
|  |                         nLen = (int)(do_base(szTemp, value, 16, "0123456789ABCDEF") - szTemp); | ||
|  |                         if (fPound && value) { | ||
|  |                             do_str(szHead, szHead + sizeof(szHead) - 1, "0X"); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else if (*pszMsg == 'd') { | ||
|  |                         pszMsg++; | ||
|  |                         if ((INT64)value < 0) { | ||
|  |                             value = -(INT64)value; | ||
|  |                             do_str(szHead, szHead + sizeof(szHead) - 1, "-"); | ||
|  |                         } | ||
|  |                         else if (fPositive) { | ||
|  |                             if (value > 0) { | ||
|  |                                 do_str(szHead, szHead + sizeof(szHead) - 1, "+"); | ||
|  |                             } | ||
|  |                         } | ||
|  |                         else if (fBlank) { | ||
|  |                             if (value > 0) { | ||
|  |                                 do_str(szHead, szHead + sizeof(szHead) - 1, " "); | ||
|  |                             } | ||
|  |                         } | ||
|  |                         nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp); | ||
|  |                         nPrecision = 0; | ||
|  |                     } | ||
|  |                     else if (*pszMsg == 'u') { | ||
|  |                         pszMsg++; | ||
|  |                         nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp); | ||
|  |                         nPrecision = 0; | ||
|  |                     } | ||
|  |                     else if (*pszMsg == 'o') { | ||
|  |                         pszMsg++; | ||
|  |                         nLen = (int)(do_base(szTemp, value, 8, "01234567") - szTemp); | ||
|  |                         nPrecision = 0; | ||
|  | 
 | ||
|  |                         if (fPound && value) { | ||
|  |                             do_str(szHead, szHead + sizeof(szHead) - 1, "0"); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else if (*pszMsg == 'b') { | ||
|  |                         pszMsg++; | ||
|  |                         nLen = (int)(do_base(szTemp, value, 2, "01") - szTemp); | ||
|  |                         nPrecision = 0; | ||
|  | 
 | ||
|  |                         if (fPound && value) { | ||
|  |                             do_str(szHead, szHead + sizeof(szHead) - 1, "0b"); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else { | ||
|  |                         pszMsg++; | ||
|  |                         if ((INT64)value < 0) { | ||
|  |                             value = -(INT64)value; | ||
|  |                             do_str(szHead, szHead + sizeof(szHead) - 1, "-"); | ||
|  |                         } | ||
|  |                         else if (fPositive) { | ||
|  |                             if (value > 0) { | ||
|  |                                 do_str(szHead, szHead + sizeof(szHead) - 1, "+"); | ||
|  |                             } | ||
|  |                         } | ||
|  |                         else if (fBlank) { | ||
|  |                             if (value > 0) { | ||
|  |                                 do_str(szHead, szHead + sizeof(szHead) - 1, " "); | ||
|  |                             } | ||
|  |                         } | ||
|  |                         nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp); | ||
|  |                         nPrecision = 0; | ||
|  |                     } | ||
|  | 
 | ||
|  |                     INT nHead = 0; | ||
|  |                     for (; szHead[nHead]; nHead++) { | ||
|  |                         // Count characters in head string.
 | ||
|  |                     } | ||
|  | 
 | ||
|  |                     if (fLeft) { | ||
|  |                         if (nHead) { | ||
|  |                             pszOut = do_str(pszOut, pszEnd, szHead); | ||
|  |                             nLen += nHead; | ||
|  |                         } | ||
|  |                         pszOut = do_str(pszOut, pszEnd, szTemp); | ||
|  |                         for (; nLen < nWidth && pszOut < pszEnd; nLen++) { | ||
|  |                             *pszOut++ = ' '; | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else if (fZero) { | ||
|  |                         if (nHead) { | ||
|  |                             pszOut = do_str(pszOut, pszEnd, szHead); | ||
|  |                             nLen += nHead; | ||
|  |                         } | ||
|  |                         for (; nLen < nWidth && pszOut < pszEnd; nLen++) { | ||
|  |                             *pszOut++ = '0'; | ||
|  |                         } | ||
|  |                         pszOut = do_str(pszOut, pszEnd, szTemp); | ||
|  |                     } | ||
|  |                     else { | ||
|  |                         if (nHead) { | ||
|  |                             nLen += nHead; | ||
|  |                         } | ||
|  |                         for (; nLen < nWidth && pszOut < pszEnd; nLen++) { | ||
|  |                             *pszOut++ = ' '; | ||
|  |                         } | ||
|  |                         if (nHead) { | ||
|  |                             pszOut = do_str(pszOut, pszEnd, szHead); | ||
|  |                         } | ||
|  |                         pszOut = do_str(pszOut, pszEnd, szTemp); | ||
|  |                     } | ||
|  |                 } | ||
|  |                 else if (*pszMsg == 'p') { | ||
|  |                     CHAR szTemp[64]; | ||
|  |                     ULONG_PTR value; | ||
|  |                     value = va_arg(args, ULONG_PTR); | ||
|  | 
 | ||
|  |                     if (*pszMsg == 'p') { | ||
|  |                         pszMsg++; | ||
|  |                         nLen = (int)(do_base(szTemp, (UINT64)value, 16, "0123456789abcdef") - szTemp); | ||
|  |                         if (fPound && value) { | ||
|  |                             do_str(szHead, szHead + sizeof(szHead) - 1, "0x"); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else { | ||
|  |                         pszMsg++; | ||
|  |                         nLen = (int)(do_base(szTemp, (UINT64)value, 16, "0123456789ABCDEF") - szTemp); | ||
|  |                         if (fPound && value) { | ||
|  |                             do_str(szHead, szHead + sizeof(szHead) - 1, "0x"); | ||
|  |                         } | ||
|  |                     } | ||
|  | 
 | ||
|  |                     INT nHead = 0; | ||
|  |                     for (; szHead[nHead]; nHead++) { | ||
|  |                         // Count characters in head string.
 | ||
|  |                     } | ||
|  | 
 | ||
|  |                     if (nHead) { | ||
|  |                         pszOut = do_str(pszOut, pszEnd, szHead); | ||
|  |                         nLen += nHead; | ||
|  |                     } | ||
|  |                     for (; nLen < nWidth && pszOut < pszEnd; nLen++) { | ||
|  |                         *pszOut++ = '0'; | ||
|  |                     } | ||
|  |                     pszOut = do_str(pszOut, pszEnd, szTemp); | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     pszMsg++; | ||
|  |                     while (pszArg < pszMsg && pszOut < pszEnd) { | ||
|  |                         *pszOut++ = *pszArg++; | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             else { | ||
|  |                 if (pszOut < pszEnd) { | ||
|  |                     *pszOut++ = *pszMsg++; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |         *pszOut = '\0'; | ||
|  |         pszBuffer[cbBuffer - 1] = '\0'; | ||
|  |     } __except(EXCEPTION_EXECUTE_HANDLER) { | ||
|  |         PCHAR pszOut = pszBuffer; | ||
|  |         *pszOut = '\0'; | ||
|  |         pszOut = do_str(pszOut, pszEnd, "-exception:"); | ||
|  |         pszOut = do_base(pszOut, (UINT64)GetExceptionCode(), 10, "0123456789"); | ||
|  |         pszOut = do_str(pszOut, pszEnd, "-"); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | #if _MSC_VER >= 1900
 | ||
|  | #pragma warning(pop)
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | PCHAR SafePrintf(PCHAR pszBuffer, LONG cbBuffer, PCSTR pszMsg, ...) | ||
|  | { | ||
|  |     va_list args; | ||
|  |     va_start(args, pszMsg); | ||
|  |     VSafePrintf(pszMsg, args, pszBuffer, cbBuffer); | ||
|  |     va_end(args); | ||
|  | 
 | ||
|  |     while (*pszBuffer) { | ||
|  |         pszBuffer++; | ||
|  |     } | ||
|  |     return pszBuffer; | ||
|  | } | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | BOOL TblogOpen() | ||
|  | { | ||
|  |     EnterCriticalSection(&s_csPipe); | ||
|  | 
 | ||
|  |     WCHAR wzPipe[256]; | ||
|  |     StringCchPrintfW(wzPipe, ARRAYSIZE(wzPipe), L"%ls.%d", TBLOG_PIPE_NAMEW, s_nTraceProcessId); | ||
|  | 
 | ||
|  |     for (int retries = 0; retries < 10; retries++) { | ||
|  |         WaitNamedPipeW(wzPipe, 10000); // Wait up to 10 seconds for a pipe to appear.
 | ||
|  | 
 | ||
|  |         s_hPipe = Real_CreateFileW(wzPipe, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); | ||
|  |         if (s_hPipe != INVALID_HANDLE_VALUE) { | ||
|  |             DWORD dwMode = PIPE_READMODE_MESSAGE; | ||
|  |             if (SetNamedPipeHandleState(s_hPipe, &dwMode, NULL, NULL)) { | ||
|  |                 LeaveCriticalSection(&s_csPipe); | ||
|  |                 return TRUE; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     LeaveCriticalSection(&s_csPipe); | ||
|  | 
 | ||
|  |     // Couldn't open pipe.
 | ||
|  |     DEBUG_BREAK(); | ||
|  |     Real_ExitProcess(9990); | ||
|  |     return FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | VOID TblogV(PCSTR pszMsgf, va_list args) | ||
|  | { | ||
|  |     if (s_hPipe == INVALID_HANDLE_VALUE) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     EnterCriticalSection(&s_csPipe); | ||
|  | 
 | ||
|  |     DWORD cbWritten = 0; | ||
|  | 
 | ||
|  |     PCHAR pszBuf = s_rMessage.szMessage; | ||
|  |     VSafePrintf(pszMsgf, args, | ||
|  |                 pszBuf, (int)(s_rMessage.szMessage + sizeof(s_rMessage.szMessage) - pszBuf)); | ||
|  | 
 | ||
|  |     PCHAR pszEnd = s_rMessage.szMessage; | ||
|  |     for (; *pszEnd; pszEnd++) { | ||
|  |         // no internal contents.
 | ||
|  |     } | ||
|  |     s_rMessage.nBytes = (DWORD)(pszEnd - ((PCSTR)&s_rMessage)); | ||
|  | 
 | ||
|  |     // If the write fails, then we abort
 | ||
|  |     if (s_hPipe != INVALID_HANDLE_VALUE) { | ||
|  |         if (!Real_WriteFile(s_hPipe, &s_rMessage, s_rMessage.nBytes, &cbWritten, NULL)) { | ||
|  |             Real_ExitProcess(9991); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     LeaveCriticalSection(&s_csPipe); | ||
|  | } | ||
|  | 
 | ||
|  | VOID Tblog(PCSTR pszMsgf, ...) | ||
|  | { | ||
|  |     if (s_hPipe == INVALID_HANDLE_VALUE) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     va_list args; | ||
|  |     va_start(args, pszMsgf); | ||
|  |     TblogV(pszMsgf, args); | ||
|  |     va_end(args); | ||
|  | } | ||
|  | 
 | ||
|  | VOID TblogClose() | ||
|  | { | ||
|  |     EnterCriticalSection(&s_csPipe); | ||
|  | 
 | ||
|  |     if (s_hPipe != INVALID_HANDLE_VALUE) { | ||
|  |         DWORD cbWritten = 0; | ||
|  | 
 | ||
|  |         s_rMessage.nBytes = 0; | ||
|  | 
 | ||
|  |         Real_WriteFile(s_hPipe, &s_rMessage, 4, &cbWritten, NULL); | ||
|  |         FlushFileBuffers(s_hPipe); | ||
|  |         Real_CloseHandle(s_hPipe); | ||
|  |         s_hPipe = INVALID_HANDLE_VALUE; | ||
|  |     } | ||
|  | 
 | ||
|  |     LeaveCriticalSection(&s_csPipe); | ||
|  | } | ||
|  | 
 | ||
|  | /////////////////////////////////////////////////////////////
 | ||
|  | // Detours
 | ||
|  | //
 | ||
|  | static BOOL IsInherited(HANDLE hHandle) | ||
|  | { | ||
|  |     DWORD dwFlags; | ||
|  | 
 | ||
|  |     if (GetHandleInformation(hHandle, &dwFlags)) { | ||
|  |         return (dwFlags & HANDLE_FLAG_INHERIT) ? TRUE : FALSE; | ||
|  |     } | ||
|  |     return FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | static void SaveStdHandleName(HANDLE hFile, PWCHAR pwzBuffer, BOOL *fAppend) | ||
|  | { | ||
|  |     pwzBuffer[0] = '\0'; | ||
|  | 
 | ||
|  |     if ((hFile != INVALID_HANDLE_VALUE) && IsInherited(hFile)) { | ||
|  |         FileInfo * pInfo = OpenFiles::RecallFile(hFile); | ||
|  |         if (pInfo) { | ||
|  |             Copy(pwzBuffer, pInfo->m_pwzPath); | ||
|  |             if (pInfo->m_fAppend && fAppend != NULL) { | ||
|  |                 *fAppend = TRUE; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | static void LoadStdHandleName(DWORD id, PCWSTR pwzBuffer, BOOL fAppend) | ||
|  | { | ||
|  |     HANDLE hFile = GetStdHandle(id); | ||
|  | 
 | ||
|  |     if ((hFile != INVALID_HANDLE_VALUE) && pwzBuffer[0] != '\0') { | ||
|  |         FileInfo *pInfo = FileNames::FindPartial(pwzBuffer); | ||
|  |         if (fAppend) { | ||
|  |             pInfo->m_fAppend = TRUE; | ||
|  |         } | ||
|  |         OpenFiles::Remember(hFile, pInfo); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | BOOL CreateProcessInternals(HANDLE hProcess, DWORD nProcessId, PCHAR pszId, | ||
|  |                             HANDLE hStdin, HANDLE hStdout, HANDLE hStderr) | ||
|  | { | ||
|  |     EnterCriticalSection(&s_csChildPayload); | ||
|  | 
 | ||
|  |     ProcInfo *proc = Procs::Create(hProcess, nProcessId); | ||
|  |     OpenFiles::Remember(hProcess, proc); | ||
|  | 
 | ||
|  |     ZeroMemory(&s_ChildPayload, sizeof(s_ChildPayload)); | ||
|  |     CopyMemory(&s_ChildPayload, &s_Payload, sizeof(s_ChildPayload)); | ||
|  | 
 | ||
|  |     s_ChildPayload.nParentProcessId = GetCurrentProcessId(); | ||
|  |     s_ChildPayload.rGeneology[s_ChildPayload.nGeneology] | ||
|  |         = (DWORD)InterlockedIncrement(&s_nChildCnt); | ||
|  |     s_ChildPayload.nGeneology++; | ||
|  | 
 | ||
|  |     SaveStdHandleName(hStdin, s_ChildPayload.wzStdin, NULL); | ||
|  |     SaveStdHandleName(hStdout, s_ChildPayload.wzStdout, &s_ChildPayload.fStdoutAppend); | ||
|  |     SaveStdHandleName(hStderr, s_ChildPayload.wzStderr, &s_ChildPayload.fStderrAppend); | ||
|  | 
 | ||
|  |     DetourCopyPayloadToProcess(hProcess, s_guidTrace, &s_ChildPayload, sizeof(s_ChildPayload)); | ||
|  | 
 | ||
|  |     for (DWORD i = 0; i < s_ChildPayload.nGeneology; i++) { | ||
|  |         pszId = SafePrintf(pszId, 16, "%d.", s_ChildPayload.rGeneology[i]); | ||
|  |     } | ||
|  |     *pszId = '\0'; | ||
|  | 
 | ||
|  |     LeaveCriticalSection(&s_csChildPayload); | ||
|  | 
 | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CreateProcessW(LPCWSTR lpApplicationName, | ||
|  |                                 LPWSTR lpCommandLine, | ||
|  |                                 LPSECURITY_ATTRIBUTES lpProcessAttributes, | ||
|  |                                 LPSECURITY_ATTRIBUTES lpThreadAttributes, | ||
|  |                                 BOOL bInheritHandles, | ||
|  |                                 DWORD dwCreationFlags, | ||
|  |                                 LPVOID lpEnvironment, | ||
|  |                                 LPCWSTR lpCurrentDirectory, | ||
|  |                                 LPSTARTUPINFOW lpStartupInfo, | ||
|  |                                 LPPROCESS_INFORMATION lpProcessInformation) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     if (lpCommandLine == NULL) { | ||
|  |         lpCommandLine = (LPWSTR)lpApplicationName; | ||
|  |     } | ||
|  | 
 | ||
|  |     CHAR szProc[MAX_PATH]; | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         LPPROCESS_INFORMATION ppi = lpProcessInformation; | ||
|  |         PROCESS_INFORMATION pi; | ||
|  |         if (ppi == NULL) { | ||
|  |             ppi = π | ||
|  |         } | ||
|  | 
 | ||
|  |         rv = DetourCreateProcessWithDllExW(lpApplicationName, | ||
|  |                                            lpCommandLine, | ||
|  |                                            lpProcessAttributes, | ||
|  |                                            lpThreadAttributes, | ||
|  |                                            bInheritHandles, | ||
|  |                                            dwCreationFlags | CREATE_SUSPENDED, | ||
|  |                                            lpEnvironment, | ||
|  |                                            lpCurrentDirectory, | ||
|  |                                            lpStartupInfo, | ||
|  |                                            ppi, | ||
|  |                                            s_szDllPath, | ||
|  |                                            Real_CreateProcessW); | ||
|  | 
 | ||
|  |         if (rv) { | ||
|  |             HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); | ||
|  |             HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); | ||
|  |             HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); | ||
|  | 
 | ||
|  |             if (lpStartupInfo != NULL && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) != 0) { | ||
|  |                 hStdin = lpStartupInfo->hStdInput; | ||
|  |                 hStdout = lpStartupInfo->hStdOutput; | ||
|  |                 hStderr = lpStartupInfo->hStdError; | ||
|  |             } | ||
|  |             CreateProcessInternals(ppi->hProcess, ppi->dwProcessId, | ||
|  |                                    szProc, hStdin, hStdout, hStderr); | ||
|  | 
 | ||
|  |             Print("<t:Child id=\"::%hs::\">\n", szProc); | ||
|  | 
 | ||
|  |             WCHAR wzPath[MAX_PATH]; | ||
|  |             FileInfo *pInfo = NULL; | ||
|  |             if (lpApplicationName == NULL) { | ||
|  |                 PWCHAR pwzDst = wzPath; | ||
|  |                 PWCHAR pwzSrc = lpCommandLine; | ||
|  | 
 | ||
|  |                 if (*pwzSrc == '\"') { | ||
|  |                     WCHAR cQuote = *pwzSrc++; | ||
|  | 
 | ||
|  |                     while (*pwzSrc && *pwzSrc != cQuote) { | ||
|  |                         *pwzDst++ = *pwzSrc++; | ||
|  |                     } | ||
|  |                     *pwzDst++ = '\0'; | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     while (*pwzSrc && *pwzSrc != ' ' && *pwzSrc != '\t') { | ||
|  |                         if (*pwzSrc == '\t') { | ||
|  |                             *pwzSrc = ' '; | ||
|  |                         } | ||
|  |                         *pwzDst++ = *pwzSrc++; | ||
|  |                     } | ||
|  |                     *pwzDst++ = '\0'; | ||
|  |                 } | ||
|  |                 pInfo = FileNames::FindPartial(wzPath); | ||
|  |             } | ||
|  |             else { | ||
|  |                 pInfo = FileNames::FindPartial(lpApplicationName); | ||
|  |             } | ||
|  | 
 | ||
|  |             Print("<t:Executable>%ls</t:Executable>\n", | ||
|  |                   FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo)); | ||
|  |             Print("<t:Line>%le</t:Line>\n", lpCommandLine); | ||
|  |             Print("</t:Child>\n"); | ||
|  | 
 | ||
|  |             if (pInfo) { | ||
|  |                 pInfo->m_fAbsorbed = true; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (!(dwCreationFlags & CREATE_SUSPENDED)) { | ||
|  |                 ResumeThread(ppi->hThread); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (ppi == &pi) { | ||
|  |                 Real_CloseHandle(ppi->hThread); | ||
|  |                 Real_CloseHandle(ppi->hProcess); | ||
|  |             } | ||
|  |         } | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (!rv) { | ||
|  |             Print("<!-- Warning: CreateProcessW failed %d: %ls; %ls -->\n", | ||
|  |                   GetLastError(), lpApplicationName, lpCommandLine); | ||
|  |         } | ||
|  |     } | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CreateProcessA(LPCSTR lpApplicationName, | ||
|  |                                 LPSTR lpCommandLine, | ||
|  |                                 LPSECURITY_ATTRIBUTES lpProcessAttributes, | ||
|  |                                 LPSECURITY_ATTRIBUTES lpThreadAttributes, | ||
|  |                                 BOOL bInheritHandles, | ||
|  |                                 DWORD dwCreationFlags, | ||
|  |                                 LPVOID lpEnvironment, | ||
|  |                                 LPCSTR lpCurrentDirectory, | ||
|  |                                 LPSTARTUPINFOA lpStartupInfo, | ||
|  |                                 LPPROCESS_INFORMATION lpProcessInformation) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     if (lpCommandLine == NULL) { | ||
|  |         lpCommandLine = (LPSTR)lpApplicationName; | ||
|  |     } | ||
|  | 
 | ||
|  |     CHAR szProc[MAX_PATH]; | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         LPPROCESS_INFORMATION ppi = lpProcessInformation; | ||
|  |         PROCESS_INFORMATION pi; | ||
|  |         if (ppi == NULL) { | ||
|  |             ppi = π | ||
|  |         } | ||
|  | 
 | ||
|  |         rv = DetourCreateProcessWithDllExA(lpApplicationName, | ||
|  |                                            lpCommandLine, | ||
|  |                                            lpProcessAttributes, | ||
|  |                                            lpThreadAttributes, | ||
|  |                                            bInheritHandles, | ||
|  |                                            dwCreationFlags | CREATE_SUSPENDED, | ||
|  |                                            lpEnvironment, | ||
|  |                                            lpCurrentDirectory, | ||
|  |                                            lpStartupInfo, | ||
|  |                                            ppi, | ||
|  |                                            s_szDllPath, | ||
|  |                                            Real_CreateProcessA); | ||
|  | 
 | ||
|  |         if (rv) { | ||
|  |             HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); | ||
|  |             HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); | ||
|  |             HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); | ||
|  | 
 | ||
|  |             if (lpStartupInfo != NULL && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) != 0) { | ||
|  |                 hStdin = lpStartupInfo->hStdInput; | ||
|  |                 hStdout = lpStartupInfo->hStdOutput; | ||
|  |                 hStderr = lpStartupInfo->hStdError; | ||
|  |             } | ||
|  |             CreateProcessInternals(ppi->hProcess, ppi->dwProcessId, | ||
|  |                                    szProc, hStdin, hStdout, hStderr); | ||
|  | 
 | ||
|  |             Print("<t:Child id=\"::%hs::\">\n", szProc); | ||
|  | 
 | ||
|  |             WCHAR wzPath[MAX_PATH]; | ||
|  |             FileInfo *pInfo = NULL; | ||
|  |             if (lpApplicationName == NULL) { | ||
|  |                 PCHAR pszDst = szProc; | ||
|  |                 PCHAR pszSrc = lpCommandLine; | ||
|  | 
 | ||
|  |                 if (*pszSrc == '\"') { | ||
|  |                     CHAR cQuote = *pszSrc++; | ||
|  | 
 | ||
|  |                     while (*pszSrc && *pszSrc != cQuote) { | ||
|  |                         *pszDst++ = *pszSrc++; | ||
|  |                     } | ||
|  |                     *pszDst++ = '\0'; | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     while (*pszSrc && *pszSrc != ' ' && *pszSrc != '\t') { | ||
|  |                         if (*pszSrc == '\t') { | ||
|  |                             *pszSrc = ' '; | ||
|  |                         } | ||
|  |                         *pszDst++ = *pszSrc++; | ||
|  |                     } | ||
|  |                     *pszDst++ = '\0'; | ||
|  |                 } | ||
|  |                 pInfo = FileNames::FindPartial(szProc); | ||
|  |             } | ||
|  |             else { | ||
|  |                 pInfo = FileNames::FindPartial(lpApplicationName); | ||
|  |             } | ||
|  | 
 | ||
|  |             Print("<t:Executable>%ls</t:Executable>\n", | ||
|  |                   FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo)); | ||
|  |             Print("<t:Line>%he</t:Line>\n", lpCommandLine); | ||
|  |             Print("</t:Child>\n"); | ||
|  | 
 | ||
|  |             if (pInfo) { | ||
|  |                 pInfo->m_fAbsorbed = true; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (!(dwCreationFlags & CREATE_SUSPENDED)) { | ||
|  |                 ResumeThread(ppi->hThread); | ||
|  |             } | ||
|  |             if (ppi == &pi) { | ||
|  |                 Real_CloseHandle(ppi->hThread); | ||
|  |                 Real_CloseHandle(ppi->hProcess); | ||
|  |             } | ||
|  |         } | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (!rv) { | ||
|  |             Print("<!-- Warning: CreateProcessA failed %d: %hs; %hs -->\n", | ||
|  |                   GetLastError(), lpApplicationName, lpCommandLine); | ||
|  |         } | ||
|  |     } | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | //
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CopyFileExA(LPCSTR a0, | ||
|  |                              LPCSTR a1, | ||
|  |                              LPPROGRESS_ROUTINE a2, | ||
|  |                              LPVOID a3, | ||
|  |                              LPBOOL a4, | ||
|  |                              DWORD a5) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_CopyFileExA(a0, a1, a2, a3, a4, a5); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  | #if 0
 | ||
|  |             Print("<!-- CopyFileExA %he to %he -->\n", a0, a1); | ||
|  | #endif
 | ||
|  |             NoteRead(a0); | ||
|  |             NoteWrite(a1); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CopyFileExW(LPCWSTR a0, | ||
|  |                              LPCWSTR a1, | ||
|  |                              LPPROGRESS_ROUTINE a2, | ||
|  |                              LPVOID a3, | ||
|  |                              LPBOOL a4, | ||
|  |                              DWORD a5) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  | #if 0
 | ||
|  |         Print("\n"); | ||
|  |         Print("<!-- CopyFileExW %le to %le before -->\n", a0, a1); | ||
|  | #endif
 | ||
|  |         rv = Real_CopyFileExW(a0, a1, a2, a3, a4, a5); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  | #if 0
 | ||
|  |             Print("<!-- CopyFileExW %le to %le -->\n", a0, a1); | ||
|  | #endif
 | ||
|  |             NoteRead(a0); | ||
|  |             NoteWrite(a1); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_PrivCopyFileExW(LPCWSTR a0, | ||
|  |                                  LPCWSTR a1, | ||
|  |                                  LPPROGRESS_ROUTINE a2, | ||
|  |                                  LPVOID a3, | ||
|  |                                  LPBOOL a4, | ||
|  |                                  DWORD a5) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_PrivCopyFileExW(a0, a1, a2, a3, a4, a5); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  | #if 0
 | ||
|  |             Print("<!-- PrivCopyFileExW %le to %le -->\n", a0, a1); | ||
|  | #endif
 | ||
|  |             NoteRead(a0); | ||
|  |             NoteWrite(a1); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CreateHardLinkA(LPCSTR a0, | ||
|  |                                  LPCSTR a1, | ||
|  |                                  LPSECURITY_ATTRIBUTES a2) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_CreateHardLinkA(a0, a1, a2); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  | #if 0
 | ||
|  |             Print("<!-- CreateHardLinkA %he to %he -->\n", a0, a1); | ||
|  | #endif
 | ||
|  |             NoteRead(a1); | ||
|  |             NoteWrite(a0); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CreateHardLinkW(LPCWSTR a0, | ||
|  |                                  LPCWSTR a1, | ||
|  |                                  LPSECURITY_ATTRIBUTES a2) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_CreateHardLinkW(a0, a1, a2); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  | #if 0
 | ||
|  |             Print("<!-- CreateHardLinkW %le to %le -->\n", a0, a1); | ||
|  | #endif
 | ||
|  |             NoteRead(a1); | ||
|  |             NoteWrite(a0); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CloseHandle(HANDLE a0) | ||
|  | { | ||
|  |     /*int nIndent =*/ EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         ProcInfo * pProc = OpenFiles::RecallProc(a0); | ||
|  |         if (pProc != NULL) { | ||
|  |             Procs::Close(pProc->m_hProc); | ||
|  |         } | ||
|  | 
 | ||
|  |         FileInfo * pFile = OpenFiles::RecallFile(a0); | ||
|  |         if (pFile != NULL) { | ||
|  |             DWORD dwErr = GetLastError(); | ||
|  |             pFile->m_cbContent = GetFileSize(a0, NULL); | ||
|  |             if (pFile->m_cbContent == INVALID_FILE_SIZE) { | ||
|  |                 pFile->m_cbContent = 0; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (pFile->m_fCantRead) { | ||
|  |                 if (pFile->m_fRead) { | ||
|  | #if 0
 | ||
|  |                     Print("<!-- Warning: Removing read from %le -->\n", pFile->m_pwzPath); | ||
|  | #endif
 | ||
|  |                     pFile->m_fRead = FALSE; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             // Here we should think about reading the file contents as appropriate.
 | ||
|  |             if (pFile->m_fTemporaryPath && pFile->m_fRead && !pFile->m_fAbsorbed && | ||
|  |                 !pFile->m_fDelete && !pFile->m_fCleanup && !pFile->m_fWrite && | ||
|  |                 pFile->m_pbContent == NULL && | ||
|  |                 pFile->m_cbContent < 16384) { | ||
|  | 
 | ||
|  |                 pFile->m_pbContent = LoadFile(a0, pFile->m_cbContent); | ||
|  |             } | ||
|  | 
 | ||
|  |             SetLastError(dwErr); | ||
|  |         } | ||
|  |         rv = Real_CloseHandle(a0); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv /* && nIndent == 0*/) { | ||
|  |             OpenFiles::Forget(a0); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_DuplicateHandle(HANDLE hSourceProcessHandle, | ||
|  |                                  HANDLE hSourceHandle, | ||
|  |                                  HANDLE hTargetProcessHandle, | ||
|  |                                  LPHANDLE lpTargetHandle, | ||
|  |                                  DWORD dwDesiredAccess, | ||
|  |                                  BOOL bInheritHandle, | ||
|  |                                  DWORD dwOptions) | ||
|  | { | ||
|  |     HANDLE hTemp = INVALID_HANDLE_VALUE; | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         if (lpTargetHandle == NULL) { | ||
|  |             lpTargetHandle = &hTemp; | ||
|  |         } | ||
|  |         *lpTargetHandle = INVALID_HANDLE_VALUE; | ||
|  | 
 | ||
|  |         rv = Real_DuplicateHandle(hSourceProcessHandle, | ||
|  |                                   hSourceHandle, | ||
|  |                                   hTargetProcessHandle, | ||
|  |                                   lpTargetHandle, | ||
|  |                                   dwDesiredAccess, | ||
|  |                                   bInheritHandle, | ||
|  |                                   dwOptions); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (*lpTargetHandle != INVALID_HANDLE_VALUE) { | ||
|  |             FileInfo *pInfo = OpenFiles::RecallFile(hSourceHandle); | ||
|  |             if (pInfo) { | ||
|  |                 OpenFiles::Remember(*lpTargetHandle, pInfo); | ||
|  |             } | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | static LONG s_nPipeCnt = 0; | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CreatePipe(PHANDLE hReadPipe, | ||
|  |                             PHANDLE hWritePipe, | ||
|  |                             LPSECURITY_ATTRIBUTES lpPipeAttributes, | ||
|  |                             DWORD nSize) | ||
|  | { | ||
|  |     HANDLE hRead = INVALID_HANDLE_VALUE; | ||
|  |     HANDLE hWrite = INVALID_HANDLE_VALUE; | ||
|  | 
 | ||
|  |     if (hReadPipe == NULL) { | ||
|  |         hReadPipe = &hRead; | ||
|  |     } | ||
|  |     if (hWritePipe == NULL) { | ||
|  |         hWritePipe = &hWrite; | ||
|  |     } | ||
|  | 
 | ||
|  |     /*int nIndent = */ EnterFunc(); | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_CreatePipe(hReadPipe, hWritePipe, lpPipeAttributes, nSize); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  |             CHAR szPipe[128]; | ||
|  | 
 | ||
|  |             SafePrintf(szPipe, ARRAYSIZE(szPipe), "\\\\.\\PIPE\\Temp.%d.%d", | ||
|  |                        GetCurrentProcessId(), | ||
|  |                        InterlockedIncrement(&s_nPipeCnt)); | ||
|  | 
 | ||
|  |             FileInfo *pInfo = FileNames::FindPartial(szPipe); | ||
|  | 
 | ||
|  |             pInfo->m_fCleanup = TRUE; | ||
|  |             OpenFiles::Remember(*hReadPipe, pInfo); | ||
|  |             OpenFiles::Remember(*hWritePipe, pInfo); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CreateDirectoryW(LPCWSTR a0, | ||
|  |                                   LPSECURITY_ATTRIBUTES a1) | ||
|  | { | ||
|  |     /* int nIndent = */ EnterFunc(); | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_CreateDirectoryW(a0, a1); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  |             FileInfo *pInfo = FileNames::FindPartial(a0); | ||
|  |             pInfo->m_fDirectory = TRUE; | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_CreateDirectoryExW(LPCWSTR a0, | ||
|  |                                     LPCWSTR a1, | ||
|  |                                     LPSECURITY_ATTRIBUTES a2) | ||
|  | { | ||
|  |     /* int nIndent = */ EnterFunc(); | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_CreateDirectoryExW(a0, a1, a2); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  |             FileInfo *pInfo = FileNames::FindPartial(a1); | ||
|  |             pInfo->m_fDirectory = TRUE; | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | HANDLE WINAPI Mine_CreateFileW(LPCWSTR a0, | ||
|  |                                DWORD access, | ||
|  |                                DWORD share, | ||
|  |                                LPSECURITY_ATTRIBUTES a3, | ||
|  |                                DWORD create, | ||
|  |                                DWORD flags, | ||
|  |                                HANDLE a6) | ||
|  | { | ||
|  |     /* int nIndent = */ EnterFunc(); | ||
|  |     HANDLE rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_CreateFileW(a0, access, share, a3, create, flags, a6); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  | #if 0
 | ||
|  |             Print("<!-- CreateFileW(%le, ac=%08x, cr=%08x, fl=%08x -->\n", | ||
|  |                   a0, | ||
|  |                   access, | ||
|  |                   create, | ||
|  |                   flags); | ||
|  | #endif
 | ||
|  | 
 | ||
|  |         if (access != 0 && /* nIndent == 0 && */ rv != INVALID_HANDLE_VALUE) { | ||
|  | 
 | ||
|  |             FileInfo *pInfo = FileNames::FindPartial(a0); | ||
|  | 
 | ||
|  |             // FILE_FLAG_WRITE_THROUGH              0x80000000
 | ||
|  |             // FILE_FLAG_OVERLAPPED                 0x40000000
 | ||
|  |             // FILE_FLAG_NO_BUFFERING               0x20000000
 | ||
|  |             // FILE_FLAG_RANDOM_ACCESS              0x10000000
 | ||
|  |             // FILE_FLAG_SEQUENTIAL_SCAN            0x08000000
 | ||
|  |             // FILE_FLAG_DELETE_ON_CLOSE            0x04000000
 | ||
|  |             // FILE_FLAG_BACKUP_SEMANTICS           0x02000000
 | ||
|  |             // FILE_FLAG_POSIX_SEMANTICS            0x01000000
 | ||
|  |             // FILE_FLAG_OPEN_REPARSE_POINT         0x00200000
 | ||
|  |             // FILE_FLAG_OPEN_NO_RECALL             0x00100000
 | ||
|  |             // FILE_FLAG_FIRST_PIPE_INSTANCE        0x00080000
 | ||
|  |             // FILE_ATTRIBUTE_ENCRYPTED             0x00004000
 | ||
|  |             // FILE_ATTRIBUTE_NOT_CONTENT_INDEXED   0x00002000
 | ||
|  |             // FILE_ATTRIBUTE_OFFLINE               0x00001000
 | ||
|  |             // FILE_ATTRIBUTE_COMPRESSED            0x00000800
 | ||
|  |             // FILE_ATTRIBUTE_REPARSE_POINT         0x00000400
 | ||
|  |             // FILE_ATTRIBUTE_SPARSE_FILE           0x00000200
 | ||
|  |             // FILE_ATTRIBUTE_TEMPORARY             0x00000100
 | ||
|  |             // FILE_ATTRIBUTE_NORMAL                0x00000080
 | ||
|  |             // FILE_ATTRIBUTE_DEVICE                0x00000040
 | ||
|  |             // FILE_ATTRIBUTE_ARCHIVE               0x00000020
 | ||
|  |             // FILE_ATTRIBUTE_DIRECTORY             0x00000010
 | ||
|  |             // FILE_ATTRIBUTE_SYSTEM                0x00000004
 | ||
|  |             // FILE_ATTRIBUTE_HIDDEN                0x00000002
 | ||
|  |             // FILE_ATTRIBUTE_READONLY              0x00000001
 | ||
|  | 
 | ||
|  |             // CREATE_NEW          1
 | ||
|  |             // CREATE_ALWAYS       2
 | ||
|  |             // OPEN_EXISTING       3
 | ||
|  |             // OPEN_ALWAYS         4
 | ||
|  |             // TRUNCATE_EXISTING   5
 | ||
|  | 
 | ||
|  |             if (create == CREATE_NEW || | ||
|  |                 create == CREATE_ALWAYS || | ||
|  |                 create == TRUNCATE_EXISTING) { | ||
|  | 
 | ||
|  |                 if (!pInfo->m_fRead) { | ||
|  |                     pInfo->m_fCantRead = TRUE; | ||
|  |                 } | ||
|  |             } | ||
|  |             else if (create == OPEN_EXISTING) { | ||
|  |             } | ||
|  |             else if (create == OPEN_ALWAYS) { | ||
|  |                 // pInfo->m_fAppend = TRUE;    // !!!
 | ||
|  |             } | ||
|  | 
 | ||
|  |             if ((flags & FILE_FLAG_DELETE_ON_CLOSE)) { | ||
|  |                 pInfo->m_fCleanup = TRUE; | ||
|  |             } | ||
|  | 
 | ||
|  |             OpenFiles::Remember(rv, pInfo); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | HANDLE WINAPI Mine_CreateFileMappingW(HANDLE hFile, | ||
|  |                                       LPSECURITY_ATTRIBUTES a1, | ||
|  |                                       DWORD flProtect, | ||
|  |                                       DWORD a3, | ||
|  |                                       DWORD a4, | ||
|  |                                       LPCWSTR a5) | ||
|  | { | ||
|  |     /* int nIndent = */ EnterFunc(); | ||
|  |     HANDLE rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_CreateFileMappingW(hFile, a1, flProtect, a3, a4, a5); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv != INVALID_HANDLE_VALUE) { | ||
|  | 
 | ||
|  |             FileInfo *pInfo = OpenFiles::RecallFile(hFile); | ||
|  | 
 | ||
|  |             if (pInfo != NULL) { | ||
|  |                 switch (flProtect) { | ||
|  |                   case PAGE_READONLY: | ||
|  |                     pInfo->m_fRead = TRUE; | ||
|  |                     break; | ||
|  |                   case PAGE_READWRITE: | ||
|  |                     pInfo->m_fRead = TRUE; | ||
|  |                     pInfo->m_fWrite = TRUE; | ||
|  |                     break; | ||
|  |                   case PAGE_WRITECOPY: | ||
|  |                     pInfo->m_fRead = TRUE; | ||
|  |                     break; | ||
|  |                   case PAGE_EXECUTE_READ: | ||
|  |                     pInfo->m_fRead = TRUE; | ||
|  |                     break; | ||
|  |                   case PAGE_EXECUTE_READWRITE: | ||
|  |                     pInfo->m_fRead = TRUE; | ||
|  |                     pInfo->m_fWrite = TRUE; | ||
|  |                     break; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_DeleteFileW(LPCWSTR a0) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_DeleteFileW(a0); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  | #if 0
 | ||
|  |         Print("<!-- DeleteFileW(%le -->\n", a0); | ||
|  | #endif
 | ||
|  |         NoteDelete(a0); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | static VOID Dump(LPVOID pvData, DWORD cbData) | ||
|  | { | ||
|  |     CHAR szBuffer[128]; | ||
|  |     PBYTE pbData = (PBYTE)pvData; | ||
|  | 
 | ||
|  |     for (DWORD i = 0; i < cbData; i += 16) { | ||
|  |         PCHAR psz = szBuffer; | ||
|  |         psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), "%4d: ", i); | ||
|  | 
 | ||
|  |         for (DWORD j = i; j < i + 16; j++) { | ||
|  |             if (j < cbData) { | ||
|  |                 psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), | ||
|  |                                  "%02x", pbData[j]); | ||
|  |             } | ||
|  |             else { | ||
|  |                 psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), "  "); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         for (DWORD j = i; j < i + 16; j++) { | ||
|  |             if (j < cbData) { | ||
|  |                 if (pbData[j] >= ' ' && pbData[j] <= 127) { | ||
|  |                     psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), | ||
|  |                                      "%c", pbData[j]); | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), "."); | ||
|  |                 } | ||
|  |             } | ||
|  |             else { | ||
|  |                 psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), " "); | ||
|  |             } | ||
|  |         } | ||
|  |         Print("%s\n", szBuffer); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_DeviceIoControl(HANDLE a0, | ||
|  |                                  DWORD a1, | ||
|  |                                  LPVOID a2, | ||
|  |                                  DWORD a3, | ||
|  |                                  LPVOID a4, | ||
|  |                                  DWORD a5, | ||
|  |                                  LPDWORD a6, | ||
|  |                                  LPOVERLAPPED a7) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD d6 = 0; | ||
|  |     if (a6 == NULL) { | ||
|  |         a6 = &d6; | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_DeviceIoControl(a0, a1, a2, a3, a4, a5, a6, a7); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         OpenFiles::SetRead(a0, 0); | ||
|  |         OpenFiles::SetWrite(a0, 0); | ||
|  |         if (rv && a1 != 0x390008 && a1 != 0x4d0008 && a1 != 0x6d0008) { | ||
|  |             FileInfo *pInfo = OpenFiles::RecallFile(a0); | ||
|  | 
 | ||
|  |             DWORD DeviceType    = (a1 & 0xffff0000) >> 16; | ||
|  |             DWORD Access        = (a1 & 0x0000c000) >> 14; | ||
|  |             DWORD Function      = (a1 & 0x00003ffc) >> 2; | ||
|  |             DWORD Method        = (a1 & 0x00000003) >> 0; | ||
|  | 
 | ||
|  |             if (pInfo) { | ||
|  |                 Print("<!-- DeviceIoControl %x [dev=%x,acc=%x,fun=%x,mth=%x] on %ls! -->\n", | ||
|  |                       a1, DeviceType, Access, Function, Method, pInfo->m_pwzPath); | ||
|  |             } | ||
|  |             else { | ||
|  |                 Print("<!-- DeviceIoControl %x [dev=%x,acc=%x,fun=%x,mth=%x,in=%d,out=%d/%d] on (%x)! -->\n", | ||
|  |                       a1, DeviceType, Access, Function, Method, a3, *a6, a5, a0); | ||
|  | 
 | ||
|  |                 if (a3 > 0) { | ||
|  |                     Dump(a2, a3); | ||
|  |                 } | ||
|  |                 if (a5 > 0) { | ||
|  |                     Dump(a4, (*a6 < a5) ? *a6 : a5); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD WINAPI Mine_GetFileAttributesW(LPCWSTR a0) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_GetFileAttributesW(a0); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_MoveFileWithProgressW(LPCWSTR a0, | ||
|  |                                        LPCWSTR a1, | ||
|  |                                        LPPROGRESS_ROUTINE a2, | ||
|  |                                        LPVOID a3, | ||
|  |                                        DWORD a4) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_MoveFileWithProgressW(a0, a1, a2, a3, a4); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  |             NoteRead(a0); | ||
|  |             NoteWrite(a1); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_MoveFileA(LPCSTR a0, | ||
|  |                            LPCSTR a1) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_MoveFileA(a0, a1); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  |             NoteRead(a0); | ||
|  |             NoteCleanup(a0); | ||
|  |             NoteWrite(a1); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_MoveFileW(LPCWSTR a0, | ||
|  |                            LPCWSTR a1) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_MoveFileW(a0, a1); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  |             NoteRead(a0); | ||
|  |             NoteCleanup(a0); | ||
|  |             NoteWrite(a1); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_MoveFileExA(LPCSTR a0, | ||
|  |                              LPCSTR a1, | ||
|  |                              DWORD a2) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_MoveFileExA(a0, a1, a2); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  |             NoteRead(a0); | ||
|  |             NoteCleanup(a0); | ||
|  |             NoteWrite(a1); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_MoveFileExW(LPCWSTR a0, | ||
|  |                              LPCWSTR a1, | ||
|  |                              DWORD a2) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_MoveFileExW(a0, a1, a2); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |         if (rv) { | ||
|  |             NoteRead(a0); | ||
|  |             NoteCleanup(a0); | ||
|  |             NoteWrite(a1); | ||
|  |         } | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | void SetHandle(PCSTR pszName, HANDLE h) | ||
|  | { | ||
|  | #if 0
 | ||
|  |     FileInfo *pInfo = OpenFiles::RecallFile(h); | ||
|  | 
 | ||
|  |     if (pInfo != NULL) { | ||
|  |         Tblog("<!-- hset: %hs (%x) %ls -->\n", pszName, h, pInfo->m_pwzPath); | ||
|  |     } | ||
|  |     else { | ||
|  |         Tblog("<!-- hset: %hs (%x) ***Unknown*** -->\n", pszName, h); | ||
|  |     } | ||
|  | #else
 | ||
|  |     (void)pszName; | ||
|  |     (void)h; | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_SetStdHandle(DWORD a0, | ||
|  |                               HANDLE a1) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_SetStdHandle(a0, a1); | ||
|  |         if (rv && a1 != 0) { | ||
|  |             switch (a0) { | ||
|  |               case STD_INPUT_HANDLE: | ||
|  |                 SetHandle("stdin", a1); | ||
|  |                 break; | ||
|  |               case STD_OUTPUT_HANDLE: | ||
|  |                 SetHandle("stdout", a1); | ||
|  |                 break; | ||
|  |               case STD_ERROR_HANDLE: | ||
|  |                 SetHandle("stderr", a1); | ||
|  |                 break; | ||
|  |             } | ||
|  |         } | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | HMODULE WINAPI Mine_LoadLibraryA(LPCSTR a0) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     HMODULE rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_LoadLibraryA(a0); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | HMODULE WINAPI Mine_LoadLibraryW(LPCWSTR a0) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     HMODULE rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_LoadLibraryW(a0); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | HMODULE WINAPI Mine_LoadLibraryExA(LPCSTR a0, | ||
|  |                                    HANDLE a1, | ||
|  |                                    DWORD a2) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     HMODULE rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_LoadLibraryExA(a0, a1, a2); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | HMODULE WINAPI Mine_LoadLibraryExW(LPCWSTR a0, | ||
|  |                                    HANDLE a1, | ||
|  |                                    DWORD a2) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     HMODULE rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_LoadLibraryExW(a0, a1, a2); | ||
|  |     } __finally { | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD WINAPI Mine_SetFilePointer(HANDLE hFile, | ||
|  |                                  LONG lDistanceToMove, | ||
|  |                                  PLONG lpDistanceToMoveHigh, | ||
|  |                                  DWORD dwMoveMethod) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_SetFilePointer(hFile, | ||
|  |                                  lDistanceToMove, | ||
|  |                                  lpDistanceToMoveHigh, | ||
|  |                                  dwMoveMethod); | ||
|  |     } __finally { | ||
|  |         LONG high = 0; | ||
|  |         if (lpDistanceToMoveHigh == NULL) { | ||
|  |             lpDistanceToMoveHigh = &high; | ||
|  |         } | ||
|  | 
 | ||
|  |         FileInfo * pInfo = OpenFiles::RecallFile(hFile); | ||
|  |         if (pInfo != NULL) { | ||
|  |             if (dwMoveMethod == FILE_END && lDistanceToMove == 0xffffffff) { | ||
|  | #if 0
 | ||
|  |                 Print("<!-- SetFilePointer(APPEND, %le) -->\n", | ||
|  |                       pInfo->m_pwzPath); | ||
|  | #endif
 | ||
|  |                 pInfo->m_fAppend = TRUE; | ||
|  |             } | ||
|  | #if 0
 | ||
|  |             else if (dwMoveMethod == FILE_END) { | ||
|  |                 Print("<!-- SetFilePointer(END:%08x:%08x, %le) -->\n", | ||
|  |                       (int)lDistanceToMove, | ||
|  |                       *lpDistanceToMoveHigh, | ||
|  |                       pInfo->m_pwzPath); | ||
|  |             } | ||
|  |             else if (dwMoveMethod == FILE_BEGIN) { | ||
|  |                 Print("<!-- SetFilePointer(BEG:%08x:%08x, %le) -->\n", | ||
|  |                       (int)lDistanceToMove, | ||
|  |                       *lpDistanceToMoveHigh, | ||
|  |                       pInfo->m_pwzPath); | ||
|  |             } | ||
|  |             else if (dwMoveMethod == FILE_CURRENT) { | ||
|  |                 Print("<!-- SetFilePointer(CUR:%08x:%08x, %le) -->\n", | ||
|  |                       (int)lDistanceToMove, | ||
|  |                       *lpDistanceToMoveHigh, | ||
|  |                       pInfo->m_pwzPath); | ||
|  |             } | ||
|  | #endif
 | ||
|  |         } | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_SetFilePointerEx(HANDLE hFile, | ||
|  |                                   LARGE_INTEGER liDistanceToMove, | ||
|  |                                   PLARGE_INTEGER lpNewFilePointer, | ||
|  |                                   DWORD dwMoveMethod) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_SetFilePointerEx(hFile, | ||
|  |                                    liDistanceToMove, | ||
|  |                                    lpNewFilePointer, | ||
|  |                                    dwMoveMethod); | ||
|  |     } __finally { | ||
|  | #if 0
 | ||
|  |         FileInfo * pInfo = OpenFiles::RecallFile(hFile); | ||
|  |         if (pInfo != NULL) { | ||
|  |             if (dwMoveMethod == FILE_END) { | ||
|  |                 Print("<!-- SetFilePointerEx(END:%I64d, %le) -->\n", | ||
|  |                       liDistanceToMove.QuadPart, | ||
|  |                       pInfo->m_pwzPath); | ||
|  |             } | ||
|  |             else if (dwMoveMethod == FILE_BEGIN) { | ||
|  |                 Print("<!-- SetFilePointerEx(BEG:%I64d, %le) -->\n", | ||
|  |                       liDistanceToMove.QuadPart, | ||
|  |                       pInfo->m_pwzPath); | ||
|  |             } | ||
|  |             else if (dwMoveMethod == FILE_CURRENT) { | ||
|  |                 Print("<!-- SetFilePointerEx(CUR:%I64d, %le) -->\n", | ||
|  |                       liDistanceToMove.QuadPart, | ||
|  |                       pInfo->m_pwzPath); | ||
|  |             } | ||
|  |         } | ||
|  | #endif
 | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_ReadFile(HANDLE a0, | ||
|  |                           LPVOID a1, | ||
|  |                           DWORD a2, | ||
|  |                           LPDWORD a3, | ||
|  |                           LPOVERLAPPED a4) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_ReadFile(a0, a1, a2, a3, a4); | ||
|  |     } __finally { | ||
|  |         if (rv) { | ||
|  |             OpenFiles::SetRead(a0, a2); | ||
|  |         } | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_ReadFileEx(HANDLE a0, | ||
|  |                             LPVOID a1, | ||
|  |                             DWORD a2, | ||
|  |                             LPOVERLAPPED a3, | ||
|  |                             LPOVERLAPPED_COMPLETION_ROUTINE a4) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_ReadFileEx(a0, a1, a2, a3, a4); | ||
|  |     } __finally { | ||
|  |         if (rv) { | ||
|  |             OpenFiles::SetRead(a0, a2); | ||
|  |         } | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_WriteFile(HANDLE a0, | ||
|  |                            LPCVOID a1, | ||
|  |                            DWORD a2, | ||
|  |                            LPDWORD a3, | ||
|  |                            LPOVERLAPPED a4) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_WriteFile(a0, a1, a2, a3, a4); | ||
|  |     } __finally { | ||
|  |         OpenFiles::SetWrite(a0, a2); | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_WriteFileEx(HANDLE a0, | ||
|  |                              LPCVOID a1, | ||
|  |                              DWORD a2, | ||
|  |                              LPOVERLAPPED a3, | ||
|  |                              LPOVERLAPPED_COMPLETION_ROUTINE a4) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_WriteFileEx(a0, a1, a2, a3, a4); | ||
|  |     } __finally { | ||
|  |         OpenFiles::SetWrite(a0, a2); | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_WriteConsoleA(HANDLE a0, | ||
|  |                                   const VOID* a1, | ||
|  |                                   DWORD a2, | ||
|  |                                   LPDWORD a3, | ||
|  |                                   LPVOID a4) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_WriteConsoleA(a0, a1, a2, a3, a4); | ||
|  |     } __finally { | ||
|  |         OpenFiles::SetWrite(a0, a2); | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI Mine_WriteConsoleW(HANDLE a0, | ||
|  |                                   const VOID* a1, | ||
|  |                                   DWORD a2, | ||
|  |                                   LPDWORD a3, | ||
|  |                                   LPVOID a4) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  | 
 | ||
|  |     BOOL rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_WriteConsoleW(a0, a1, a2, a3, a4); | ||
|  |     } __finally { | ||
|  |         OpenFiles::SetWrite(a0, a2); | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | DWORD WINAPI Mine_ExpandEnvironmentStringsA(PCSTR lpSrc, PCHAR lpDst, DWORD nSize) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_ExpandEnvironmentStringsA(lpSrc, lpDst, nSize); | ||
|  |     } | ||
|  |     __finally { | ||
|  |         if (rv > 0) { | ||
|  | #if 0
 | ||
|  |             Print("<!-- ExpandEnvironmentStringsA(%he) -->\n", lpSrc); | ||
|  | #endif
 | ||
|  |         } | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD WINAPI Mine_ExpandEnvironmentStringsW(PCWSTR lpSrc, PWCHAR lpDst, DWORD nSize) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_ExpandEnvironmentStringsW(lpSrc, lpDst, nSize); | ||
|  |     } | ||
|  |     __finally { | ||
|  |         if (rv > 0) { | ||
|  | #if 0
 | ||
|  |             Print("<!-- ExpandEnvironmentStringsW(%le) -->\n", lpSrc); | ||
|  | #endif
 | ||
|  |         } | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD WINAPI Mine_GetEnvironmentVariableA(PCSTR lpName, PCHAR lpBuffer, DWORD nSize) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_GetEnvironmentVariableA(lpName, lpBuffer, nSize); | ||
|  |         //        if (rv > 0 && rv < nSize && lpBuffer != NULL) {
 | ||
|  |         //            EnvVars::Used(lpName);
 | ||
|  |         //        }
 | ||
|  |     } | ||
|  |     __finally { | ||
|  |         EnvVars::Used(lpName); | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD WINAPI Mine_GetEnvironmentVariableW(PCWSTR lpName, PWCHAR lpBuffer, DWORD nSize) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_GetEnvironmentVariableW(lpName, lpBuffer, nSize); | ||
|  |         //        if (rv > 0 && rv < nSize && lpBuffer != NULL) {
 | ||
|  |         //            EnvVars::Used(lpName);
 | ||
|  |         //        }
 | ||
|  |     } | ||
|  |     __finally { | ||
|  |         EnvVars::Used(lpName); | ||
|  |         ExitFunc(); | ||
|  |     }; | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | PCWSTR CDECL Mine_wgetenv(PCWSTR var) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     PCWSTR rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_wgetenv(var); | ||
|  |         //        if (rv != NULL) {
 | ||
|  |         //            EnvVars::Used(var);
 | ||
|  |         //        }
 | ||
|  |     } | ||
|  |     __finally { | ||
|  |         EnvVars::Used(var); | ||
|  |         ExitFunc(); | ||
|  |     } | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | PCSTR CDECL Mine_getenv(PCSTR var) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     PCSTR rv = 0; | ||
|  |     __try { | ||
|  |         rv = Real_getenv(var); | ||
|  |         //        if (rv) {
 | ||
|  |         //            EnvVars::Used(var);
 | ||
|  |         //        }
 | ||
|  |     } | ||
|  |     __finally { | ||
|  |         EnvVars::Used(var); | ||
|  |         ExitFunc(); | ||
|  |     } | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD CDECL Mine_getenv_s(DWORD *pValue, PCHAR pBuffer, DWORD cBuffer, PCSTR varname) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         DWORD value; | ||
|  |         if (pValue == NULL) { | ||
|  |             pValue = &value; | ||
|  |         } | ||
|  |         rv = Real_getenv_s(pValue, pBuffer, cBuffer, varname); | ||
|  |         //        if (rv == 0 && *pValue > 0) {
 | ||
|  |         //            EnvVars::Used(varname);
 | ||
|  |         //        }
 | ||
|  |     } | ||
|  |     __finally { | ||
|  |         EnvVars::Used(varname); | ||
|  |         ExitFunc(); | ||
|  |     } | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD CDECL Mine_wgetenv_s(DWORD *pValue, PWCHAR pBuffer, DWORD cBuffer, PCWSTR varname) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         DWORD value; | ||
|  |         if (pValue == NULL) { | ||
|  |             pValue = &value; | ||
|  |         } | ||
|  |         rv = Real_wgetenv_s(pValue, pBuffer, cBuffer, varname); | ||
|  |         //        if (rv == 0 && *pValue > 0) {
 | ||
|  |         //            EnvVars::Used(varname);
 | ||
|  |         //        }
 | ||
|  |     } | ||
|  |     __finally { | ||
|  |         EnvVars::Used(varname); | ||
|  |         ExitFunc(); | ||
|  |     } | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD CDECL Mine_dupenv_s(PCHAR *ppBuffer, DWORD *pcBuffer, PCSTR varname) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         PCHAR pb; | ||
|  |         DWORD cb; | ||
|  |         if (ppBuffer == NULL) { | ||
|  |             ppBuffer = &pb; | ||
|  |         } | ||
|  |         if (pcBuffer == NULL) { | ||
|  |             pcBuffer = &cb; | ||
|  |         } | ||
|  |         rv = Real_dupenv_s(ppBuffer, pcBuffer, varname); | ||
|  |         //        if (rv == 0 && *pcBuffer > 0 && *ppBuffer != NULL) {
 | ||
|  |         //            EnvVars::Used(varname);
 | ||
|  |         //        }
 | ||
|  |     } | ||
|  |     __finally { | ||
|  |         EnvVars::Used(varname); | ||
|  |         ExitFunc(); | ||
|  |     } | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD CDECL Mine_wdupenv_s(PWCHAR *ppBuffer, DWORD *pcBuffer, PCWSTR varname) | ||
|  | { | ||
|  |     EnterFunc(); | ||
|  |     DWORD rv = 0; | ||
|  |     __try { | ||
|  |         PWCHAR pb; | ||
|  |         DWORD cb; | ||
|  |         if (ppBuffer == NULL) { | ||
|  |             ppBuffer = &pb; | ||
|  |         } | ||
|  |         if (pcBuffer == NULL) { | ||
|  |             pcBuffer = &cb; | ||
|  |         } | ||
|  |         rv = Real_wdupenv_s(ppBuffer, pcBuffer, varname); | ||
|  |         //        if (rv == 0 && *pcBuffer > 0 && *ppBuffer != NULL) {
 | ||
|  |         //            EnvVars::Used(varname);
 | ||
|  |         //        }
 | ||
|  |     } | ||
|  |     __finally { | ||
|  |         EnvVars::Used(varname); | ||
|  |         ExitFunc(); | ||
|  |     } | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /////////////////////////////////////////////////////////////
 | ||
|  | // AttachDetours
 | ||
|  | //
 | ||
|  | LONG AttachDetours(VOID) | ||
|  | { | ||
|  |     DetourTransactionBegin(); | ||
|  |     DetourUpdateThread(GetCurrentThread()); | ||
|  | 
 | ||
|  |     DetourAttach(&(PVOID&)Real_EntryPoint, Mine_EntryPoint); | ||
|  |     DetourAttach(&(PVOID&)Real_ExitProcess, Mine_ExitProcess); | ||
|  |     DetourAttach(&(PVOID&)Real_CopyFileExA, Mine_CopyFileExA); | ||
|  |     DetourAttach(&(PVOID&)Real_CopyFileExW, Mine_CopyFileExW); | ||
|  |     DetourAttach(&(PVOID&)Real_PrivCopyFileExW, Mine_PrivCopyFileExW); | ||
|  |     DetourAttach(&(PVOID&)Real_CreateHardLinkA, Mine_CreateHardLinkA); | ||
|  |     DetourAttach(&(PVOID&)Real_CreateHardLinkW, Mine_CreateHardLinkW); | ||
|  |     DetourAttach(&(PVOID&)Real_CreateDirectoryW, Mine_CreateDirectoryW); | ||
|  |     DetourAttach(&(PVOID&)Real_CreateDirectoryExW, Mine_CreateDirectoryExW); | ||
|  |     DetourAttach(&(PVOID&)Real_CreateFileW, Mine_CreateFileW); | ||
|  |     DetourAttach(&(PVOID&)Real_CreatePipe, Mine_CreatePipe); | ||
|  |     DetourAttach(&(PVOID&)Real_CreateFileMappingW, Mine_CreateFileMappingW); | ||
|  |     DetourAttach(&(PVOID&)Real_CloseHandle, Mine_CloseHandle); | ||
|  |     DetourAttach(&(PVOID&)Real_DuplicateHandle, Mine_DuplicateHandle); | ||
|  |     DetourAttach(&(PVOID&)Real_CreateProcessW, Mine_CreateProcessW); | ||
|  |     DetourAttach(&(PVOID&)Real_CreateProcessA, Mine_CreateProcessA); | ||
|  |     DetourAttach(&(PVOID&)Real_DeleteFileW, Mine_DeleteFileW); | ||
|  |     DetourAttach(&(PVOID&)Real_DeviceIoControl, Mine_DeviceIoControl); | ||
|  |     DetourAttach(&(PVOID&)Real_GetFileAttributesW, Mine_GetFileAttributesW); | ||
|  |     DetourAttach(&(PVOID&)Real_MoveFileA, Mine_MoveFileA); | ||
|  |     DetourAttach(&(PVOID&)Real_MoveFileW, Mine_MoveFileW); | ||
|  |     DetourAttach(&(PVOID&)Real_MoveFileExA, Mine_MoveFileExA); | ||
|  |     DetourAttach(&(PVOID&)Real_MoveFileExW, Mine_MoveFileExW); | ||
|  |     DetourAttach(&(PVOID&)Real_MoveFileWithProgressW, Mine_MoveFileWithProgressW); | ||
|  |     DetourAttach(&(PVOID&)Real_SetStdHandle, Mine_SetStdHandle); | ||
|  |     DetourAttach(&(PVOID&)Real_LoadLibraryA, Mine_LoadLibraryA); | ||
|  |     DetourAttach(&(PVOID&)Real_LoadLibraryW, Mine_LoadLibraryW); | ||
|  |     DetourAttach(&(PVOID&)Real_LoadLibraryExA, Mine_LoadLibraryExA); | ||
|  |     DetourAttach(&(PVOID&)Real_LoadLibraryExW, Mine_LoadLibraryExW); | ||
|  |     DetourAttach(&(PVOID&)Real_SetFilePointer, Mine_SetFilePointer); | ||
|  |     DetourAttach(&(PVOID&)Real_SetFilePointerEx, Mine_SetFilePointerEx); | ||
|  |     DetourAttach(&(PVOID&)Real_ReadFile, Mine_ReadFile); | ||
|  |     DetourAttach(&(PVOID&)Real_ReadFileEx, Mine_ReadFileEx); | ||
|  |     DetourAttach(&(PVOID&)Real_WriteFile, Mine_WriteFile); | ||
|  |     DetourAttach(&(PVOID&)Real_WriteFileEx, Mine_WriteFileEx); | ||
|  |     DetourAttach(&(PVOID&)Real_WriteConsoleA, Mine_WriteConsoleA); | ||
|  |     DetourAttach(&(PVOID&)Real_WriteConsoleW, Mine_WriteConsoleW); | ||
|  |     DetourAttach(&(PVOID&)Real_ExpandEnvironmentStringsA, Mine_ExpandEnvironmentStringsA); | ||
|  |     DetourAttach(&(PVOID&)Real_ExpandEnvironmentStringsW, Mine_ExpandEnvironmentStringsW); | ||
|  |     DetourAttach(&(PVOID&)Real_GetEnvironmentVariableA, Mine_GetEnvironmentVariableA); | ||
|  |     DetourAttach(&(PVOID&)Real_GetEnvironmentVariableW, Mine_GetEnvironmentVariableW); | ||
|  | 
 | ||
|  |     return DetourTransactionCommit(); | ||
|  | } | ||
|  | 
 | ||
|  | LONG DetachDetours(VOID) | ||
|  | { | ||
|  |     DetourTransactionBegin(); | ||
|  |     DetourUpdateThread(GetCurrentThread()); | ||
|  | 
 | ||
|  |     DetourDetach(&(PVOID&)Real_EntryPoint, Mine_EntryPoint); | ||
|  |     DetourAttach(&(PVOID&)Real_ExitProcess, Mine_ExitProcess); | ||
|  |     DetourDetach(&(PVOID&)Real_CopyFileExA, Mine_CopyFileExA); | ||
|  |     DetourDetach(&(PVOID&)Real_CopyFileExW, Mine_CopyFileExW); | ||
|  |     DetourDetach(&(PVOID&)Real_PrivCopyFileExW, Mine_PrivCopyFileExW); | ||
|  |     DetourDetach(&(PVOID&)Real_CreateHardLinkA, Mine_CreateHardLinkA); | ||
|  |     DetourDetach(&(PVOID&)Real_CreateHardLinkW, Mine_CreateHardLinkW); | ||
|  |     DetourDetach(&(PVOID&)Real_CreateDirectoryW, Mine_CreateDirectoryW); | ||
|  |     DetourDetach(&(PVOID&)Real_CreateDirectoryExW, Mine_CreateDirectoryExW); | ||
|  |     DetourDetach(&(PVOID&)Real_CreateFileW, Mine_CreateFileW); | ||
|  |     DetourDetach(&(PVOID&)Real_CreatePipe, Mine_CreatePipe); | ||
|  |     DetourDetach(&(PVOID&)Real_CreateFileMappingW, Mine_CreateFileMappingW); | ||
|  |     DetourDetach(&(PVOID&)Real_CloseHandle, Mine_CloseHandle); | ||
|  |     DetourDetach(&(PVOID&)Real_DuplicateHandle, Mine_DuplicateHandle); | ||
|  |     DetourDetach(&(PVOID&)Real_CreateProcessW, Mine_CreateProcessW); | ||
|  |     DetourDetach(&(PVOID&)Real_CreateProcessA, Mine_CreateProcessA); | ||
|  |     DetourDetach(&(PVOID&)Real_DeleteFileW, Mine_DeleteFileW); | ||
|  |     DetourDetach(&(PVOID&)Real_DeviceIoControl, Mine_DeviceIoControl); | ||
|  |     DetourDetach(&(PVOID&)Real_GetFileAttributesW, Mine_GetFileAttributesW); | ||
|  |     DetourDetach(&(PVOID&)Real_MoveFileA, Mine_MoveFileA); | ||
|  |     DetourDetach(&(PVOID&)Real_MoveFileW, Mine_MoveFileW); | ||
|  |     DetourDetach(&(PVOID&)Real_MoveFileExA, Mine_MoveFileExA); | ||
|  |     DetourDetach(&(PVOID&)Real_MoveFileExW, Mine_MoveFileExW); | ||
|  |     DetourDetach(&(PVOID&)Real_MoveFileWithProgressW, Mine_MoveFileWithProgressW); | ||
|  |     DetourDetach(&(PVOID&)Real_SetStdHandle, Mine_SetStdHandle); | ||
|  |     DetourDetach(&(PVOID&)Real_LoadLibraryA, Mine_LoadLibraryA); | ||
|  |     DetourDetach(&(PVOID&)Real_LoadLibraryW, Mine_LoadLibraryW); | ||
|  |     DetourDetach(&(PVOID&)Real_LoadLibraryExA, Mine_LoadLibraryExA); | ||
|  |     DetourDetach(&(PVOID&)Real_LoadLibraryExW, Mine_LoadLibraryExW); | ||
|  |     DetourDetach(&(PVOID&)Real_SetFilePointer, Mine_SetFilePointer); | ||
|  |     DetourDetach(&(PVOID&)Real_SetFilePointerEx, Mine_SetFilePointerEx); | ||
|  |     DetourDetach(&(PVOID&)Real_ReadFile, Mine_ReadFile); | ||
|  |     DetourDetach(&(PVOID&)Real_ReadFileEx, Mine_ReadFileEx); | ||
|  |     DetourDetach(&(PVOID&)Real_WriteFile, Mine_WriteFile); | ||
|  |     DetourDetach(&(PVOID&)Real_WriteFileEx, Mine_WriteFileEx); | ||
|  |     DetourDetach(&(PVOID&)Real_WriteConsoleA, Mine_WriteConsoleA); | ||
|  |     DetourDetach(&(PVOID&)Real_WriteConsoleW, Mine_WriteConsoleW); | ||
|  |     DetourDetach(&(PVOID&)Real_ExpandEnvironmentStringsA, Mine_ExpandEnvironmentStringsA); | ||
|  |     DetourDetach(&(PVOID&)Real_ExpandEnvironmentStringsW, Mine_ExpandEnvironmentStringsW); | ||
|  |     DetourDetach(&(PVOID&)Real_GetEnvironmentVariableA, Mine_GetEnvironmentVariableA); | ||
|  |     DetourDetach(&(PVOID&)Real_GetEnvironmentVariableW, Mine_GetEnvironmentVariableW); | ||
|  | 
 | ||
|  |     if (Real_getenv) { DetourDetach(&(PVOID&)Real_getenv, Mine_getenv); } | ||
|  |     if (Real_getenv_s) { DetourDetach(&(PVOID&)Real_getenv_s, Mine_getenv_s); } | ||
|  |     if (Real_wgetenv) { DetourDetach(&(PVOID&)Real_wgetenv, Mine_wgetenv); } | ||
|  |     if (Real_wgetenv_s) { DetourDetach(&(PVOID&)Real_wgetenv, Mine_wgetenv_s); } | ||
|  |     if (Real_dupenv_s) { DetourDetach(&(PVOID&)Real_dupenv_s, Mine_dupenv_s); } | ||
|  |     if (Real_wdupenv_s) { DetourDetach(&(PVOID&)Real_wdupenv_s, Mine_wdupenv_s); } | ||
|  | 
 | ||
|  |     return DetourTransactionCommit(); | ||
|  | } | ||
|  | //
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | 
 | ||
|  | VOID NoteRead(PCSTR psz) | ||
|  | { | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(psz); | ||
|  |     pInfo->m_fRead = TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | VOID NoteRead(PCWSTR pwz) | ||
|  | { | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(pwz); | ||
|  |     pInfo->m_fRead = TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | VOID NoteWrite(PCSTR psz) | ||
|  | { | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(psz); | ||
|  |     pInfo->m_fWrite = TRUE; | ||
|  |     if (!pInfo->m_fRead) { | ||
|  |         pInfo->m_fCantRead = TRUE; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID NoteWrite(PCWSTR pwz) | ||
|  | { | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(pwz); | ||
|  |     pInfo->m_fWrite = TRUE; | ||
|  |     if (!pInfo->m_fRead) { | ||
|  |         pInfo->m_fCantRead = TRUE; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID NoteDelete(PCSTR psz) | ||
|  | { | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(psz); | ||
|  |     if (pInfo->m_fWrite || pInfo->m_fRead) { | ||
|  |         pInfo->m_fCleanup = TRUE; | ||
|  |     } | ||
|  |     else { | ||
|  |         pInfo->m_fDelete = TRUE; | ||
|  |     } | ||
|  |     if (!pInfo->m_fRead) { | ||
|  |         pInfo->m_fCantRead = TRUE; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID NoteDelete(PCWSTR pwz) | ||
|  | { | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(pwz); | ||
|  |     if (pInfo->m_fWrite || pInfo->m_fRead) { | ||
|  |         pInfo->m_fCleanup = TRUE; | ||
|  |     } | ||
|  |     else { | ||
|  |         pInfo->m_fDelete = TRUE; | ||
|  |     } | ||
|  |     if (!pInfo->m_fRead) { | ||
|  |         pInfo->m_fCantRead = TRUE; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | VOID NoteCleanup(PCSTR psz) | ||
|  | { | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(psz); | ||
|  |     pInfo->m_fCleanup = TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | VOID NoteCleanup(PCWSTR pwz) | ||
|  | { | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(pwz); | ||
|  |     pInfo->m_fCleanup = TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | ////////////////////////////////////////////////////////////// Logging System.
 | ||
|  | //
 | ||
|  | static BOOL s_bLog = 1; | ||
|  | static LONG s_nTlsIndent = -1; | ||
|  | static LONG s_nTlsThread = -1; | ||
|  | static LONG s_nThreadCnt = 0; | ||
|  | 
 | ||
|  | LONG EnterFunc() | ||
|  | { | ||
|  |     DWORD dwErr = GetLastError(); | ||
|  | 
 | ||
|  |     LONG nIndent = 0; | ||
|  |     LONG nThread = 0; | ||
|  |     if (s_nTlsIndent >= 0) { | ||
|  |         nIndent = (LONG)(LONG_PTR)TlsGetValue(s_nTlsIndent); | ||
|  |         TlsSetValue(s_nTlsIndent, (PVOID)(LONG_PTR)(nIndent + 1)); | ||
|  |     } | ||
|  |     if (s_nTlsThread >= 0) { | ||
|  |         nThread = (LONG)(LONG_PTR)TlsGetValue(s_nTlsThread); | ||
|  |     } | ||
|  | 
 | ||
|  |     SetLastError(dwErr); | ||
|  | 
 | ||
|  |     return nIndent; | ||
|  | } | ||
|  | 
 | ||
|  | VOID ExitFunc() | ||
|  | { | ||
|  |     DWORD dwErr = GetLastError(); | ||
|  | 
 | ||
|  |     LONG nIndent = 0; | ||
|  |     LONG nThread = 0; | ||
|  |     if (s_nTlsIndent >= 0) { | ||
|  |         nIndent = (LONG)(LONG_PTR)TlsGetValue(s_nTlsIndent) - 1; | ||
|  |         ASSERT(nIndent >= 0); | ||
|  |         TlsSetValue(s_nTlsIndent, (PVOID)(LONG_PTR)nIndent); | ||
|  |     } | ||
|  |     if (s_nTlsThread >= 0) { | ||
|  |         nThread = (LONG)(LONG_PTR)TlsGetValue(s_nTlsThread); | ||
|  |     } | ||
|  | 
 | ||
|  |     SetLastError(dwErr); | ||
|  | } | ||
|  | 
 | ||
|  | VOID Print(const CHAR *psz, ...) | ||
|  | { | ||
|  |     DWORD dwErr = GetLastError(); | ||
|  | 
 | ||
|  |     if (s_bLog && psz) { | ||
|  |         va_list  args; | ||
|  |         va_start(args, psz); | ||
|  | 
 | ||
|  |         TblogV(psz, args); | ||
|  | 
 | ||
|  |         va_end(args); | ||
|  |     } | ||
|  | 
 | ||
|  |     SetLastError(dwErr); | ||
|  | } | ||
|  | 
 | ||
|  | VOID AssertFailed(CONST PCHAR pszMsg, CONST PCHAR pszFile, ULONG nLine) | ||
|  | { | ||
|  |     Tblog("ASSERT(%hs) failed in %s, line %d.\n", pszMsg, pszFile, nLine); | ||
|  | } | ||
|  | 
 | ||
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | // DLL module information
 | ||
|  | //
 | ||
|  | BOOL ThreadAttach(HMODULE hDll) | ||
|  | { | ||
|  |     (void)hDll; | ||
|  | 
 | ||
|  |     if (s_nTlsIndent >= 0) { | ||
|  |         TlsSetValue(s_nTlsIndent, (PVOID)0); | ||
|  |     } | ||
|  |     if (s_nTlsThread >= 0) { | ||
|  |         LONG nThread = InterlockedIncrement(&s_nThreadCnt); | ||
|  |         TlsSetValue(s_nTlsThread, (PVOID)(LONG_PTR)nThread); | ||
|  |     } | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL ThreadDetach(HMODULE hDll) | ||
|  | { | ||
|  |     (void)hDll; | ||
|  | 
 | ||
|  |     if (s_nTlsIndent >= 0) { | ||
|  |         TlsSetValue(s_nTlsIndent, (PVOID)0); | ||
|  |     } | ||
|  |     if (s_nTlsThread >= 0) { | ||
|  |         TlsSetValue(s_nTlsThread, (PVOID)0); | ||
|  |     } | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL ProcessAttach(HMODULE hDll) | ||
|  | { | ||
|  |     InitializeCriticalSection(&s_csPipe); | ||
|  |     InitializeCriticalSection(&s_csChildPayload); | ||
|  | 
 | ||
|  |     Procs::Initialize(); | ||
|  |     EnvVars::Initialize(); | ||
|  |     FileNames::Initialize(); | ||
|  |     OpenFiles::Initialize(); | ||
|  | 
 | ||
|  |     s_bLog = FALSE; | ||
|  |     s_nTlsIndent = TlsAlloc(); | ||
|  |     s_nTlsThread = TlsAlloc(); | ||
|  | 
 | ||
|  |     s_hInst = hDll; | ||
|  |     s_hKernel32 = NULL; | ||
|  | 
 | ||
|  |     PBYTE xCreate = (PBYTE)DetourCodeFromPointer((PVOID)Real_CreateProcessW, NULL); | ||
|  |     PTBLOG_PAYLOAD pPayload = NULL; | ||
|  | 
 | ||
|  |     for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) { | ||
|  |         ULONG cbData; | ||
|  |         PVOID pvData = DetourFindPayload(hMod, s_guidTrace, &cbData); | ||
|  | 
 | ||
|  |         if (pvData != NULL && pPayload == NULL) { | ||
|  |             pPayload = (PTBLOG_PAYLOAD)pvData; | ||
|  |         } | ||
|  | 
 | ||
|  |         ULONG cbMod = DetourGetModuleSize(hMod); | ||
|  | 
 | ||
|  |         if (((PBYTE)hMod) < xCreate && ((PBYTE)hMod + cbMod) > xCreate) { | ||
|  |             s_hKernel32 = hMod; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     ZeroMemory(&s_Payload, sizeof(s_Payload)); | ||
|  | 
 | ||
|  |     if (pPayload == NULL) { | ||
|  |         return FALSE; | ||
|  |     } | ||
|  | 
 | ||
|  |     CopyMemory(&s_Payload, pPayload, sizeof(s_Payload)); | ||
|  | 
 | ||
|  |     LoadStdHandleName(STD_INPUT_HANDLE, s_Payload.wzStdin, FALSE); | ||
|  |     LoadStdHandleName(STD_OUTPUT_HANDLE, s_Payload.wzStdout, s_Payload.fStdoutAppend); | ||
|  |     LoadStdHandleName(STD_ERROR_HANDLE, s_Payload.wzStderr, s_Payload.fStderrAppend); | ||
|  |     s_nTraceProcessId = s_Payload.nTraceProcessId; | ||
|  | 
 | ||
|  |     GetModuleFileNameA(s_hInst, s_szDllPath, ARRAYSIZE(s_szDllPath)); | ||
|  | 
 | ||
|  |     // Find hidden functions.
 | ||
|  |     Real_PrivCopyFileExW = | ||
|  |         (BOOL (WINAPI *)(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD)) | ||
|  |         GetProcAddress(s_hKernel32, "PrivCopyFileExW"); | ||
|  |     if (Real_PrivCopyFileExW == NULL) { | ||
|  |         DEBUG_BREAK(); | ||
|  |     } | ||
|  | 
 | ||
|  |     LONG error = AttachDetours(); | ||
|  |     if (error != NO_ERROR) { | ||
|  |         DEBUG_BREAK(); | ||
|  |         Tblog("<!-- Error attaching detours: %d -->\n", error); | ||
|  |     } | ||
|  | 
 | ||
|  |     ThreadAttach(hDll); | ||
|  | 
 | ||
|  |     s_bLog = TRUE; | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL ProcessDetach(HMODULE hDll) | ||
|  | { | ||
|  |     ThreadDetach(hDll); | ||
|  |     s_bLog = FALSE; | ||
|  | 
 | ||
|  |     LONG error = DetachDetours(); | ||
|  |     if (error != NO_ERROR) { | ||
|  |         Tblog("<!-- Error detaching detours: %d -->\n", error); | ||
|  |     } | ||
|  | 
 | ||
|  |     TblogClose(); | ||
|  | 
 | ||
|  |     if (s_nTlsIndent >= 0) { | ||
|  |         TlsFree(s_nTlsIndent); | ||
|  |     } | ||
|  |     if (s_nTlsThread >= 0) { | ||
|  |         TlsFree(s_nTlsThread); | ||
|  |     } | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | inline VOID UpdateIfRoom(PWCHAR& pwzDst, PWCHAR pwzDstEnd, WCHAR c) | ||
|  | { | ||
|  |     if (pwzDst < pwzDstEnd) { | ||
|  |         *pwzDst++ = c;  // Write character if room in buffer.
 | ||
|  |     } | ||
|  |     else { | ||
|  |         pwzDst++;       // If no room, just advance pointer (to alloc calculation)
 | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | static PCHAR RemoveReturns(PCHAR pszBuffer) | ||
|  | { | ||
|  |     PCHAR pszIn = pszBuffer; | ||
|  |     PCHAR pszOut = pszBuffer; | ||
|  | 
 | ||
|  |     while (*pszIn) { | ||
|  |         if (*pszIn == '\r') { | ||
|  |             pszIn++; | ||
|  |             continue; | ||
|  |         } | ||
|  |         *pszOut++ = *pszIn++; | ||
|  |     } | ||
|  |     *pszOut = '\0'; | ||
|  | 
 | ||
|  |     return pszBuffer; | ||
|  | } | ||
|  | 
 | ||
|  | static PWCHAR RemoveReturns(PWCHAR pwzBuffer) | ||
|  | { | ||
|  |     PWCHAR pwzIn = pwzBuffer; | ||
|  |     PWCHAR pwzOut = pwzBuffer; | ||
|  | 
 | ||
|  |     while (*pwzIn) { | ||
|  |         if (*pwzIn == '\r') { | ||
|  |             pwzIn++; | ||
|  |             continue; | ||
|  |         } | ||
|  |         *pwzOut++ = *pwzIn++; | ||
|  |     } | ||
|  |     *pwzOut = '\0'; | ||
|  | 
 | ||
|  |     return pwzBuffer; | ||
|  | } | ||
|  | 
 | ||
|  | PBYTE LoadFile(HANDLE hFile, DWORD cbFile) | ||
|  | { | ||
|  |     PBYTE pbFile = (PBYTE)GlobalAlloc(GPTR, cbFile + 3); | ||
|  |     if (pbFile == NULL) { | ||
|  |         return NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     DWORD cbRead = 0; | ||
|  |     Real_SetFilePointer(hFile, 0, NULL, FILE_BEGIN); | ||
|  |     Real_ReadFile(hFile, pbFile, cbFile, &cbRead, NULL); | ||
|  | 
 | ||
|  |     // Make sure the file is zero terminated.
 | ||
|  |     pbFile[cbRead + 0] = 0; | ||
|  |     pbFile[cbRead + 1] = 0; | ||
|  |     pbFile[cbRead + 2] = 0; | ||
|  | 
 | ||
|  |     return pbFile; | ||
|  | } | ||
|  | 
 | ||
|  | PWCHAR More(PCWSTR pwzPath, PWCHAR pwzDst, PWCHAR pwzDstEnd) | ||
|  | { | ||
|  |     HANDLE hFile = Real_CreateFileW(pwzPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); | ||
|  |     if (hFile == INVALID_HANDLE_VALUE) { | ||
|  |         return NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     FileInfo *pInfo = FileNames::FindPartial(pwzPath); | ||
|  |     pInfo->m_fAbsorbed = true; | ||
|  | 
 | ||
|  |     DWORD cbFile = Real_SetFilePointer(hFile, 0, NULL, FILE_END); | ||
|  |     DWORD cbRead = 0; | ||
|  | 
 | ||
|  |     PCHAR pszFile = (PCHAR)GlobalAlloc(GPTR, cbFile + 2);   // 2 bytes null for Unicode or Ascii.
 | ||
|  |     if (pszFile != NULL) { | ||
|  |         Real_SetFilePointer(hFile, 0, NULL, FILE_BEGIN); | ||
|  |         Real_ReadFile(hFile, pszFile, cbFile, &cbRead, NULL); | ||
|  | 
 | ||
|  |         if (((PUCHAR)pszFile)[0] == 0xff && ((PUCHAR)pszFile)[1] == 0xfe) { | ||
|  |             // Unicode
 | ||
|  |             PWCHAR pwzFile = ((PWCHAR)pszFile) + 1; | ||
|  |             PCWSTR pwzIn = pwzFile; | ||
|  |             while (*pwzIn) { | ||
|  |                 if (*pwzIn == ' ' || *pwzIn == '\t' || *pwzIn == '\r' || *pwzIn == '\n') { | ||
|  |                     UpdateIfRoom(pwzDst, pwzDstEnd, ' '); | ||
|  |                     while (*pwzIn == ' ' || *pwzIn == '\t' || *pwzIn == '\r' || *pwzIn == '\n') { | ||
|  |                         pwzIn++; | ||
|  |                     } | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     UpdateIfRoom(pwzDst, pwzDstEnd, *pwzIn++); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |         else { | ||
|  |             PCSTR pszIn = pszFile; | ||
|  |             while (*pszIn) { | ||
|  |                 if (*pszIn == ' ' || *pszIn == '\t' || *pszIn == '\r' || *pszIn == '\n') { | ||
|  |                     UpdateIfRoom(pwzDst, pwzDstEnd, ' '); | ||
|  |                     while (*pszIn == ' ' || *pszIn == '\t' || *pszIn == '\r' || *pszIn == '\n') { | ||
|  |                         pszIn++; | ||
|  |                     } | ||
|  |                 } | ||
|  |                 else { | ||
|  |                     UpdateIfRoom(pwzDst, pwzDstEnd, *pszIn++); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         GlobalFree(pszFile); | ||
|  |     } | ||
|  | 
 | ||
|  |     Real_CloseHandle(hFile); | ||
|  | 
 | ||
|  |     return pwzDst; | ||
|  | } | ||
|  | 
 | ||
|  | // This function is called twice.  On the first call, pwzDstEnd <= pwzDst and
 | ||
|  | // no data is copied, but pwzDst is advanced so we can see how big of a
 | ||
|  | // buffer is needed to hold the command line.
 | ||
|  | //
 | ||
|  | // On the second call, the command line is actually populated.
 | ||
|  | PWCHAR LoadCommandLine(PCWSTR pwz, PWCHAR pwzDst, PWCHAR pwzDstEnd) | ||
|  | { | ||
|  |     while (*pwz) { | ||
|  |         PCWSTR pwzArgBeg = NULL; | ||
|  |         PCWSTR pwzArgEnd = NULL; | ||
|  |         WCHAR cQuote = '\0'; | ||
|  |         BOOL fMore = false; | ||
|  | 
 | ||
|  |         if (*pwz == '@') { | ||
|  |             fMore = true; | ||
|  |             pwz++; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (*pwz == '\"' || *pwz == '\'') { | ||
|  |             cQuote = *pwz++; | ||
|  | 
 | ||
|  |             pwzArgBeg = pwz; | ||
|  |             while (*pwz != '\0' && *pwz != cQuote) { | ||
|  |                 pwz++; | ||
|  |             } | ||
|  |             pwzArgEnd = pwz; | ||
|  | 
 | ||
|  |             if (*pwz == cQuote) { | ||
|  |                 pwz++; | ||
|  |             } | ||
|  |         } | ||
|  |         else { | ||
|  |             pwzArgBeg = pwz; | ||
|  |             while (*pwz != '\0' && *pwz != ' ' && *pwz != '\t' && *pwz != '\n' && *pwz != '\r') { | ||
|  |                 pwz++; | ||
|  |             } | ||
|  |             pwzArgEnd = pwz; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (fMore) { | ||
|  |             // More arguments!
 | ||
|  |             WCHAR wzPath[MAX_PATH]; | ||
|  |             PWCHAR pwzPath = wzPath; | ||
|  |             PCWSTR pwzTmp = pwzArgBeg + 1; | ||
|  |             while (pwzTmp < pwzArgEnd && pwzPath < wzPath + ARRAYSIZE(wzPath)-2) { | ||
|  |                 *pwzPath++ = *pwzTmp++; | ||
|  |             } | ||
|  |             *pwzPath = '\0'; | ||
|  | 
 | ||
|  |             PWCHAR pwzOut = More(wzPath, pwzDst, pwzDstEnd); | ||
|  |             if (pwzOut != NULL) { | ||
|  |                 pwzDst = pwzOut; | ||
|  | 
 | ||
|  |                 cQuote = 0; | ||
|  |                 pwzArgBeg = pwzArgEnd; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         if (cQuote) { | ||
|  |             UpdateIfRoom(pwzDst, pwzDstEnd, cQuote); | ||
|  |         } | ||
|  |         for (; pwzArgBeg < pwzArgEnd; pwzArgBeg++) { | ||
|  |             UpdateIfRoom(pwzDst, pwzDstEnd, *pwzArgBeg); | ||
|  |         } | ||
|  |         if (cQuote) { | ||
|  |             UpdateIfRoom(pwzDst, pwzDstEnd, cQuote); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (*pwz) { | ||
|  |             UpdateIfRoom(pwzDst, pwzDstEnd, ' '); | ||
|  |         } | ||
|  | 
 | ||
|  |         // skip over separating spaces.
 | ||
|  |         while (*pwz == ' ' || *pwz == '\t' || *pwz == '\n' || *pwz == '\r') { | ||
|  |             pwz++; | ||
|  |         } | ||
|  |     } | ||
|  |     return pwzDst; | ||
|  | } | ||
|  | 
 | ||
|  | void TestHandle(PCSTR pszName, HANDLE h) | ||
|  | { | ||
|  |     FileInfo *pInfo = OpenFiles::RecallFile(h); | ||
|  | 
 | ||
|  |     if (pInfo != NULL) { | ||
|  | #if 1 // Ignore PIPEs.
 | ||
|  |         if (FileNames::PrefixMatch(pInfo->m_pwzPath, L"\\\\.\\PIPE\\")) { | ||
|  |             // Ignore;
 | ||
|  |         } | ||
|  |         else | ||
|  | #endif
 | ||
|  |             if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conout$")) { | ||
|  |             // Ignore;
 | ||
|  |         } | ||
|  |         else if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conin$")) { | ||
|  |             // Ignore;
 | ||
|  |         } | ||
|  |         else if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\nul")) { | ||
|  |             // Ignore;
 | ||
|  |         } | ||
|  |         else { | ||
|  |             Tblog("<%hs%hs>%le</%hs>\n", | ||
|  |                   pszName, pInfo->m_fAppend ? " append=\"true\"" : "", pInfo->m_pwzPath, pszName); | ||
|  |         } | ||
|  |     } | ||
|  |     else { | ||
|  |         Tblog("<!-- hand: %hs (%x) ***Unknown*** -->\n", pszName, h); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | LONG WINAPI DetourAttachIf(PVOID *ppPointer, PVOID pDetour) | ||
|  | { | ||
|  |     if (*ppPointer == NULL) { | ||
|  |         Tblog("<!-- DetourAttachIf failed: %p -->\n", pDetour); | ||
|  |         return NO_ERROR; | ||
|  |     } | ||
|  | 
 | ||
|  |     PDETOUR_TRAMPOLINE pRealTrampoline; | ||
|  |     PVOID pRealTarget; | ||
|  |     PVOID pRealDetour; | ||
|  | 
 | ||
|  |     LONG err = DetourAttachEx(ppPointer, pDetour, &pRealTrampoline, &pRealTarget, &pRealDetour); | ||
|  |     if (err == NO_ERROR) { | ||
|  |         // Tblog("<!-- DetourAttachIf %p at %p -->\n", pDetour, pRealTarget);
 | ||
|  |         return NO_ERROR; | ||
|  |     } | ||
|  |     return err; | ||
|  | } | ||
|  | 
 | ||
|  | int WINAPI Mine_EntryPoint(VOID) | ||
|  | { | ||
|  |     // This function is invoked instead of the process EntryPoint (Real_EntryPoint).
 | ||
|  | 
 | ||
|  |     TblogOpen(); | ||
|  | 
 | ||
|  |     SaveEnvironment(); | ||
|  | 
 | ||
|  |     { | ||
|  |         CHAR szExeName[MAX_PATH]; | ||
|  |         CHAR szId[128]; | ||
|  |         CHAR szParent[128]; | ||
|  |         WCHAR wzPath[MAX_PATH]; | ||
|  |         PCHAR pszExeName = szExeName; | ||
|  | 
 | ||
|  |         // Get the base command line (skipping over the executable name)
 | ||
|  |         PCWSTR pwzLine = GetCommandLineW(); | ||
|  |         if (*pwzLine == '\"') { | ||
|  |             pwzLine++; | ||
|  |             while (*pwzLine && *pwzLine != '\"') { | ||
|  |                 pwzLine++; | ||
|  |             } | ||
|  |             if (*pwzLine == '\"') { | ||
|  |                 pwzLine++; | ||
|  |             } | ||
|  |         } | ||
|  |         else { | ||
|  |             while (*pwzLine && *pwzLine != ' ' && *pwzLine != '\t') { | ||
|  |                 pwzLine++; | ||
|  |             } | ||
|  |         } | ||
|  |         while (*pwzLine && (*pwzLine == ' ' || *pwzLine == '\t')) { | ||
|  |             pwzLine++; | ||
|  |         } | ||
|  | 
 | ||
|  |         // Get the root executable name.
 | ||
|  |         if (GetModuleFileNameA(0, szExeName, ARRAYSIZE(szExeName))) { | ||
|  |             PCHAR psz = szExeName; | ||
|  | 
 | ||
|  |             while (*psz) { | ||
|  |                 psz++; | ||
|  |             } | ||
|  | 
 | ||
|  |             while (psz > szExeName && psz[-1] != ':' && psz[-1] != '\\' && psz[-1] != '/') { | ||
|  |                 psz--; | ||
|  |             } | ||
|  |             pszExeName = psz; | ||
|  |             while (*psz && *psz != '.') { | ||
|  |                 psz++; | ||
|  |             } | ||
|  |             *psz = '\0'; | ||
|  |         } | ||
|  |         else { | ||
|  |             szExeName[0] = '\0'; | ||
|  |         } | ||
|  | 
 | ||
|  |         // Start the XML process node.
 | ||
|  |         Tblog("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); | ||
|  |         { | ||
|  |             PCHAR pszId = szId; | ||
|  |             PCHAR pszParent = szParent; | ||
|  |             for (DWORD i = 0; i < s_Payload.nGeneology; i++) { | ||
|  |                 pszId = SafePrintf(pszId, 16, "%d.", s_Payload.rGeneology[i]); | ||
|  |                 if (i < s_Payload.nGeneology - 1) { | ||
|  |                     pszParent = SafePrintf(pszParent, 16, "%d.", s_Payload.rGeneology[i]); | ||
|  |                 } | ||
|  |             } | ||
|  |             *pszId = '\0'; | ||
|  |             *pszParent = '\0'; | ||
|  | 
 | ||
|  |             if (szParent[0] == '\0') { | ||
|  |                 Tblog("<t:Process id=\"::%hs::\"", szId); | ||
|  |             } | ||
|  |             else { | ||
|  |                 Tblog("<t:Process id=\"::%hs::\" parentId=\"::%hs::\"", szId, szParent); | ||
|  |             } | ||
|  | 
 | ||
|  |             Tblog(" par=\"%ls\" exe=\"%hs\"", s_Payload.wzParents, pszExeName); | ||
|  | 
 | ||
|  |             BOOL drop = false; | ||
|  |             PCWSTR pwzz = s_Payload.wzzDrop; | ||
|  |             while (*pwzz) { | ||
|  |                 if (Compare(pwzz, pszExeName) == 0) { | ||
|  |                     // match
 | ||
|  |                     drop = true; | ||
|  |                     break; | ||
|  |                 } | ||
|  |                 pwzz += Size(pwzz) + 1; | ||
|  |             } | ||
|  |             if (drop) { | ||
|  |                 Tblog(" drop=\"true\""); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         { | ||
|  |             PWCHAR pwz = s_Payload.wzParents; | ||
|  |             while (*pwz) { | ||
|  |                 pwz++; | ||
|  |             } | ||
|  |             *pwz++ = '/'; | ||
|  |             PCSTR psz = pszExeName; | ||
|  |             while (*psz) { | ||
|  |                 *pwz++ = *psz++; | ||
|  |             } | ||
|  |             *pwz = '\0'; | ||
|  |         } | ||
|  | 
 | ||
|  | 
 | ||
|  |         if (HasChar(pwzLine, '|')) { | ||
|  |             Tblog(" pipes=\"true\""); | ||
|  |         } | ||
|  |         if (HasChar(pwzLine, '>')) { | ||
|  |             Tblog(" redirects=\"true\""); | ||
|  |         } | ||
|  | 
 | ||
|  |         Tblog(" xmlns:t=\"http://schemas.microsoft.com/research/tracebld/2008\">\n"); | ||
|  | 
 | ||
|  |         // Get the directory.
 | ||
|  |         DWORD dwSize = GetCurrentDirectoryA(ARRAYSIZE(szExeName), szExeName); | ||
|  |         if (dwSize > 0 && dwSize < ARRAYSIZE(szExeName)) { | ||
|  |             Tblog("<t:Directory>%hs</t:Directory>\n", szExeName); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Get the real executable name.
 | ||
|  |         wzPath[0] = '\0'; | ||
|  |         if (GetModuleFileNameA(0, szExeName, ARRAYSIZE(szExeName))) { | ||
|  |             FileInfo *pInfo = FileNames::FindPartial(szExeName); | ||
|  |             Tblog("<t:Executable>%ls</t:Executable>\n", | ||
|  |                   FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo)); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Construct the processed command line.
 | ||
|  |         PWCHAR pwzDstEnd = (PWCHAR)pwzLine; | ||
|  |         PWCHAR pwzDst = pwzDstEnd; | ||
|  |         pwzDst = LoadCommandLine(pwzLine, pwzDst, pwzDstEnd); | ||
|  |         DWORD wcNew = (DWORD)((pwzDst - pwzDstEnd) + 1); | ||
|  |         PWCHAR pwzFin = (PWCHAR)GlobalAlloc(GPTR, wcNew * sizeof(WCHAR)); | ||
|  |         pwzDst = pwzFin; | ||
|  |         pwzDstEnd = pwzFin + wcNew; | ||
|  |         pwzDst = LoadCommandLine(pwzLine, pwzDst, pwzDstEnd); | ||
|  |         *pwzDst = '\0'; | ||
|  | 
 | ||
|  |         FileNames::ParameterizeLine(pwzFin, pwzFin + wcNew); | ||
|  |         if (HasSpace(wzPath)) { | ||
|  |             Tblog("<t:Line>"%le" %le</t:Line>\n", wzPath, pwzFin); | ||
|  |         } | ||
|  |         else { | ||
|  |             Tblog("<t:Line>%le %le</t:Line>\n", wzPath, pwzFin); | ||
|  |         } | ||
|  | 
 | ||
|  |         TestHandle("t:StdIn", GetStdHandle(STD_INPUT_HANDLE)); | ||
|  |         TestHandle("t:StdOut", GetStdHandle(STD_OUTPUT_HANDLE)); | ||
|  |         TestHandle("t:StdErr", GetStdHandle(STD_ERROR_HANDLE)); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (FindMsvcr()) { | ||
|  |         FindProc(&(PVOID&)Real_getenv, "getenv"); | ||
|  |         FindProc(&(PVOID&)Real_wgetenv, "_wgetenv"); | ||
|  |         FindProc(&(PVOID&)Real_getenv_s, "getenv_s"); | ||
|  |         FindProc(&(PVOID&)Real_wgetenv_s, "_wgetenv_s"); | ||
|  |         FindProc(&(PVOID&)Real_dupenv_s, "_dupenv_s"); | ||
|  |         FindProc(&(PVOID&)Real_wdupenv_s, "_wdupenv_s"); | ||
|  | 
 | ||
|  |         DetourTransactionBegin(); | ||
|  |         DetourUpdateThread(GetCurrentThread()); | ||
|  | 
 | ||
|  |         DetourAttachIf(&(PVOID&)Real_getenv, Mine_getenv); | ||
|  |         DetourAttachIf(&(PVOID&)Real_getenv_s, Mine_getenv_s); | ||
|  |         DetourAttachIf(&(PVOID&)Real_wgetenv, Mine_wgetenv); | ||
|  |         DetourAttachIf(&(PVOID&)Real_wgetenv, Mine_wgetenv_s); | ||
|  |         DetourAttachIf(&(PVOID&)Real_dupenv_s, Mine_dupenv_s); | ||
|  |         DetourAttachIf(&(PVOID&)Real_wdupenv_s, Mine_wdupenv_s); | ||
|  | 
 | ||
|  |         DetourTransactionCommit(); | ||
|  |     } | ||
|  | 
 | ||
|  |     return Real_EntryPoint(); | ||
|  | } | ||
|  | 
 | ||
|  | VOID WINAPI Mine_ExitProcess(UINT a0) | ||
|  | { | ||
|  |     if (a0 & 0x80000000) { | ||
|  |         Tblog("<t:Return>%d</t:Return>\n", -(int)a0); | ||
|  |     } | ||
|  |     else { | ||
|  |         Tblog("<t:Return>%d</t:Return>\n", a0); | ||
|  |     } | ||
|  | 
 | ||
|  |     FileNames::Dump(); | ||
|  |     EnvVars::Dump(); | ||
|  | 
 | ||
|  |     TblogClose(); | ||
|  | 
 | ||
|  |     Real_ExitProcess(a0); | ||
|  | } | ||
|  | 
 | ||
|  | BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, PVOID lpReserved) | ||
|  | { | ||
|  |     (void)hModule; | ||
|  |     (void)lpReserved; | ||
|  | 
 | ||
|  |     if (DetourIsHelperProcess()) { | ||
|  |         return TRUE; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (dwReason == DLL_PROCESS_ATTACH) { | ||
|  |         DetourRestoreAfterWith(); | ||
|  |         Real_EntryPoint = (int (WINAPI *)(VOID))DetourGetEntryPoint(NULL); | ||
|  |         return ProcessAttach(hModule); | ||
|  |     } | ||
|  |     else if (dwReason == DLL_PROCESS_DETACH) { | ||
|  |         return ProcessDetach(hModule); | ||
|  |     } | ||
|  |     else if (dwReason == DLL_THREAD_ATTACH) { | ||
|  |         return ThreadAttach(hModule); | ||
|  |     } | ||
|  |     else if (dwReason == DLL_THREAD_DETACH) { | ||
|  |         return ThreadDetach(hModule); | ||
|  |     } | ||
|  |     return TRUE; | ||
|  | } | ||
|  | //
 | ||
|  | ///////////////////////////////////////////////////////////////// End of File.
 |