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

4573 lines
129 KiB
C++
Vendored

/////////////////////////////////////////////////////////////////////////////
//
// Detours Test Program (trcbld.cpp of trcbld.dll)
//
// Microsoft Research Detours Package
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#define _WIN32_WINNT 0x0500
#define WIN32
#define NT
#define DBG_TRACE 0
#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 "tracebld.h"
#define PULONG_PTR PVOID
#define PLONG_PTR PVOID
#define ULONG_PTR PVOID
//////////////////////////////////////////////////////////////////////////////
#pragma warning(disable:4127) // Many of our asserts are constants.
#define DEBUG_BREAK() DebugBreak()
#define ASSERT_ALWAYS(x) \
do { \
if (!(x)) { \
AssertFailed(#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 HMODULE s_hKernel32 = NULL;
static CHAR s_szDllPath[MAX_PATH];
static TBLOG_PAYLOAD s_Payload;
static TBLOG_PAYLOAD s_ChildPayload;
static CRITICAL_SECTION s_csChildPayload;
static DWORD s_nTraceProcessId = 0;
static LONG s_nChildCnt = 0;
static CRITICAL_SECTION s_csPipe; // Guards access to hPipe.
static HANDLE s_hPipe = INVALID_HANDLE_VALUE;
static TBLOG_MESSAGE s_rMessage;
// Logging Functions.
//
VOID Tblog(PCSTR pszMsgf, ...);
VOID TblogV(PCSTR pszMsgf, va_list args);
VOID VSafePrintf(PCSTR pszMsg, va_list args, PCHAR pszBuffer, LONG cbBuffer);
PCHAR SafePrintf(PCHAR pszBuffer, LONG cbBuffer, PCSTR pszMsg, ...);
LONG EnterFunc();
VOID ExitFunc();
VOID Print(PCSTR psz, ...);
VOID NoteRead(PCSTR psz);
VOID NoteRead(PCWSTR pwz);
VOID NoteWrite(PCSTR psz);
VOID NoteWrite(PCWSTR pwz);
VOID NoteDelete(PCSTR psz);
VOID NoteDelete(PCWSTR pwz);
VOID NoteCleanup(PCSTR psz);
VOID NoteCleanup(PCWSTR pwz);
PBYTE LoadFile(HANDLE hFile, DWORD cbFile);
static PCHAR RemoveReturns(PCHAR pszBuffer);
static PWCHAR RemoveReturns(PWCHAR pwzBuffer);
VOID AssertFailed(CONST PCHAR pszMsg, CONST PCHAR pszFile, ULONG nLine);
int WINAPI Mine_EntryPoint(VOID);
VOID WINAPI Mine_ExitProcess(UINT a0);
//////////////////////////////////////////////////////////////////////////////
//
int (WINAPI * Real_EntryPoint)(VOID)
= NULL;
BOOL (WINAPI * Real_CreateDirectoryW)(LPCWSTR a0,
LPSECURITY_ATTRIBUTES a1)
= CreateDirectoryW;
BOOL (WINAPI * Real_CreateDirectoryExW)(LPCWSTR a0,
LPCWSTR a1,
LPSECURITY_ATTRIBUTES a2)
= CreateDirectoryExW;
HANDLE (WINAPI * Real_CreateFileW)(LPCWSTR a0,
DWORD a1,
DWORD a2,
LPSECURITY_ATTRIBUTES a3,
DWORD a4,
DWORD a5,
HANDLE a6)
= CreateFileW;
HANDLE (WINAPI * Real_CreateFileMappingW)(HANDLE hFile,
LPSECURITY_ATTRIBUTES lpAttributes,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
LPCWSTR lpName
)
= CreateFileMappingW;
BOOL (WINAPI * Real_CreatePipe)(PHANDLE hReadPipe,
PHANDLE hWritePipe,
LPSECURITY_ATTRIBUTES lpPipeAttributes,
DWORD nSize)
= CreatePipe;
BOOL (WINAPI * Real_CloseHandle)(HANDLE a0)
= CloseHandle;
BOOL (WINAPI * Real_DuplicateHandle)(HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
LPHANDLE lpTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions)
= DuplicateHandle;
BOOL (WINAPI * Real_CreateProcessW)(LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
= CreateProcessW;
BOOL (WINAPI * Real_CreateProcessA)(LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
= CreateProcessA;
BOOL (WINAPI * Real_DeleteFileW)(LPCWSTR a0)
= DeleteFileW;
BOOL (WINAPI * Real_DeviceIoControl)(HANDLE a0,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped)
= DeviceIoControl;
DWORD (WINAPI * Real_GetFileAttributesW)(LPCWSTR a0)
= GetFileAttributesW;
BOOL (WINAPI * Real_MoveFileWithProgressW)(LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
LPPROGRESS_ROUTINE lpProgressRoutine,
LPVOID lpData,
DWORD dwFlags)
= MoveFileWithProgressW;
BOOL (WINAPI * Real_MoveFileA)(LPCSTR a0,
LPCSTR a1)
= MoveFileA;
BOOL (WINAPI * Real_MoveFileW)(LPCWSTR a0,
LPCWSTR a12)
= MoveFileW;
BOOL (WINAPI * Real_MoveFileExA)(LPCSTR a0,
LPCSTR a1,
DWORD a2)
= MoveFileExA;
BOOL (WINAPI * Real_MoveFileExW)(LPCWSTR a0,
LPCWSTR a1,
DWORD a2)
= MoveFileExW;
BOOL (WINAPI * Real_CopyFileExA)(LPCSTR a0,
LPCSTR a1,
LPPROGRESS_ROUTINE a2,
LPVOID a4,
LPBOOL a5,
DWORD a6)
= CopyFileExA;
BOOL (WINAPI * Real_CopyFileExW)(LPCWSTR a0,
LPCWSTR a1,
LPPROGRESS_ROUTINE a2,
LPVOID a4,
LPBOOL a5,
DWORD a6)
= CopyFileExW;
BOOL (WINAPI * Real_PrivCopyFileExW)(LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
LPPROGRESS_ROUTINE lpProgressRoutine,
LPVOID lpData,
LPBOOL pbCancel,
DWORD dwCopyFlags)
= NULL;
BOOL (WINAPI * Real_CreateHardLinkA)(LPCSTR a0,
LPCSTR a1,
LPSECURITY_ATTRIBUTES a2)
= CreateHardLinkA;
BOOL (WINAPI * Real_CreateHardLinkW)(LPCWSTR a0,
LPCWSTR a1,
LPSECURITY_ATTRIBUTES a2)
= CreateHardLinkW;
BOOL (WINAPI * Real_SetStdHandle)(DWORD a0,
HANDLE a1)
= SetStdHandle;
HMODULE (WINAPI * Real_LoadLibraryA)(LPCSTR a0)
= LoadLibraryA;
HMODULE (WINAPI * Real_LoadLibraryW)(LPCWSTR a0)
= LoadLibraryW;
HMODULE (WINAPI * Real_LoadLibraryExA)(LPCSTR a0,
HANDLE a1,
DWORD a2)
= LoadLibraryExA;
HMODULE (WINAPI * Real_LoadLibraryExW)(LPCWSTR a0,
HANDLE a1,
DWORD a2)
= LoadLibraryExW;
DWORD (WINAPI * Real_SetFilePointer)(HANDLE hFile,
LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod)
= SetFilePointer;
BOOL (WINAPI * Real_SetFilePointerEx)(HANDLE hFile,
LARGE_INTEGER liDistanceToMove,
PLARGE_INTEGER lpNewFilePointer,
DWORD dwMoveMethod)
= SetFilePointerEx;
BOOL (WINAPI * Real_ReadFile)(HANDLE a0,
LPVOID a1,
DWORD a2,
LPDWORD a3,
LPOVERLAPPED a4)
= ReadFile;
BOOL (WINAPI * Real_ReadFileEx)(HANDLE a0,
LPVOID a1,
DWORD a2,
LPOVERLAPPED a3,
LPOVERLAPPED_COMPLETION_ROUTINE a4)
= ReadFileEx;
BOOL (WINAPI * Real_WriteFile)(HANDLE a0,
LPCVOID a1,
DWORD a2,
LPDWORD a3,
LPOVERLAPPED a4)
= WriteFile;
BOOL (WINAPI * Real_WriteFileEx)(HANDLE a0,
LPCVOID a1,
DWORD a2,
LPOVERLAPPED a3,
LPOVERLAPPED_COMPLETION_ROUTINE a4)
= WriteFileEx;
BOOL (WINAPI * Real_WriteConsoleA)(HANDLE a0,
const VOID* a1,
DWORD a2,
LPDWORD a3,
LPVOID a4)
= WriteConsoleA;
BOOL (WINAPI * Real_WriteConsoleW)(HANDLE a0,
const VOID* a1,
DWORD a2,
LPDWORD a3,
LPVOID a4)
= WriteConsoleW;
VOID (WINAPI * Real_ExitProcess)(UINT a0)
= ExitProcess;
DWORD (WINAPI * Real_ExpandEnvironmentStringsA)(PCSTR lpSrc, PCHAR lpDst, DWORD nSize)
= ExpandEnvironmentStringsA;
DWORD (WINAPI * Real_ExpandEnvironmentStringsW)(PCWSTR lpSrc, PWCHAR lpDst, DWORD nSize)
= ExpandEnvironmentStringsW;
DWORD (WINAPI * Real_GetEnvironmentVariableA)(PCSTR lpName, PCHAR lpBuffer, DWORD nSize)
= GetEnvironmentVariableA;
DWORD (WINAPI * Real_GetEnvironmentVariableW)(PCWSTR lpName, PWCHAR lpBuffer, DWORD nSize)
= GetEnvironmentVariableW;
PCWSTR (CDECL * Real_wgetenv)(PCWSTR var) = NULL;
PCSTR (CDECL * Real_getenv)(PCSTR var) = NULL;
DWORD (CDECL * Real_getenv_s)(DWORD *pValue, PCHAR pBuffer, DWORD cBuffer, PCSTR varname) = NULL;
DWORD (CDECL * Real_wgetenv_s)(DWORD *pValue, PWCHAR pBuffer, DWORD cBuffer, PCWSTR varname) = NULL;
DWORD (CDECL * Real_dupenv_s)(PCHAR *ppBuffer, DWORD *pcBuffer, PCSTR varname) = NULL;
DWORD (CDECL * Real_wdupenv_s)(PWCHAR *ppBuffer, DWORD *pcBuffer, PCWSTR varname) = NULL;
//////////////////////////////////////////////////////////////////////////////
//
static VOID Copy(PWCHAR pwzDst, PCWSTR pwzSrc)
{
while (*pwzSrc) {
*pwzDst++ = *pwzSrc++;
}
*pwzDst = '\0';
}
static DWORD Size(PCWSTR pwzSrc)
{
DWORD c = 0;
while (pwzSrc[c]) {
c++;
}
return c;
}
static PCWSTR Save(PCWSTR pwzSrc)
{
DWORD c = (Size(pwzSrc) + 1) * sizeof(WCHAR);
PWCHAR pwzDst = (PWCHAR)GlobalAlloc(GPTR, c);
CopyMemory(pwzDst, pwzSrc, c);
return pwzDst;
}
static BOOL HasSpace(PCWSTR pwz)
{
for (; *pwz; pwz++) {
if (*pwz == ' ' || *pwz == '\t' || *pwz == '\r' || *pwz == '\n') {
return TRUE;
}
}
return FALSE;
}
static BOOL HasChar(PCWSTR pwz, WCHAR w)
{
for (; *pwz; pwz++) {
if (*pwz == w) {
return TRUE;
}
}
return FALSE;
}
static DWORD Compare(PCWSTR pwzA, PCWSTR pwzB)
{
for (;;) {
WCHAR cA = *pwzA++;
WCHAR cB = *pwzB++;
if (cA >= 'A' && cA <= 'Z') {
cA += ('a' - 'A');
}
if (cB >= 'A' && cB <= 'Z') {
cB += ('a' - 'A');
}
if (cA == 0 && cB == 0) {
return 0;
}
if (cA != cB) {
return cA - cB;
}
}
}
static DWORD Compare(PCWSTR pwzA, PCSTR pszB)
{
for (;;) {
WCHAR cA = *pwzA++;
WCHAR cB = *pszB++;
if (cA >= 'A' && cA <= 'Z') {
cA += ('a' - 'A');
}
if (cB >= 'A' && cB <= 'Z') {
cB += ('a' - 'A');
}
if (cA == 0 && cB == 0) {
return 0;
}
if (cA != cB) {
return cA - cB;
}
}
}
static DWORD Compare(PCSTR pszA, PCSTR pszB)
{
for (;;) {
CHAR cA = *pszA++;
CHAR cB = *pszB++;
if (cA >= 'A' && cA <= 'Z') {
cA += ('a' - 'A');
}
if (cB >= 'A' && cB <= 'Z') {
cB += ('a' - 'A');
}
if (cA == 0 && cB == 0) {
return 0;
}
if (cA != cB) {
return cA - cB;
}
}
}
//////////////////////////////////////////////////////////////////////////////
static PCSTR s_rpszMsvcrNames[] = {
"msvcr80.dll",
"msvcr80d.dll",
"msvcr71.dll",
"msvcr71d.dll",
"msvcr70.dll",
"msvcr70d.dll",
NULL
};
HMODULE s_hMsvcr = NULL;
PCSTR s_pszMsvcr = NULL;
static BOOL WINAPI ImportFileCallback(PVOID pContext, HMODULE hFile, PCSTR pszFile)
{
UNUSED(pContext);
if (pszFile != NULL) {
for (int i = 0; s_rpszMsvcrNames[i]; i++) {
if (Compare(pszFile, s_rpszMsvcrNames[i]) == 0) {
s_hMsvcr = hFile;
s_pszMsvcr = s_rpszMsvcrNames[i];
return FALSE;
}
}
}
return TRUE;
}
BOOL FindMsvcr()
{
DetourEnumerateImports(NULL, NULL, ImportFileCallback, NULL);
if (s_hMsvcr != NULL) {
return TRUE;
}
return FALSE;
}
BOOL FindProc(PVOID * ppvCode, PCSTR pwzFunc)
{
PVOID pv = GetProcAddress(s_hMsvcr, pwzFunc);
if (pv != NULL) {
*ppvCode = pv;
return TRUE;
}
else {
*ppvCode = NULL;
return FALSE;
}
}
//////////////////////////////////////////////////////////////////////////////
//
struct EnvInfo
{
DWORD m_nHash;
DWORD m_nIndex;
PCWSTR m_pwzVar;
PCWSTR m_pwzVal;
BOOL m_fDefined;
BOOL m_fUsed;
BOOL m_fOriginal;
};
//////////////////////////////////////////////////////////////////////////////
//
class EnvVars
{
private:
static CRITICAL_SECTION s_csLock;
static DWORD s_nVars;
static DWORD s_nCapacity;
static EnvInfo ** s_pVars;
private:
static DWORD Hash(PCWSTR pwzVar)
{
DWORD hash = 5381;
while (*pwzVar != 0) {
WCHAR c = *pwzVar++;
if (c >= 'A' && c <= 'Z') {
c += ('a' - 'A');
}
hash = ((hash << 5) + hash) + c;
}
return hash;
}
static VOID LockAcquire()
{
EnterCriticalSection(&s_csLock);
}
static VOID LockRelease()
{
LeaveCriticalSection(&s_csLock);
}
static VOID Resize(DWORD nCapacity);
static VOID Set(EnvInfo *info);
static EnvInfo * Find(PCWSTR pwzVar);
public:
static BOOL Equal(PCWSTR pwzA, PCWSTR pwzB)
{
return (Compare(pwzA, pwzB) == 0);
}
public:
static VOID Initialize();
static VOID Dump();
static VOID Add(PCWSTR pwzVar, PCWSTR pwzVal);
static VOID Used(PCWSTR pwzVar);
static VOID Used(PCSTR pszVar);
};
CRITICAL_SECTION EnvVars::s_csLock;
DWORD EnvVars::s_nVars = 0;
DWORD EnvVars::s_nCapacity = 0;
EnvInfo ** EnvVars::s_pVars = NULL;
VOID EnvVars::Initialize()
{
InitializeCriticalSection(&s_csLock);
Resize(919);
}
VOID EnvVars::Resize(DWORD nCapacity)
{
if (nCapacity > s_nCapacity) {
DWORD nOld = s_nCapacity;
EnvInfo ** pOld = s_pVars;
// DEBUG_BREAK();
s_pVars = (EnvInfo **)GlobalAlloc(GPTR, nCapacity * sizeof(EnvInfo *));
s_nCapacity = nCapacity;
if (pOld != NULL) {
for (DWORD n = 0; n < nOld; n++) {
if (pOld[n] != NULL) {
Set(pOld[n]);
}
}
GlobalFree((HGLOBAL)pOld);
pOld = NULL;
}
}
}
VOID EnvVars::Set(EnvInfo *info)
{
DWORD hash = info->m_nHash;
DWORD slot = hash % s_nCapacity;
DWORD death = 0;
// Find an empty slot.
for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
if (++death > s_nCapacity) {
// We should have dropped out at some point...
DEBUG_BREAK();
}
}
s_pVars[slot] = info;
}
EnvInfo * EnvVars::Find(PCWSTR pwzVar)
{
DWORD hash = Hash(pwzVar);
DWORD slot = hash % s_nCapacity;
LockAcquire();
// Find the the matching slot, or an empty one.
for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
if (Equal(s_pVars[slot]->m_pwzVar, pwzVar)) {
LockRelease();
return s_pVars[slot];
}
}
LockRelease();
return NULL;
}
VOID EnvVars::Add(PCWSTR pwzVar, PCWSTR pwzVal)
{
if (pwzVar == NULL) {
return;
}
WCHAR wzVar[MAX_PATH];
PWCHAR pwzDst = wzVar;
while (*pwzVar) {
if (*pwzVar >= 'a' && *pwzVar <= 'z') {
*pwzDst++ = *pwzVar - ('a' - 'A');
}
else {
*pwzDst++ = *pwzVar;
}
pwzVar++;
}
*pwzDst = '\0';
pwzVar = wzVar;
WCHAR wzVal[] = L"";
if (pwzVal != NULL) {
while (*pwzVal == ' ' || *pwzVal == '\t') {
*pwzVal++;
}
}
else {
pwzVal = wzVal;
}
// Tblog("<!-- ::Add var=[%le] val=[%le] -->\n", pwzVar, pwzVal);
LockAcquire();
// DEBUG_BREAK();
DWORD hash = Hash(pwzVar);
DWORD slot = hash % s_nCapacity;
EnvInfo *info = NULL;
DWORD death = 0;
// Find the the matching slot, or an empty one.
for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
if (Equal(s_pVars[slot]->m_pwzVar, pwzVar)) {
LockRelease();
return;
}
if (++death > s_nCapacity) {
// We should have dropped out at some point...
DEBUG_BREAK();
}
}
// Add the var to list of known vars.
info = (EnvInfo *)GlobalAlloc(GPTR, sizeof(EnvInfo));
info->m_nHash = hash;
info->m_nIndex = s_nVars++;
info->m_pwzVar = Save(pwzVar);
info->m_pwzVal = Save(pwzVal);
if (pwzVal[0] == '\0') {
info->m_fDefined = FALSE;
info->m_fUsed = TRUE;
}
else {
info->m_fDefined = TRUE;
}
s_pVars[slot] = info;
// Check if we should grow the table.
if (s_nVars > (s_nCapacity / 2)) {
Resize(s_nCapacity * 2 - 1);
}
LockRelease();
}
VOID EnvVars::Used(PCWSTR pwzVar)
{
if (pwzVar != NULL) {
// Tblog("<!-- Used [%le] -->\n", pwzVar);
EnvInfo *pInfo = Find(pwzVar);
if (pInfo) {
pInfo->m_fUsed = TRUE;
}
#if 0
else {
Add(pwzVar, NULL);
}
#endif
}
}
VOID EnvVars::Used(PCSTR pszVar)
{
if (pszVar != NULL) {
WCHAR wzVar[MAX_PATH];
PWCHAR pwzVar = wzVar;
while (*pszVar) {
*pwzVar++ = *pszVar++;
}
*pwzVar = '\0';
Used(wzVar);
}
}
VOID EnvVars::Dump()
{
if (s_nVars == 0) {
return;
}
LockAcquire();
Tblog("<t:Vars>\n");
// Remove any variables that match the original environment.
PCWSTR pwzz = s_Payload.wzzEnvironment;
while (*pwzz) {
WCHAR wzVar[MAX_PATH];
PWCHAR pwzVar = wzVar;
while (*pwzz && *pwzz != '=') {
*pwzVar++ = *pwzz++;
}
*pwzVar = '\0';
if (*pwzz == '=') {
pwzz++;
}
EnvInfo *pInfo = Find(wzVar);
if (pInfo) {
if (Compare(pwzz, pInfo->m_pwzVal) == 0) {
pInfo->m_fUsed = FALSE;
}
}
pwzz += Size(pwzz) + 1;
}
EnvInfo ** pSorted = (EnvInfo **)GlobalAlloc(GPTR, s_nVars * sizeof(EnvInfo *));
for (DWORD n = 0; n < s_nCapacity; n++) {
if (s_pVars[n] != NULL) {
if (s_pVars[n]->m_nIndex > s_nVars) {
DEBUG_BREAK();
}
pSorted[s_pVars[n]->m_nIndex] = s_pVars[n];
}
}
for (DWORD n = 0; n < s_nVars; n++) {
EnvInfo *pInfo = pSorted[n];
if (pInfo == NULL) {
Print("<!-- Warning: Missing %d of %d -->\n", n, s_nVars);
continue;
}
if (pInfo->m_fUsed && pInfo->m_pwzVal[0]) {
Print("<t:Var var=\"%le\">%le</t:Var>\n", pInfo->m_pwzVar, pInfo->m_pwzVal);
}
}
GlobalFree((HGLOBAL)pSorted);
Tblog("</t:Vars>\n");
LockRelease();
}
void SaveEnvironment()
{
LPWCH pwStrings = GetEnvironmentStringsW();
PCWSTR pwEnv = (PCWSTR)pwStrings;
while (*pwEnv != '\0') {
WCHAR wzVar[MAX_PATH];
PWCHAR pwzDst = wzVar;
PCWSTR pwzVal = NULL;
if (*pwEnv == '=') {
*pwzDst++ = *pwEnv++;
}
while (*pwEnv != '\0' && *pwEnv != '=') {
*pwzDst++ = *pwEnv++;
}
*pwzDst++ = '\0';
if (*pwEnv == '=') {
pwEnv++;
}
pwzVal = pwEnv;
while (*pwEnv != '\0') {
pwEnv++;
}
if (*pwEnv == '\0') {
pwEnv++;
}
if (wzVar[0] != '=') {
EnvVars::Add(wzVar, pwzVal);
}
}
FreeEnvironmentStringsW(pwStrings);
}
//////////////////////////////////////////////////////////////////////////////
//
struct ProcInfo
{
HANDLE m_hProc;
DWORD m_nProcId;
DWORD m_nProc;
};
class Procs
{
private:
static CRITICAL_SECTION s_csLock;
static DWORD s_nProcs;
static ProcInfo s_rProcs[4049];
private:
static ProcInfo& HashToSlot(HANDLE handle)
{
return s_rProcs[((DWORD_PTR)handle) % ARRAYSIZE(s_rProcs)];
}
static VOID LockAcquire()
{
EnterCriticalSection(&s_csLock);
}
static VOID LockRelease()
{
LeaveCriticalSection(&s_csLock);
}
public:
static VOID Initialize();
static ProcInfo * Create(HANDLE hProc, DWORD nProcId);
static BOOL Close(HANDLE hProc);
};
CRITICAL_SECTION Procs::s_csLock;
DWORD Procs::s_nProcs = 0;
ProcInfo Procs::s_rProcs[4049];
VOID Procs::Initialize()
{
InitializeCriticalSection(&s_csLock);
for (DWORD i = 0; i < ARRAYSIZE(s_rProcs); i++) {
s_rProcs[i].m_hProc = INVALID_HANDLE_VALUE;
}
}
ProcInfo * Procs::Create(HANDLE hProc, DWORD nProcId)
{
LockAcquire();
s_nProcs++;
ProcInfo& slot = HashToSlot(hProc);
slot.m_hProc = hProc;
slot.m_nProcId = nProcId;
slot.m_nProc = s_nProcs;
Print("<!-- CreateProcess (%d)-->\n", slot.m_nProc);
LockRelease();
return &slot;
}
BOOL Procs::Close(HANDLE hProc)
{
BOOL first = false;
LockAcquire();
ProcInfo& slot = HashToSlot(hProc);
if (slot.m_hProc == hProc) {
first = true;
Print("<!-- CloseProcess (%d)-->\n", slot.m_nProc);
slot.m_hProc = INVALID_HANDLE_VALUE;
slot.m_nProcId = 0;
slot.m_nProc = 0;
s_nProcs--;
}
LockRelease();
return first;
}
//////////////////////////////////////////////////////////////////////////////
//
struct FileInfo
{
DWORD m_nHash;
DWORD m_nIndex;
BOOL m_fCantRead; // Set for file that are opened Create
BOOL m_fRead;
BOOL m_fWrite;
BOOL m_fDelete;
BOOL m_fCleanup;
BOOL m_fSystemPath;
BOOL m_fTemporaryPath;
BOOL m_fTemporaryFile;
DWORD m_cbRead;
DWORD m_cbWrite;
BOOL m_fAppend;
BOOL m_fAbsorbed; // Absorbed by TraceBld.
BOOL m_fDirectory;
PCWSTR m_pwzPath;
PBYTE m_pbContent;
DWORD m_cbContent;
};
//////////////////////////////////////////////////////////////////////////////
//
class FileNames
{
private:
static CRITICAL_SECTION s_csLock;
static DWORD s_nFiles;
static DWORD s_nCapacity;
static FileInfo ** s_pFiles;
public:
static WCHAR s_wzSysPath[MAX_PATH];
static WCHAR s_wzS64Path[MAX_PATH];
static WCHAR s_wzTmpPath[MAX_PATH];
static WCHAR s_wzExePath[MAX_PATH];
static DWORD s_wcSysPath;
static DWORD s_wcS64Path;
static DWORD s_wcTmpPath;
static DWORD s_wcExePath;
private:
static DWORD Hash(PCWSTR pwzFile)
{
DWORD hash = 5381;
while (*pwzFile != 0) {
WCHAR c = *pwzFile++;
if (c >= 'A' && c <= 'Z') {
c += ('a' - 'A');
}
hash = ((hash << 5) + hash) + c;
}
return hash;
}
static VOID LockAcquire()
{
EnterCriticalSection(&s_csLock);
}
static VOID LockRelease()
{
LeaveCriticalSection(&s_csLock);
}
static VOID Resize(DWORD nCapacity);
static VOID Set(FileInfo *info);
static VOID Replace(PWCHAR pwzBuffer, PWCHAR pwzDstEnd, DWORD cwOld, PCWSTR pwzNew);
public:
static BOOL Equal(PCWSTR pwzA, PCWSTR pwzB)
{
return (Compare(pwzA, pwzB) == 0);
}
static BOOL PrefixMatch(PCWSTR pwzFile, PCWSTR pwzPrefix)
{
for (;;) {
WCHAR cFile = *pwzFile++;
WCHAR cPrefix = *pwzPrefix++;
if (cFile >= 'A' && cFile <= 'Z') {
cFile += ('a' - 'A');
}
if (cPrefix >= 'A' && cPrefix <= 'Z') {
cPrefix += ('a' - 'A');
}
if (cPrefix == 0) {
return TRUE;
}
if (cFile != cPrefix) {
return FALSE;
}
}
}
static BOOL SuffixMatch(PCWSTR pwzFile, PCWSTR pwzSuffix)
{
// Move both pointers to the end of the strings.
PCWSTR pwzFileBeg = pwzFile;
while (*pwzFile) {
pwzFile++;
}
PCWSTR pwzSuffixBeg = pwzSuffix;
while (*pwzSuffix) {
pwzSuffix++;
}
// Now walk backwards comparing strings.
for (;;) {
WCHAR cFile = (pwzFile > pwzFileBeg) ? *--pwzFile : 0;
WCHAR cSuffix = (pwzSuffix > pwzSuffixBeg) ? *--pwzSuffix : 0;
if (cFile >= 'A' && cFile <= 'Z') {
cFile += ('a' - 'A');
}
if (cSuffix >= 'A' && cSuffix <= 'Z') {
cSuffix += ('a' - 'A');
}
if (cSuffix == 0) {
return TRUE;
}
if (cFile != cSuffix) {
return FALSE;
}
}
}
static VOID EndInSlash(PWCHAR pwzPath)
{
if (*pwzPath) {
while (*pwzPath) {
pwzPath++;
}
if (pwzPath[-1] != '\\') {
*pwzPath++ = '\\';
*pwzPath = '\0';
}
}
}
public:
static VOID Initialize();
static VOID Dump();
static FileInfo * FindPartial(PCWSTR pwzPath);
static FileInfo * FindPartial(PCSTR pszPath);
static FileInfo * FindFull(PCWSTR pwzPath);
static PCWSTR ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, PCWSTR pwzPath);
static PCWSTR ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, FileInfo *pInfo);
static VOID ParameterizeLine(PWCHAR pwzDst, PWCHAR pwzDstEnd);
};
CRITICAL_SECTION FileNames::s_csLock;
DWORD FileNames::s_nFiles = 0;
DWORD FileNames::s_nCapacity = 0;
FileInfo ** FileNames::s_pFiles;
WCHAR FileNames::s_wzSysPath[MAX_PATH];
WCHAR FileNames::s_wzS64Path[MAX_PATH];
WCHAR FileNames::s_wzTmpPath[MAX_PATH];
WCHAR FileNames::s_wzExePath[MAX_PATH];
DWORD FileNames::s_wcSysPath;
DWORD FileNames::s_wcS64Path;
DWORD FileNames::s_wcTmpPath;
DWORD FileNames::s_wcExePath;
VOID FileNames::Initialize()
{
InitializeCriticalSection(&s_csLock);
s_wzSysPath[0] = '\0';
GetSystemDirectoryW(s_wzSysPath, ARRAYSIZE(s_wzSysPath));
EndInSlash(s_wzSysPath);
s_wzS64Path[0] = '\0';
GetWindowsDirectoryW(s_wzS64Path, ARRAYSIZE(s_wzS64Path));
EndInSlash(s_wzS64Path);
Copy(s_wzS64Path + Size(s_wzS64Path), L"SysWOW64\\");
s_wzTmpPath[0] = '\0';
GetTempPathW(ARRAYSIZE(s_wzTmpPath), s_wzTmpPath);
EndInSlash(s_wzTmpPath);
s_wzExePath[0] = '\0';
GetModuleFileNameW(NULL, s_wzExePath, ARRAYSIZE(s_wzExePath));
PWCHAR pwzLast = s_wzExePath;
for (PWCHAR pwz = s_wzExePath; *pwz; pwz++) {
if (*pwz == '\\') {
pwzLast = pwz;
}
}
if (*pwzLast == '\\') {
*++pwzLast = '\0';
}
s_wcSysPath = Size(s_wzSysPath);
s_wcS64Path = Size(s_wzS64Path);
s_wcTmpPath = Size(s_wzTmpPath);
s_wcExePath = Size(s_wzExePath);
Resize(4049);
}
VOID FileNames::Resize(DWORD nCapacity)
{
if (nCapacity > s_nCapacity) {
DWORD nOld = s_nCapacity;
FileInfo ** pOld = s_pFiles;
s_pFiles = (FileInfo **)GlobalAlloc(GPTR, nCapacity * sizeof(FileInfo *));
s_nCapacity = nCapacity;
if (pOld != NULL) {
for (DWORD n = 0; n < nOld; n++) {
if (pOld[n] != NULL) {
Set(pOld[n]);
}
}
GlobalFree((HGLOBAL)pOld);
pOld = NULL;
}
s_nCapacity = nCapacity;
}
}
VOID FileNames::Set(FileInfo *info)
{
DWORD hash = info->m_nHash;
DWORD slot = hash % s_nCapacity;
DWORD death = 0;
// Find an empty slot.
for (; s_pFiles[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
if (++death > s_nCapacity) {
// We should have dropped out at some point...
DEBUG_BREAK();
}
}
s_pFiles[slot] = info;
}
FileInfo * FileNames::FindFull(PCWSTR pwzPath)
{
if (pwzPath == NULL) {
return NULL;
}
LockAcquire();
DWORD hash = Hash(pwzPath);
DWORD slot = hash % s_nCapacity;
FileInfo *info = NULL;
DWORD death = 0;
// Find the the matching slot, or an empty one.
for (; s_pFiles[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
if (Equal(s_pFiles[slot]->m_pwzPath, pwzPath)) {
info = s_pFiles[slot];
goto succeed;
}
if (++death > s_nCapacity) {
// We should have dropped out at some point...
DEBUG_BREAK();
}
}
// Add the file to list of known files.
info = (FileInfo *)GlobalAlloc(GPTR, sizeof(FileInfo));
info->m_nHash = hash;
info->m_nIndex = s_nFiles++;
info->m_pwzPath = Save(pwzPath);
info->m_fSystemPath = (PrefixMatch(info->m_pwzPath, s_wzSysPath) ||
PrefixMatch(info->m_pwzPath, s_wzS64Path));
info->m_fTemporaryPath = PrefixMatch(info->m_pwzPath, s_wzTmpPath);
info->m_fTemporaryFile = SuffixMatch(info->m_pwzPath, L".tmp");
s_pFiles[slot] = info;
// Check if we should grow the table.
if (s_nFiles > (s_nCapacity / 2)) {
Resize(s_nCapacity * 2 - 1);
}
succeed:
LockRelease();
return info;
}
FileInfo * FileNames::FindPartial(PCWSTR pwzPath)
{
WCHAR wzPath[MAX_PATH];
PWCHAR pwzFile = NULL;
if (!GetFullPathNameW(pwzPath, ARRAYSIZE(wzPath), wzPath, &pwzFile)) {
return FindFull(pwzPath);
}
else {
return FindFull(wzPath);
}
}
FileInfo * FileNames::FindPartial(PCSTR pwzPath)
{
WCHAR wzPath[MAX_PATH];
PWCHAR pwzFile = wzPath;
while (*pwzPath) {
*pwzFile++ = *pwzPath++;
}
*pwzFile = '\0';
return FindPartial(wzPath);
}
PCWSTR FileNames::ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, FileInfo *pInfo)
{
return ParameterizeName(pwzDst, cMaxDst, pInfo->m_pwzPath);
}
PCWSTR FileNames::ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, PCWSTR pwzPath)
{
if (PrefixMatch(pwzPath, s_wzSysPath)) {
Copy(pwzDst, L"%SYSDIR%\\");
Copy(pwzDst + Size(pwzDst), pwzPath + s_wcSysPath);
goto finish;
}
else if (PrefixMatch(pwzPath, s_wzS64Path)) {
Copy(pwzDst, L"%SYSDIR%\\");
Copy(pwzDst + Size(pwzDst), pwzPath + s_wcS64Path);
goto finish;
}
else if (PrefixMatch(pwzPath, s_wzTmpPath)) {
Copy(pwzDst, L"%TMPDIR%\\");
Copy(pwzDst + Size(pwzDst), pwzPath + s_wcTmpPath);
goto finish;
}
else {
Copy(pwzDst, pwzPath);
finish:
#if 0 // to convert to all lower case.
for (PWCHAR pwz = pwzDst; *pwz && pwz < pwzDst + cMaxDst; pwz++) {
if (*pwz >= 'A' && *pwz <= 'Z') {
*pwz = 'a' + (*pwz - 'A');
}
}
#else
(void)cMaxDst;
#endif
return pwzDst;
}
}
VOID FileNames::Replace(PWCHAR pwzDst, PWCHAR pwzDstEnd, DWORD cwOld, PCWSTR pwzNew)
{
DWORD cwNew = Size(pwzNew);
DWORD cwDst = Size(pwzDst);
if (cwOld < cwNew) { // We have to insert.
if ((cwDst + cwNew - cwOld) >= (DWORD)(pwzDstEnd - pwzDst)) {
// Won't fit, so abort.
return;
}
PWCHAR pwzTo = pwzDst + cwDst + (cwNew - cwOld);
PWCHAR pwzFm = pwzDst + cwDst;
while (pwzTo >= pwzDst) {
*pwzTo-- = *pwzFm--;
}
}
else if (cwOld > cwNew) { // We have to remove.
PWCHAR pwzTo = pwzDst + cwNew;
PWCHAR pwzFm = pwzDst + cwOld;
while (*pwzFm) {
*pwzTo++ = *pwzFm++;
}
*pwzTo = '\0';
}
// Now write the new string.
while (*pwzNew) {
*pwzDst++ = *pwzNew++;
}
}
VOID FileNames::ParameterizeLine(PWCHAR pwzDst, PWCHAR pwzDstEnd)
{
for (; *pwzDst != '\0'; pwzDst++) {
if (PrefixMatch(pwzDst, s_wzSysPath)) {
Replace(pwzDst, pwzDstEnd, s_wcSysPath, L"%SYSDIR%\\");
}
else if (PrefixMatch(pwzDst, s_wzS64Path)) {
Replace(pwzDst, pwzDstEnd, s_wcS64Path, L"%SYSDIR%\\");
}
else if (PrefixMatch(pwzDst, s_wzTmpPath)) {
Replace(pwzDst, pwzDstEnd, s_wcTmpPath, L"%TMPDIR%\\");
}
}
}
VOID FileNames::Dump()
{
WCHAR wzPath[MAX_PATH];
if (s_nFiles == 0) {
return;
}
LockAcquire();
Tblog("<t:Files>\n");
FileInfo ** pSorted = (FileInfo **)GlobalAlloc(GPTR, s_nFiles * sizeof(FileInfo *));
for (DWORD n = 0; n < s_nCapacity; n++) {
if (s_pFiles[n] != NULL) {
if (s_pFiles[n]->m_nIndex > s_nFiles) {
DEBUG_BREAK();
}
pSorted[s_pFiles[n]->m_nIndex] = s_pFiles[n];
}
}
for (DWORD n = 0; n < s_nFiles; n++) {
FileInfo *pInfo = pSorted[n];
if (pInfo == NULL) {
Print("<!-- Warning: Missing %d of %d -->\n", n, s_nFiles);
continue;
}
BOOL fRead = pInfo->m_fRead;
BOOL fWrite = pInfo->m_fWrite;
BOOL fDelete = (pInfo->m_fDelete);
BOOL fCleanup = (pInfo->m_fCleanup);
BOOL fAppend = (pInfo->m_fAppend);
#if 0
if (fDelete && !fRead && !fWrite) {
Print("<!-- Discarding: %ls -->\n", pInfo->m_pwzPath);
// Discard pipe files only passed to children.
continue;
}
#endif
if (pInfo->m_fAbsorbed) {
// Discard response fles
continue;
}
if (PrefixMatch(pInfo->m_pwzPath, s_wzExePath) ||
PrefixMatch(pInfo->m_pwzPath, s_wzSysPath) ||
PrefixMatch(pInfo->m_pwzPath, s_wzS64Path)) {
// Discard files from exec directory (because considered internal to code).
continue;
}
#if 1 // Ignore PIPEs.
if (FileNames::PrefixMatch(pInfo->m_pwzPath, L"\\\\.\\PIPE\\")) {
continue;
}
#endif
if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conout$")) {
continue;
}
if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conin$")) {
continue;
}
if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\nul")) {
continue;
}
ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo);
if (pInfo->m_fDirectory) {
Print("<t:File mkdir=\"true\">%ls</t:File>\n", wzPath);
continue;
}
if (!fRead && !fWrite && !fDelete && !fCleanup) {
// Discard do "none" files.
continue;
}
if (pInfo->m_pbContent == NULL ||
pInfo->m_fDelete ||
pInfo->m_fCleanup ||
pInfo->m_fWrite) {
Print("<t:File%s%s%s%s%s>%ls</t:File>\n",
fRead ? " read=\"true\"" : "",
fWrite ? " write=\"true\"" : "",
fDelete ? " delete=\"true\"" : "",
fCleanup ? " cleanup=\"true\"" : "",
fAppend ? " append=\"true\"" : "",
// size=\"%d\" pInfo->m_cbContent,
wzPath);
}
else if ((pInfo->m_pbContent)[0] == 0xff && (pInfo->m_pbContent)[1] == 0xfe) {
// Unicode
Print("<t:File%s%s%s%s%s>%ls<t:Data>%le</t:Data></t:File>\n",
fRead ? " read=\"true\"" : "",
fWrite ? " write=\"true\"" : "",
fDelete ? " delete=\"true\"" : "",
fCleanup ? " cleanup=\"true\"" : "",
fAppend ? " append=\"true\"" : "",
// size=\"%d\" pInfo->m_cbContent,
wzPath,
RemoveReturns((PWCHAR)pInfo->m_pbContent));
}
else {
// Ascii
Print("<t:File%s%s%s%s%s>%ls<t:Data>%he</t:Data></t:File>\n",
fRead ? " read=\"true\"" : "",
fWrite ? " write=\"true\"" : "",
fDelete ? " delete=\"true\"" : "",
fCleanup ? " cleanup=\"true\"" : "",
fAppend ? " append=\"true\"" : "",
// size=\"%d\" pInfo->m_cbContent,
wzPath,
RemoveReturns((PCHAR)pInfo->m_pbContent));
}
if (pInfo->m_pbContent != NULL) {
GlobalFree((HGLOBAL)pInfo->m_pbContent);
pInfo->m_pbContent = NULL;
}
}
GlobalFree((HGLOBAL)pSorted);
Tblog("</t:Files>\n");
LockRelease();
}
//////////////////////////////////////////////////////////////////////////////
//
class OpenFiles
{
private:
struct SLOT
{
HANDLE m_hHandle;
FileInfo * m_pFile;
ProcInfo * m_pProc;
};
private:
static CRITICAL_SECTION s_csLock;
static DWORD s_nHandles;
static SLOT s_rHandles[4049];
private:
static SLOT& HashToSlot(HANDLE handle)
{
return s_rHandles[((DWORD_PTR)handle) % ARRAYSIZE(s_rHandles)];
}
static VOID LockAcquire()
{
EnterCriticalSection(&s_csLock);
}
static VOID LockRelease()
{
LeaveCriticalSection(&s_csLock);
}
public:
static VOID Initialize();
static VOID SetWrite(HANDLE hFile, DWORD cbData)
{
SLOT& slot = HashToSlot(hFile);
if (slot.m_hHandle == hFile) {
slot.m_pFile->m_fWrite = TRUE;
slot.m_pFile->m_cbWrite += cbData;
}
}
static VOID SetRead(HANDLE hFile, DWORD cbData)
{
SLOT& slot = HashToSlot(hFile);
if (slot.m_hHandle == hFile) {
slot.m_pFile->m_fRead = TRUE;
slot.m_pFile->m_cbRead += cbData;
}
}
static BOOL Forget(HANDLE handle);
static BOOL Remember(HANDLE hFile, FileInfo *pInfo);
static BOOL Remember(HANDLE hProc, ProcInfo *pInfo);
static FileInfo * RecallFile(HANDLE hFile);
static ProcInfo * RecallProc(HANDLE hProc);
};
CRITICAL_SECTION OpenFiles::s_csLock; // Guards access to OpenFile stuctures.
DWORD OpenFiles::s_nHandles = 0;
OpenFiles::SLOT OpenFiles::s_rHandles[4049];
VOID OpenFiles::Initialize()
{
InitializeCriticalSection(&s_csLock);
for (DWORD n = 0; n < ARRAYSIZE(s_rHandles); n++) {
s_rHandles[n].m_hHandle = INVALID_HANDLE_VALUE;
s_rHandles[n].m_pFile = NULL;
s_rHandles[n].m_pProc = NULL;
}
}
BOOL OpenFiles::Forget(HANDLE handle)
{
LockAcquire();
OpenFiles::SLOT& slot = HashToSlot(handle);
if (slot.m_hHandle == handle ) {
slot.m_hHandle = INVALID_HANDLE_VALUE;
slot.m_pFile = NULL;
slot.m_pProc = NULL;
s_nHandles--;
}
LockRelease();
return FALSE;
}
BOOL OpenFiles::Remember(HANDLE hFile, FileInfo *pFile)
{
LockAcquire();
OpenFiles::SLOT& slot = HashToSlot(hFile);
if (slot.m_hHandle != hFile && slot.m_hHandle != INVALID_HANDLE_VALUE) {
// hash collision
DEBUG_BREAK();
}
slot.m_hHandle = hFile;
slot.m_pFile = pFile;
slot.m_pProc = NULL;
s_nHandles++;
LockRelease();
return TRUE;
}
BOOL OpenFiles::Remember(HANDLE hProc, ProcInfo *pProc)
{
LockAcquire();
OpenFiles::SLOT& slot = HashToSlot(hProc);
if (slot.m_hHandle != hProc && slot.m_hHandle != INVALID_HANDLE_VALUE) {
// hash collision
DEBUG_BREAK();
}
slot.m_hHandle = hProc;
slot.m_pProc = pProc;
slot.m_pFile = NULL;
s_nHandles++;
LockRelease();
return TRUE;
}
FileInfo * OpenFiles::RecallFile(HANDLE hFile)
{
LockAcquire();
OpenFiles::SLOT& slot = HashToSlot(hFile);
if (slot.m_hHandle == hFile) {
LockRelease();
return slot.m_pFile;
}
LockRelease();
return NULL;
}
ProcInfo * OpenFiles::RecallProc(HANDLE hProc)
{
LockAcquire();
OpenFiles::SLOT& slot = HashToSlot(hProc);
if (slot.m_hHandle == hProc) {
LockRelease();
return slot.m_pProc;
}
LockRelease();
return NULL;
}
///////////////////////////////////////////////////////////////////// VPrintf.
//
// Completely side-effect free printf replacement (but no FP numbers).
//
static PCHAR do_base(PCHAR pszOut, UINT64 nValue, UINT nBase, PCSTR pszDigits)
{
CHAR szTmp[96];
int nDigit = sizeof(szTmp)-2;
for (; nDigit >= 0; nDigit--) {
szTmp[nDigit] = pszDigits[nValue % nBase];
nValue /= nBase;
}
for (nDigit = 0; nDigit < sizeof(szTmp) - 2 && szTmp[nDigit] == '0'; nDigit++) {
// skip leading zeros.
}
for (; nDigit < sizeof(szTmp) - 1; nDigit++) {
*pszOut++ = szTmp[nDigit];
}
*pszOut = '\0';
return pszOut;
}
static PCHAR do_str(PCHAR pszOut, PCHAR pszEnd, PCSTR pszIn)
{
while (*pszIn && pszOut < pszEnd) {
*pszOut++ = *pszIn++;
}
*pszOut = '\0';
return pszOut;
}
static PCHAR do_wstr(PCHAR pszOut, PCHAR pszEnd, PCWSTR pszIn)
{
while (*pszIn && pszOut < pszEnd) {
*pszOut++ = (CHAR)*pszIn++;
}
*pszOut = '\0';
return pszOut;
}
static PCHAR do_estr(PCHAR pszOut, PCHAR pszEnd, PCSTR pszIn)
{
while (*pszIn && pszOut < pszEnd) {
if (*pszIn == '<') {
if (pszOut + 4 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'l';
*pszOut++ = 't';
*pszOut++ = ';';
}
else if (*pszIn == '>') {
if (pszOut + 4 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'g';
*pszOut++ = 't';
*pszOut++ = ';';
}
else if (*pszIn == '&') {
if (pszOut + 5 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'a';
*pszOut++ = 'm';
*pszOut++ = 'p';
*pszOut++ = ';';
}
else if (*pszIn == '\"') {
if (pszOut + 6 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'q';
*pszOut++ = 'u';
*pszOut++ = 'o';
*pszOut++ = 't';
*pszOut++ = ';';
}
else if (*pszIn == '\'') {
if (pszOut + 6 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'a';
*pszOut++ = 'p';
*pszOut++ = 'o';
*pszOut++ = 's';
*pszOut++ = ';';
}
else if (*pszIn < ' ') {
BYTE c = (BYTE)(*pszIn++);
if (c < 10 && pszOut + 4 <= pszEnd) {
*pszOut++ = '&';
*pszOut++ = '#';
*pszOut++ = '0' + (c % 10);
*pszOut++ = ';';
}
else if (c < 100 && pszOut + 5 <= pszEnd) {
*pszOut++ = '&';
*pszOut++ = '#';
*pszOut++ = '0' + ((c / 10) % 10);
*pszOut++ = '0' + (c % 10);
*pszOut++ = ';';
}
else if (c < 1000 && pszOut + 6 <= pszEnd) {
*pszOut++ = '&';
*pszOut++ = '#';
*pszOut++ = '0' + ((c / 100) % 10);
*pszOut++ = '0' + ((c / 10) % 10);
*pszOut++ = '0' + (c % 10);
*pszOut++ = ';';
}
else {
break;
}
}
else {
*pszOut++ = *pszIn++;
}
}
*pszOut = '\0';
return pszOut;
}
static PCHAR do_ewstr(PCHAR pszOut, PCHAR pszEnd, PCWSTR pszIn)
{
while (*pszIn && pszOut < pszEnd) {
if (*pszIn == '<') {
if (pszOut + 4 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'l';
*pszOut++ = 't';
*pszOut++ = ';';
}
else if (*pszIn == '>') {
if (pszOut + 4 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'g';
*pszOut++ = 't';
*pszOut++ = ';';
}
else if (*pszIn == '&') {
if (pszOut + 5 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'a';
*pszOut++ = 'm';
*pszOut++ = 'p';
*pszOut++ = ';';
}
else if (*pszIn == '\"') {
if (pszOut + 6 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'q';
*pszOut++ = 'u';
*pszOut++ = 'o';
*pszOut++ = 't';
*pszOut++ = ';';
}
else if (*pszIn == '\'') {
if (pszOut + 6 > pszEnd) {
break;
}
pszIn++;
*pszOut++ = '&';
*pszOut++ = 'a';
*pszOut++ = 'p';
*pszOut++ = 'o';
*pszOut++ = 's';
*pszOut++ = ';';
}
else if (*pszIn < ' ' || *pszIn > 127) {
WCHAR c = *pszIn++;
if (c < 10 && pszOut + 4 <= pszEnd) {
*pszOut++ = '&';
*pszOut++ = '#';
*pszOut++ = '0' + (CHAR)(c % 10);
*pszOut++ = ';';
}
else if (c < 100 && pszOut + 5 <= pszEnd) {
*pszOut++ = '&';
*pszOut++ = '#';
*pszOut++ = '0' + (CHAR)((c / 10) % 10);
*pszOut++ = '0' + (CHAR)(c % 10);
*pszOut++ = ';';
}
else if (c < 1000 && pszOut + 6 <= pszEnd) {
*pszOut++ = '&';
*pszOut++ = '#';
*pszOut++ = '0' + (CHAR)((c / 100) % 10);
*pszOut++ = '0' + (CHAR)((c / 10) % 10);
*pszOut++ = '0' + (CHAR)(c % 10);
*pszOut++ = ';';
}
else {
break;
}
}
else {
*pszOut++ = (CHAR)*pszIn++;
}
}
*pszOut = '\0';
return pszOut;
}
#if _MSC_VER >= 1900
#pragma warning(push)
#pragma warning(disable:4456) // declaration hides previous local declaration
#endif
VOID VSafePrintf(PCSTR pszMsg, va_list args, PCHAR pszBuffer, LONG cbBuffer)
{
PCHAR pszOut = pszBuffer;
PCHAR pszEnd = pszBuffer + cbBuffer - 1;
pszBuffer[0] = '\0';
__try {
while (*pszMsg && pszOut < pszEnd) {
if (*pszMsg == '%') {
CHAR szHead[4] = "";
INT nLen;
INT nWidth = 0;
INT nPrecision = 0;
BOOL fLeft = FALSE;
BOOL fPositive = FALSE;
BOOL fPound = FALSE;
BOOL fBlank = FALSE;
BOOL fZero = FALSE;
BOOL fDigit = FALSE;
BOOL fSmall = FALSE;
BOOL fLarge = FALSE;
BOOL f64Bit = FALSE;
PCSTR pszArg = pszMsg;
pszMsg++;
for (; (*pszMsg == '-' ||
*pszMsg == '+' ||
*pszMsg == '#' ||
*pszMsg == ' ' ||
*pszMsg == '0'); pszMsg++) {
switch (*pszMsg) {
case '-': fLeft = TRUE; break;
case '+': fPositive = TRUE; break;
case '#': fPound = TRUE; break;
case ' ': fBlank = TRUE; break;
case '0': fZero = TRUE; break;
}
}
if (*pszMsg == '*') {
nWidth = va_arg(args, INT);
pszMsg++;
}
else {
while (*pszMsg >= '0' && *pszMsg <= '9') {
nWidth = nWidth * 10 + (*pszMsg++ - '0');
}
}
if (*pszMsg == '.') {
pszMsg++;
fDigit = TRUE;
if (*pszMsg == '*') {
nPrecision = va_arg(args, INT);
pszMsg++;
}
else {
while (*pszMsg >= '0' && *pszMsg <= '9') {
nPrecision = nPrecision * 10 + (*pszMsg++ - '0');
}
}
}
if (*pszMsg == 'h') {
fSmall = TRUE;
pszMsg++;
}
else if (*pszMsg == 'l') {
fLarge = TRUE;
pszMsg++;
}
else if (*pszMsg == 'I' && pszMsg[1] == '6' && pszMsg[2] == '4') {
f64Bit = TRUE;
pszMsg += 3;
}
if (*pszMsg == 's' || *pszMsg == 'e' || *pszMsg == 'c') {
// We ignore the length, precision, and alignment
// to avoid using a temporary buffer.
if (*pszMsg == 's') { // [GalenH] need to not use temp.
PVOID pvData = va_arg(args, PVOID);
pszMsg++;
if (fSmall) {
fLarge = FALSE;
}
__try {
if (pvData == NULL) {
pszOut = do_str(pszOut, pszEnd, "-NULL-");
}
else if (fLarge) {
pszOut = do_wstr(pszOut, pszEnd, (PWCHAR)pvData);
}
else {
pszOut = do_str(pszOut, pszEnd, (PCHAR)pvData);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
pszOut = do_str(pszOut, pszEnd, "-");
pszOut = do_base(pszOut, (UINT64)pvData, 16,
"0123456789ABCDEF");
pszOut = do_str(pszOut, pszEnd, "-");
}
}
else if (*pszMsg == 'e') { // Escape the string.
PVOID pvData = va_arg(args, PVOID);
pszMsg++;
if (fSmall) {
fLarge = FALSE;
}
__try {
if (pvData == NULL) {
pszOut = do_str(pszOut, pszEnd, "-NULL-");
}
else if (fLarge) {
pszOut = do_ewstr(pszOut, pszEnd, (PWCHAR)pvData);
}
else {
pszOut = do_estr(pszOut, pszEnd, (PCHAR)pvData);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
pszOut = do_str(pszOut, pszEnd, "-");
pszOut = do_base(pszOut, (UINT64)pvData, 16,
"0123456789ABCDEF");
pszOut = do_str(pszOut, pszEnd, "-");
}
}
else {
CHAR szTemp[2];
pszMsg++;
szTemp[0] = (CHAR)va_arg(args, INT);
szTemp[1] = '\0';
pszOut = do_str(pszOut, pszEnd, szTemp);
}
}
else if (*pszMsg == 'd' || *pszMsg == 'i' || *pszMsg == 'o' ||
*pszMsg == 'x' || *pszMsg == 'X' || *pszMsg == 'b' ||
*pszMsg == 'u') {
CHAR szTemp[128];
UINT64 value;
if (f64Bit) {
value = va_arg(args, UINT64);
}
else {
value = va_arg(args, UINT);
}
if (*pszMsg == 'x') {
pszMsg++;
nLen = (int)(do_base(szTemp, value, 16, "0123456789abcdef") - szTemp);
if (fPound && value) {
do_str(szHead, szHead + sizeof(szHead) - 1, "0x");
}
}
else if (*pszMsg == 'X') {
pszMsg++;
nLen = (int)(do_base(szTemp, value, 16, "0123456789ABCDEF") - szTemp);
if (fPound && value) {
do_str(szHead, szHead + sizeof(szHead) - 1, "0X");
}
}
else if (*pszMsg == 'd') {
pszMsg++;
if ((INT64)value < 0) {
value = -(INT64)value;
do_str(szHead, szHead + sizeof(szHead) - 1, "-");
}
else if (fPositive) {
if (value > 0) {
do_str(szHead, szHead + sizeof(szHead) - 1, "+");
}
}
else if (fBlank) {
if (value > 0) {
do_str(szHead, szHead + sizeof(szHead) - 1, " ");
}
}
nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp);
nPrecision = 0;
}
else if (*pszMsg == 'u') {
pszMsg++;
nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp);
nPrecision = 0;
}
else if (*pszMsg == 'o') {
pszMsg++;
nLen = (int)(do_base(szTemp, value, 8, "01234567") - szTemp);
nPrecision = 0;
if (fPound && value) {
do_str(szHead, szHead + sizeof(szHead) - 1, "0");
}
}
else if (*pszMsg == 'b') {
pszMsg++;
nLen = (int)(do_base(szTemp, value, 2, "01") - szTemp);
nPrecision = 0;
if (fPound && value) {
do_str(szHead, szHead + sizeof(szHead) - 1, "0b");
}
}
else {
pszMsg++;
if ((INT64)value < 0) {
value = -(INT64)value;
do_str(szHead, szHead + sizeof(szHead) - 1, "-");
}
else if (fPositive) {
if (value > 0) {
do_str(szHead, szHead + sizeof(szHead) - 1, "+");
}
}
else if (fBlank) {
if (value > 0) {
do_str(szHead, szHead + sizeof(szHead) - 1, " ");
}
}
nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp);
nPrecision = 0;
}
INT nHead = 0;
for (; szHead[nHead]; nHead++) {
// Count characters in head string.
}
if (fLeft) {
if (nHead) {
pszOut = do_str(pszOut, pszEnd, szHead);
nLen += nHead;
}
pszOut = do_str(pszOut, pszEnd, szTemp);
for (; nLen < nWidth && pszOut < pszEnd; nLen++) {
*pszOut++ = ' ';
}
}
else if (fZero) {
if (nHead) {
pszOut = do_str(pszOut, pszEnd, szHead);
nLen += nHead;
}
for (; nLen < nWidth && pszOut < pszEnd; nLen++) {
*pszOut++ = '0';
}
pszOut = do_str(pszOut, pszEnd, szTemp);
}
else {
if (nHead) {
nLen += nHead;
}
for (; nLen < nWidth && pszOut < pszEnd; nLen++) {
*pszOut++ = ' ';
}
if (nHead) {
pszOut = do_str(pszOut, pszEnd, szHead);
}
pszOut = do_str(pszOut, pszEnd, szTemp);
}
}
else if (*pszMsg == 'p') {
CHAR szTemp[64];
ULONG_PTR value;
value = va_arg(args, ULONG_PTR);
if (*pszMsg == 'p') {
pszMsg++;
nLen = (int)(do_base(szTemp, (UINT64)value, 16, "0123456789abcdef") - szTemp);
if (fPound && value) {
do_str(szHead, szHead + sizeof(szHead) - 1, "0x");
}
}
else {
pszMsg++;
nLen = (int)(do_base(szTemp, (UINT64)value, 16, "0123456789ABCDEF") - szTemp);
if (fPound && value) {
do_str(szHead, szHead + sizeof(szHead) - 1, "0x");
}
}
INT nHead = 0;
for (; szHead[nHead]; nHead++) {
// Count characters in head string.
}
if (nHead) {
pszOut = do_str(pszOut, pszEnd, szHead);
nLen += nHead;
}
for (; nLen < nWidth && pszOut < pszEnd; nLen++) {
*pszOut++ = '0';
}
pszOut = do_str(pszOut, pszEnd, szTemp);
}
else {
pszMsg++;
while (pszArg < pszMsg && pszOut < pszEnd) {
*pszOut++ = *pszArg++;
}
}
}
else {
if (pszOut < pszEnd) {
*pszOut++ = *pszMsg++;
}
}
}
*pszOut = '\0';
pszBuffer[cbBuffer - 1] = '\0';
} __except(EXCEPTION_EXECUTE_HANDLER) {
PCHAR pszOut = pszBuffer;
*pszOut = '\0';
pszOut = do_str(pszOut, pszEnd, "-exception:");
pszOut = do_base(pszOut, (UINT64)GetExceptionCode(), 10, "0123456789");
pszOut = do_str(pszOut, pszEnd, "-");
}
}
#if _MSC_VER >= 1900
#pragma warning(pop)
#endif
PCHAR SafePrintf(PCHAR pszBuffer, LONG cbBuffer, PCSTR pszMsg, ...)
{
va_list args;
va_start(args, pszMsg);
VSafePrintf(pszMsg, args, pszBuffer, cbBuffer);
va_end(args);
while (*pszBuffer) {
pszBuffer++;
}
return pszBuffer;
}
//////////////////////////////////////////////////////////////////////////////
//
BOOL TblogOpen()
{
EnterCriticalSection(&s_csPipe);
WCHAR wzPipe[256];
StringCchPrintfW(wzPipe, ARRAYSIZE(wzPipe), L"%ls.%d", TBLOG_PIPE_NAMEW, s_nTraceProcessId);
for (int retries = 0; retries < 10; retries++) {
WaitNamedPipeW(wzPipe, 10000); // Wait up to 10 seconds for a pipe to appear.
s_hPipe = Real_CreateFileW(wzPipe, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (s_hPipe != INVALID_HANDLE_VALUE) {
DWORD dwMode = PIPE_READMODE_MESSAGE;
if (SetNamedPipeHandleState(s_hPipe, &dwMode, NULL, NULL)) {
LeaveCriticalSection(&s_csPipe);
return TRUE;
}
}
}
LeaveCriticalSection(&s_csPipe);
// Couldn't open pipe.
DEBUG_BREAK();
Real_ExitProcess(9990);
return FALSE;
}
VOID TblogV(PCSTR pszMsgf, va_list args)
{
if (s_hPipe == INVALID_HANDLE_VALUE) {
return;
}
EnterCriticalSection(&s_csPipe);
DWORD cbWritten = 0;
PCHAR pszBuf = s_rMessage.szMessage;
VSafePrintf(pszMsgf, args,
pszBuf, (int)(s_rMessage.szMessage + sizeof(s_rMessage.szMessage) - pszBuf));
PCHAR pszEnd = s_rMessage.szMessage;
for (; *pszEnd; pszEnd++) {
// no internal contents.
}
s_rMessage.nBytes = (DWORD)(pszEnd - ((PCSTR)&s_rMessage));
// If the write fails, then we abort
if (s_hPipe != INVALID_HANDLE_VALUE) {
if (!Real_WriteFile(s_hPipe, &s_rMessage, s_rMessage.nBytes, &cbWritten, NULL)) {
Real_ExitProcess(9991);
}
}
LeaveCriticalSection(&s_csPipe);
}
VOID Tblog(PCSTR pszMsgf, ...)
{
if (s_hPipe == INVALID_HANDLE_VALUE) {
return;
}
va_list args;
va_start(args, pszMsgf);
TblogV(pszMsgf, args);
va_end(args);
}
VOID TblogClose()
{
EnterCriticalSection(&s_csPipe);
if (s_hPipe != INVALID_HANDLE_VALUE) {
DWORD cbWritten = 0;
s_rMessage.nBytes = 0;
Real_WriteFile(s_hPipe, &s_rMessage, 4, &cbWritten, NULL);
FlushFileBuffers(s_hPipe);
Real_CloseHandle(s_hPipe);
s_hPipe = INVALID_HANDLE_VALUE;
}
LeaveCriticalSection(&s_csPipe);
}
/////////////////////////////////////////////////////////////
// Detours
//
static BOOL IsInherited(HANDLE hHandle)
{
DWORD dwFlags;
if (GetHandleInformation(hHandle, &dwFlags)) {
return (dwFlags & HANDLE_FLAG_INHERIT) ? TRUE : FALSE;
}
return FALSE;
}
static void SaveStdHandleName(HANDLE hFile, PWCHAR pwzBuffer, BOOL *fAppend)
{
pwzBuffer[0] = '\0';
if ((hFile != INVALID_HANDLE_VALUE) && IsInherited(hFile)) {
FileInfo * pInfo = OpenFiles::RecallFile(hFile);
if (pInfo) {
Copy(pwzBuffer, pInfo->m_pwzPath);
if (pInfo->m_fAppend && fAppend != NULL) {
*fAppend = TRUE;
}
}
}
}
static void LoadStdHandleName(DWORD id, PCWSTR pwzBuffer, BOOL fAppend)
{
HANDLE hFile = GetStdHandle(id);
if ((hFile != INVALID_HANDLE_VALUE) && pwzBuffer[0] != '\0') {
FileInfo *pInfo = FileNames::FindPartial(pwzBuffer);
if (fAppend) {
pInfo->m_fAppend = TRUE;
}
OpenFiles::Remember(hFile, pInfo);
}
}
BOOL CreateProcessInternals(HANDLE hProcess, DWORD nProcessId, PCHAR pszId,
HANDLE hStdin, HANDLE hStdout, HANDLE hStderr)
{
EnterCriticalSection(&s_csChildPayload);
ProcInfo *proc = Procs::Create(hProcess, nProcessId);
OpenFiles::Remember(hProcess, proc);
ZeroMemory(&s_ChildPayload, sizeof(s_ChildPayload));
CopyMemory(&s_ChildPayload, &s_Payload, sizeof(s_ChildPayload));
s_ChildPayload.nParentProcessId = GetCurrentProcessId();
s_ChildPayload.rGeneology[s_ChildPayload.nGeneology]
= (DWORD)InterlockedIncrement(&s_nChildCnt);
s_ChildPayload.nGeneology++;
SaveStdHandleName(hStdin, s_ChildPayload.wzStdin, NULL);
SaveStdHandleName(hStdout, s_ChildPayload.wzStdout, &s_ChildPayload.fStdoutAppend);
SaveStdHandleName(hStderr, s_ChildPayload.wzStderr, &s_ChildPayload.fStderrAppend);
DetourCopyPayloadToProcess(hProcess, s_guidTrace, &s_ChildPayload, sizeof(s_ChildPayload));
for (DWORD i = 0; i < s_ChildPayload.nGeneology; i++) {
pszId = SafePrintf(pszId, 16, "%d.", s_ChildPayload.rGeneology[i]);
}
*pszId = '\0';
LeaveCriticalSection(&s_csChildPayload);
return TRUE;
}
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)
{
EnterFunc();
if (lpCommandLine == NULL) {
lpCommandLine = (LPWSTR)lpApplicationName;
}
CHAR szProc[MAX_PATH];
BOOL rv = 0;
__try {
LPPROCESS_INFORMATION ppi = lpProcessInformation;
PROCESS_INFORMATION pi;
if (ppi == NULL) {
ppi = &pi;
}
rv = DetourCreateProcessWithDllExW(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags | CREATE_SUSPENDED,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
ppi,
s_szDllPath,
Real_CreateProcessW);
if (rv) {
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
if (lpStartupInfo != NULL && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) != 0) {
hStdin = lpStartupInfo->hStdInput;
hStdout = lpStartupInfo->hStdOutput;
hStderr = lpStartupInfo->hStdError;
}
CreateProcessInternals(ppi->hProcess, ppi->dwProcessId,
szProc, hStdin, hStdout, hStderr);
Print("<t:Child id=\"::%hs::\">\n", szProc);
WCHAR wzPath[MAX_PATH];
FileInfo *pInfo = NULL;
if (lpApplicationName == NULL) {
PWCHAR pwzDst = wzPath;
PWCHAR pwzSrc = lpCommandLine;
if (*pwzSrc == '\"') {
WCHAR cQuote = *pwzSrc++;
while (*pwzSrc && *pwzSrc != cQuote) {
*pwzDst++ = *pwzSrc++;
}
*pwzDst++ = '\0';
}
else {
while (*pwzSrc && *pwzSrc != ' ' && *pwzSrc != '\t') {
if (*pwzSrc == '\t') {
*pwzSrc = ' ';
}
*pwzDst++ = *pwzSrc++;
}
*pwzDst++ = '\0';
}
pInfo = FileNames::FindPartial(wzPath);
}
else {
pInfo = FileNames::FindPartial(lpApplicationName);
}
Print("<t:Executable>%ls</t:Executable>\n",
FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo));
Print("<t:Line>%le</t:Line>\n", lpCommandLine);
Print("</t:Child>\n");
if (pInfo) {
pInfo->m_fAbsorbed = true;
}
if (!(dwCreationFlags & CREATE_SUSPENDED)) {
ResumeThread(ppi->hThread);
}
if (ppi == &pi) {
Real_CloseHandle(ppi->hThread);
Real_CloseHandle(ppi->hProcess);
}
}
} __finally {
ExitFunc();
if (!rv) {
Print("<!-- Warning: CreateProcessW failed %d: %ls; %ls -->\n",
GetLastError(), lpApplicationName, lpCommandLine);
}
}
return rv;
}
BOOL WINAPI Mine_CreateProcessA(LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
EnterFunc();
if (lpCommandLine == NULL) {
lpCommandLine = (LPSTR)lpApplicationName;
}
CHAR szProc[MAX_PATH];
BOOL rv = 0;
__try {
LPPROCESS_INFORMATION ppi = lpProcessInformation;
PROCESS_INFORMATION pi;
if (ppi == NULL) {
ppi = &pi;
}
rv = DetourCreateProcessWithDllExA(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags | CREATE_SUSPENDED,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
ppi,
s_szDllPath,
Real_CreateProcessA);
if (rv) {
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
if (lpStartupInfo != NULL && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) != 0) {
hStdin = lpStartupInfo->hStdInput;
hStdout = lpStartupInfo->hStdOutput;
hStderr = lpStartupInfo->hStdError;
}
CreateProcessInternals(ppi->hProcess, ppi->dwProcessId,
szProc, hStdin, hStdout, hStderr);
Print("<t:Child id=\"::%hs::\">\n", szProc);
WCHAR wzPath[MAX_PATH];
FileInfo *pInfo = NULL;
if (lpApplicationName == NULL) {
PCHAR pszDst = szProc;
PCHAR pszSrc = lpCommandLine;
if (*pszSrc == '\"') {
CHAR cQuote = *pszSrc++;
while (*pszSrc && *pszSrc != cQuote) {
*pszDst++ = *pszSrc++;
}
*pszDst++ = '\0';
}
else {
while (*pszSrc && *pszSrc != ' ' && *pszSrc != '\t') {
if (*pszSrc == '\t') {
*pszSrc = ' ';
}
*pszDst++ = *pszSrc++;
}
*pszDst++ = '\0';
}
pInfo = FileNames::FindPartial(szProc);
}
else {
pInfo = FileNames::FindPartial(lpApplicationName);
}
Print("<t:Executable>%ls</t:Executable>\n",
FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo));
Print("<t:Line>%he</t:Line>\n", lpCommandLine);
Print("</t:Child>\n");
if (pInfo) {
pInfo->m_fAbsorbed = true;
}
if (!(dwCreationFlags & CREATE_SUSPENDED)) {
ResumeThread(ppi->hThread);
}
if (ppi == &pi) {
Real_CloseHandle(ppi->hThread);
Real_CloseHandle(ppi->hProcess);
}
}
} __finally {
ExitFunc();
if (!rv) {
Print("<!-- Warning: CreateProcessA failed %d: %hs; %hs -->\n",
GetLastError(), lpApplicationName, lpCommandLine);
}
}
return rv;
}
//
//////////////////////////////////////////////////////////////////////////////
BOOL WINAPI Mine_CopyFileExA(LPCSTR a0,
LPCSTR a1,
LPPROGRESS_ROUTINE a2,
LPVOID a3,
LPBOOL a4,
DWORD a5)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_CopyFileExA(a0, a1, a2, a3, a4, a5);
} __finally {
ExitFunc();
if (rv) {
#if 0
Print("<!-- CopyFileExA %he to %he -->\n", a0, a1);
#endif
NoteRead(a0);
NoteWrite(a1);
}
};
return rv;
}
BOOL WINAPI Mine_CopyFileExW(LPCWSTR a0,
LPCWSTR a1,
LPPROGRESS_ROUTINE a2,
LPVOID a3,
LPBOOL a4,
DWORD a5)
{
EnterFunc();
BOOL rv = 0;
__try {
#if 0
Print("\n");
Print("<!-- CopyFileExW %le to %le before -->\n", a0, a1);
#endif
rv = Real_CopyFileExW(a0, a1, a2, a3, a4, a5);
} __finally {
ExitFunc();
if (rv) {
#if 0
Print("<!-- CopyFileExW %le to %le -->\n", a0, a1);
#endif
NoteRead(a0);
NoteWrite(a1);
}
};
return rv;
}
BOOL WINAPI Mine_PrivCopyFileExW(LPCWSTR a0,
LPCWSTR a1,
LPPROGRESS_ROUTINE a2,
LPVOID a3,
LPBOOL a4,
DWORD a5)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_PrivCopyFileExW(a0, a1, a2, a3, a4, a5);
} __finally {
ExitFunc();
if (rv) {
#if 0
Print("<!-- PrivCopyFileExW %le to %le -->\n", a0, a1);
#endif
NoteRead(a0);
NoteWrite(a1);
}
};
return rv;
}
BOOL WINAPI Mine_CreateHardLinkA(LPCSTR a0,
LPCSTR a1,
LPSECURITY_ATTRIBUTES a2)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_CreateHardLinkA(a0, a1, a2);
} __finally {
ExitFunc();
if (rv) {
#if 0
Print("<!-- CreateHardLinkA %he to %he -->\n", a0, a1);
#endif
NoteRead(a1);
NoteWrite(a0);
}
};
return rv;
}
BOOL WINAPI Mine_CreateHardLinkW(LPCWSTR a0,
LPCWSTR a1,
LPSECURITY_ATTRIBUTES a2)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_CreateHardLinkW(a0, a1, a2);
} __finally {
ExitFunc();
if (rv) {
#if 0
Print("<!-- CreateHardLinkW %le to %le -->\n", a0, a1);
#endif
NoteRead(a1);
NoteWrite(a0);
}
};
return rv;
}
BOOL WINAPI Mine_CloseHandle(HANDLE a0)
{
/*int nIndent =*/ EnterFunc();
BOOL rv = 0;
__try {
ProcInfo * pProc = OpenFiles::RecallProc(a0);
if (pProc != NULL) {
Procs::Close(pProc->m_hProc);
}
FileInfo * pFile = OpenFiles::RecallFile(a0);
if (pFile != NULL) {
DWORD dwErr = GetLastError();
pFile->m_cbContent = GetFileSize(a0, NULL);
if (pFile->m_cbContent == INVALID_FILE_SIZE) {
pFile->m_cbContent = 0;
}
if (pFile->m_fCantRead) {
if (pFile->m_fRead) {
#if 0
Print("<!-- Warning: Removing read from %le -->\n", pFile->m_pwzPath);
#endif
pFile->m_fRead = FALSE;
}
}
// Here we should think about reading the file contents as appropriate.
if (pFile->m_fTemporaryPath && pFile->m_fRead && !pFile->m_fAbsorbed &&
!pFile->m_fDelete && !pFile->m_fCleanup && !pFile->m_fWrite &&
pFile->m_pbContent == NULL &&
pFile->m_cbContent < 16384) {
pFile->m_pbContent = LoadFile(a0, pFile->m_cbContent);
}
SetLastError(dwErr);
}
rv = Real_CloseHandle(a0);
} __finally {
ExitFunc();
if (rv /* && nIndent == 0*/) {
OpenFiles::Forget(a0);
}
};
return rv;
}
BOOL WINAPI Mine_DuplicateHandle(HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
LPHANDLE lpTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions)
{
HANDLE hTemp = INVALID_HANDLE_VALUE;
EnterFunc();
BOOL rv = 0;
__try {
if (lpTargetHandle == NULL) {
lpTargetHandle = &hTemp;
}
*lpTargetHandle = INVALID_HANDLE_VALUE;
rv = Real_DuplicateHandle(hSourceProcessHandle,
hSourceHandle,
hTargetProcessHandle,
lpTargetHandle,
dwDesiredAccess,
bInheritHandle,
dwOptions);
} __finally {
ExitFunc();
if (*lpTargetHandle != INVALID_HANDLE_VALUE) {
FileInfo *pInfo = OpenFiles::RecallFile(hSourceHandle);
if (pInfo) {
OpenFiles::Remember(*lpTargetHandle, pInfo);
}
}
};
return rv;
}
static LONG s_nPipeCnt = 0;
BOOL WINAPI Mine_CreatePipe(PHANDLE hReadPipe,
PHANDLE hWritePipe,
LPSECURITY_ATTRIBUTES lpPipeAttributes,
DWORD nSize)
{
HANDLE hRead = INVALID_HANDLE_VALUE;
HANDLE hWrite = INVALID_HANDLE_VALUE;
if (hReadPipe == NULL) {
hReadPipe = &hRead;
}
if (hWritePipe == NULL) {
hWritePipe = &hWrite;
}
/*int nIndent = */ EnterFunc();
BOOL rv = 0;
__try {
rv = Real_CreatePipe(hReadPipe, hWritePipe, lpPipeAttributes, nSize);
} __finally {
ExitFunc();
if (rv) {
CHAR szPipe[128];
SafePrintf(szPipe, ARRAYSIZE(szPipe), "\\\\.\\PIPE\\Temp.%d.%d",
GetCurrentProcessId(),
InterlockedIncrement(&s_nPipeCnt));
FileInfo *pInfo = FileNames::FindPartial(szPipe);
pInfo->m_fCleanup = TRUE;
OpenFiles::Remember(*hReadPipe, pInfo);
OpenFiles::Remember(*hWritePipe, pInfo);
}
};
return rv;
}
BOOL WINAPI Mine_CreateDirectoryW(LPCWSTR a0,
LPSECURITY_ATTRIBUTES a1)
{
/* int nIndent = */ EnterFunc();
BOOL rv = 0;
__try {
rv = Real_CreateDirectoryW(a0, a1);
} __finally {
ExitFunc();
if (rv) {
FileInfo *pInfo = FileNames::FindPartial(a0);
pInfo->m_fDirectory = TRUE;
}
};
return rv;
}
BOOL WINAPI Mine_CreateDirectoryExW(LPCWSTR a0,
LPCWSTR a1,
LPSECURITY_ATTRIBUTES a2)
{
/* int nIndent = */ EnterFunc();
BOOL rv = 0;
__try {
rv = Real_CreateDirectoryExW(a0, a1, a2);
} __finally {
ExitFunc();
if (rv) {
FileInfo *pInfo = FileNames::FindPartial(a1);
pInfo->m_fDirectory = TRUE;
}
};
return rv;
}
HANDLE WINAPI Mine_CreateFileW(LPCWSTR a0,
DWORD access,
DWORD share,
LPSECURITY_ATTRIBUTES a3,
DWORD create,
DWORD flags,
HANDLE a6)
{
/* int nIndent = */ EnterFunc();
HANDLE rv = 0;
__try {
rv = Real_CreateFileW(a0, access, share, a3, create, flags, a6);
} __finally {
ExitFunc();
#if 0
Print("<!-- CreateFileW(%le, ac=%08x, cr=%08x, fl=%08x -->\n",
a0,
access,
create,
flags);
#endif
if (access != 0 && /* nIndent == 0 && */ rv != INVALID_HANDLE_VALUE) {
FileInfo *pInfo = FileNames::FindPartial(a0);
// FILE_FLAG_WRITE_THROUGH 0x80000000
// FILE_FLAG_OVERLAPPED 0x40000000
// FILE_FLAG_NO_BUFFERING 0x20000000
// FILE_FLAG_RANDOM_ACCESS 0x10000000
// FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
// FILE_FLAG_DELETE_ON_CLOSE 0x04000000
// FILE_FLAG_BACKUP_SEMANTICS 0x02000000
// FILE_FLAG_POSIX_SEMANTICS 0x01000000
// FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
// FILE_FLAG_OPEN_NO_RECALL 0x00100000
// FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
// FILE_ATTRIBUTE_ENCRYPTED 0x00004000
// FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
// FILE_ATTRIBUTE_OFFLINE 0x00001000
// FILE_ATTRIBUTE_COMPRESSED 0x00000800
// FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
// FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
// FILE_ATTRIBUTE_TEMPORARY 0x00000100
// FILE_ATTRIBUTE_NORMAL 0x00000080
// FILE_ATTRIBUTE_DEVICE 0x00000040
// FILE_ATTRIBUTE_ARCHIVE 0x00000020
// FILE_ATTRIBUTE_DIRECTORY 0x00000010
// FILE_ATTRIBUTE_SYSTEM 0x00000004
// FILE_ATTRIBUTE_HIDDEN 0x00000002
// FILE_ATTRIBUTE_READONLY 0x00000001
// CREATE_NEW 1
// CREATE_ALWAYS 2
// OPEN_EXISTING 3
// OPEN_ALWAYS 4
// TRUNCATE_EXISTING 5
if (create == CREATE_NEW ||
create == CREATE_ALWAYS ||
create == TRUNCATE_EXISTING) {
if (!pInfo->m_fRead) {
pInfo->m_fCantRead = TRUE;
}
}
else if (create == OPEN_EXISTING) {
}
else if (create == OPEN_ALWAYS) {
// pInfo->m_fAppend = TRUE; // !!!
}
if ((flags & FILE_FLAG_DELETE_ON_CLOSE)) {
pInfo->m_fCleanup = TRUE;
}
OpenFiles::Remember(rv, pInfo);
}
};
return rv;
}
HANDLE WINAPI Mine_CreateFileMappingW(HANDLE hFile,
LPSECURITY_ATTRIBUTES a1,
DWORD flProtect,
DWORD a3,
DWORD a4,
LPCWSTR a5)
{
/* int nIndent = */ EnterFunc();
HANDLE rv = 0;
__try {
rv = Real_CreateFileMappingW(hFile, a1, flProtect, a3, a4, a5);
} __finally {
ExitFunc();
if (rv != INVALID_HANDLE_VALUE) {
FileInfo *pInfo = OpenFiles::RecallFile(hFile);
if (pInfo != NULL) {
switch (flProtect) {
case PAGE_READONLY:
pInfo->m_fRead = TRUE;
break;
case PAGE_READWRITE:
pInfo->m_fRead = TRUE;
pInfo->m_fWrite = TRUE;
break;
case PAGE_WRITECOPY:
pInfo->m_fRead = TRUE;
break;
case PAGE_EXECUTE_READ:
pInfo->m_fRead = TRUE;
break;
case PAGE_EXECUTE_READWRITE:
pInfo->m_fRead = TRUE;
pInfo->m_fWrite = TRUE;
break;
}
}
}
};
return rv;
}
BOOL WINAPI Mine_DeleteFileW(LPCWSTR a0)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_DeleteFileW(a0);
} __finally {
ExitFunc();
#if 0
Print("<!-- DeleteFileW(%le -->\n", a0);
#endif
NoteDelete(a0);
};
return rv;
}
static VOID Dump(LPVOID pvData, DWORD cbData)
{
CHAR szBuffer[128];
PBYTE pbData = (PBYTE)pvData;
for (DWORD i = 0; i < cbData; i += 16) {
PCHAR psz = szBuffer;
psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), "%4d: ", i);
for (DWORD j = i; j < i + 16; j++) {
if (j < cbData) {
psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz),
"%02x", pbData[j]);
}
else {
psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), " ");
}
}
for (DWORD j = i; j < i + 16; j++) {
if (j < cbData) {
if (pbData[j] >= ' ' && pbData[j] <= 127) {
psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz),
"%c", pbData[j]);
}
else {
psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), ".");
}
}
else {
psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), " ");
}
}
Print("%s\n", szBuffer);
}
}
BOOL WINAPI Mine_DeviceIoControl(HANDLE a0,
DWORD a1,
LPVOID a2,
DWORD a3,
LPVOID a4,
DWORD a5,
LPDWORD a6,
LPOVERLAPPED a7)
{
EnterFunc();
DWORD d6 = 0;
if (a6 == NULL) {
a6 = &d6;
}
BOOL rv = 0;
__try {
rv = Real_DeviceIoControl(a0, a1, a2, a3, a4, a5, a6, a7);
} __finally {
ExitFunc();
OpenFiles::SetRead(a0, 0);
OpenFiles::SetWrite(a0, 0);
if (rv && a1 != 0x390008 && a1 != 0x4d0008 && a1 != 0x6d0008) {
FileInfo *pInfo = OpenFiles::RecallFile(a0);
DWORD DeviceType = (a1 & 0xffff0000) >> 16;
DWORD Access = (a1 & 0x0000c000) >> 14;
DWORD Function = (a1 & 0x00003ffc) >> 2;
DWORD Method = (a1 & 0x00000003) >> 0;
if (pInfo) {
Print("<!-- DeviceIoControl %x [dev=%x,acc=%x,fun=%x,mth=%x] on %ls! -->\n",
a1, DeviceType, Access, Function, Method, pInfo->m_pwzPath);
}
else {
Print("<!-- DeviceIoControl %x [dev=%x,acc=%x,fun=%x,mth=%x,in=%d,out=%d/%d] on (%x)! -->\n",
a1, DeviceType, Access, Function, Method, a3, *a6, a5, a0);
if (a3 > 0) {
Dump(a2, a3);
}
if (a5 > 0) {
Dump(a4, (*a6 < a5) ? *a6 : a5);
}
}
}
};
return rv;
}
DWORD WINAPI Mine_GetFileAttributesW(LPCWSTR a0)
{
EnterFunc();
DWORD rv = 0;
__try {
rv = Real_GetFileAttributesW(a0);
} __finally {
ExitFunc();
};
return rv;
}
BOOL WINAPI Mine_MoveFileWithProgressW(LPCWSTR a0,
LPCWSTR a1,
LPPROGRESS_ROUTINE a2,
LPVOID a3,
DWORD a4)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_MoveFileWithProgressW(a0, a1, a2, a3, a4);
} __finally {
ExitFunc();
if (rv) {
NoteRead(a0);
NoteWrite(a1);
}
};
return rv;
}
BOOL WINAPI Mine_MoveFileA(LPCSTR a0,
LPCSTR a1)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_MoveFileA(a0, a1);
} __finally {
ExitFunc();
if (rv) {
NoteRead(a0);
NoteCleanup(a0);
NoteWrite(a1);
}
};
return rv;
}
BOOL WINAPI Mine_MoveFileW(LPCWSTR a0,
LPCWSTR a1)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_MoveFileW(a0, a1);
} __finally {
ExitFunc();
if (rv) {
NoteRead(a0);
NoteCleanup(a0);
NoteWrite(a1);
}
};
return rv;
}
BOOL WINAPI Mine_MoveFileExA(LPCSTR a0,
LPCSTR a1,
DWORD a2)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_MoveFileExA(a0, a1, a2);
} __finally {
ExitFunc();
if (rv) {
NoteRead(a0);
NoteCleanup(a0);
NoteWrite(a1);
}
};
return rv;
}
BOOL WINAPI Mine_MoveFileExW(LPCWSTR a0,
LPCWSTR a1,
DWORD a2)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_MoveFileExW(a0, a1, a2);
} __finally {
ExitFunc();
if (rv) {
NoteRead(a0);
NoteCleanup(a0);
NoteWrite(a1);
}
};
return rv;
}
void SetHandle(PCSTR pszName, HANDLE h)
{
#if 0
FileInfo *pInfo = OpenFiles::RecallFile(h);
if (pInfo != NULL) {
Tblog("<!-- hset: %hs (%x) %ls -->\n", pszName, h, pInfo->m_pwzPath);
}
else {
Tblog("<!-- hset: %hs (%x) ***Unknown*** -->\n", pszName, h);
}
#else
(void)pszName;
(void)h;
#endif
}
BOOL WINAPI Mine_SetStdHandle(DWORD a0,
HANDLE a1)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_SetStdHandle(a0, a1);
if (rv && a1 != 0) {
switch (a0) {
case STD_INPUT_HANDLE:
SetHandle("stdin", a1);
break;
case STD_OUTPUT_HANDLE:
SetHandle("stdout", a1);
break;
case STD_ERROR_HANDLE:
SetHandle("stderr", a1);
break;
}
}
} __finally {
ExitFunc();
};
return rv;
}
HMODULE WINAPI Mine_LoadLibraryA(LPCSTR a0)
{
EnterFunc();
HMODULE rv = 0;
__try {
rv = Real_LoadLibraryA(a0);
} __finally {
ExitFunc();
};
return rv;
}
HMODULE WINAPI Mine_LoadLibraryW(LPCWSTR a0)
{
EnterFunc();
HMODULE rv = 0;
__try {
rv = Real_LoadLibraryW(a0);
} __finally {
ExitFunc();
};
return rv;
}
HMODULE WINAPI Mine_LoadLibraryExA(LPCSTR a0,
HANDLE a1,
DWORD a2)
{
EnterFunc();
HMODULE rv = 0;
__try {
rv = Real_LoadLibraryExA(a0, a1, a2);
} __finally {
ExitFunc();
};
return rv;
}
HMODULE WINAPI Mine_LoadLibraryExW(LPCWSTR a0,
HANDLE a1,
DWORD a2)
{
EnterFunc();
HMODULE rv = 0;
__try {
rv = Real_LoadLibraryExW(a0, a1, a2);
} __finally {
ExitFunc();
};
return rv;
}
DWORD WINAPI Mine_SetFilePointer(HANDLE hFile,
LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod)
{
EnterFunc();
DWORD rv = 0;
__try {
rv = Real_SetFilePointer(hFile,
lDistanceToMove,
lpDistanceToMoveHigh,
dwMoveMethod);
} __finally {
LONG high = 0;
if (lpDistanceToMoveHigh == NULL) {
lpDistanceToMoveHigh = &high;
}
FileInfo * pInfo = OpenFiles::RecallFile(hFile);
if (pInfo != NULL) {
if (dwMoveMethod == FILE_END && lDistanceToMove == 0xffffffff) {
#if 0
Print("<!-- SetFilePointer(APPEND, %le) -->\n",
pInfo->m_pwzPath);
#endif
pInfo->m_fAppend = TRUE;
}
#if 0
else if (dwMoveMethod == FILE_END) {
Print("<!-- SetFilePointer(END:%08x:%08x, %le) -->\n",
(int)lDistanceToMove,
*lpDistanceToMoveHigh,
pInfo->m_pwzPath);
}
else if (dwMoveMethod == FILE_BEGIN) {
Print("<!-- SetFilePointer(BEG:%08x:%08x, %le) -->\n",
(int)lDistanceToMove,
*lpDistanceToMoveHigh,
pInfo->m_pwzPath);
}
else if (dwMoveMethod == FILE_CURRENT) {
Print("<!-- SetFilePointer(CUR:%08x:%08x, %le) -->\n",
(int)lDistanceToMove,
*lpDistanceToMoveHigh,
pInfo->m_pwzPath);
}
#endif
}
ExitFunc();
};
return rv;
}
BOOL WINAPI Mine_SetFilePointerEx(HANDLE hFile,
LARGE_INTEGER liDistanceToMove,
PLARGE_INTEGER lpNewFilePointer,
DWORD dwMoveMethod)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_SetFilePointerEx(hFile,
liDistanceToMove,
lpNewFilePointer,
dwMoveMethod);
} __finally {
#if 0
FileInfo * pInfo = OpenFiles::RecallFile(hFile);
if (pInfo != NULL) {
if (dwMoveMethod == FILE_END) {
Print("<!-- SetFilePointerEx(END:%I64d, %le) -->\n",
liDistanceToMove.QuadPart,
pInfo->m_pwzPath);
}
else if (dwMoveMethod == FILE_BEGIN) {
Print("<!-- SetFilePointerEx(BEG:%I64d, %le) -->\n",
liDistanceToMove.QuadPart,
pInfo->m_pwzPath);
}
else if (dwMoveMethod == FILE_CURRENT) {
Print("<!-- SetFilePointerEx(CUR:%I64d, %le) -->\n",
liDistanceToMove.QuadPart,
pInfo->m_pwzPath);
}
}
#endif
ExitFunc();
};
return rv;
}
BOOL WINAPI Mine_ReadFile(HANDLE a0,
LPVOID a1,
DWORD a2,
LPDWORD a3,
LPOVERLAPPED a4)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_ReadFile(a0, a1, a2, a3, a4);
} __finally {
if (rv) {
OpenFiles::SetRead(a0, a2);
}
ExitFunc();
};
return rv;
}
BOOL WINAPI Mine_ReadFileEx(HANDLE a0,
LPVOID a1,
DWORD a2,
LPOVERLAPPED a3,
LPOVERLAPPED_COMPLETION_ROUTINE a4)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_ReadFileEx(a0, a1, a2, a3, a4);
} __finally {
if (rv) {
OpenFiles::SetRead(a0, a2);
}
ExitFunc();
};
return rv;
}
BOOL WINAPI Mine_WriteFile(HANDLE a0,
LPCVOID a1,
DWORD a2,
LPDWORD a3,
LPOVERLAPPED a4)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_WriteFile(a0, a1, a2, a3, a4);
} __finally {
OpenFiles::SetWrite(a0, a2);
ExitFunc();
};
return rv;
}
BOOL WINAPI Mine_WriteFileEx(HANDLE a0,
LPCVOID a1,
DWORD a2,
LPOVERLAPPED a3,
LPOVERLAPPED_COMPLETION_ROUTINE a4)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_WriteFileEx(a0, a1, a2, a3, a4);
} __finally {
OpenFiles::SetWrite(a0, a2);
ExitFunc();
};
return rv;
}
BOOL WINAPI Mine_WriteConsoleA(HANDLE a0,
const VOID* a1,
DWORD a2,
LPDWORD a3,
LPVOID a4)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_WriteConsoleA(a0, a1, a2, a3, a4);
} __finally {
OpenFiles::SetWrite(a0, a2);
ExitFunc();
};
return rv;
}
BOOL WINAPI Mine_WriteConsoleW(HANDLE a0,
const VOID* a1,
DWORD a2,
LPDWORD a3,
LPVOID a4)
{
EnterFunc();
BOOL rv = 0;
__try {
rv = Real_WriteConsoleW(a0, a1, a2, a3, a4);
} __finally {
OpenFiles::SetWrite(a0, a2);
ExitFunc();
};
return rv;
}
//////////////////////////////////////////////////////////////////////////////
//
DWORD WINAPI Mine_ExpandEnvironmentStringsA(PCSTR lpSrc, PCHAR lpDst, DWORD nSize)
{
EnterFunc();
DWORD rv = 0;
__try {
rv = Real_ExpandEnvironmentStringsA(lpSrc, lpDst, nSize);
}
__finally {
if (rv > 0) {
#if 0
Print("<!-- ExpandEnvironmentStringsA(%he) -->\n", lpSrc);
#endif
}
ExitFunc();
};
return rv;
}
DWORD WINAPI Mine_ExpandEnvironmentStringsW(PCWSTR lpSrc, PWCHAR lpDst, DWORD nSize)
{
EnterFunc();
DWORD rv = 0;
__try {
rv = Real_ExpandEnvironmentStringsW(lpSrc, lpDst, nSize);
}
__finally {
if (rv > 0) {
#if 0
Print("<!-- ExpandEnvironmentStringsW(%le) -->\n", lpSrc);
#endif
}
ExitFunc();
};
return rv;
}
DWORD WINAPI Mine_GetEnvironmentVariableA(PCSTR lpName, PCHAR lpBuffer, DWORD nSize)
{
EnterFunc();
DWORD rv = 0;
__try {
rv = Real_GetEnvironmentVariableA(lpName, lpBuffer, nSize);
// if (rv > 0 && rv < nSize && lpBuffer != NULL) {
// EnvVars::Used(lpName);
// }
}
__finally {
EnvVars::Used(lpName);
ExitFunc();
};
return rv;
}
DWORD WINAPI Mine_GetEnvironmentVariableW(PCWSTR lpName, PWCHAR lpBuffer, DWORD nSize)
{
EnterFunc();
DWORD rv = 0;
__try {
rv = Real_GetEnvironmentVariableW(lpName, lpBuffer, nSize);
// if (rv > 0 && rv < nSize && lpBuffer != NULL) {
// EnvVars::Used(lpName);
// }
}
__finally {
EnvVars::Used(lpName);
ExitFunc();
};
return rv;
}
PCWSTR CDECL Mine_wgetenv(PCWSTR var)
{
EnterFunc();
PCWSTR rv = 0;
__try {
rv = Real_wgetenv(var);
// if (rv != NULL) {
// EnvVars::Used(var);
// }
}
__finally {
EnvVars::Used(var);
ExitFunc();
}
return rv;
}
PCSTR CDECL Mine_getenv(PCSTR var)
{
EnterFunc();
PCSTR rv = 0;
__try {
rv = Real_getenv(var);
// if (rv) {
// EnvVars::Used(var);
// }
}
__finally {
EnvVars::Used(var);
ExitFunc();
}
return rv;
}
DWORD CDECL Mine_getenv_s(DWORD *pValue, PCHAR pBuffer, DWORD cBuffer, PCSTR varname)
{
EnterFunc();
DWORD rv = 0;
__try {
DWORD value;
if (pValue == NULL) {
pValue = &value;
}
rv = Real_getenv_s(pValue, pBuffer, cBuffer, varname);
// if (rv == 0 && *pValue > 0) {
// EnvVars::Used(varname);
// }
}
__finally {
EnvVars::Used(varname);
ExitFunc();
}
return rv;
}
DWORD CDECL Mine_wgetenv_s(DWORD *pValue, PWCHAR pBuffer, DWORD cBuffer, PCWSTR varname)
{
EnterFunc();
DWORD rv = 0;
__try {
DWORD value;
if (pValue == NULL) {
pValue = &value;
}
rv = Real_wgetenv_s(pValue, pBuffer, cBuffer, varname);
// if (rv == 0 && *pValue > 0) {
// EnvVars::Used(varname);
// }
}
__finally {
EnvVars::Used(varname);
ExitFunc();
}
return rv;
}
DWORD CDECL Mine_dupenv_s(PCHAR *ppBuffer, DWORD *pcBuffer, PCSTR varname)
{
EnterFunc();
DWORD rv = 0;
__try {
PCHAR pb;
DWORD cb;
if (ppBuffer == NULL) {
ppBuffer = &pb;
}
if (pcBuffer == NULL) {
pcBuffer = &cb;
}
rv = Real_dupenv_s(ppBuffer, pcBuffer, varname);
// if (rv == 0 && *pcBuffer > 0 && *ppBuffer != NULL) {
// EnvVars::Used(varname);
// }
}
__finally {
EnvVars::Used(varname);
ExitFunc();
}
return rv;
}
DWORD CDECL Mine_wdupenv_s(PWCHAR *ppBuffer, DWORD *pcBuffer, PCWSTR varname)
{
EnterFunc();
DWORD rv = 0;
__try {
PWCHAR pb;
DWORD cb;
if (ppBuffer == NULL) {
ppBuffer = &pb;
}
if (pcBuffer == NULL) {
pcBuffer = &cb;
}
rv = Real_wdupenv_s(ppBuffer, pcBuffer, varname);
// if (rv == 0 && *pcBuffer > 0 && *ppBuffer != NULL) {
// EnvVars::Used(varname);
// }
}
__finally {
EnvVars::Used(varname);
ExitFunc();
}
return rv;
}
/////////////////////////////////////////////////////////////
// AttachDetours
//
LONG AttachDetours(VOID)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Real_EntryPoint, Mine_EntryPoint);
DetourAttach(&(PVOID&)Real_ExitProcess, Mine_ExitProcess);
DetourAttach(&(PVOID&)Real_CopyFileExA, Mine_CopyFileExA);
DetourAttach(&(PVOID&)Real_CopyFileExW, Mine_CopyFileExW);
DetourAttach(&(PVOID&)Real_PrivCopyFileExW, Mine_PrivCopyFileExW);
DetourAttach(&(PVOID&)Real_CreateHardLinkA, Mine_CreateHardLinkA);
DetourAttach(&(PVOID&)Real_CreateHardLinkW, Mine_CreateHardLinkW);
DetourAttach(&(PVOID&)Real_CreateDirectoryW, Mine_CreateDirectoryW);
DetourAttach(&(PVOID&)Real_CreateDirectoryExW, Mine_CreateDirectoryExW);
DetourAttach(&(PVOID&)Real_CreateFileW, Mine_CreateFileW);
DetourAttach(&(PVOID&)Real_CreatePipe, Mine_CreatePipe);
DetourAttach(&(PVOID&)Real_CreateFileMappingW, Mine_CreateFileMappingW);
DetourAttach(&(PVOID&)Real_CloseHandle, Mine_CloseHandle);
DetourAttach(&(PVOID&)Real_DuplicateHandle, Mine_DuplicateHandle);
DetourAttach(&(PVOID&)Real_CreateProcessW, Mine_CreateProcessW);
DetourAttach(&(PVOID&)Real_CreateProcessA, Mine_CreateProcessA);
DetourAttach(&(PVOID&)Real_DeleteFileW, Mine_DeleteFileW);
DetourAttach(&(PVOID&)Real_DeviceIoControl, Mine_DeviceIoControl);
DetourAttach(&(PVOID&)Real_GetFileAttributesW, Mine_GetFileAttributesW);
DetourAttach(&(PVOID&)Real_MoveFileA, Mine_MoveFileA);
DetourAttach(&(PVOID&)Real_MoveFileW, Mine_MoveFileW);
DetourAttach(&(PVOID&)Real_MoveFileExA, Mine_MoveFileExA);
DetourAttach(&(PVOID&)Real_MoveFileExW, Mine_MoveFileExW);
DetourAttach(&(PVOID&)Real_MoveFileWithProgressW, Mine_MoveFileWithProgressW);
DetourAttach(&(PVOID&)Real_SetStdHandle, Mine_SetStdHandle);
DetourAttach(&(PVOID&)Real_LoadLibraryA, Mine_LoadLibraryA);
DetourAttach(&(PVOID&)Real_LoadLibraryW, Mine_LoadLibraryW);
DetourAttach(&(PVOID&)Real_LoadLibraryExA, Mine_LoadLibraryExA);
DetourAttach(&(PVOID&)Real_LoadLibraryExW, Mine_LoadLibraryExW);
DetourAttach(&(PVOID&)Real_SetFilePointer, Mine_SetFilePointer);
DetourAttach(&(PVOID&)Real_SetFilePointerEx, Mine_SetFilePointerEx);
DetourAttach(&(PVOID&)Real_ReadFile, Mine_ReadFile);
DetourAttach(&(PVOID&)Real_ReadFileEx, Mine_ReadFileEx);
DetourAttach(&(PVOID&)Real_WriteFile, Mine_WriteFile);
DetourAttach(&(PVOID&)Real_WriteFileEx, Mine_WriteFileEx);
DetourAttach(&(PVOID&)Real_WriteConsoleA, Mine_WriteConsoleA);
DetourAttach(&(PVOID&)Real_WriteConsoleW, Mine_WriteConsoleW);
DetourAttach(&(PVOID&)Real_ExpandEnvironmentStringsA, Mine_ExpandEnvironmentStringsA);
DetourAttach(&(PVOID&)Real_ExpandEnvironmentStringsW, Mine_ExpandEnvironmentStringsW);
DetourAttach(&(PVOID&)Real_GetEnvironmentVariableA, Mine_GetEnvironmentVariableA);
DetourAttach(&(PVOID&)Real_GetEnvironmentVariableW, Mine_GetEnvironmentVariableW);
return DetourTransactionCommit();
}
LONG DetachDetours(VOID)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)Real_EntryPoint, Mine_EntryPoint);
DetourAttach(&(PVOID&)Real_ExitProcess, Mine_ExitProcess);
DetourDetach(&(PVOID&)Real_CopyFileExA, Mine_CopyFileExA);
DetourDetach(&(PVOID&)Real_CopyFileExW, Mine_CopyFileExW);
DetourDetach(&(PVOID&)Real_PrivCopyFileExW, Mine_PrivCopyFileExW);
DetourDetach(&(PVOID&)Real_CreateHardLinkA, Mine_CreateHardLinkA);
DetourDetach(&(PVOID&)Real_CreateHardLinkW, Mine_CreateHardLinkW);
DetourDetach(&(PVOID&)Real_CreateDirectoryW, Mine_CreateDirectoryW);
DetourDetach(&(PVOID&)Real_CreateDirectoryExW, Mine_CreateDirectoryExW);
DetourDetach(&(PVOID&)Real_CreateFileW, Mine_CreateFileW);
DetourDetach(&(PVOID&)Real_CreatePipe, Mine_CreatePipe);
DetourDetach(&(PVOID&)Real_CreateFileMappingW, Mine_CreateFileMappingW);
DetourDetach(&(PVOID&)Real_CloseHandle, Mine_CloseHandle);
DetourDetach(&(PVOID&)Real_DuplicateHandle, Mine_DuplicateHandle);
DetourDetach(&(PVOID&)Real_CreateProcessW, Mine_CreateProcessW);
DetourDetach(&(PVOID&)Real_CreateProcessA, Mine_CreateProcessA);
DetourDetach(&(PVOID&)Real_DeleteFileW, Mine_DeleteFileW);
DetourDetach(&(PVOID&)Real_DeviceIoControl, Mine_DeviceIoControl);
DetourDetach(&(PVOID&)Real_GetFileAttributesW, Mine_GetFileAttributesW);
DetourDetach(&(PVOID&)Real_MoveFileA, Mine_MoveFileA);
DetourDetach(&(PVOID&)Real_MoveFileW, Mine_MoveFileW);
DetourDetach(&(PVOID&)Real_MoveFileExA, Mine_MoveFileExA);
DetourDetach(&(PVOID&)Real_MoveFileExW, Mine_MoveFileExW);
DetourDetach(&(PVOID&)Real_MoveFileWithProgressW, Mine_MoveFileWithProgressW);
DetourDetach(&(PVOID&)Real_SetStdHandle, Mine_SetStdHandle);
DetourDetach(&(PVOID&)Real_LoadLibraryA, Mine_LoadLibraryA);
DetourDetach(&(PVOID&)Real_LoadLibraryW, Mine_LoadLibraryW);
DetourDetach(&(PVOID&)Real_LoadLibraryExA, Mine_LoadLibraryExA);
DetourDetach(&(PVOID&)Real_LoadLibraryExW, Mine_LoadLibraryExW);
DetourDetach(&(PVOID&)Real_SetFilePointer, Mine_SetFilePointer);
DetourDetach(&(PVOID&)Real_SetFilePointerEx, Mine_SetFilePointerEx);
DetourDetach(&(PVOID&)Real_ReadFile, Mine_ReadFile);
DetourDetach(&(PVOID&)Real_ReadFileEx, Mine_ReadFileEx);
DetourDetach(&(PVOID&)Real_WriteFile, Mine_WriteFile);
DetourDetach(&(PVOID&)Real_WriteFileEx, Mine_WriteFileEx);
DetourDetach(&(PVOID&)Real_WriteConsoleA, Mine_WriteConsoleA);
DetourDetach(&(PVOID&)Real_WriteConsoleW, Mine_WriteConsoleW);
DetourDetach(&(PVOID&)Real_ExpandEnvironmentStringsA, Mine_ExpandEnvironmentStringsA);
DetourDetach(&(PVOID&)Real_ExpandEnvironmentStringsW, Mine_ExpandEnvironmentStringsW);
DetourDetach(&(PVOID&)Real_GetEnvironmentVariableA, Mine_GetEnvironmentVariableA);
DetourDetach(&(PVOID&)Real_GetEnvironmentVariableW, Mine_GetEnvironmentVariableW);
if (Real_getenv) { DetourDetach(&(PVOID&)Real_getenv, Mine_getenv); }
if (Real_getenv_s) { DetourDetach(&(PVOID&)Real_getenv_s, Mine_getenv_s); }
if (Real_wgetenv) { DetourDetach(&(PVOID&)Real_wgetenv, Mine_wgetenv); }
if (Real_wgetenv_s) { DetourDetach(&(PVOID&)Real_wgetenv, Mine_wgetenv_s); }
if (Real_dupenv_s) { DetourDetach(&(PVOID&)Real_dupenv_s, Mine_dupenv_s); }
if (Real_wdupenv_s) { DetourDetach(&(PVOID&)Real_wdupenv_s, Mine_wdupenv_s); }
return DetourTransactionCommit();
}
//
//////////////////////////////////////////////////////////////////////////////
VOID NoteRead(PCSTR psz)
{
FileInfo *pInfo = FileNames::FindPartial(psz);
pInfo->m_fRead = TRUE;
}
VOID NoteRead(PCWSTR pwz)
{
FileInfo *pInfo = FileNames::FindPartial(pwz);
pInfo->m_fRead = TRUE;
}
VOID NoteWrite(PCSTR psz)
{
FileInfo *pInfo = FileNames::FindPartial(psz);
pInfo->m_fWrite = TRUE;
if (!pInfo->m_fRead) {
pInfo->m_fCantRead = TRUE;
}
}
VOID NoteWrite(PCWSTR pwz)
{
FileInfo *pInfo = FileNames::FindPartial(pwz);
pInfo->m_fWrite = TRUE;
if (!pInfo->m_fRead) {
pInfo->m_fCantRead = TRUE;
}
}
VOID NoteDelete(PCSTR psz)
{
FileInfo *pInfo = FileNames::FindPartial(psz);
if (pInfo->m_fWrite || pInfo->m_fRead) {
pInfo->m_fCleanup = TRUE;
}
else {
pInfo->m_fDelete = TRUE;
}
if (!pInfo->m_fRead) {
pInfo->m_fCantRead = TRUE;
}
}
VOID NoteDelete(PCWSTR pwz)
{
FileInfo *pInfo = FileNames::FindPartial(pwz);
if (pInfo->m_fWrite || pInfo->m_fRead) {
pInfo->m_fCleanup = TRUE;
}
else {
pInfo->m_fDelete = TRUE;
}
if (!pInfo->m_fRead) {
pInfo->m_fCantRead = TRUE;
}
}
VOID NoteCleanup(PCSTR psz)
{
FileInfo *pInfo = FileNames::FindPartial(psz);
pInfo->m_fCleanup = TRUE;
}
VOID NoteCleanup(PCWSTR pwz)
{
FileInfo *pInfo = FileNames::FindPartial(pwz);
pInfo->m_fCleanup = TRUE;
}
////////////////////////////////////////////////////////////// Logging System.
//
static BOOL s_bLog = 1;
static LONG s_nTlsIndent = -1;
static LONG s_nTlsThread = -1;
static LONG s_nThreadCnt = 0;
LONG EnterFunc()
{
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);
}
SetLastError(dwErr);
return nIndent;
}
VOID ExitFunc()
{
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);
}
SetLastError(dwErr);
}
VOID Print(const CHAR *psz, ...)
{
DWORD dwErr = GetLastError();
if (s_bLog && psz) {
va_list args;
va_start(args, psz);
TblogV(psz, args);
va_end(args);
}
SetLastError(dwErr);
}
VOID AssertFailed(CONST PCHAR pszMsg, CONST PCHAR pszFile, ULONG nLine)
{
Tblog("ASSERT(%hs) 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)
{
InitializeCriticalSection(&s_csPipe);
InitializeCriticalSection(&s_csChildPayload);
Procs::Initialize();
EnvVars::Initialize();
FileNames::Initialize();
OpenFiles::Initialize();
s_bLog = FALSE;
s_nTlsIndent = TlsAlloc();
s_nTlsThread = TlsAlloc();
s_hInst = hDll;
s_hKernel32 = NULL;
PBYTE xCreate = (PBYTE)DetourCodeFromPointer((PVOID)Real_CreateProcessW, NULL);
PTBLOG_PAYLOAD pPayload = NULL;
for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) {
ULONG cbData;
PVOID pvData = DetourFindPayload(hMod, s_guidTrace, &cbData);
if (pvData != NULL && pPayload == NULL) {
pPayload = (PTBLOG_PAYLOAD)pvData;
}
ULONG cbMod = DetourGetModuleSize(hMod);
if (((PBYTE)hMod) < xCreate && ((PBYTE)hMod + cbMod) > xCreate) {
s_hKernel32 = hMod;
}
}
ZeroMemory(&s_Payload, sizeof(s_Payload));
if (pPayload == NULL) {
return FALSE;
}
CopyMemory(&s_Payload, pPayload, sizeof(s_Payload));
LoadStdHandleName(STD_INPUT_HANDLE, s_Payload.wzStdin, FALSE);
LoadStdHandleName(STD_OUTPUT_HANDLE, s_Payload.wzStdout, s_Payload.fStdoutAppend);
LoadStdHandleName(STD_ERROR_HANDLE, s_Payload.wzStderr, s_Payload.fStderrAppend);
s_nTraceProcessId = s_Payload.nTraceProcessId;
GetModuleFileNameA(s_hInst, s_szDllPath, ARRAYSIZE(s_szDllPath));
// Find hidden functions.
Real_PrivCopyFileExW =
(BOOL (WINAPI *)(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD))
GetProcAddress(s_hKernel32, "PrivCopyFileExW");
if (Real_PrivCopyFileExW == NULL) {
DEBUG_BREAK();
}
LONG error = AttachDetours();
if (error != NO_ERROR) {
DEBUG_BREAK();
Tblog("<!-- 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) {
Tblog("<!-- Error detaching detours: %d -->\n", error);
}
TblogClose();
if (s_nTlsIndent >= 0) {
TlsFree(s_nTlsIndent);
}
if (s_nTlsThread >= 0) {
TlsFree(s_nTlsThread);
}
return TRUE;
}
inline VOID UpdateIfRoom(PWCHAR& pwzDst, PWCHAR pwzDstEnd, WCHAR c)
{
if (pwzDst < pwzDstEnd) {
*pwzDst++ = c; // Write character if room in buffer.
}
else {
pwzDst++; // If no room, just advance pointer (to alloc calculation)
}
}
static PCHAR RemoveReturns(PCHAR pszBuffer)
{
PCHAR pszIn = pszBuffer;
PCHAR pszOut = pszBuffer;
while (*pszIn) {
if (*pszIn == '\r') {
pszIn++;
continue;
}
*pszOut++ = *pszIn++;
}
*pszOut = '\0';
return pszBuffer;
}
static PWCHAR RemoveReturns(PWCHAR pwzBuffer)
{
PWCHAR pwzIn = pwzBuffer;
PWCHAR pwzOut = pwzBuffer;
while (*pwzIn) {
if (*pwzIn == '\r') {
pwzIn++;
continue;
}
*pwzOut++ = *pwzIn++;
}
*pwzOut = '\0';
return pwzBuffer;
}
PBYTE LoadFile(HANDLE hFile, DWORD cbFile)
{
PBYTE pbFile = (PBYTE)GlobalAlloc(GPTR, cbFile + 3);
if (pbFile == NULL) {
return NULL;
}
DWORD cbRead = 0;
Real_SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
Real_ReadFile(hFile, pbFile, cbFile, &cbRead, NULL);
// Make sure the file is zero terminated.
pbFile[cbRead + 0] = 0;
pbFile[cbRead + 1] = 0;
pbFile[cbRead + 2] = 0;
return pbFile;
}
PWCHAR More(PCWSTR pwzPath, PWCHAR pwzDst, PWCHAR pwzDstEnd)
{
HANDLE hFile = Real_CreateFileW(pwzPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return NULL;
}
FileInfo *pInfo = FileNames::FindPartial(pwzPath);
pInfo->m_fAbsorbed = true;
DWORD cbFile = Real_SetFilePointer(hFile, 0, NULL, FILE_END);
DWORD cbRead = 0;
PCHAR pszFile = (PCHAR)GlobalAlloc(GPTR, cbFile + 2); // 2 bytes null for Unicode or Ascii.
if (pszFile != NULL) {
Real_SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
Real_ReadFile(hFile, pszFile, cbFile, &cbRead, NULL);
if (((PUCHAR)pszFile)[0] == 0xff && ((PUCHAR)pszFile)[1] == 0xfe) {
// Unicode
PWCHAR pwzFile = ((PWCHAR)pszFile) + 1;
PCWSTR pwzIn = pwzFile;
while (*pwzIn) {
if (*pwzIn == ' ' || *pwzIn == '\t' || *pwzIn == '\r' || *pwzIn == '\n') {
UpdateIfRoom(pwzDst, pwzDstEnd, ' ');
while (*pwzIn == ' ' || *pwzIn == '\t' || *pwzIn == '\r' || *pwzIn == '\n') {
pwzIn++;
}
}
else {
UpdateIfRoom(pwzDst, pwzDstEnd, *pwzIn++);
}
}
}
else {
PCSTR pszIn = pszFile;
while (*pszIn) {
if (*pszIn == ' ' || *pszIn == '\t' || *pszIn == '\r' || *pszIn == '\n') {
UpdateIfRoom(pwzDst, pwzDstEnd, ' ');
while (*pszIn == ' ' || *pszIn == '\t' || *pszIn == '\r' || *pszIn == '\n') {
pszIn++;
}
}
else {
UpdateIfRoom(pwzDst, pwzDstEnd, *pszIn++);
}
}
}
GlobalFree(pszFile);
}
Real_CloseHandle(hFile);
return pwzDst;
}
// This function is called twice. On the first call, pwzDstEnd <= pwzDst and
// no data is copied, but pwzDst is advanced so we can see how big of a
// buffer is needed to hold the command line.
//
// On the second call, the command line is actually populated.
PWCHAR LoadCommandLine(PCWSTR pwz, PWCHAR pwzDst, PWCHAR pwzDstEnd)
{
while (*pwz) {
PCWSTR pwzArgBeg = NULL;
PCWSTR pwzArgEnd = NULL;
WCHAR cQuote = '\0';
BOOL fMore = false;
if (*pwz == '@') {
fMore = true;
pwz++;
}
if (*pwz == '\"' || *pwz == '\'') {
cQuote = *pwz++;
pwzArgBeg = pwz;
while (*pwz != '\0' && *pwz != cQuote) {
pwz++;
}
pwzArgEnd = pwz;
if (*pwz == cQuote) {
pwz++;
}
}
else {
pwzArgBeg = pwz;
while (*pwz != '\0' && *pwz != ' ' && *pwz != '\t' && *pwz != '\n' && *pwz != '\r') {
pwz++;
}
pwzArgEnd = pwz;
}
if (fMore) {
// More arguments!
WCHAR wzPath[MAX_PATH];
PWCHAR pwzPath = wzPath;
PCWSTR pwzTmp = pwzArgBeg + 1;
while (pwzTmp < pwzArgEnd && pwzPath < wzPath + ARRAYSIZE(wzPath)-2) {
*pwzPath++ = *pwzTmp++;
}
*pwzPath = '\0';
PWCHAR pwzOut = More(wzPath, pwzDst, pwzDstEnd);
if (pwzOut != NULL) {
pwzDst = pwzOut;
cQuote = 0;
pwzArgBeg = pwzArgEnd;
}
}
if (cQuote) {
UpdateIfRoom(pwzDst, pwzDstEnd, cQuote);
}
for (; pwzArgBeg < pwzArgEnd; pwzArgBeg++) {
UpdateIfRoom(pwzDst, pwzDstEnd, *pwzArgBeg);
}
if (cQuote) {
UpdateIfRoom(pwzDst, pwzDstEnd, cQuote);
}
if (*pwz) {
UpdateIfRoom(pwzDst, pwzDstEnd, ' ');
}
// skip over separating spaces.
while (*pwz == ' ' || *pwz == '\t' || *pwz == '\n' || *pwz == '\r') {
pwz++;
}
}
return pwzDst;
}
void TestHandle(PCSTR pszName, HANDLE h)
{
FileInfo *pInfo = OpenFiles::RecallFile(h);
if (pInfo != NULL) {
#if 1 // Ignore PIPEs.
if (FileNames::PrefixMatch(pInfo->m_pwzPath, L"\\\\.\\PIPE\\")) {
// Ignore;
}
else
#endif
if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conout$")) {
// Ignore;
}
else if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conin$")) {
// Ignore;
}
else if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\nul")) {
// Ignore;
}
else {
Tblog("<%hs%hs>%le</%hs>\n",
pszName, pInfo->m_fAppend ? " append=\"true\"" : "", pInfo->m_pwzPath, pszName);
}
}
else {
Tblog("<!-- hand: %hs (%x) ***Unknown*** -->\n", pszName, h);
}
}
LONG WINAPI DetourAttachIf(PVOID *ppPointer, PVOID pDetour)
{
if (*ppPointer == NULL) {
Tblog("<!-- DetourAttachIf failed: %p -->\n", pDetour);
return NO_ERROR;
}
PDETOUR_TRAMPOLINE pRealTrampoline;
PVOID pRealTarget;
PVOID pRealDetour;
LONG err = DetourAttachEx(ppPointer, pDetour, &pRealTrampoline, &pRealTarget, &pRealDetour);
if (err == NO_ERROR) {
// Tblog("<!-- DetourAttachIf %p at %p -->\n", pDetour, pRealTarget);
return NO_ERROR;
}
return err;
}
int WINAPI Mine_EntryPoint(VOID)
{
// This function is invoked instead of the process EntryPoint (Real_EntryPoint).
TblogOpen();
SaveEnvironment();
{
CHAR szExeName[MAX_PATH];
CHAR szId[128];
CHAR szParent[128];
WCHAR wzPath[MAX_PATH];
PCHAR pszExeName = szExeName;
// Get the base command line (skipping over the executable name)
PCWSTR pwzLine = GetCommandLineW();
if (*pwzLine == '\"') {
pwzLine++;
while (*pwzLine && *pwzLine != '\"') {
pwzLine++;
}
if (*pwzLine == '\"') {
pwzLine++;
}
}
else {
while (*pwzLine && *pwzLine != ' ' && *pwzLine != '\t') {
pwzLine++;
}
}
while (*pwzLine && (*pwzLine == ' ' || *pwzLine == '\t')) {
pwzLine++;
}
// Get the root executable name.
if (GetModuleFileNameA(0, szExeName, ARRAYSIZE(szExeName))) {
PCHAR psz = szExeName;
while (*psz) {
psz++;
}
while (psz > szExeName && psz[-1] != ':' && psz[-1] != '\\' && psz[-1] != '/') {
psz--;
}
pszExeName = psz;
while (*psz && *psz != '.') {
psz++;
}
*psz = '\0';
}
else {
szExeName[0] = '\0';
}
// Start the XML process node.
Tblog("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
{
PCHAR pszId = szId;
PCHAR pszParent = szParent;
for (DWORD i = 0; i < s_Payload.nGeneology; i++) {
pszId = SafePrintf(pszId, 16, "%d.", s_Payload.rGeneology[i]);
if (i < s_Payload.nGeneology - 1) {
pszParent = SafePrintf(pszParent, 16, "%d.", s_Payload.rGeneology[i]);
}
}
*pszId = '\0';
*pszParent = '\0';
if (szParent[0] == '\0') {
Tblog("<t:Process id=\"::%hs::\"", szId);
}
else {
Tblog("<t:Process id=\"::%hs::\" parentId=\"::%hs::\"", szId, szParent);
}
Tblog(" par=\"%ls\" exe=\"%hs\"", s_Payload.wzParents, pszExeName);
BOOL drop = false;
PCWSTR pwzz = s_Payload.wzzDrop;
while (*pwzz) {
if (Compare(pwzz, pszExeName) == 0) {
// match
drop = true;
break;
}
pwzz += Size(pwzz) + 1;
}
if (drop) {
Tblog(" drop=\"true\"");
}
}
{
PWCHAR pwz = s_Payload.wzParents;
while (*pwz) {
pwz++;
}
*pwz++ = '/';
PCSTR psz = pszExeName;
while (*psz) {
*pwz++ = *psz++;
}
*pwz = '\0';
}
if (HasChar(pwzLine, '|')) {
Tblog(" pipes=\"true\"");
}
if (HasChar(pwzLine, '>')) {
Tblog(" redirects=\"true\"");
}
Tblog(" xmlns:t=\"http://schemas.microsoft.com/research/tracebld/2008\">\n");
// Get the directory.
DWORD dwSize = GetCurrentDirectoryA(ARRAYSIZE(szExeName), szExeName);
if (dwSize > 0 && dwSize < ARRAYSIZE(szExeName)) {
Tblog("<t:Directory>%hs</t:Directory>\n", szExeName);
}
// Get the real executable name.
wzPath[0] = '\0';
if (GetModuleFileNameA(0, szExeName, ARRAYSIZE(szExeName))) {
FileInfo *pInfo = FileNames::FindPartial(szExeName);
Tblog("<t:Executable>%ls</t:Executable>\n",
FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo));
}
// Construct the processed command line.
PWCHAR pwzDstEnd = (PWCHAR)pwzLine;
PWCHAR pwzDst = pwzDstEnd;
pwzDst = LoadCommandLine(pwzLine, pwzDst, pwzDstEnd);
DWORD wcNew = (DWORD)((pwzDst - pwzDstEnd) + 1);
PWCHAR pwzFin = (PWCHAR)GlobalAlloc(GPTR, wcNew * sizeof(WCHAR));
pwzDst = pwzFin;
pwzDstEnd = pwzFin + wcNew;
pwzDst = LoadCommandLine(pwzLine, pwzDst, pwzDstEnd);
*pwzDst = '\0';
FileNames::ParameterizeLine(pwzFin, pwzFin + wcNew);
if (HasSpace(wzPath)) {
Tblog("<t:Line>&quot;%le&quot; %le</t:Line>\n", wzPath, pwzFin);
}
else {
Tblog("<t:Line>%le %le</t:Line>\n", wzPath, pwzFin);
}
TestHandle("t:StdIn", GetStdHandle(STD_INPUT_HANDLE));
TestHandle("t:StdOut", GetStdHandle(STD_OUTPUT_HANDLE));
TestHandle("t:StdErr", GetStdHandle(STD_ERROR_HANDLE));
}
if (FindMsvcr()) {
FindProc(&(PVOID&)Real_getenv, "getenv");
FindProc(&(PVOID&)Real_wgetenv, "_wgetenv");
FindProc(&(PVOID&)Real_getenv_s, "getenv_s");
FindProc(&(PVOID&)Real_wgetenv_s, "_wgetenv_s");
FindProc(&(PVOID&)Real_dupenv_s, "_dupenv_s");
FindProc(&(PVOID&)Real_wdupenv_s, "_wdupenv_s");
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttachIf(&(PVOID&)Real_getenv, Mine_getenv);
DetourAttachIf(&(PVOID&)Real_getenv_s, Mine_getenv_s);
DetourAttachIf(&(PVOID&)Real_wgetenv, Mine_wgetenv);
DetourAttachIf(&(PVOID&)Real_wgetenv, Mine_wgetenv_s);
DetourAttachIf(&(PVOID&)Real_dupenv_s, Mine_dupenv_s);
DetourAttachIf(&(PVOID&)Real_wdupenv_s, Mine_wdupenv_s);
DetourTransactionCommit();
}
return Real_EntryPoint();
}
VOID WINAPI Mine_ExitProcess(UINT a0)
{
if (a0 & 0x80000000) {
Tblog("<t:Return>%d</t:Return>\n", -(int)a0);
}
else {
Tblog("<t:Return>%d</t:Return>\n", a0);
}
FileNames::Dump();
EnvVars::Dump();
TblogClose();
Real_ExitProcess(a0);
}
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, PVOID lpReserved)
{
(void)hModule;
(void)lpReserved;
if (DetourIsHelperProcess()) {
return TRUE;
}
if (dwReason == DLL_PROCESS_ATTACH) {
DetourRestoreAfterWith();
Real_EntryPoint = (int (WINAPI *)(VOID))DetourGetEntryPoint(NULL);
return ProcessAttach(hModule);
}
else if (dwReason == DLL_PROCESS_DETACH) {
return ProcessDetach(hModule);
}
else if (dwReason == DLL_THREAD_ATTACH) {
return ThreadAttach(hModule);
}
else if (dwReason == DLL_THREAD_DETACH) {
return ThreadDetach(hModule);
}
return TRUE;
}
//
///////////////////////////////////////////////////////////////// End of File.