diff options
Diffstat (limited to 'ext/detours/samples/traceapi/trcapi.cpp')
-rw-r--r-- | ext/detours/samples/traceapi/trcapi.cpp | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/ext/detours/samples/traceapi/trcapi.cpp b/ext/detours/samples/traceapi/trcapi.cpp new file mode 100644 index 0000000..e7b7240 --- /dev/null +++ b/ext/detours/samples/traceapi/trcapi.cpp @@ -0,0 +1,473 @@ +////////////////////////////////////////////////////////////////////////////// +// +// 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. |