ZLUDA/ext/detours/samples/tracelnk/trclnk.cpp
2021-01-03 17:52:14 +01:00

685 lines
18 KiB
C++
Vendored

//////////////////////////////////////////////////////////////////////////////
//
// Detours Test Program (trclnk.cpp of trclnk.dll)
//
// Microsoft Research Detours Package
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#define _WIN32_WINNT 0x0400
#define WIN32
#define NT
#define DBG_TRACE 0
#include <windows.h>
#include <stdio.h>
#include "detours.h"
#include "syelog.h"
#define PULONG_PTR PVOID
#define PLONG_PTR PVOID
#define ULONG_PTR PVOID
#define ENUMRESNAMEPROCA PVOID
#define ENUMRESNAMEPROCW PVOID
#define ENUMRESLANGPROCA PVOID
#define ENUMRESLANGPROCW PVOID
#define ENUMRESTYPEPROCA PVOID
#define ENUMRESTYPEPROCW PVOID
#define STGOPTIONS PVOID
//////////////////////////////////////////////////////////////////////////////
#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];
BOOL ProcessEnumerate();
BOOL InstanceEnumerate(HINSTANCE hInst);
BOOL ImportEnumerate(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.
//
HANDLE (WINAPI *
Real_CreateFileW)(LPCWSTR a0, DWORD a1, DWORD a2,
LPSECURITY_ATTRIBUTES a3, DWORD a4, DWORD a5,
HANDLE a6)
= CreateFileW;
BOOL (WINAPI *
Real_WriteFile)(HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
= WriteFile;
BOOL (WINAPI *
Real_FlushFileBuffers)(HANDLE hFile)
= FlushFileBuffers;
BOOL (WINAPI *
Real_CloseHandle)(HANDLE hObject)
= CloseHandle;
BOOL (WINAPI *
Real_WaitNamedPipeW)(LPCWSTR lpNamedPipeName, DWORD nTimeOut)
= WaitNamedPipeW;
BOOL (WINAPI *
Real_SetNamedPipeHandleState)(HANDLE hNamedPipe,
LPDWORD lpMode,
LPDWORD lpMaxCollectionCount,
LPDWORD lpCollectDataTimeout)
= SetNamedPipeHandleState;
DWORD (WINAPI *
Real_GetCurrentProcessId)(VOID)
= GetCurrentProcessId;
VOID (WINAPI *
Real_GetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTime)
= GetSystemTimeAsFileTime;
VOID (WINAPI *
Real_InitializeCriticalSection)(LPCRITICAL_SECTION lpSection)
= InitializeCriticalSection;
VOID (WINAPI *
Real_EnterCriticalSection)(LPCRITICAL_SECTION lpSection)
= EnterCriticalSection;
VOID (WINAPI *
Real_LeaveCriticalSection)(LPCRITICAL_SECTION lpSection)
= LeaveCriticalSection;
}
BOOL (WINAPI *
Real_FreeLibrary)(HMODULE a0)
= FreeLibrary;
DWORD (WINAPI *
Real_GetModuleFileNameW)(HMODULE a0,
LPWSTR a1,
DWORD a2)
= GetModuleFileNameW;
HMODULE (WINAPI *
Real_GetModuleHandleW)(LPCWSTR a0)
= GetModuleHandleW;
FARPROC (WINAPI *
Real_GetProcAddress)(HMODULE a0,
LPCSTR a1)
= GetProcAddress;
HMODULE (WINAPI *
Real_LoadLibraryExW)(LPCWSTR a0,
HANDLE a1,
DWORD a2)
= LoadLibraryExW;
HMODULE (WINAPI *
Real_LoadLibraryW)(LPCWSTR a0)
= LoadLibraryW;
//////////////////////////////////////////////////////////////////////////////
//
BOOL WINAPI Mine_FreeLibrary(HMODULE a0)
{
(void)a0;
return TRUE;
}
DWORD WINAPI Mine_GetModuleFileNameW(HMODULE a0,
LPWSTR a1,
DWORD a2)
{
return Real_GetModuleFileNameW(a0, a1, a2);
}
HMODULE WINAPI Mine_GetModuleHandleW(LPCWSTR a0)
{
return Real_GetModuleHandleW(a0);
}
FARPROC WINAPI Mine_GetProcAddress(HMODULE a0,
LPCSTR a1)
{
_PrintEnter("GetProcAddress(%p,%hs)\n", a0, a1);
FARPROC rv = 0;
__try {
rv = Real_GetProcAddress(a0, a1);
} __finally {
_PrintExit("GetProcAddress(,) -> %p\n", rv);
};
return rv;
}
HMODULE WINAPI Mine_LoadLibraryExW(LPCWSTR a0,
HANDLE a1,
DWORD a2)
{
_PrintEnter("LoadLibraryExW(%ls,%p,%x)\n", a0, a1, a2);
HMODULE rv = 0;
__try {
rv = Real_LoadLibraryExW(a0, a1, a2);
} __finally {
_PrintExit("LoadLibraryExW(,,) -> %p\n", rv);
if (rv) {
InstanceEnumerate(rv);
ImportEnumerate(rv);
}
};
return rv;
}
HMODULE WINAPI Mine_LoadLibraryW(LPCWSTR a0)
{
_PrintEnter("LoadLibraryW(%ls)\n", a0);
HMODULE rv = 0;
__try {
rv = Real_LoadLibraryW(a0);
} __finally {
_PrintExit("LoadLibraryW() -> %p\n", rv);
};
return rv;
}
/////////////////////////////////////////////////////////////
// AttachDetours
//
PCHAR DetRealName(PCHAR psz)
{
PCHAR pszBeg = psz;
// Move to end of name.
while (*psz) {
psz++;
}
// Move back through A-Za-z0-9 names.
while (psz > pszBeg &&
((psz[-1] >= 'A' && psz[-1] <= 'Z') ||
(psz[-1] >= 'a' && psz[-1] <= 'z') ||
(psz[-1] >= '0' && psz[-1] <= '9'))) {
psz--;
}
return psz;
}
VOID DetAttach(PVOID *ppbReal, PVOID pbMine, PCHAR psz)
{
LONG l = DetourAttach(ppbReal, pbMine);
if (l != 0) {
Syelog(SYELOG_SEVERITY_NOTICE,
"Attach failed: `%s': error %d\n", DetRealName(psz), l);
}
}
VOID DetDetach(PVOID *ppbReal, PVOID pbMine, PCHAR psz)
{
LONG l = DetourDetach(ppbReal, pbMine);
if (l != 0) {
Syelog(SYELOG_SEVERITY_NOTICE,
"Detach failed: `%s': error %d\n", DetRealName(psz), l);
}
}
#define ATTACH(x) DetAttach(&(PVOID&)Real_##x,Mine_##x,#x)
#define DETACH(x) DetDetach(&(PVOID&)Real_##x,Mine_##x,#x)
LONG AttachDetours(VOID)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
ATTACH(FreeLibrary);
ATTACH(GetModuleHandleW);
ATTACH(GetProcAddress);
ATTACH(LoadLibraryExW);
ATTACH(LoadLibraryW);
return DetourTransactionCommit();
}
LONG DetachDetours(VOID)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DETACH(FreeLibrary);
DETACH(GetModuleHandleW);
DETACH(GetProcAddress);
DETACH(LoadLibraryExW);
DETACH(LoadLibraryW);
return DetourTransactionCommit();
}
////////////////////////////////////////////////////////////// Logging System.
//
static BOOL s_bLog = 1;
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++ = ' ';
}
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(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 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++ = ' ';
}
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 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++ = ' ';
}
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;
}
static inline PBYTE RvaToVa(PBYTE pbBase, DWORD nOffset)
{
return nOffset ? pbBase + nOffset : NULL;
}
#if _MSC_VER >= 1900
#pragma warning(push)
#pragma warning(disable:4456) // declaration hides previous local declaration
#endif
BOOL ImportEnumerate(HINSTANCE hInst)
{
PBYTE pbBase = (PBYTE)hInst;
PIMAGE_NT_HEADERS pNtHeader; // Read & Write
PIMAGE_SECTION_HEADER pSectionHeaders;
DWORD nPeOffset;
DWORD nSectionsOffset;
////////////////////////////////////////////////////// Process DOS Header.
//
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbBase;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
return FALSE;
}
nPeOffset = pDosHeader->e_lfanew;
/////////////////////////////////////////////////////// Process PE Header.
//
pNtHeader = (PIMAGE_NT_HEADERS)RvaToVa(pbBase, nPeOffset);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
return FALSE;
}
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
return FALSE;
}
nSectionsOffset = nPeOffset
+ sizeof(pNtHeader->Signature)
+ sizeof(pNtHeader->FileHeader)
+ pNtHeader->FileHeader.SizeOfOptionalHeader;
///////////////////////////////////////////////// Process Section Headers.
//
pSectionHeaders = (PIMAGE_SECTION_HEADER)RvaToVa(pbBase, nSectionsOffset);
//////////////////////////////////////////////////////// Get Import Table.
//
DWORD rvaImageDirectory = pNtHeader->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
PIMAGE_IMPORT_DESCRIPTOR iidp
= (PIMAGE_IMPORT_DESCRIPTOR)RvaToVa(pbBase, rvaImageDirectory);
if (iidp == NULL) {
return FALSE;
}
DWORD nFiles = 0;
for (; iidp[nFiles].Characteristics != 0; nFiles++) {
// Count the files.
}
for (DWORD n = 0; n < nFiles; n++, iidp++) {
DWORD rvaName = iidp->Name;
PCHAR pszName = (PCHAR)RvaToVa(pbBase, rvaName);
DWORD rvaThunk = (DWORD)iidp->OriginalFirstThunk;
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)RvaToVa(pbBase, rvaThunk);
rvaThunk = (DWORD)iidp->FirstThunk;
PIMAGE_THUNK_DATA pBoundThunk = (PIMAGE_THUNK_DATA)RvaToVa(pbBase, rvaThunk);
Syelog(SYELOG_SEVERITY_INFORMATION,
"%s [%p %p]\n", pszName, pThunk, pBoundThunk);
DWORD nNames = 0;
if (pThunk == NULL) {
break;
}
for (; pThunk[nNames].u1.Ordinal; nNames++) {
// Count the imports.
}
for (DWORD f = 0; f < nNames; f++) {
DWORD nOrdinal = 0;
PCHAR pszName = NULL;
PDWORD pFunc = (PDWORD)pBoundThunk[f].u1.Function;
DWORD rvaName = (DWORD)pThunk[f].u1.Ordinal;
if (rvaName & IMAGE_ORDINAL_FLAG) {
nOrdinal = IMAGE_ORDINAL(rvaName);
}
else {
PIMAGE_IMPORT_BY_NAME pName
= (PIMAGE_IMPORT_BY_NAME)RvaToVa(pbBase, rvaName);
if (pName) {
pszName = (PCHAR)pName->Name;
}
}
Syelog(SYELOG_SEVERITY_INFORMATION,
" %-32.32s %4I64d %p\n", pszName, nOrdinal, pFunc);
}
}
return TRUE;
}
#if _MSC_VER >= 1900
#pragma warning(pop)
#endif
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,
"### %08lx: %-43.43ls %08x\n",
hInst, wzDllName, pinh->OptionalHeader.CheckSum);
return TRUE;
}
return FALSE;
}
BOOL ProcessEnumerate()
{
Syelog(SYELOG_SEVERITY_INFORMATION,
"######################################################### Binaries\n");
for (HINSTANCE hInst = NULL; (hInst = DetourEnumerateModules(hInst)) != NULL;) {
InstanceEnumerate(hInst);
}
Syelog(SYELOG_SEVERITY_INFORMATION, "###\n");
return ImportEnumerate(GetModuleHandle(NULL));
}
//////////////////////////////////////////////////////////////////////////////
//
// 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));
SyelogOpen("trclnk" 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;
if (DetourIsHelperProcess()) {
return TRUE;
}
switch (dwReason) {
case DLL_PROCESS_ATTACH:
DetourRestoreAfterWith();
return ProcessAttach(hModule);
case DLL_PROCESS_DETACH:
return ProcessDetach(hModule);
case DLL_THREAD_ATTACH:
return ThreadAttach(hModule);
case DLL_THREAD_DETACH:
return ThreadDetach(hModule);
}
return TRUE;
}
//
///////////////////////////////////////////////////////////////// End of File.