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

521 lines
15 KiB
C++
Vendored

//////////////////////////////////////////////////////////////////////////////
//
// Detours Test Program (trcmem.cpp of trcmem.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 CHAR s_szDllPath[MAX_PATH];
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" {
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;
}
#if _MSC_VER < 1300
LPVOID (WINAPI *
Real_HeapAlloc)(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes)
= HeapAlloc;
#else
LPVOID (WINAPI *
Real_HeapAlloc)(HANDLE hHeap, DWORD dwFlags, DWORD_PTR dwBytes)
= HeapAlloc;
#endif
DWORD (WINAPI * Real_GetModuleFileNameW)(HMODULE a0,
LPWSTR a1,
DWORD a2)
= GetModuleFileNameW;
DWORD (WINAPI * Real_GetModuleFileNameA)(HMODULE a0,
LPSTR a1,
DWORD a2)
= GetModuleFileNameA;
BOOL (WINAPI * Real_CreateProcessW)(LPCWSTR a0,
LPWSTR a1,
LPSECURITY_ATTRIBUTES a2,
LPSECURITY_ATTRIBUTES a3,
BOOL a4,
DWORD a5,
LPVOID a6,
LPCWSTR a7,
struct _STARTUPINFOW* a8,
LPPROCESS_INFORMATION a9)
= CreateProcessW;
//////////////////////////////////////////////////////////////////////////////
// Detours
//
#if _MSC_VER < 1300
LPVOID WINAPI Mine_HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes)
#else
LPVOID WINAPI Mine_HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD_PTR dwBytes)
#endif
{
_PrintEnter("HeapAlloc(%p, %x, %p))\n", hHeap, dwFlags, dwBytes);
LPVOID rv = 0;
__try {
rv = Real_HeapAlloc(hHeap, dwFlags, dwBytes);
} __finally {
_PrintExit("HeapAlloc() -> %p\n", rv);
};
return rv;
}
BOOL WINAPI Mine_CreateProcessW(LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
_PrintEnter("CreateProcessW(%ls,%ls,%p,%p,%x,%x,%p,%ls,%p,%p)\n",
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
_Print("Calling DetourCreateProcessWithDllExW(,%hs)\n", s_szDllPath);
BOOL rv = 0;
__try {
rv = DetourCreateProcessWithDllExW(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation,
s_szDllPath,
Real_CreateProcessW);
} __finally {
_PrintExit("CreateProcessW(,,,,,,,,,) -> %x\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(CreateProcessW);
ATTACH(HeapAlloc);
return DetourTransactionCommit();
}
LONG DetachDetours(VOID)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DETACH(CreateProcessW);
DETACH(HeapAlloc);
return DetourTransactionCommit();
}
////////////////////////////////////////////////////////////// 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++ = ' ';
}
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);
}
//////////////////////////////////////////////////////////////////////////////
//
// 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();
WCHAR wzExePath[MAX_PATH];
s_hInst = hDll;
Real_GetModuleFileNameA(s_hInst, s_szDllPath, ARRAYSIZE(s_szDllPath));
Real_GetModuleFileNameW(NULL, wzExePath, ARRAYSIZE(wzExePath));
SyelogOpen("trcmem" DETOURS_STRINGIFY(DETOURS_BITS), SYELOG_FACILITY_APPLICATION);
Syelog(SYELOG_SEVERITY_INFORMATION, "##########################################\n");
Syelog(SYELOG_SEVERITY_INFORMATION, "### %ls\n", wzExePath);
LONG error = AttachDetours();
if (error != NO_ERROR) {
Syelog(SYELOG_SEVERITY_FATAL, "### Error attaching detours: %d\n", error);
}
ThreadAttach(hDll);
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.