474 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			474 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| //  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        0x400
 | |
| #define WIN32
 | |
| #define NT
 | |
| #define _WINSOCK_DEPRECATED_NO_WARNINGS
 | |
| 
 | |
| #define DBG_TRACE   0
 | |
| 
 | |
| #if _MSC_VER >= 1300
 | |
| #include <winsock2.h>
 | |
| #endif
 | |
| #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 "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.
 |