////////////////////////////////////////////////////////////////////////////// // // Detours Test Program (trcapi.cpp of trcapi.dll) // // Microsoft Research Detours Package // // Copyright (c) Microsoft Corporation. All rights reserved. // #undef WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0501 #define WIN32 #define NT #define _WINSOCK_DEPRECATED_NO_WARNINGS #define DBG_TRACE 0 #if _MSC_VER >= 1300 #include #endif #include #include #pragma warning(push) #if _MSC_VER > 1400 #pragma warning(disable:6102 6103) // /analyze warnings #endif #include #pragma warning(pop) #include "detours.h" #include "syelog.h" #if (_MSC_VER < 1299) #define LONG_PTR LONG #define ULONG_PTR ULONG #define PLONG_PTR PLONG #define PULONG_PTR PULONG #define INT_PTR INT #define UINT_PTR UINT #define PINT_PTR PINT #define PUINT_PTR PUINT #define DWORD_PTR DWORD #define PDWORD_PTR PDWORD #endif #pragma warning(disable:4996) // We don't care about deprecated APIs. ////////////////////////////////////////////////////////////////////////////// #pragma warning(disable:4127) // Many of our asserts are constants. #define ASSERT_ALWAYS(x) \ do { \ if (!(x)) { \ AssertMessage(#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 WCHAR s_wzDllPath[MAX_PATH]; static CHAR s_szDllPath[MAX_PATH]; BOOL ProcessEnumerate(); BOOL InstanceEnumerate(HINSTANCE hInst); VOID _PrintEnter(const CHAR *psz, ...); VOID _PrintExit(const CHAR *psz, ...); VOID _Print(const CHAR *psz, ...); VOID _VPrint(PCSTR msg, va_list args, PCHAR pszBuf, LONG cbBuf); VOID AssertMessage(CONST PCHAR pszMsg, CONST PCHAR pszFile, ULONG nLine); ////////////////////////////////////////////////////////////////////////////// // // Trampolines // extern "C" { // Trampolines for SYELOG library. // extern HANDLE (WINAPI *Real_CreateFileW)(LPCWSTR a0, DWORD a1, DWORD a2, LPSECURITY_ATTRIBUTES a3, DWORD a4, DWORD a5, HANDLE a6); extern BOOL (WINAPI *Real_WriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); extern BOOL (WINAPI *Real_FlushFileBuffers)(HANDLE hFile); extern BOOL (WINAPI *Real_CloseHandle)(HANDLE hObject); extern BOOL (WINAPI *Real_WaitNamedPipeW)(LPCWSTR lpNamedPipeName, DWORD nTimeOut); extern BOOL (WINAPI *Real_SetNamedPipeHandleState)(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout); extern DWORD (WINAPI *Real_GetCurrentProcessId)(VOID); extern VOID (WINAPI *Real_GetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTime); VOID ( WINAPI * Real_InitializeCriticalSection)(LPCRITICAL_SECTION lpSection) = InitializeCriticalSection; VOID ( WINAPI * Real_EnterCriticalSection)(LPCRITICAL_SECTION lpSection) = EnterCriticalSection; VOID ( WINAPI * Real_LeaveCriticalSection)(LPCRITICAL_SECTION lpSection) = LeaveCriticalSection; } #include "_win32.cpp" ////////////////////////////////////////////////////////////// Logging System. // static BOOL s_bLog = FALSE; static LONG s_nTlsIndent = -1; static LONG s_nTlsThread = -1; static LONG s_nThreadCnt = 0; VOID _PrintEnter(const CHAR *psz, ...) { 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); } if (s_bLog && psz) { CHAR szBuf[1024]; PCHAR pszBuf = szBuf; PCHAR pszEnd = szBuf + ARRAYSIZE(szBuf) - 1; LONG nLen = (nIndent > 0) ? (nIndent < 35 ? nIndent * 2 : 70) : 0; *pszBuf++ = (CHAR)('0' + ((nThread / 100) % 10)); *pszBuf++ = (CHAR)('0' + ((nThread / 10) % 10)); *pszBuf++ = (CHAR)('0' + ((nThread / 1) % 10)); *pszBuf++ = ' '; while (nLen-- > 0) { *pszBuf++ = ' '; } *pszBuf++ = '+'; *pszBuf = '\0'; va_list args; va_start(args, psz); while ((*pszBuf++ = *psz++) != 0 && pszBuf < pszEnd) { // Copy characters. } *pszEnd = '\0'; SyelogV(SYELOG_SEVERITY_INFORMATION, szBuf, args); va_end(args); } SetLastError(dwErr); } VOID _PrintExit(const CHAR *psz, ...) { DWORD dwErr = GetLastError(); LONG nIndent = 0; LONG nThread = 0; if (s_nTlsIndent >= 0) { nIndent = (LONG)(LONG_PTR)TlsGetValue(s_nTlsIndent) - 1; ASSERT_ALWAYS(nIndent >= 0); TlsSetValue(s_nTlsIndent, (PVOID)(LONG_PTR)nIndent); } if (s_nTlsThread >= 0) { nThread = (LONG)(LONG_PTR)TlsGetValue(s_nTlsThread); } if (s_bLog && psz) { CHAR szBuf[1024]; PCHAR pszEnd = szBuf + ARRAYSIZE(szBuf) - 1; PCHAR pszBuf = szBuf; LONG nLen = (nIndent > 0) ? (nIndent < 35 ? nIndent * 2 : 70) : 0; *pszBuf++ = (CHAR)('0' + ((nThread / 100) % 10)); *pszBuf++ = (CHAR)('0' + ((nThread / 10) % 10)); *pszBuf++ = (CHAR)('0' + ((nThread / 1) % 10)); *pszBuf++ = ' '; while (nLen-- > 0) { *pszBuf++ = ' '; } *pszBuf++ = '-'; *pszBuf = '\0'; va_list args; va_start(args, psz); while ((*pszBuf++ = *psz++) != 0 && pszBuf < pszEnd) { // Copy characters. } *pszEnd = '\0'; SyelogV(SYELOG_SEVERITY_INFORMATION, szBuf, args); va_end(args); } SetLastError(dwErr); } VOID _Print(const CHAR *psz, ...) { DWORD dwErr = GetLastError(); LONG nIndent = 0; LONG nThread = 0; if (s_nTlsIndent >= 0) { nIndent = (LONG)(LONG_PTR)TlsGetValue(s_nTlsIndent); } if (s_nTlsThread >= 0) { nThread = (LONG)(LONG_PTR)TlsGetValue(s_nTlsThread); } if (s_bLog && psz) { CHAR szBuf[1024]; PCHAR pszEnd = szBuf + ARRAYSIZE(szBuf) - 1; PCHAR pszBuf = szBuf; LONG nLen = (nIndent > 0) ? (nIndent < 35 ? nIndent * 2 : 70) : 0; *pszBuf++ = (CHAR)('0' + ((nThread / 100) % 10)); *pszBuf++ = (CHAR)('0' + ((nThread / 10) % 10)); *pszBuf++ = (CHAR)('0' + ((nThread / 1) % 10)); *pszBuf++ = ' '; while (nLen-- > 0) { *pszBuf++ = ' '; } *pszBuf = '\0'; va_list args; va_start(args, psz); while ((*pszBuf++ = *psz++) != 0 && pszBuf < pszEnd) { // Copy characters. } *pszEnd = '\0'; SyelogV(SYELOG_SEVERITY_INFORMATION, szBuf, args); va_end(args); } SetLastError(dwErr); } VOID AssertMessage(CONST PCHAR pszMsg, CONST PCHAR pszFile, ULONG nLine) { Syelog(SYELOG_SEVERITY_FATAL, "ASSERT(%s) failed in %s, line %d.\n", pszMsg, pszFile, nLine); } ////////////////////////////////////////////////////////////////////////////// // PIMAGE_NT_HEADERS NtHeadersForInstance(HINSTANCE hInst) { PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hInst; __try { if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + pDosHeader->e_lfanew); if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { SetLastError(ERROR_INVALID_EXE_SIGNATURE); return NULL; } if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { SetLastError(ERROR_EXE_MARKED_INVALID); return NULL; } return pNtHeader; } __except(EXCEPTION_EXECUTE_HANDLER) { } SetLastError(ERROR_EXE_MARKED_INVALID); return NULL; } BOOL InstanceEnumerate(HINSTANCE hInst) { WCHAR wzDllName[MAX_PATH]; PIMAGE_NT_HEADERS pinh = NtHeadersForInstance(hInst); if (pinh && Real_GetModuleFileNameW(hInst, wzDllName, ARRAYSIZE(wzDllName))) { Syelog(SYELOG_SEVERITY_INFORMATION, "### %p: %ls\n", hInst, wzDllName); return TRUE; } return FALSE; } BOOL ProcessEnumerate() { Syelog(SYELOG_SEVERITY_INFORMATION, "######################################################### Binaries\n"); PBYTE pbNext; for (PBYTE pbRegion = (PBYTE)0x10000;; pbRegion = pbNext) { MEMORY_BASIC_INFORMATION mbi; ZeroMemory(&mbi, sizeof(mbi)); if (VirtualQuery((PVOID)pbRegion, &mbi, sizeof(mbi)) <= 0) { break; } pbNext = (PBYTE)mbi.BaseAddress + mbi.RegionSize; // Skip free regions, reserver regions, and guard pages. // if (mbi.State == MEM_FREE || mbi.State == MEM_RESERVE) { continue; } if (mbi.Protect & PAGE_GUARD || mbi.Protect & PAGE_NOCACHE) { continue; } if (mbi.Protect == PAGE_NOACCESS) { continue; } // Skip over regions from the same allocation... { MEMORY_BASIC_INFORMATION mbiStep; while (VirtualQuery((PVOID)pbNext, &mbiStep, sizeof(mbiStep)) > 0) { if ((PBYTE)mbiStep.AllocationBase != pbRegion) { break; } pbNext = (PBYTE)mbiStep.BaseAddress + mbiStep.RegionSize; mbi.Protect |= mbiStep.Protect; } } WCHAR wzDllName[MAX_PATH]; PIMAGE_NT_HEADERS pinh = NtHeadersForInstance((HINSTANCE)pbRegion); if (pinh && Real_GetModuleFileNameW((HINSTANCE)pbRegion,wzDllName,ARRAYSIZE(wzDllName))) { Syelog(SYELOG_SEVERITY_INFORMATION, "### %p..%p: %ls\n", pbRegion, pbNext, wzDllName); } else { Syelog(SYELOG_SEVERITY_INFORMATION, "### %p..%p: State=%04x, Protect=%08x\n", pbRegion, pbNext, mbi.State, mbi.Protect); } } Syelog(SYELOG_SEVERITY_INFORMATION, "###\n"); LPVOID lpvEnv = Real_GetEnvironmentStrings(); Syelog(SYELOG_SEVERITY_INFORMATION, "### Env= %08x [%08x %08x]\n", lpvEnv, ((PVOID*)lpvEnv)[0], ((PVOID*)lpvEnv)[1]); return TRUE; } ////////////////////////////////////////////////////////////////////////////// // // 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) { s_bLog = FALSE; s_nTlsIndent = TlsAlloc(); s_nTlsThread = TlsAlloc(); ThreadAttach(hDll); WCHAR wzExeName[MAX_PATH]; s_hInst = hDll; Real_GetModuleFileNameW(hDll, s_wzDllPath, ARRAYSIZE(s_wzDllPath)); Real_GetModuleFileNameW(NULL, wzExeName, ARRAYSIZE(wzExeName)); StringCchPrintfA(s_szDllPath, ARRAYSIZE(s_szDllPath), "%ls", s_wzDllPath); SyelogOpen("trcapi" DETOURS_STRINGIFY(DETOURS_BITS), SYELOG_FACILITY_APPLICATION); ProcessEnumerate(); LONG error = AttachDetours(); if (error != NO_ERROR) { Syelog(SYELOG_SEVERITY_FATAL, "### Error attaching detours: %d\n", error); } s_bLog = TRUE; return TRUE; } BOOL ProcessDetach(HMODULE hDll) { ThreadDetach(hDll); s_bLog = FALSE; LONG error = DetachDetours(); if (error != NO_ERROR) { Syelog(SYELOG_SEVERITY_FATAL, "### Error detaching detours: %d\n", error); } Syelog(SYELOG_SEVERITY_NOTICE, "### Closing.\n"); SyelogClose(FALSE); if (s_nTlsIndent >= 0) { TlsFree(s_nTlsIndent); } if (s_nTlsThread >= 0) { TlsFree(s_nTlsThread); } return TRUE; } BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, PVOID lpReserved) { (void)hModule; (void)lpReserved; BOOL ret; if (DetourIsHelperProcess()) { return TRUE; } switch (dwReason) { case DLL_PROCESS_ATTACH: DetourRestoreAfterWith(); OutputDebugStringA("trcapi" DETOURS_STRINGIFY(DETOURS_BITS) ".dll:" " DllMain DLL_PROCESS_ATTACH\n"); return ProcessAttach(hModule); case DLL_PROCESS_DETACH: ret = ProcessDetach(hModule); OutputDebugStringA("trcapi" DETOURS_STRINGIFY(DETOURS_BITS) ".dll:" " DllMain DLL_PROCESS_DETACH\n"); return ret; case DLL_THREAD_ATTACH: OutputDebugStringA("trcapi" DETOURS_STRINGIFY(DETOURS_BITS) ".dll:" " DllMain DLL_THREAD_ATTACH\n"); return ThreadAttach(hModule); case DLL_THREAD_DETACH: OutputDebugStringA("trcapi" DETOURS_STRINGIFY(DETOURS_BITS) ".dll:" " DllMain DLL_THREAD_DETACH\n"); return ThreadDetach(hModule); } return TRUE; } // ///////////////////////////////////////////////////////////////// End of File.