diff options
Diffstat (limited to 'samples/tracebld/trcbld.cpp')
-rw-r--r-- | samples/tracebld/trcbld.cpp | 4573 |
1 files changed, 4573 insertions, 0 deletions
diff --git a/samples/tracebld/trcbld.cpp b/samples/tracebld/trcbld.cpp new file mode 100644 index 0000000..5392f90 --- /dev/null +++ b/samples/tracebld/trcbld.cpp @@ -0,0 +1,4573 @@ +///////////////////////////////////////////////////////////////////////////// +// +// 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. |