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

473 lines
14 KiB
C++
Vendored

//////////////////////////////////////////////////////////////////////////////
//
// 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.