diff --git a/src/compat/dir_mutex.c b/src/compat/dir_mutex.c index 8e02fa756..d64d211c9 100644 --- a/src/compat/dir_mutex.c +++ b/src/compat/dir_mutex.c @@ -51,9 +51,13 @@ void dir_mutex_lock(int dfd) if(dir_mutex_enabled) pthread_mutex_lock(&dir_mutex); + // AT_FDCWD + if (dfd == -100) + return; + if(fchdir(dfd) < 0) { perror("fchdir"); - fprintf(stderr, "tup error: Failed to fchdir in a compat wrapper function.\n"); + fprintf(stderr, "tup error: Failed to fchdir in a compat wrapper function at %p.\n", __builtin_return_address(0)); exit(1); } } diff --git a/src/compat/fstatat.c b/src/compat/fstatat.c index d74322d3f..616dae87f 100644 --- a/src/compat/fstatat.c +++ b/src/compat/fstatat.c @@ -23,27 +23,39 @@ #include #include #include +#include "tup/compat.h" #include "dir_mutex.h" -#ifdef _WIN32 -#include "open_notify.h" -#endif int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags) { int rc; +#ifdef _WINDOWS + char cwd[PATH_MAX]; + getcwd(cwd, PATH_MAX); +#endif dir_mutex_lock(dirfd); + // No symlinks on windows... if(flags & AT_SYMLINK_NOFOLLOW) { -#ifdef _WIN32 - open_notify(ACCESS_READ, pathname); -#endif +#if defined(_WIN64) + rc = _stat64(pathname, buf); +#elif defined(_WIN32) + rc = _stat32(pathname, buf); +#else rc = lstat(pathname, buf); - } else { -#ifdef _WIN32 - open_notify(ACCESS_READ, pathname); #endif + } else { +#if defined(_WIN64) + rc = _stat64(pathname, buf); +#elif defined(_WIN32) + rc = _stat32(pathname, buf); +#else rc = stat(pathname, buf); +#endif } +#ifdef _WINDOWS + chdir(cwd); +#endif dir_mutex_unlock(); return rc; } diff --git a/src/compat/mkdirat.c b/src/compat/mkdirat.c index 690e9a46f..e58fdbeed 100644 --- a/src/compat/mkdirat.c +++ b/src/compat/mkdirat.c @@ -22,6 +22,7 @@ #include #include #include +#include "tup/compat.h" #include "dir_mutex.h" #ifdef _WIN32 @@ -31,11 +32,17 @@ int mkdirat(int dirfd, const char *pathname, mode_t mode) { int rc; - +#ifdef _WINDOWS + char cwd[PATH_MAX]; + getcwd(cwd, PATH_MAX); +#endif if(mode) {/* for win32 */} dir_mutex_lock(dirfd); rc = mkdir(pathname, mode); +#ifdef _WINDOWS + chdir(cwd); +#endif dir_mutex_unlock(); return rc; } diff --git a/src/compat/openat.c b/src/compat/openat.c index 76b08f99a..0eddbf100 100644 --- a/src/compat/openat.c +++ b/src/compat/openat.c @@ -22,13 +22,17 @@ #include #include #include +#include "tup/compat.h" #include "dir_mutex.h" int openat(int dirfd, const char *pathname, int flags, ...) { int fd; mode_t mode = 0; - +#ifdef _WINDOWS + char cwd[PATH_MAX]; + getcwd(cwd, PATH_MAX); +#endif dir_mutex_lock(dirfd); if(flags & O_CREAT) { va_list ap; @@ -37,6 +41,9 @@ int openat(int dirfd, const char *pathname, int flags, ...) va_end(ap); } fd = open(pathname, flags, mode); +#ifdef _WINDOWS + chdir(cwd); +#endif dir_mutex_unlock(); return fd; } diff --git a/src/compat/unlinkat.c b/src/compat/unlinkat.c index 53d72e3bc..006df195a 100644 --- a/src/compat/unlinkat.c +++ b/src/compat/unlinkat.c @@ -21,17 +21,24 @@ #include #include #include +#include "tup/compat.h" #include "dir_mutex.h" int unlinkat(int dirfd, const char *pathname, int flags) { int rc; - +#ifdef _WINDOWS + char cwd[PATH_MAX]; + getcwd(cwd, PATH_MAX); +#endif dir_mutex_lock(dirfd); if(flags == AT_REMOVEDIR) rc = rmdir(pathname); else rc = unlink(pathname); +#ifdef _WINDOWS + chdir(cwd); +#endif dir_mutex_unlock(); return rc; } diff --git a/src/compat/win32/wow64.h b/src/compat/win32/wow64.h index 6ee276c77..ce8799f25 100644 --- a/src/compat/win32/wow64.h +++ b/src/compat/win32/wow64.h @@ -1,9 +1,14 @@ +#ifdef _WIN64 #ifndef tup_win32_wow64_h #define tup_win32_wow64_h #define WOW64_CONTEXT_i386 0x00010000 #define WOW64_CONTEXT_CONTROL (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000001)) +#define WOW64_MAXIMUM_SUPPORTED_EXTENSION 512 +#define WOW64_SIZE_OF_80387_REGISTERS 80 + BOOL WINAPI Wow64GetThreadContext(HANDLE hThread, PWOW64_CONTEXT lpContext); BOOL WINAPI Wow64SetThreadContext(HANDLE hThread, const WOW64_CONTEXT *lpContext); #endif +#endif diff --git a/src/dllinject/dllinject.c b/src/dllinject/dllinject.c index d9012b13c..a9150b05f 100644 --- a/src/dllinject/dllinject.c +++ b/src/dllinject/dllinject.c @@ -53,279 +53,445 @@ #define __reserved #endif -typedef HFILE (WINAPI *OpenFile_t)( - __in LPCSTR lpFileName, - __inout LPOFSTRUCT lpReOpenBuff, - __in UINT uStyle); - -typedef BOOL (WINAPI *DeleteFileA_t)( - __in LPCSTR lpFileName); - -typedef BOOL (WINAPI *DeleteFileW_t)( - __in LPCWSTR lpFileName); - -typedef BOOL (WINAPI *DeleteFileTransactedA_t)( - __in LPCSTR lpFileName, - __in HANDLE hTransaction); - -typedef BOOL (WINAPI *DeleteFileTransactedW_t)( - __in LPCWSTR lpFileName, - __in HANDLE hTransaction); - -typedef BOOL (WINAPI *MoveFileA_t)( - __in LPCSTR lpExistingFileName, - __in LPCSTR lpNewFileName); - -typedef BOOL (WINAPI *MoveFileW_t)( - __in LPCWSTR lpExistingFileName, - __in LPCWSTR lpNewFileName); - -typedef BOOL (WINAPI *MoveFileExA_t)( - __in LPCSTR lpExistingFileName, - __in_opt LPCSTR lpNewFileName, - __in DWORD dwFlags); - -typedef BOOL (WINAPI *MoveFileExW_t)( - __in LPCWSTR lpExistingFileName, - __in_opt LPCWSTR lpNewFileName, - __in DWORD dwFlags); - -typedef BOOL (WINAPI *MoveFileWithProgressA_t)( - __in LPCSTR lpExistingFileName, - __in_opt LPCSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in DWORD dwFlags); - -typedef BOOL (WINAPI *MoveFileWithProgressW_t)( - __in LPCWSTR lpExistingFileName, - __in_opt LPCWSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in DWORD dwFlags); - -typedef BOOL (WINAPI *MoveFileTransactedA_t)( - __in LPCSTR lpExistingFileName, - __in_opt LPCSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in DWORD dwFlags, - __in HANDLE hTransaction); +#define countof(arr) (sizeof(arr) / sizeof(arr[0])) +#define safewcpy(dest, src) wcsncpy(dest, src, countof(dest)) + +typedef HFILE(WINAPI *OpenFile_t)( + __in LPCSTR lpFileName, + __inout LPOFSTRUCT lpReOpenBuff, + __in UINT uStyle); + +#if 0 +typedef HANDLE(WINAPI *CreateFileA_t)( + __in LPCSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile); + +typedef HANDLE(WINAPI *CreateFileW_t)( + __in LPCWSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile); + +typedef HANDLE(WINAPI *CreateFileTransactedA_t)( + __in LPCSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile, + __in HANDLE hTransaction, + __in_opt PUSHORT pusMiniVersion, + __reserved PVOID lpExtendedParameter); + +typedef HANDLE(WINAPI *CreateFileTransactedW_t)( + __in LPCWSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile, + __in HANDLE hTransaction, + __in_opt PUSHORT pusMiniVersion, + __reserved PVOID lpExtendedParameter); +#endif -typedef BOOL (WINAPI *MoveFileTransactedW_t)( - __in LPCWSTR lpExistingFileName, - __in_opt LPCWSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in DWORD dwFlags, - __in HANDLE hTransaction); +typedef BOOL(WINAPI *DeleteFileA_t)( + __in LPCSTR lpFileName); + +typedef BOOL(WINAPI *DeleteFileW_t)( + __in LPCWSTR lpFileName); + +typedef BOOL(WINAPI *DeleteFileTransactedA_t)( + __in LPCSTR lpFileName, + __in HANDLE hTransaction); + +typedef BOOL(WINAPI *DeleteFileTransactedW_t)( + __in LPCWSTR lpFileName, + __in HANDLE hTransaction); + +typedef BOOL(WINAPI *MoveFileA_t)( + __in LPCSTR lpExistingFileName, + __in LPCSTR lpNewFileName); + +typedef BOOL(WINAPI *MoveFileW_t)( + __in LPCWSTR lpExistingFileName, + __in LPCWSTR lpNewFileName); + +typedef BOOL(WINAPI *MoveFileExA_t)( + __in LPCSTR lpExistingFileName, + __in_opt LPCSTR lpNewFileName, + __in DWORD dwFlags); + +typedef BOOL(WINAPI *MoveFileExW_t)( + __in LPCWSTR lpExistingFileName, + __in_opt LPCWSTR lpNewFileName, + __in DWORD dwFlags); + +typedef BOOL(WINAPI *MoveFileWithProgressA_t)( + __in LPCSTR lpExistingFileName, + __in_opt LPCSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in DWORD dwFlags); + +typedef BOOL(WINAPI *MoveFileWithProgressW_t)( + __in LPCWSTR lpExistingFileName, + __in_opt LPCWSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in DWORD dwFlags); + +typedef BOOL(WINAPI *MoveFileTransactedA_t)( + __in LPCSTR lpExistingFileName, + __in_opt LPCSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in DWORD dwFlags, + __in HANDLE hTransaction); + +typedef BOOL(WINAPI *MoveFileTransactedW_t)( + __in LPCWSTR lpExistingFileName, + __in_opt LPCWSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in DWORD dwFlags, + __in HANDLE hTransaction); + +typedef BOOL(WINAPI *ReplaceFileA_t)( + __in LPCSTR lpReplacedFileName, + __in LPCSTR lpReplacementFileName, + __in_opt LPCSTR lpBackupFileName, + __in DWORD dwReplaceFlags, + __reserved LPVOID lpExclude, + __reserved LPVOID lpReserved); + +typedef BOOL(WINAPI *ReplaceFileW_t)( + __in LPCWSTR lpReplacedFileName, + __in LPCWSTR lpReplacementFileName, + __in_opt LPCWSTR lpBackupFileName, + __in DWORD dwReplaceFlags, + __reserved LPVOID lpExclude, + __reserved LPVOID lpReserved); + +typedef BOOL(WINAPI *CopyFileA_t)( + __in LPCSTR lpExistingFileName, + __in LPCSTR lpNewFileName, + __in BOOL bFailIfExists); + +typedef BOOL(WINAPI *CopyFileW_t)( + __in LPCWSTR lpExistingFileName, + __in LPCWSTR lpNewFileName, + __in BOOL bFailIfExists); + +typedef BOOL(WINAPI *CopyFileExA_t)( + __in LPCSTR lpExistingFileName, + __in LPCSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in_opt LPBOOL pbCancel, + __in DWORD dwCopyFlags); + +typedef BOOL(WINAPI *CopyFileExW_t)( + __in LPCWSTR lpExistingFileName, + __in LPCWSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in_opt LPBOOL pbCancel, + __in DWORD dwCopyFlags); + +typedef BOOL(WINAPI *CopyFileTransactedA_t)( + __in LPCSTR lpExistingFileName, + __in LPCSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in_opt LPBOOL pbCancel, + __in DWORD dwCopyFlags, + __in HANDLE hTransaction); + +typedef BOOL(WINAPI *CopyFileTransactedW_t)( + __in LPCWSTR lpExistingFileName, + __in LPCWSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in_opt LPBOOL pbCancel, + __in DWORD dwCopyFlags, + __in HANDLE hTransaction); + +typedef DWORD(WINAPI *GetFileAttributesA_t)( + __in LPCSTR lpFileName); + +typedef DWORD(WINAPI *GetFileAttributesW_t)( + __in LPCWSTR lpFileName); + +typedef BOOL(WINAPI *GetFileAttributesExA_t)( + __in LPCSTR lpFileName, + __in GET_FILEEX_INFO_LEVELS fInfoLevelId, + __out LPVOID lpFileInformation); + +typedef BOOL(WINAPI *GetFileAttributesExW_t)( + __in LPCWSTR lpFileName, + __in GET_FILEEX_INFO_LEVELS fInfoLevelId, + __out LPVOID lpFileInformation); + +typedef __out HANDLE(WINAPI *FindFirstFileA_t)( + __in LPCSTR lpFileName, + __out LPWIN32_FIND_DATAA lpFindFileData); + +typedef __out HANDLE(WINAPI *FindFirstFileW_t)( + __in LPCWSTR lpFileName, + __out LPWIN32_FIND_DATAW lpFindFileData); + +typedef BOOL(WINAPI *FindNextFileA_t)( + __in HANDLE hFindFile, + __out LPWIN32_FIND_DATAA lpFindFileData); + +typedef BOOL(WINAPI *FindNextFileW_t)( + __in HANDLE hFindFile, + __out LPWIN32_FIND_DATAW lpFindFileData); -typedef BOOL (WINAPI *ReplaceFileA_t)( - __in LPCSTR lpReplacedFileName, - __in LPCSTR lpReplacementFileName, - __in_opt LPCSTR lpBackupFileName, - __in DWORD dwReplaceFlags, - __reserved LPVOID lpExclude, - __reserved LPVOID lpReserved); +typedef BOOL (WINAPI *CreateProcessA_t)( + __in_opt LPCSTR lpApplicationName, + __inout_opt LPSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCSTR lpCurrentDirectory, + __in LPSTARTUPINFOA lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation); -typedef BOOL (WINAPI *ReplaceFileW_t)( - __in LPCWSTR lpReplacedFileName, - __in LPCWSTR lpReplacementFileName, - __in_opt LPCWSTR lpBackupFileName, - __in DWORD dwReplaceFlags, - __reserved LPVOID lpExclude, - __reserved LPVOID lpReserved); +typedef BOOL (WINAPI * CreateProcessW_t)( + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation); -typedef BOOL (WINAPI *CopyFileA_t)( - __in LPCSTR lpExistingFileName, - __in LPCSTR lpNewFileName, - __in BOOL bFailIfExists); +typedef BOOL (WINAPI *CreateProcessAsUserA_t)( + __in_opt HANDLE hToken, + __in_opt LPCSTR lpApplicationName, + __inout_opt LPSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCSTR lpCurrentDirectory, + __in LPSTARTUPINFOA lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation); -typedef BOOL (WINAPI *CopyFileW_t)( - __in LPCWSTR lpExistingFileName, - __in LPCWSTR lpNewFileName, - __in BOOL bFailIfExists); +typedef BOOL (WINAPI *CreateProcessAsUserW_t)( + __in_opt HANDLE hToken, + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation + ); -typedef BOOL (WINAPI *CopyFileExA_t)( - __in LPCSTR lpExistingFileName, - __in LPCSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in_opt LPBOOL pbCancel, - __in DWORD dwCopyFlags); +typedef BOOL (WINAPI *CreateProcessWithLogonW_t)( + __in LPCWSTR lpUsername, + __in_opt LPCWSTR lpDomain, + __in LPCWSTR lpPassword, + __in DWORD dwLogonFlags, + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation); -typedef BOOL (WINAPI *CopyFileExW_t)( - __in LPCWSTR lpExistingFileName, - __in LPCWSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in_opt LPBOOL pbCancel, - __in DWORD dwCopyFlags); +typedef BOOL (WINAPI *CreateProcessWithTokenW_t)( + __in HANDLE hToken, + __in DWORD dwLogonFlags, + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation); + +typedef NTSTATUS(WINAPI *NtOpenFile_t)( + __out PHANDLE FileHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __out PIO_STATUS_BLOCK IoStatusBlock, + __in ULONG ShareAccess, + __in ULONG OpenOptions); + +typedef NTSTATUS(WINAPI *NtCreateFile_t)( + __out PHANDLE FileHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __out PIO_STATUS_BLOCK IoStatusBlock, + __in_opt PLARGE_INTEGER AllocationSize, + __in ULONG FileAttributes, + __in ULONG ShareAccess, + __in ULONG CreateDisposition, + __in ULONG CreateOptions, + __in PVOID EaBuffer, + __in ULONG EaLength); + +typedef NTSTATUS(WINAPI *NtCreateUserProcess_t)( + PHANDLE ProcessHandle, + PHANDLE ThreadHandle, + ACCESS_MASK ProcessDesiredAccess, + ACCESS_MASK ThreadDesiredAccess, + POBJECT_ATTRIBUTES ProcessObjectAttributes, + POBJECT_ATTRIBUTES ThreadObjectAttributes, + ULONG ProcessFlags, + ULONG ThreadFlags, + PRTL_USER_PROCESS_PARAMETERS ProcessParameters, + ULONG_PTR CreateInfo, + ULONG_PTR AttributeList + ); + +typedef int(*access_t)(const char *pathname, int mode); +typedef FILE *(*fopen_t)(const char *path, const char *mode); +typedef int(*rename_t)(const char *oldpath, const char *newpath); +typedef int(*remove_t)(const char *pathname); +typedef int(*stat64_t)(const char *path, void *buffer); +typedef int(*stat32_t)(const char *path, void *buffer); + +static int canon_path(const wchar_t *file, int filelen, char *dest); +static int canon_path_w(const wchar_t *file, int filelen, wchar_t *dest); + +static wchar_t execdir[MAX_PATH]; +static wchar_t tuptopdir[MAX_PATH]; + +typedef struct variant_dir variant_dir; + +struct variant_dir { + wchar_t *name; + variant_dir *next; +}; -typedef BOOL (WINAPI *CopyFileTransactedA_t)( - __in LPCSTR lpExistingFileName, - __in LPCSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in_opt LPBOOL pbCancel, - __in DWORD dwCopyFlags, - __in HANDLE hTransaction); +static variant_dir *TupVariants = NULL; +static HANDLE hHeap = INVALID_HANDLE_VALUE; -typedef BOOL (WINAPI *CopyFileTransactedW_t)( - __in LPCWSTR lpExistingFileName, - __in LPCWSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in_opt LPBOOL pbCancel, - __in DWORD dwCopyFlags, - __in HANDLE hTransaction); +static void *MemoryPool = NULL; +static size_t TotalMemory = 4096 * 4096; +static size_t CurrentAllocatedMemory = 0; +static HANDLE hMemoryLock; -typedef DWORD (WINAPI *GetFileAttributesA_t)( - __in LPCSTR lpFileName); -typedef DWORD (WINAPI *GetFileAttributesW_t)( - __in LPCWSTR lpFileName); +/* + * This memory allocator (which is really rudimentary) is used to avoid + * generating heap corruptions. At some point we should really track + * down the root cause of the the corruption instead of using this hack. + */ +static void *dll_malloc(size_t size) +{ + if (hHeap == INVALID_HANDLE_VALUE) { + DEBUG_HOOK("FAILURE: dll_malloc called without heap\n"); + return NULL; + } -typedef BOOL (WINAPI *GetFileAttributesExA_t)( - __in LPCSTR lpFileName, - __in GET_FILEEX_INFO_LEVELS fInfoLevelId, - __out LPVOID lpFileInformation); + if(size == 0) { + DEBUG_HOOK("FAILURE: dll_malloc called with size 0\n"); + } -typedef BOOL (WINAPI *GetFileAttributesExW_t)( - __in LPCWSTR lpFileName, - __in GET_FILEEX_INFO_LEVELS fInfoLevelId, - __out LPVOID lpFileInformation); + WaitForSingleObject(hMemoryLock, INFINITE); -typedef __out HANDLE (WINAPI *FindFirstFileA_t)( - __in LPCSTR lpFileName, - __out LPWIN32_FIND_DATAA lpFindFileData); + void *memory = NULL; + // align memory to 16 byte boundary + size_t realSize = (size + 0x0F) & ~0x0F; -typedef __out HANDLE (WINAPI *FindFirstFileW_t)( - __in LPCWSTR lpFileName, - __out LPWIN32_FIND_DATAW lpFindFileData); + if ((realSize + CurrentAllocatedMemory) > TotalMemory) { + DEBUG_HOOK("FAILURE: OUT OF MEMORY\n"); + goto out; + } -typedef BOOL (WINAPI *FindNextFileA_t)( - __in HANDLE hFindFile, - __out LPWIN32_FIND_DATAA lpFindFileData); + memory = (void*)((size_t)MemoryPool + CurrentAllocatedMemory); + CurrentAllocatedMemory += realSize; -typedef BOOL (WINAPI *FindNextFileW_t)( - __in HANDLE hFindFile, - __out LPWIN32_FIND_DATAW lpFindFileData); +out: + ReleaseMutex(hMemoryLock); -typedef BOOL (WINAPI *CreateProcessA_t)( - __in_opt LPCSTR lpApplicationName, - __inout_opt LPSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCSTR lpCurrentDirectory, - __in LPSTARTUPINFOA lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation); + //DEBUG_HOOK("Allocating %d bytes memory\n", size); + //size_t realSize = (size + 0x0F) & ~0x0F; + //memory = HeapAlloc(hHeap, 0, realSize); + //if (memory == NULL) { + // DEBUG_HOOK("DllMalloc failed\n"); + //} + return memory; +} -typedef BOOL (WINAPI * CreateProcessW_t)( - __in_opt LPCWSTR lpApplicationName, - __inout_opt LPWSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCWSTR lpCurrentDirectory, - __in LPSTARTUPINFOW lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation); +static void dll_free(void *memory) +{ + if (hHeap == INVALID_HANDLE_VALUE) { + DEBUG_HOOK("dll_free called without heap\n"); + return; + } -typedef BOOL (WINAPI *CreateProcessAsUserA_t)( - __in_opt HANDLE hToken, - __in_opt LPCSTR lpApplicationName, - __inout_opt LPSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCSTR lpCurrentDirectory, - __in LPSTARTUPINFOA lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation); + if (memory) {} -typedef BOOL (WINAPI *CreateProcessAsUserW_t)( - __in_opt HANDLE hToken, - __in_opt LPCWSTR lpApplicationName, - __inout_opt LPWSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCWSTR lpCurrentDirectory, - __in LPSTARTUPINFOW lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation - ); + //BOOL rc = HeapFree(hHeap, 0, memory); + //if (!rc) { + // DEBUG_HOOK("DllFree faile\n"); + //} +} -typedef BOOL (WINAPI *CreateProcessWithLogonW_t)( - __in LPCWSTR lpUsername, - __in_opt LPCWSTR lpDomain, - __in LPCWSTR lpPassword, - __in DWORD dwLogonFlags, - __in_opt LPCWSTR lpApplicationName, - __inout_opt LPWSTR lpCommandLine, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCWSTR lpCurrentDirectory, - __in LPSTARTUPINFOW lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation); +#define HAS_VARIANTS() ({DEBUG_HOOK("VarCheck in: %s:%d\n", __FUNCTION__, __LINE__); (TupVariants != NULL);}) +//#define HAS_VARIANTS() (TupVariants != NULL) -typedef BOOL (WINAPI *CreateProcessWithTokenW_t)( - __in HANDLE hToken, - __in DWORD dwLogonFlags, - __in_opt LPCWSTR lpApplicationName, - __inout_opt LPWSTR lpCommandLine, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCWSTR lpCurrentDirectory, - __in LPSTARTUPINFOW lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation); - -typedef NTSTATUS (WINAPI *NtOpenFile_t)( - __out PHANDLE FileHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __out PIO_STATUS_BLOCK IoStatusBlock, - __in ULONG ShareAccess, - __in ULONG OpenOptions); +static BOOL add_variant(const wchar_t *path) +{ + wchar_t canonical_path[PATH_MAX]; + canon_path_w(path, wcslen(path), canonical_path); + DEBUG_HOOK("Adding variant %S -> canonical: %S\n", path, canonical_path); -typedef NTSTATUS (WINAPI *NtCreateFile_t)( - __out PHANDLE FileHandle, - __in ACCESS_MASK DesiredAccess, - __in POBJECT_ATTRIBUTES ObjectAttributes, - __out PIO_STATUS_BLOCK IoStatusBlock, - __in_opt PLARGE_INTEGER AllocationSize, - __in ULONG FileAttributes, - __in ULONG ShareAccess, - __in ULONG CreateDisposition, - __in ULONG CreateOptions, - __in PVOID EaBuffer, - __in ULONG EaLength); + variant_dir *dir = dll_malloc(sizeof(variant_dir)); + if (dir == NULL) + return FALSE; -typedef NTSTATUS (WINAPI *NtCreateUserProcess_t)( -PHANDLE ProcessHandle, -PHANDLE ThreadHandle, -ACCESS_MASK ProcessDesiredAccess, -ACCESS_MASK ThreadDesiredAccess, -POBJECT_ATTRIBUTES ProcessObjectAttributes, -POBJECT_ATTRIBUTES ThreadObjectAttributes, -ULONG ProcessFlags, -ULONG ThreadFlags, -PRTL_USER_PROCESS_PARAMETERS ProcessParameters, -ULONG_PTR CreateInfo, -ULONG_PTR AttributeList -); + dir->name = dll_malloc(sizeof(wchar_t) * (wcslen(canonical_path) + 1)); + if (dir->name == NULL) + return FALSE; + wcscpy(dir->name, canonical_path); + dir->next = NULL; -typedef int (*rename_t)(const char *oldpath, const char *newpath); + if (TupVariants == NULL) + TupVariants = dir; + else { + variant_dir *ptr = TupVariants; + while (ptr->next != NULL) ptr = ptr->next; + ptr->next = dir; + } + return TRUE; +} static OpenFile_t OpenFile_orig; +#if 0 +static CreateFileA_t CreateFileA_orig; +static CreateFileW_t CreateFileW_orig; +static CreateFileTransactedA_t CreateFileTransactedA_orig; +static CreateFileTransactedW_t CreateFileTransactedW_orig; +#endif static DeleteFileA_t DeleteFileA_orig; static DeleteFileW_t DeleteFileW_orig; static DeleteFileTransactedA_t DeleteFileTransactedA_orig; @@ -363,7 +529,12 @@ static CreateProcessWithTokenW_t CreateProcessWithTokenW_orig; static NtCreateFile_t NtCreateFile_orig; static NtOpenFile_t NtOpenFile_orig; static NtCreateUserProcess_t NtCreateUserProcess_orig; +static access_t _access_orig; +static fopen_t fopen_orig; static rename_t rename_orig; +static remove_t remove_orig; +static stat64_t _stat64_orig; +static stat32_t _stat32_orig; #define TUP_CREATE_WRITE_FLAGS (GENERIC_WRITE | FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES) /* Including ddk/wdm.h causes other issues, and this is all we need... */ @@ -373,49 +544,456 @@ static rename_t rename_orig; #define handle_file_w(a, b, c, d) mhandle_file_w(a, b, c, d, __LINE__) static void mhandle_file(const char* file, const char* file2, enum access_type at, int line); static void mhandle_file_w(const wchar_t* file, int filelen, const wchar_t* file2, enum access_type at, int line); - static const char *strcasestr(const char *arg1, const char *arg2); static const wchar_t *wcscasestr(const wchar_t *arg1, const wchar_t *arg2); +static int tup_inject_dll_w(LPPROCESS_INFORMATION lpProcessInformation, const wchar_t *depfilename, const wchar_t *vardict_file); -static char s_depfilename[PATH_MAX]; -static char s_vardict_file[PATH_MAX]; +static wchar_t s_depfilename[PATH_MAX]; +static wchar_t s_vardict_file[PATH_MAX]; static HANDLE deph = INVALID_HANDLE_VALUE; +static HANDLE vardicth = INVALID_HANDLE_VALUE; static int writef(const char *data, unsigned int len) { int rc = 0; DWORD num_written; - if(!WriteFile(deph, data, len, &num_written, NULL)) { + if (!WriteFile(deph, data, len, &num_written, NULL)) { DEBUG_HOOK("failed to write %i bytes\n", len); rc = -1; } - if(num_written != len) { + if (num_written != len) { DEBUG_HOOK("failed to write exactly %i bytes\n", len); rc = -1; } return rc; } +static int wchar_to_ansi(const wchar_t* uni, char* outstr, int outlen) +{ + int len = WideCharToMultiByte(CP_UTF8, 0, uni, -1, 0, 0, NULL, NULL); + if (len >= outlen) + return -1; + if (!WideCharToMultiByte(CP_UTF8, 0, uni, -1, outstr, outlen, NULL, NULL)) + return -1; + return len; +} + +static int ansi_to_wchar(const char *instr, wchar_t *outstr, int outlen) +{ + int len = MultiByteToWideChar(CP_UTF8, 0, instr, -1, NULL, 0); + if (len >= outlen) + return -1; + if (MultiByteToWideChar(CP_UTF8, 0, instr, -1, outstr, outlen) < 0) + return -1; + return len; +} + +static PUNICODE_STRING unicode_from_wstr(LPCWSTR wstr) +{ + PUNICODE_STRING outstr = dll_malloc(sizeof(UNICODE_STRING)); + if (outstr == NULL) + return NULL; + + outstr->Length = outstr->MaximumLength = wcslen(wstr) * sizeof(wchar_t); + outstr->Buffer = dll_malloc(outstr->Length + sizeof(wchar_t)); // extra character for the null-terminator + if (!outstr->Buffer) + return NULL; + + wcscpy(outstr->Buffer, wstr); + return outstr; +} + +static int variant_to_source_w(const wchar_t *fileName, wchar_t *dest, int destlen) +{ + wchar_t *src, *dst; + + variant_dir *dir = TupVariants; + int found = 0; + + if (destlen < PATH_MAX) {} + + if (!canon_path_w(fileName, wcslen(fileName), dest)) + return -1; + + while (dir != NULL) { + if (_wcsnicmp(dest, dir->name, wcslen(dir->name)) == 0) { + found = 1; + break; + } + dir = dir->next; + } + + if (!found) { + DEBUG_HOOK("FAILURE to match a variant path to a variant dir\n";) + return -1; + } + + // Remove variant directory + dst = dest + wcslen(tuptopdir); + dst++; + + src = wcschr(dst, L'\\'); + src++; + + wcscpy(dst, src); + DEBUG_HOOK("Resolved variant path '%S' to '%S'\n", fileName, dest); + return 0; +} + +static int variant_to_source(const char *fileName, char *dest, int destlen) +{ + wchar_t wFilename[MAX_PATH], realFile[MAX_PATH]; + + if (ansi_to_wchar(fileName, wFilename, MAX_PATH) < 0) { + return -1; + } + if (variant_to_source_w(wFilename, realFile, MAX_PATH) != 0) { + return -1; + } + if (wchar_to_ansi(realFile, dest, destlen) < 0) { + return -1; + } + return 0; +} + +static int variant_to_sourceOA(POBJECT_ATTRIBUTES original, POBJECT_ATTRIBUTES *variant) +{ + wchar_t realName[MAX_PATH]; + PUNICODE_STRING origPath = original->ObjectName; + PUNICODE_STRING resolvedPath = NULL; + + // NT Paths need \??\ prefix to be valid + wcscpy(realName, L"\\??\\"); + if (variant_to_source_w(origPath->Buffer, realName + 4, MAX_PATH - 4) != 0) { + DEBUG_HOOK("UNABLE to resolve '%.*ls'\n", origPath->Length/2, origPath->Buffer); + goto error; + } + + resolvedPath = unicode_from_wstr(realName); + if (resolvedPath == NULL) { + goto error; + } + + (*variant) = dll_malloc(sizeof(OBJECT_ATTRIBUTES)); + if ((*variant) == NULL) { + goto error; + } + + InitializeObjectAttributes(*variant, resolvedPath, original->Attributes, NULL, original->SecurityDescriptor); + return 0; + +error: + DEBUG_HOOK("FAILURE in %s: %S\n", __FUNCTION__, realName); + if (resolvedPath != NULL) { + if (resolvedPath->Buffer != NULL) + dll_free(resolvedPath->Buffer); + dll_free(resolvedPath); + } + return -1; +} + +static void free_object_attribute(POBJECT_ATTRIBUTES attrib) +{ + if (attrib != NULL) { + if (attrib->ObjectName != NULL) { + if (attrib->ObjectName->Buffer != NULL) + dll_free(attrib->ObjectName->Buffer); + dll_free(attrib->ObjectName); + } + dll_free(attrib); + } +} + static HFILE WINAPI OpenFile_hook( - __in LPCSTR lpFileName, - __inout LPOFSTRUCT lpReOpenBuff, - __in UINT uStyle) + __in LPCSTR lpFileName, + __inout LPOFSTRUCT lpReOpenBuff, + __in UINT uStyle) { + char realName[PATH_MAX]; + LPCSTR fileName = lpFileName; + HFILE f; + DWORD err; + + f = OpenFile_orig( + fileName, + lpReOpenBuff, + uStyle); + + if (f == HFILE_ERROR && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(fileName, realName, PATH_MAX) == 0) { + fileName = realName; + f = OpenFile_orig( + fileName, + lpReOpenBuff, + uStyle); + } + if (f == HFILE_ERROR) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s %s (%s)\n", __FUNCTION__, fileName, f != HFILE_ERROR ? "SUCCESS" : "FAILED"); + if (uStyle & OF_DELETE) { - handle_file(lpFileName, NULL, ACCESS_UNLINK); + handle_file(fileName, NULL, ACCESS_UNLINK); } else if (uStyle & (OF_READWRITE | OF_WRITE | OF_SHARE_DENY_WRITE | OF_SHARE_EXCLUSIVE | OF_CREATE)) { - handle_file(lpFileName, NULL, ACCESS_WRITE); + handle_file(fileName, NULL, ACCESS_WRITE); } else { - handle_file(lpFileName, NULL, ACCESS_READ); + handle_file(fileName, NULL, ACCESS_READ); } - return OpenFile_orig( + return f; +} + +#if 0 +static HANDLE WINAPI CreateFileA_hook( + __in LPCSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile) +{ + LPCSTR fileName = lpFileName; + char realName[PATH_MAX]; + DWORD lastError; + + HANDLE h = CreateFileA_orig( + fileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile); + + if (h == INVALID_HANDLE_VALUE && HAS_VARIANTS()) { + lastError = GetLastError(); + if (variant_to_source(lpFileName, realName, PATH_MAX) == 0) { + fileName = realName; + h = CreateFileA_orig( + fileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile); + } + if (h == INVALID_HANDLE_VALUE) { + SetLastError(lastError); + fileName = lpFileName; + } + } + + DEBUG_HOOK("CreateFileA '%s', %p:%X, %x, %x, %x, %x\n", + fileName, + h, + GetLastError(), + dwDesiredAccess, + dwShareMode, + dwCreationDisposition, + dwFlagsAndAttributes); + + if (h != INVALID_HANDLE_VALUE && dwDesiredAccess & TUP_CREATE_WRITE_FLAGS) { + handle_file(fileName, NULL, ACCESS_WRITE); + } else { + handle_file(fileName, NULL, ACCESS_READ); + } + + return h; +} + + +/* -------------------------------------------------------------------------- */ + +static HANDLE WINAPI CreateFileW_hook( + __in LPCWSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile) +{ + LPCWSTR fileName = lpFileName; + wchar_t realName[PATH_MAX]; + DWORD err; + + HANDLE h = CreateFileW_orig( + fileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile); + + if (h == INVALID_HANDLE_VALUE && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(lpFileName, realName, PATH_MAX) == 0) { + fileName = realName; + h = CreateFileW_orig( + fileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile); + } + if (h == INVALID_HANDLE_VALUE) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("CreateFileW '%S' => '%S', %p:%x, %x, %x, %x, %x\n", lpFileName, - lpReOpenBuff, - uStyle); + fileName, + h, + GetLastError(), + dwDesiredAccess, + dwShareMode, + dwCreationDisposition, + dwFlagsAndAttributes); + + if (h != INVALID_HANDLE_VALUE && dwDesiredAccess & TUP_CREATE_WRITE_FLAGS) { + handle_file_w(fileName, -1, NULL, ACCESS_WRITE); + } else { + handle_file_w(fileName, -1, NULL, ACCESS_READ); + } + + return h; } +HANDLE WINAPI CreateFileTransactedA_hook( + __in LPCSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile, + __in HANDLE hTransaction, + __in_opt PUSHORT pusMiniVersion, + __reserved PVOID lpExtendedParameter) +{ + LPCSTR fileName = lpFileName; + char realName[PATH_MAX]; + DWORD err; + + HANDLE h = CreateFileTransactedA_orig( + fileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile, + hTransaction, + pusMiniVersion, + lpExtendedParameter); + + if (h == INVALID_HANDLE_VALUE && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(lpFileName, realName, PATH_MAX) == 0) { + fileName = realName; + h = CreateFileTransactedA_orig( + fileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile, + hTransaction, + pusMiniVersion, + lpExtendedParameter); + } + if (h == INVALID_HANDLE_VALUE) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("CreateFileTransactedA '%s' %p:%x", fileName, h, GetLastError()); + + if (h != INVALID_HANDLE_VALUE && dwDesiredAccess & TUP_CREATE_WRITE_FLAGS) { + handle_file(fileName, NULL, ACCESS_WRITE); + } else { + handle_file(fileName, NULL, ACCESS_READ); + } + + return h; +} + +HANDLE WINAPI CreateFileTransactedW_hook( + __in LPCWSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile, + __in HANDLE hTransaction, + __in_opt PUSHORT pusMiniVersion, + __reserved PVOID lpExtendedParameter) +{ + LPCWSTR fileName = lpFileName; + wchar_t realName[PATH_MAX]; + DWORD err; + + HANDLE h = CreateFileTransactedW_orig( + fileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile, + hTransaction, + pusMiniVersion, + lpExtendedParameter); + + if (h == INVALID_HANDLE_VALUE && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(lpFileName, realName, PATH_MAX) == 0) { + fileName = realName; + h = CreateFileTransactedW_orig( + fileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile, + hTransaction, + pusMiniVersion, + lpExtendedParameter); + } + if (h == INVALID_HANDLE_VALUE) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("CreateFileTransactedA '%s' %p:%x", fileName, h, GetLastError()); + + if (h != INVALID_HANDLE_VALUE && dwDesiredAccess & TUP_CREATE_WRITE_FLAGS) { + handle_file_w(fileName, -1, NULL, ACCESS_WRITE); + } else { + handle_file_w(fileName, -1, NULL, ACCESS_READ); + } + + return h; +} +#endif + NTSTATUS WINAPI NtCreateFile_hook( __out PHANDLE FileHandle, __in ACCESS_MASK DesiredAccess, @@ -429,27 +1007,67 @@ NTSTATUS WINAPI NtCreateFile_hook( __in PVOID EaBuffer, __in ULONG EaLength) { - NTSTATUS rc = NtCreateFile_orig(FileHandle, - DesiredAccess, - ObjectAttributes, - IoStatusBlock, - AllocationSize, - FileAttributes, - ShareAccess, - CreateDisposition, - CreateOptions, - EaBuffer, - EaLength); - PUNICODE_STRING uni = ObjectAttributes->ObjectName; - - DEBUG_HOOK("NtCreateFile[%08x] '%.*ls': %x, %x, %x\n", rc, uni->Length/2, uni->Buffer, ShareAccess, DesiredAccess, CreateOptions); + POBJECT_ATTRIBUTES objectAttributes = ObjectAttributes; + POBJECT_ATTRIBUTES variantObjectAttributes = NULL; + DWORD err; + NTSTATUS origRc, rc; + + origRc = rc = NtCreateFile_orig(FileHandle, + DesiredAccess, + objectAttributes, + IoStatusBlock, + AllocationSize, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + EaBuffer, + EaLength); + + if (!NT_SUCCESS(rc) && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_sourceOA(objectAttributes, &variantObjectAttributes) == 0) { + objectAttributes = variantObjectAttributes; + rc = NtCreateFile_orig(FileHandle, + DesiredAccess, + objectAttributes, + IoStatusBlock, + AllocationSize, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + EaBuffer, + EaLength); + } + if (!NT_SUCCESS(rc)) { + objectAttributes = ObjectAttributes; + rc = origRc; + SetLastError(err); + } + } + PUNICODE_STRING name = objectAttributes->ObjectName; + DEBUG_HOOK("NtCreateFile[%08x] '%.*ls': %x, %x, %x\n", rc, name->Length/2, name->Buffer, ShareAccess, DesiredAccess, CreateOptions); + if (wcsncmp(name->Buffer, L"\\??\\", 4) == 0) { + /* Windows started trying to read a file called + * "\??\Ip", which broke some of the tests. This just + * skips anything that doesn't begin with something + * like "C:" + */ + if (name->Buffer[4] != 0 && name->Buffer[5] != L':') + goto exit; + } if (rc == STATUS_SUCCESS && DesiredAccess & TUP_CREATE_WRITE_FLAGS) { - handle_file_w(uni->Buffer, uni->Length/2, NULL, ACCESS_WRITE); + handle_file_w(name->Buffer, name->Length/2, NULL, ACCESS_WRITE); } else { - handle_file_w(uni->Buffer, uni->Length/2, NULL, ACCESS_READ); + handle_file_w(name->Buffer, name->Length/2, NULL, ACCESS_READ); } + if (variantObjectAttributes != NULL) + free_object_attribute(variantObjectAttributes); + +exit: return rc; } @@ -461,13 +1079,48 @@ NTSTATUS WINAPI NtOpenFile_hook( __in ULONG ShareAccess, __in ULONG OpenOptions) { - NTSTATUS rc = NtOpenFile_orig(FileHandle, - DesiredAccess, - ObjectAttributes, - IoStatusBlock, - ShareAccess, - OpenOptions); - PUNICODE_STRING uni = ObjectAttributes->ObjectName; + POBJECT_ATTRIBUTES objectAttributes = ObjectAttributes; + POBJECT_ATTRIBUTES variantObjectAttributes = NULL; + NTSTATUS rc, origRc; + DWORD err; + + origRc = rc = NtOpenFile_orig(FileHandle, + DesiredAccess, + objectAttributes, + IoStatusBlock, + ShareAccess, + OpenOptions); + + if (!NT_SUCCESS(rc) && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_sourceOA(objectAttributes, &variantObjectAttributes) == 0) { + objectAttributes = variantObjectAttributes; + rc = NtOpenFile_orig(FileHandle, + DesiredAccess, + objectAttributes, + IoStatusBlock, + ShareAccess, + OpenOptions); + } + if (!NT_SUCCESS(rc)) { + objectAttributes = ObjectAttributes; + rc = origRc; + SetLastError(err); + } + } + + PUNICODE_STRING uni = objectAttributes->ObjectName; + wchar_t *name = uni->Buffer; + + if (wcsncmp(name, L"\\??\\", 4) == 0) { + name += 4; + /* Windows started trying to read a file called "\??\Ip", + * which broke some of the tests. This just skips + * anything that doesn't begin with something like "C:" + */ + if (name[0] != 0 && name[1] != L':') + goto out_free; + } DEBUG_HOOK("NtOpenFile[%08x] '%.*ls': %x, %x, %x\n", rc, uni->Length/2, uni->Buffer, ShareAccess, DesiredAccess, OpenOptions); @@ -495,136 +1148,351 @@ NTSTATUS WINAPI NtOpenFile_hook( } } +out_free: + if (variantObjectAttributes != NULL) + free_object_attribute(variantObjectAttributes); + return rc; } NTSTATUS WINAPI NtCreateUserProcess_hook(PHANDLE ProcessHandle, -PHANDLE ThreadHandle, -ACCESS_MASK ProcessDesiredAccess, -ACCESS_MASK ThreadDesiredAccess, -POBJECT_ATTRIBUTES ProcessObjectAttributes, -POBJECT_ATTRIBUTES ThreadObjectAttributes, -ULONG ProcessFlags, -ULONG ThreadFlags, -PRTL_USER_PROCESS_PARAMETERS ProcessParameters, -ULONG_PTR CreateInfo, -ULONG_PTR AttributeList) + PHANDLE ThreadHandle, + ACCESS_MASK ProcessDesiredAccess, + ACCESS_MASK ThreadDesiredAccess, + POBJECT_ATTRIBUTES ProcessObjectAttributes, + POBJECT_ATTRIBUTES ThreadObjectAttributes, + ULONG ProcessFlags, + ULONG ThreadFlags, + PRTL_USER_PROCESS_PARAMETERS ProcessParameters, + ULONG_PTR CreateInfo, + ULONG_PTR AttributeList) { - + DWORD err; NTSTATUS rc = NtCreateUserProcess_orig(ProcessHandle, ThreadHandle, ProcessDesiredAccess, ThreadDesiredAccess, ProcessObjectAttributes, ThreadObjectAttributes, ProcessFlags, ThreadFlags, - ProcessParameters,CreateInfo, AttributeList); + ProcessParameters, CreateInfo, AttributeList); - if (rc != STATUS_SUCCESS) { - return rc; - } - TCHAR wbuffer[1024]; - if (GetModuleFileNameEx(*ProcessHandle,0,wbuffer,1024)){ - char buffer[PATH_MAX]; - WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, PATH_MAX, NULL, NULL); - char *exec = strrchr(buffer, '\\'); - if (exec == NULL) return rc; + DEBUG_HOOK("NtCreateUserProcess: %X\n", rc); - exec++; - if (strncasecmp(exec, "tup32detect.exe", 15) == 0 || - strncasecmp(exec, "mspdbsrv.exe", 12) == 0) - return rc; + if (!NT_SUCCESS(rc)) { + return rc; + } - DEBUG_HOOK("NtCreateUser: %s\n", buffer); + err = GetLastError(); - PROCESS_INFORMATION processInformation; - processInformation.hProcess = *ProcessHandle; - processInformation.hThread = *ThreadHandle; + char buffer[1024]; + if (GetProcessImageFileNameA(*ProcessHandle, buffer, 1024) == 0) { + DEBUG_HOOK("Not able to get proces name: %X\n", GetLastError()); + goto done; + } - tup_inject_dll(&processInformation, s_depfilename, s_vardict_file); - } + char *exec = strrchr(buffer, '\\'); + if (exec == NULL) { + DEBUG_HOOK("Failed to parse exec @ %d: %s\n", __LINE__, buffer); + goto done; + } + exec++; + + if (strncasecmp(exec, "tup32detect.exe", 15) == 0 || + strncasecmp(exec, "mspdbsrv.exe", 12) == 0) + goto done; + + DEBUG_HOOK("NtCreateUserProcess: %s\n", buffer); + + PROCESS_INFORMATION processInformation; + processInformation.hProcess = *ProcessHandle; + processInformation.hThread = *ThreadHandle; + + tup_inject_dll_w(&processInformation, s_depfilename, s_vardict_file); + +done: + SetLastError(err); return rc; } BOOL WINAPI DeleteFileA_hook( - __in LPCSTR lpFileName) + __in LPCSTR lpFileName) { - handle_file(lpFileName, NULL, ACCESS_UNLINK); - return DeleteFileA_orig(lpFileName); + char realName[MAX_PATH]; + DWORD err; + LPCSTR fileName = lpFileName; + BOOL rc = DeleteFileA_orig(fileName); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(fileName, realName, MAX_PATH) == 0) { + fileName = realName; + rc = DeleteFileA_orig(fileName); + + } + if (!rc) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s '%s' (%s)\n", __FUNCTION__, fileName, rc ? "SUCCESS" : "FAILED"); + + handle_file(fileName, NULL, ACCESS_UNLINK); + return rc; } BOOL WINAPI DeleteFileW_hook( - __in LPCWSTR lpFileName) + __in LPCWSTR lpFileName) { - handle_file_w(lpFileName, -1, NULL, ACCESS_UNLINK); - return DeleteFileW_orig(lpFileName); + wchar_t realName[MAX_PATH]; + LPCWSTR fileName = lpFileName; + DWORD err; + BOOL rc = DeleteFileW_orig(fileName); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(fileName, realName, MAX_PATH) == 0) { + fileName = realName; + rc = DeleteFileW_orig(fileName); + } + if (!rc) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s '%S' (%s)\n", __FUNCTION__, fileName, rc ? "SUCCESS" : "FAILED"); + + handle_file_w(fileName, -1, NULL, ACCESS_UNLINK); + return rc; } BOOL WINAPI DeleteFileTransactedA_hook( - __in LPCSTR lpFileName, - __in HANDLE hTransaction) + __in LPCSTR lpFileName, + __in HANDLE hTransaction) { - handle_file(lpFileName, NULL, ACCESS_UNLINK); - return DeleteFileTransactedA_orig(lpFileName, hTransaction); + char realName[MAX_PATH]; + LPCSTR fileName = lpFileName; + DWORD err; + BOOL rc = DeleteFileTransactedA_orig(fileName, hTransaction); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(fileName, realName, MAX_PATH) == 0) { + fileName = realName; + rc = DeleteFileTransactedA_orig(fileName, hTransaction); + } + if (!rc) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s '%s' (%s)\n", __FUNCTION__, fileName, rc ? "SUCCESS" : "FAILED"); + + handle_file(fileName, NULL, ACCESS_UNLINK); + return rc; } BOOL WINAPI DeleteFileTransactedW_hook( - __in LPCWSTR lpFileName, - __in HANDLE hTransaction) + __in LPCWSTR lpFileName, + __in HANDLE hTransaction) { - handle_file_w(lpFileName, -1, NULL, ACCESS_UNLINK); - return DeleteFileTransactedW_orig(lpFileName, hTransaction); + wchar_t realName[MAX_PATH]; + LPCWSTR fileName = lpFileName; + DWORD err; + BOOL rc = DeleteFileTransactedW_orig(fileName, hTransaction); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(fileName, realName, MAX_PATH) == 0) { + fileName = realName; + rc = DeleteFileTransactedW_orig(fileName, hTransaction); + } + if (!rc) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s '%S' (%s)\n", __FUNCTION__, fileName, rc ? "SUCCESS" : "FAILED"); + + handle_file_w(fileName, -1, NULL, ACCESS_UNLINK); + return rc; } BOOL WINAPI MoveFileA_hook( - __in LPCSTR lpExistingFileName, - __in LPCSTR lpNewFileName) + __in LPCSTR lpExistingFileName, + __in LPCSTR lpNewFileName) { - handle_file(lpExistingFileName, lpNewFileName, ACCESS_RENAME); - return MoveFileA_orig(lpExistingFileName, lpNewFileName); + char existingName[MAX_PATH], newName[MAX_PATH]; + LPCSTR existingFileName = lpExistingFileName; + LPCSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = MoveFileA_orig(existingFileName, newFileName); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) + rc = MoveFileA_orig(existingFileName, newFileName); + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s '%s' => '%s' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + handle_file(existingFileName, newFileName, ACCESS_RENAME); + return rc; } BOOL WINAPI MoveFileW_hook( - __in LPCWSTR lpExistingFileName, - __in LPCWSTR lpNewFileName) + __in LPCWSTR lpExistingFileName, + __in LPCWSTR lpNewFileName) { - handle_file_w(lpExistingFileName, -1, lpNewFileName, ACCESS_RENAME); - return MoveFileW_orig(lpExistingFileName, lpNewFileName); + wchar_t existingName[MAX_PATH], newName[MAX_PATH]; + LPCWSTR existingFileName = lpExistingFileName; + LPCWSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = MoveFileW_orig(existingFileName, newFileName); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source_w(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) + rc = MoveFileW_orig(existingFileName, newFileName); + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file_w(existingFileName, -1, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%S' => '%S' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI MoveFileExA_hook( - __in LPCSTR lpExistingFileName, - __in_opt LPCSTR lpNewFileName, - __in DWORD dwFlags) + __in LPCSTR lpExistingFileName, + __in_opt LPCSTR lpNewFileName, + __in DWORD dwFlags) { - handle_file(lpExistingFileName, lpNewFileName, ACCESS_RENAME); - return MoveFileExA_orig(lpExistingFileName, lpNewFileName, dwFlags); + char existingName[MAX_PATH], newName[MAX_PATH]; + LPCSTR existingFileName = lpExistingFileName; + LPCSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = MoveFileExA_orig(existingFileName, newFileName, dwFlags); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) + rc = MoveFileExA_orig(existingFileName, newFileName, dwFlags); + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file(existingFileName, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%s' => '%s' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI MoveFileExW_hook( - __in LPCWSTR lpExistingFileName, - __in_opt LPCWSTR lpNewFileName, - __in DWORD dwFlags) + __in LPCWSTR lpExistingFileName, + __in_opt LPCWSTR lpNewFileName, + __in DWORD dwFlags) { - handle_file_w(lpExistingFileName, -1, lpNewFileName, ACCESS_RENAME); - return MoveFileExW_orig(lpExistingFileName, lpNewFileName, dwFlags); + wchar_t existingName[MAX_PATH], newName[MAX_PATH]; + LPCWSTR existingFileName = lpExistingFileName; + LPCWSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = MoveFileExW_orig(existingFileName, newFileName, dwFlags); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source_w(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) + rc = MoveFileExW_orig(existingFileName, newFileName, dwFlags); + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file_w(existingFileName, -1, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%S' => '%S' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI MoveFileWithProgressA_hook( - __in LPCSTR lpExistingFileName, - __in_opt LPCSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in DWORD dwFlags) + __in LPCSTR lpExistingFileName, + __in_opt LPCSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in DWORD dwFlags) { - handle_file(lpExistingFileName, lpNewFileName, ACCESS_RENAME); - return MoveFileWithProgressA_orig( - lpExistingFileName, - lpNewFileName, + char existingName[MAX_PATH], newName[MAX_PATH]; + LPCSTR existingFileName = lpExistingFileName; + LPCSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = MoveFileWithProgressA_orig( + existingFileName, + newFileName, lpProgressRoutine, lpData, dwFlags); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = MoveFileWithProgressA_orig( + existingFileName, + newFileName, + lpProgressRoutine, + lpData, + dwFlags); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file(existingFileName, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%s' => '%s' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI MoveFileWithProgressW_hook( @@ -634,31 +1502,90 @@ BOOL WINAPI MoveFileWithProgressW_hook( __in_opt LPVOID lpData, __in DWORD dwFlags) { - handle_file_w(lpExistingFileName, -1, lpNewFileName, ACCESS_RENAME); - return MoveFileWithProgressW_orig( - lpExistingFileName, - lpNewFileName, + wchar_t existingName[MAX_PATH], newName[MAX_PATH]; + LPCWSTR existingFileName = lpExistingFileName; + LPCWSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = MoveFileWithProgressW_orig( + existingFileName, + newFileName, lpProgressRoutine, lpData, dwFlags); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source_w(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = MoveFileWithProgressW_orig( + existingFileName, + newFileName, + lpProgressRoutine, + lpData, + dwFlags); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file_w(existingFileName, -1, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%S' => '%S' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI MoveFileTransactedA_hook( - __in LPCSTR lpExistingFileName, - __in_opt LPCSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in DWORD dwFlags, - __in HANDLE hTransaction) + __in LPCSTR lpExistingFileName, + __in_opt LPCSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in DWORD dwFlags, + __in HANDLE hTransaction) { - handle_file(lpExistingFileName, lpNewFileName, ACCESS_RENAME); - return MoveFileTransactedA_orig( - lpExistingFileName, - lpNewFileName, + char existingName[MAX_PATH], newName[MAX_PATH]; + LPCSTR existingFileName = lpExistingFileName; + LPCSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = MoveFileTransactedA_orig( + existingFileName, + newFileName, lpProgressRoutine, lpData, dwFlags, hTransaction); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = MoveFileTransactedA_orig( + existingFileName, + newFileName, + lpProgressRoutine, + lpData, + dwFlags, + hTransaction); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file(existingFileName, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%s' => '%s' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI MoveFileTransactedW_hook( @@ -669,32 +1596,92 @@ BOOL WINAPI MoveFileTransactedW_hook( __in DWORD dwFlags, __in HANDLE hTransaction) { - handle_file_w(lpExistingFileName, -1, lpNewFileName, ACCESS_RENAME); - return MoveFileTransactedW_orig( - lpExistingFileName, - lpNewFileName, + wchar_t existingName[MAX_PATH], newName[MAX_PATH]; + LPCWSTR existingFileName = lpExistingFileName; + LPCWSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = MoveFileTransactedW_orig( + existingFileName, + newFileName, lpProgressRoutine, lpData, dwFlags, hTransaction); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source_w(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = MoveFileTransactedW_orig( + existingFileName, + newFileName, + lpProgressRoutine, + lpData, + dwFlags, + hTransaction); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file_w(existingFileName, -1, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%S' => '%S' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI ReplaceFileA_hook( - __in LPCSTR lpReplacedFileName, - __in LPCSTR lpReplacementFileName, - __in_opt LPCSTR lpBackupFileName, - __in DWORD dwReplaceFlags, - __reserved LPVOID lpExclude, - __reserved LPVOID lpReserved) + __in LPCSTR lpReplacedFileName, + __in LPCSTR lpReplacementFileName, + __in_opt LPCSTR lpBackupFileName, + __in DWORD dwReplaceFlags, + __reserved LPVOID lpExclude, + __reserved LPVOID lpReserved) { - handle_file(lpReplacementFileName, lpReplacedFileName, ACCESS_RENAME); - return ReplaceFileA_orig( - lpReplacedFileName, - lpReplacementFileName, + char existingName[MAX_PATH], newName[MAX_PATH]; + LPCSTR existingFileName = lpReplacedFileName; + LPCSTR newFileName = lpReplacementFileName; + DWORD err; + BOOL rc = ReplaceFileA_orig( + existingFileName, + newFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpReplacementFileName || existingFileName != lpReplacedFileName) { + rc = ReplaceFileA_orig( + existingFileName, + newFileName, + lpBackupFileName, + dwReplaceFlags, + lpExclude, + lpReserved); + } + if (!rc) { + existingFileName = lpReplacedFileName; + newFileName = lpReplacementFileName; + SetLastError(err); + } + } + + handle_file(existingFileName, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%s' => '%s' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI ReplaceFileW_hook( @@ -705,27 +1692,84 @@ BOOL WINAPI ReplaceFileW_hook( __reserved LPVOID lpExclude, __reserved LPVOID lpReserved) { - handle_file_w(lpReplacementFileName, -1, lpReplacedFileName, ACCESS_RENAME); - return ReplaceFileW_orig( - lpReplacedFileName, - lpReplacementFileName, + wchar_t existingName[MAX_PATH], newName[MAX_PATH]; + LPCWSTR existingFileName = lpReplacedFileName; + LPCWSTR newFileName = lpReplacementFileName; + DWORD err; + BOOL rc = ReplaceFileW_orig( + existingFileName, + newFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source_w(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpReplacementFileName || existingFileName != lpReplacedFileName) { + rc = ReplaceFileW_orig( + existingFileName, + newFileName, + lpBackupFileName, + dwReplaceFlags, + lpExclude, + lpReserved); + } + if (!rc) { + existingFileName = lpReplacedFileName; + newFileName = lpReplacementFileName; + SetLastError(err); + } + } + + handle_file_w(existingFileName, -1, newFileName, ACCESS_RENAME); + DEBUG_HOOK("%s '%S' => '%S' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI CopyFileA_hook( - __in LPCSTR lpExistingFileName, - __in LPCSTR lpNewFileName, - __in BOOL bFailIfExists) + __in LPCSTR lpExistingFileName, + __in LPCSTR lpNewFileName, + __in BOOL bFailIfExists) { - handle_file(lpExistingFileName, NULL, ACCESS_READ); - handle_file(lpNewFileName, NULL, ACCESS_WRITE); - return CopyFileA_orig( - lpExistingFileName, - lpNewFileName, + char existingName[MAX_PATH], newName[MAX_PATH]; + LPCSTR existingFileName = lpExistingFileName; + LPCSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = CopyFileA_orig( + existingFileName, + newFileName, bFailIfExists); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = CopyFileA_orig( + existingFileName, + newFileName, + bFailIfExists); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file(existingFileName, NULL, ACCESS_READ); + handle_file(newFileName, NULL, ACCESS_WRITE); + DEBUG_HOOK("%s '%s' => '%s' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI CopyFileW_hook( @@ -733,31 +1777,88 @@ BOOL WINAPI CopyFileW_hook( __in LPCWSTR lpNewFileName, __in BOOL bFailIfExists) { - handle_file_w(lpExistingFileName, -1, NULL, ACCESS_READ); - handle_file_w(lpNewFileName, -1, NULL, ACCESS_WRITE); - return CopyFileW_orig( - lpExistingFileName, - lpNewFileName, + wchar_t existingName[MAX_PATH], newName[MAX_PATH]; + LPCWSTR existingFileName = lpExistingFileName; + LPCWSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = CopyFileW_orig( + existingFileName, + newFileName, bFailIfExists); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source_w(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = CopyFileW_orig( + existingFileName, + newFileName, + bFailIfExists); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file_w(existingFileName, -1, NULL, ACCESS_READ); + handle_file_w(newFileName, -1, NULL, ACCESS_WRITE); + DEBUG_HOOK("%s '%S' => '%S' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI CopyFileExA_hook( - __in LPCSTR lpExistingFileName, - __in LPCSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in_opt LPBOOL pbCancel, - __in DWORD dwCopyFlags) + __in LPCSTR lpExistingFileName, + __in LPCSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in_opt LPBOOL pbCancel, + __in DWORD dwCopyFlags) { - handle_file(lpExistingFileName, NULL, ACCESS_READ); - handle_file(lpNewFileName, NULL, ACCESS_WRITE); - return CopyFileExA_orig( - lpExistingFileName, - lpNewFileName, + char existingName[MAX_PATH], newName[MAX_PATH]; + LPCSTR existingFileName = lpExistingFileName; + LPCSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = CopyFileExA_orig( + existingFileName, + newFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = CopyFileExA_orig( + existingFileName, + newFileName, + lpProgressRoutine, + lpData, + pbCancel, + dwCopyFlags); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file(existingFileName, NULL, ACCESS_READ); + handle_file(newFileName, NULL, ACCESS_WRITE); + DEBUG_HOOK("%s '%s' => '%s' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI CopyFileExW_hook( @@ -768,36 +1869,98 @@ BOOL WINAPI CopyFileExW_hook( __in_opt LPBOOL pbCancel, __in DWORD dwCopyFlags) { - handle_file_w(lpExistingFileName, -1, NULL, ACCESS_READ); - handle_file_w(lpNewFileName, -1, NULL, ACCESS_WRITE); - return CopyFileExW_orig( - lpExistingFileName, - lpNewFileName, + wchar_t existingName[MAX_PATH], newName[MAX_PATH]; + LPCWSTR existingFileName = lpExistingFileName; + LPCWSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = CopyFileExW_orig( + existingFileName, + newFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source_w(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = CopyFileExW_orig( + existingFileName, + newFileName, + lpProgressRoutine, + lpData, + pbCancel, + dwCopyFlags); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file_w(existingFileName, -1, NULL, ACCESS_READ); + handle_file_w(newFileName, -1, NULL, ACCESS_WRITE); + DEBUG_HOOK("%s '%S' => '%S' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI CopyFileTransactedA_hook( - __in LPCSTR lpExistingFileName, - __in LPCSTR lpNewFileName, - __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, - __in_opt LPVOID lpData, - __in_opt LPBOOL pbCancel, - __in DWORD dwCopyFlags, - __in HANDLE hTransaction) + __in LPCSTR lpExistingFileName, + __in LPCSTR lpNewFileName, + __in_opt LPPROGRESS_ROUTINE lpProgressRoutine, + __in_opt LPVOID lpData, + __in_opt LPBOOL pbCancel, + __in DWORD dwCopyFlags, + __in HANDLE hTransaction) { - handle_file(lpExistingFileName, NULL, ACCESS_READ); - handle_file(lpNewFileName, NULL, ACCESS_WRITE); - return CopyFileTransactedA_orig( - lpExistingFileName, - lpNewFileName, + char existingName[MAX_PATH], newName[MAX_PATH]; + LPCSTR existingFileName = lpExistingFileName; + LPCSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = CopyFileTransactedA_orig( + existingFileName, + newFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags, hTransaction); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = CopyFileTransactedA_orig( + existingFileName, + newFileName, + lpProgressRoutine, + lpData, + pbCancel, + dwCopyFlags, + hTransaction); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file(existingFileName, NULL, ACCESS_READ); + handle_file(newFileName, NULL, ACCESS_WRITE); + DEBUG_HOOK("%s '%s' => '%s' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } BOOL WINAPI CopyFileTransactedW_hook( @@ -809,92 +1972,238 @@ BOOL WINAPI CopyFileTransactedW_hook( __in DWORD dwCopyFlags, __in HANDLE hTransaction) { - handle_file_w(lpExistingFileName, -1, NULL, ACCESS_READ); - handle_file_w(lpNewFileName, -1, NULL, ACCESS_WRITE); - return CopyFileTransactedW_orig( - lpExistingFileName, - lpNewFileName, + wchar_t existingName[MAX_PATH], newName[MAX_PATH]; + LPCWSTR existingFileName = lpExistingFileName; + LPCWSTR newFileName = lpNewFileName; + DWORD err; + BOOL rc = CopyFileTransactedW_orig( + existingFileName, + newFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags, hTransaction); + + if (!rc && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(existingFileName, existingName, MAX_PATH) == 0) + existingFileName = existingName; + if (variant_to_source_w(newFileName, newName, MAX_PATH) == 0) + newFileName = newName; + if (newFileName != lpNewFileName || existingFileName != lpExistingFileName) { + rc = CopyFileTransactedW_orig( + existingFileName, + newFileName, + lpProgressRoutine, + lpData, + pbCancel, + dwCopyFlags, + hTransaction); + } + if (!rc) { + existingFileName = lpExistingFileName; + newFileName = lpNewFileName; + SetLastError(err); + } + } + + handle_file_w(existingFileName, -1, NULL, ACCESS_READ); + handle_file_w(newFileName, -1, NULL, ACCESS_WRITE); + DEBUG_HOOK("%s '%S' => '%S' (%s)\n", __FUNCTION__, existingFileName, newFileName, rc ? "SUCCESS" : "FAILED"); + + return rc; } #define ATTRIB_FAIL 0xffffffff DWORD WINAPI GetFileAttributesA_hook( - __in LPCSTR lpFileName) + __in LPCSTR lpFileName) { - DWORD attributes = GetFileAttributesA_orig(lpFileName); - DEBUG_HOOK("GetFileAttributesA '%s'\n", lpFileName); + char realName[PATH_MAX]; + LPCSTR fileName = lpFileName; + DWORD err; + DWORD attributes = GetFileAttributesA_orig(fileName); + + // If failed, try variant + if (attributes == ATTRIB_FAIL && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(lpFileName, realName, PATH_MAX) == 0) { + fileName = realName; + attributes = GetFileAttributesA_orig(fileName); + } + if (attributes == ATTRIB_FAIL) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("GetFileAttributesA '%s' (%X)\n", fileName, attributes); /* If it fails (attributes == -1), we need to handle the read since * it will be a ghost. If the file exists, we only care if it's a file * and not a directory. */ - if(attributes == ATTRIB_FAIL || ! (attributes & FILE_ATTRIBUTE_DIRECTORY)) - handle_file(lpFileName, NULL, ACCESS_READ); + if (attributes == ATTRIB_FAIL || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) + handle_file(fileName, NULL, ACCESS_READ); return attributes; } DWORD WINAPI GetFileAttributesW_hook( - __in LPCWSTR lpFileName) + __in LPCWSTR lpFileName) { - DWORD attributes = GetFileAttributesW_orig(lpFileName); - if(attributes == ATTRIB_FAIL || ! (attributes & FILE_ATTRIBUTE_DIRECTORY)) - handle_file_w(lpFileName, -1, NULL, ACCESS_READ); + LPCWSTR fileName = lpFileName; + DWORD err; + DWORD attributes = GetFileAttributesW_orig(fileName); + + if (attributes == ATTRIB_FAIL && HAS_VARIANTS()) { + err = GetLastError(); + wchar_t realName[PATH_MAX]; + if (variant_to_source_w(lpFileName, realName, PATH_MAX) == 0) { + fileName = realName; + attributes = GetFileAttributesW_orig(fileName); + } + if (attributes == ATTRIB_FAIL) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s '%S' (%X)\n", __FUNCTION__, fileName, attributes); + + if (attributes == ATTRIB_FAIL || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) + handle_file_w(fileName, -1, NULL, ACCESS_READ); + return attributes; } BOOL WINAPI GetFileAttributesExA_hook( - __in LPCSTR lpFileName, - __in GET_FILEEX_INFO_LEVELS fInfoLevelId, - __out LPVOID lpFileInformation) + __in LPCSTR lpFileName, + __in GET_FILEEX_INFO_LEVELS fInfoLevelId, + __out LPVOID lpFileInformation) { + LPCSTR fileName = lpFileName; + DWORD err; DWORD attributes = GetFileAttributesExA_orig( - lpFileName, + fileName, fInfoLevelId, lpFileInformation); - if(attributes == ATTRIB_FAIL || ! (attributes & FILE_ATTRIBUTE_DIRECTORY)) - handle_file(lpFileName, NULL, ACCESS_READ); + + if (attributes == ATTRIB_FAIL && HAS_VARIANTS()) { + err = GetLastError(); + char realName[PATH_MAX]; + if (variant_to_source(lpFileName, realName, PATH_MAX) == 0) { + fileName = realName; + attributes = GetFileAttributesExA_orig( + fileName, + fInfoLevelId, + lpFileInformation); + } + if (attributes == ATTRIB_FAIL) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s '%s' (%X)\n", __FUNCTION__, fileName, attributes); + + if (attributes == ATTRIB_FAIL || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) + handle_file(fileName, NULL, ACCESS_READ); return attributes; } BOOL WINAPI GetFileAttributesExW_hook( - __in LPCWSTR lpFileName, - __in GET_FILEEX_INFO_LEVELS fInfoLevelId, - __out LPVOID lpFileInformation) + __in LPCWSTR lpFileName, + __in GET_FILEEX_INFO_LEVELS fInfoLevelId, + __out LPVOID lpFileInformation) { + LPCWSTR fileName = lpFileName; + DWORD err; DWORD attributes = GetFileAttributesExW_orig( - lpFileName, + fileName, fInfoLevelId, lpFileInformation); - if(attributes == ATTRIB_FAIL || ! (attributes & FILE_ATTRIBUTE_DIRECTORY)) - handle_file_w(lpFileName, -1, NULL, ACCESS_READ); + + if (attributes == ATTRIB_FAIL && HAS_VARIANTS()) { + err = GetLastError(); + wchar_t realName[PATH_MAX]; + if (variant_to_source_w(lpFileName, realName, PATH_MAX) == 0) { + fileName = realName; + attributes = GetFileAttributesExW_orig( + fileName, + fInfoLevelId, + lpFileInformation); + } + if (attributes == ATTRIB_FAIL) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("%s '%S' (%X)\n", __FUNCTION__, fileName, attributes); + + if (attributes == ATTRIB_FAIL || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) + handle_file_w(fileName, -1, NULL, ACCESS_READ); + return attributes; } __out HANDLE WINAPI FindFirstFileA_hook( - __in LPCSTR lpFileName, - __out LPWIN32_FIND_DATAA lpFindFileData) + __in LPCSTR lpFileName, + __out LPWIN32_FIND_DATAA lpFindFileData) { - DEBUG_HOOK("FindFirstFileA '%s'\n", lpFileName); - handle_file(lpFileName, NULL, ACCESS_READ); - return FindFirstFileA_orig(lpFileName, lpFindFileData); + char realName[MAX_PATH]; + LPCSTR fileName = lpFileName; + DWORD err; + HANDLE h = FindFirstFileA_orig(fileName, lpFindFileData); + + if (h == INVALID_HANDLE_VALUE && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(fileName, realName, MAX_PATH) == 0) { + fileName = realName; + h = FindFirstFileA_orig(fileName, lpFindFileData); + } + if (h == INVALID_HANDLE_VALUE) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("FindFirstFileA '%s'\n", fileName); + handle_file(fileName, NULL, ACCESS_READ); + return h; } __out HANDLE WINAPI FindFirstFileW_hook( - __in LPCWSTR lpFileName, - __out LPWIN32_FIND_DATAW lpFindFileData) + __in LPCWSTR lpFileName, + __out LPWIN32_FIND_DATAW lpFindFileData) { - DEBUG_HOOK("FindFirstFileW '%S'\n", lpFileName); - handle_file_w(lpFileName, -1, NULL, ACCESS_READ); - return FindFirstFileW_orig(lpFileName, lpFindFileData); + wchar_t realName[MAX_PATH]; + LPCWSTR fileName = lpFileName; + DWORD err; + + HANDLE h = FindFirstFileW_orig(fileName, lpFindFileData); + + if (h == INVALID_HANDLE_VALUE && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source_w(fileName, realName, MAX_PATH) == 0) { + fileName = realName; + h = FindFirstFileW_orig(fileName, lpFindFileData); + } + if (h == INVALID_HANDLE_VALUE) { + fileName = lpFileName; + SetLastError(err); + } + } + + DEBUG_HOOK("FindFirstFileW '%S'\n", fileName); + + handle_file_w(fileName, -1, NULL, ACCESS_READ); + return h; } BOOL WINAPI FindNextFileA_hook( - __in HANDLE hFindFile, - __out LPWIN32_FIND_DATAA lpFindFileData) + __in HANDLE hFindFile, + __out LPWIN32_FIND_DATAA lpFindFileData) { if (!FindNextFileA_orig(hFindFile, lpFindFileData)) return 0; @@ -904,8 +2213,8 @@ BOOL WINAPI FindNextFileA_hook( } BOOL WINAPI FindNextFileW_hook( - __in HANDLE hFindFile, - __out LPWIN32_FIND_DATAW lpFindFileData) + __in HANDLE hFindFile, + __out LPWIN32_FIND_DATAW lpFindFileData) { if (!FindNextFileW_orig(hFindFile, lpFindFileData)) return 0; @@ -915,16 +2224,16 @@ BOOL WINAPI FindNextFileW_hook( } BOOL WINAPI CreateProcessA_hook( - __in_opt LPCSTR lpApplicationName, - __inout_opt LPSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCSTR lpCurrentDirectory, - __in LPSTARTUPINFOA lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation) + __in_opt LPCSTR lpApplicationName, + __inout_opt LPSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCSTR lpCurrentDirectory, + __in LPSTARTUPINFOA lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation) { BOOL ret = CreateProcessA_orig( lpApplicationName, @@ -949,8 +2258,8 @@ BOOL WINAPI CreateProcessA_hook( /* Ignore mspdbsrv.exe, since it continues to run in the background */ if(!lpApplicationName || strcasestr(lpApplicationName, "mspdbsrv.exe") == NULL - || strcasestr(lpApplicationName, "tup32detect.exe") == NULL) { - tup_inject_dll(lpProcessInformation, s_depfilename, s_vardict_file); + || strcasestr(lpApplicationName, "tup32detect.exe") == NULL) { + tup_inject_dll_w(lpProcessInformation, s_depfilename, s_vardict_file); } if ((dwCreationFlags & CREATE_SUSPENDED) != 0) @@ -960,16 +2269,16 @@ BOOL WINAPI CreateProcessA_hook( } BOOL WINAPI CreateProcessW_hook( - __in_opt LPCWSTR lpApplicationName, - __inout_opt LPWSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCWSTR lpCurrentDirectory, - __in LPSTARTUPINFOW lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation) + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation) { BOOL ret = CreateProcessW_orig( lpApplicationName, @@ -995,8 +2304,8 @@ BOOL WINAPI CreateProcessW_hook( /* Ignore mspdbsrv.exe, since it continues to run in the background */ if(!lpApplicationName || wcscasestr(lpApplicationName, L"mspdbsrv.exe") == NULL - || wcscasestr(lpApplicationName, L"tup32detect.exe") == NULL) { - tup_inject_dll(lpProcessInformation, s_depfilename, s_vardict_file); + || wcscasestr(lpApplicationName, L"tup32detect.exe") == NULL) { + tup_inject_dll_w(lpProcessInformation, s_depfilename, s_vardict_file); } if ((dwCreationFlags & CREATE_SUSPENDED) != 0) @@ -1006,17 +2315,17 @@ BOOL WINAPI CreateProcessW_hook( } BOOL WINAPI CreateProcessAsUserA_hook( - __in_opt HANDLE hToken, - __in_opt LPCSTR lpApplicationName, - __inout_opt LPSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCSTR lpCurrentDirectory, - __in LPSTARTUPINFOA lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation) + __in_opt HANDLE hToken, + __in_opt LPCSTR lpApplicationName, + __inout_opt LPSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCSTR lpCurrentDirectory, + __in LPSTARTUPINFOA lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation) { BOOL ret = CreateProcessAsUserA_orig( hToken, @@ -1042,8 +2351,8 @@ BOOL WINAPI CreateProcessAsUserA_hook( /* Ignore mspdbsrv.exe, since it continues to run in the background */ if(!lpApplicationName || strcasestr(lpApplicationName, "mspdbsrv.exe") == NULL - || strcasestr(lpApplicationName, "tup32detect.exe") == NULL) { - tup_inject_dll(lpProcessInformation, s_depfilename, s_vardict_file); + || strcasestr(lpApplicationName, "tup32detect.exe") == NULL) { + tup_inject_dll_w(lpProcessInformation, s_depfilename, s_vardict_file); } if ((dwCreationFlags & CREATE_SUSPENDED) != 0) @@ -1053,17 +2362,17 @@ BOOL WINAPI CreateProcessAsUserA_hook( } BOOL WINAPI CreateProcessAsUserW_hook( - __in_opt HANDLE hToken, - __in_opt LPCWSTR lpApplicationName, - __inout_opt LPWSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCWSTR lpCurrentDirectory, - __in LPSTARTUPINFOW lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation) + __in_opt HANDLE hToken, + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation) { BOOL ret = CreateProcessAsUserW_orig( hToken, @@ -1089,8 +2398,8 @@ BOOL WINAPI CreateProcessAsUserW_hook( /* Ignore mspdbsrv.exe, since it continues to run in the background */ if(!lpApplicationName || wcscasestr(lpApplicationName, L"mspdbsrv.exe") == NULL - || wcscasestr(lpApplicationName, L"tup32detect.exe") == NULL) { - tup_inject_dll(lpProcessInformation, s_depfilename, s_vardict_file); + || wcscasestr(lpApplicationName, L"tup32detect.exe") == NULL) { + tup_inject_dll_w(lpProcessInformation, s_depfilename, s_vardict_file); } if ((dwCreationFlags & CREATE_SUSPENDED) != 0) @@ -1100,17 +2409,17 @@ BOOL WINAPI CreateProcessAsUserW_hook( } BOOL WINAPI CreateProcessWithLogonW_hook( - __in LPCWSTR lpUsername, - __in_opt LPCWSTR lpDomain, - __in LPCWSTR lpPassword, - __in DWORD dwLogonFlags, - __in_opt LPCWSTR lpApplicationName, - __inout_opt LPWSTR lpCommandLine, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCWSTR lpCurrentDirectory, - __in LPSTARTUPINFOW lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation) + __in LPCWSTR lpUsername, + __in_opt LPCWSTR lpDomain, + __in LPCWSTR lpPassword, + __in DWORD dwLogonFlags, + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation) { BOOL ret = CreateProcessWithLogonW_orig( lpUsername, @@ -1136,8 +2445,8 @@ BOOL WINAPI CreateProcessWithLogonW_hook( /* Ignore mspdbsrv.exe, since it continues to run in the background */ if(!lpApplicationName || wcscasestr(lpApplicationName, L"mspdbsrv.exe") == NULL - || wcscasestr(lpApplicationName, L"tup32detect.exe") == NULL) { - tup_inject_dll(lpProcessInformation, s_depfilename, s_vardict_file); + || wcscasestr(lpApplicationName, L"tup32detect.exe") == NULL) { + tup_inject_dll_w(lpProcessInformation, s_depfilename, s_vardict_file); } if ((dwCreationFlags & CREATE_SUSPENDED) != 0) @@ -1147,15 +2456,15 @@ BOOL WINAPI CreateProcessWithLogonW_hook( } BOOL WINAPI CreateProcessWithTokenW_hook( - __in HANDLE hToken, - __in DWORD dwLogonFlags, - __in_opt LPCWSTR lpApplicationName, - __inout_opt LPWSTR lpCommandLine, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCWSTR lpCurrentDirectory, - __in LPSTARTUPINFOW lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation) + __in HANDLE hToken, + __in DWORD dwLogonFlags, + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation) { BOOL ret = CreateProcessWithTokenW_orig( hToken, @@ -1179,8 +2488,8 @@ BOOL WINAPI CreateProcessWithTokenW_hook( /* Ignore mspdbsrv.exe, since it continues to run in the background */ if(!lpApplicationName || wcscasestr(lpApplicationName, L"mspdbsrv.exe") == NULL - || wcscasestr(lpApplicationName, L"tup32detect.exe") == NULL) { - tup_inject_dll(lpProcessInformation, s_depfilename, s_vardict_file); + || wcscasestr(lpApplicationName, L"tup32detect.exe") == NULL) { + tup_inject_dll_w(lpProcessInformation, s_depfilename, s_vardict_file); } if ((dwCreationFlags & CREATE_SUSPENDED) != 0) @@ -1189,49 +2498,214 @@ BOOL WINAPI CreateProcessWithTokenW_hook( return ResumeThread(lpProcessInformation->hThread) != 0xFFFFFFFF; } -int rename_hook(const char *oldpath, const char *newpath) +int _access_hook(const char *pathname, int mode) { - handle_file(oldpath, newpath, ACCESS_RENAME); - return rename_orig(oldpath, newpath); + int rc; + char variantPathName[MAX_PATH]; + const char *path = pathname; + DWORD err; + + rc = _access_orig(path, mode); + + if (rc == -1 && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(path, variantPathName, MAX_PATH) == 0) { + path = variantPathName; + rc = _access_orig(path, mode); + } + if (rc == -1) { + path = pathname; + SetLastError(err); + } + } + + DEBUG_HOOK("_access_hook: %s (%d)\n", path, rc); + handle_file(path, NULL, ACCESS_READ); + return rc; } -/* -------------------------------------------------------------------------- */ +FILE *fopen_hook(const char *path, const char *mode) +{ + char variantPathName[MAX_PATH]; + const char *pathName = path; + DWORD err; + FILE *ret = fopen_orig(pathName, mode); + + if (ret == NULL && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(pathName, variantPathName, MAX_PATH) == 0) { + pathName = variantPathName; + ret = fopen_orig(pathName, mode); + } + if (ret == NULL) { + pathName = path; + SetLastError(err); + } + } + + DEBUG_HOOK("fopen %s mode = %s\n", pathName, mode); + + if (strchr(mode, 'w') == NULL && + strchr(mode, 'a') == NULL && + (strchr(mode, '+') == NULL || ret == NULL)) { + handle_file(pathName, NULL, ACCESS_READ); + } else { + handle_file(pathName, NULL, ACCESS_WRITE); + } + return ret; +} + +int rename_hook(const char *oldpath, const char *newpath) +{ + int rc; + char variantPathName[MAX_PATH]; + const char *path = oldpath; + DWORD err; + + rc = rename_orig(path, newpath); + + if (rc == -1 && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(path, variantPathName, MAX_PATH) == 0) { + path = variantPathName; + rc = rename_orig(path, newpath); + } + if (rc == -1) { + path = oldpath; + SetLastError(err); + } + } + + DEBUG_HOOK("rename_hook: %s => %s\n", path, newpath); + handle_file(path, newpath, ACCESS_RENAME); + return rc; +} +int remove_hook(const char *pathname) +{ + int rc; + char variantPathName[MAX_PATH]; + const char *path = pathname; + DWORD err; + rc = remove_orig(path); + + if (rc == -1 && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(path, variantPathName, MAX_PATH) == 0) { + path = variantPathName; + rc = remove_orig(path); + } + if (rc == -1) { + path = pathname; + SetLastError(err); + } + } -typedef HMODULE (WINAPI *LoadLibraryA_t)(const char*); -typedef FARPROC (WINAPI *GetProcAddress_t)(HMODULE, const char*); + DEBUG_HOOK("remove_hook: %s\n", path); + handle_file(path, NULL, ACCESS_UNLINK); + return rc; +} +int _stat64_hook(const char *path, void *buffer) +{ + int rc; + char variantPathName[MAX_PATH]; + const char *pathName = path; + DWORD err; + + rc = _stat64_orig(pathName, buffer); + if (rc == -1 && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(pathName, variantPathName, MAX_PATH) == 0) { + pathName = variantPathName; + rc = _stat64_orig(pathName, buffer); + } + if (rc == -1) { + pathName = path; + SetLastError(err); + } + } + DEBUG_HOOK("_stat_hook: %s (%d)\n", pathName, rc); + handle_file(pathName, NULL, ACCESS_READ); + return rc; +} -struct remote_thread_t +int _stat32_hook(const char *path, void *buffer) { + int rc; + char variantPathName[MAX_PATH]; + const char *pathName = path; + DWORD err; + + rc = _stat32_orig(pathName, buffer); + if (rc == -1 && HAS_VARIANTS()) { + err = GetLastError(); + if (variant_to_source(pathName, variantPathName, MAX_PATH) == 0) { + pathName = variantPathName; + rc = _stat32_orig(pathName, buffer); + } + if (rc == -1) { + pathName = path; + SetLastError(err); + } + } + + DEBUG_HOOK("_stat_hook32: %s (%d)\n", pathName, rc); + handle_file(pathName, NULL, ACCESS_READ); + return rc; +} + +typedef HMODULE(WINAPI *LoadLibraryA_t)(const char*); +typedef FARPROC(WINAPI *GetProcAddress_t)(HMODULE, const char*); + +// #define USE_WIDE_PATHS_IN_REMOTE_THREAD +// This will require a recompilation of the injection `init` code + +struct remote_thread_t { LoadLibraryA_t load_library; GetProcAddress_t get_proc_address; +#ifdef USE_WIDE_PATHS_IN_REMOTE_THREAD + wchar_t depfilename[MAX_PATH]; + wchar_t vardict_file[MAX_PATH]; + wchar_t execdir[MAX_PATH]; + wchar_t dll_name[MAX_PATH]; +#else char depfilename[MAX_PATH]; char vardict_file[MAX_PATH]; char execdir[MAX_PATH]; char dll_name[MAX_PATH]; +#endif char func_name[256]; }; -struct remote_thread32_t -{ +struct remote_thread32_t { uint32_t load_library; uint32_t get_proc_address; +#ifdef USE_WIDE_PATHS_IN_REMOTE_THREAD + wchar_t depfilename[MAX_PATH]; + wchar_t vardict_file[MAX_PATH]; + wchar_t execdir[MAX_PATH]; + wchar_t dll_name[MAX_PATH]; +#else char depfilename[MAX_PATH]; char vardict_file[MAX_PATH]; char execdir[MAX_PATH]; char dll_name[MAX_PATH]; +#endif char func_name[256]; }__attribute__((packed)); - - - #define HOOK(name) { MODULE_NAME, #name, name##_hook, (void**)&name##_orig, 0 } static struct patch_entry patch_table[] = { #define MODULE_NAME "kernel32.dll" HOOK(OpenFile), +#if 0 + HOOK(CreateFileA), + HOOK(CreateFileW), + HOOK(CreateFileTransactedA), + HOOK(CreateFileTransactedW), +#endif HOOK(DeleteFileA), HOOK(DeleteFileW), HOOK(DeleteFileTransactedA), @@ -1275,22 +2749,22 @@ static struct patch_entry patch_table[] = { HOOK(NtCreateUserProcess), #undef MODULE_NAME #define MODULE_NAME "msvcrt.dll" + HOOK(_access), + //HOOK(fopen), // Redundant, as it chains to NtCreateFile anyway HOOK(rename), + HOOK(remove), + HOOK(_stat64), + HOOK(_stat32), }; #undef HOOK #undef MODULE_NAME -enum { patch_table_len = sizeof( patch_table ) / sizeof( patch_table[0] ) }; - +enum { patch_table_len = countof(patch_table) }; /* -------------------------------------------------------------------------- */ -static char execdir[MAX_PATH]; - void tup_inject_setexecdir(const char* dir) { - execdir[0] = '\0'; - strncat(execdir, dir, MAX_PATH); - execdir[MAX_PATH - 1] = '\0'; + ansi_to_wchar(dir, execdir, MAX_PATH); } /* -------------------------------------------------------------------------- */ @@ -1299,13 +2773,13 @@ static const char *strcasestr(const char *arg1, const char *arg2) { const char *a, *b; - for(;*arg1;arg1++) { + for (; *arg1; arg1++) { a = arg1; b = arg2; - while(tolower(*a++) == tolower(*b++)) { - if(!*b) { + while (tolower(*a++) == tolower(*b++)) { + if (!*b) { return (arg1); } } @@ -1319,13 +2793,13 @@ static const wchar_t *wcscasestr(const wchar_t *arg1, const wchar_t *arg2) { const wchar_t *a, *b; - for(;*arg1;arg1++) { + for (; *arg1; arg1++) { a = arg1; b = arg2; - while(tolower(*a++) == tolower(*b++)) { - if(!*b) { + while (tolower(*a++) == tolower(*b++)) { + if (!*b) { return (arg1); } } @@ -1366,7 +2840,7 @@ static int ignore_file_w(const wchar_t* file) return 0; } -static int canon_path(const wchar_t *file, int filelen, char *dest) +static int canon_path_w(const wchar_t *file, int filelen, wchar_t *dest) { wchar_t widepath[WIDE_PATH_MAX]; wchar_t widefullpath[WIDE_PATH_MAX]; @@ -1431,13 +2905,27 @@ static int canon_path(const wchar_t *file, int filelen, char *dest) } DEBUG_HOOK("GetFullPathName[%ls] -> %i, '%ls'\n", widepath, len, widefullpath); - count = WideCharToMultiByte(CP_UTF8, 0, widefullpath+prefix_len, len+1-prefix_len, dest, WIDE_PATH_MAX, NULL, NULL); - if(!count) { - goto out_empty; - } - DEBUG_HOOK("WideCharToMultiByte[%ls] -> %i, '%s'\n", widefullpath, count, dest); + count = len+1-prefix_len; + wcsncpy(dest, widefullpath+prefix_len, count); + DEBUG_HOOK("CanonPath W [%ls] -> %i, '%S'\n", widefullpath, count, dest); /* Discount the nul-terminator */ + return count; + +out_empty: + dest[0] = 0; + return 0; +} + +static int canon_path(const wchar_t *file, int filelen, char *dest) +{ + wchar_t canonical[WIDE_PATH_MAX]; + int len = canon_path_w(file, filelen, canonical); + int count = WideCharToMultiByte(CP_UTF8, 0, canonical, len, dest, WIDE_PATH_MAX, NULL, NULL); + if(!count) + goto out_empty; + + DEBUG_HOOK("CanonPath A: '%s'\n", dest); return count - 1; out_empty: @@ -1533,59 +3021,212 @@ static int open_file(const char *depfilename) return 0; } -/* -------------------------------------------------------------------------- */ +static int open_vardict_file(const char *vardict_file) +{ + vardicth = CreateFileA(vardict_file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (vardicth == INVALID_HANDLE_VALUE) { + /* Not an error if the file doesn't exist - we may not have a vardict. */ + if (GetLastError() != ERROR_FILE_NOT_FOUND) { + fprintf(stderr, "tup error: Unable to open vardict file '%s' in dllinject. Windows error code: 0x%08lx\n", vardict_file, GetLastError()); + return -1; + } + } + return 0; +} BOOL WINAPI DllMain(HANDLE HDllHandle, DWORD Reason, LPVOID Reserved) { - (void) HDllHandle; - (void) Reason; - (void) Reserved; - return 1; + (void)HDllHandle; + + CHAR filename[1024]; + HANDLE currentProcess; + + currentProcess = GetCurrentProcess(); + GetProcessImageFileNameA(currentProcess, filename, 1024); + + switch (Reason) { + case DLL_PROCESS_ATTACH: + { + DEBUG_HOOK("DllMain attaching to %s (%s)\n", filename, Reserved == NULL ? "DYNAMIC" : "STATIC"); + if (hHeap == INVALID_HANDLE_VALUE) { + hHeap = GetProcessHeap(); + + if (hHeap == INVALID_HANDLE_VALUE) { + DEBUG_HOOK("Unable to retrieve process heap\n"); + return FALSE; + } + + MemoryPool = HeapAlloc(hHeap, 0, TotalMemory); + if (MemoryPool == NULL) { + DEBUG_HOOK("Memory pool allocation failed\n"); + return FALSE; + } + + hMemoryLock = CreateMutex(NULL, FALSE, NULL); + if (hMemoryLock == NULL) { + DEBUG_HOOK("Memory pool mutex creation failed\n"); + return FALSE; + } + + DEBUG_HOOK("DLL Heap created at %X\n", hHeap); + } else { + DEBUG_HOOK("Heap already initialized!\n"); + } + break; + } + case DLL_PROCESS_DETACH: + DEBUG_HOOK("DllMain detaching from %s (%s)\n", filename, Reserved == NULL ? "ERROR" : "TERMINATING"); + // Only free heap if we are being dynamically unloaded + // Not used while using process heap + if (hHeap != INVALID_HANDLE_VALUE && Reserved == NULL) { + } + break; + case DLL_THREAD_ATTACH: + DEBUG_HOOK("DllMain attached a new thread to %s\n", filename); + break; + } + + + return TRUE; } /* -------------------------------------------------------------------------- */ -typedef DWORD (*tup_init_t)(remote_thread_t*); +static int PathExists(const wchar_t *path) +{ + DWORD attrs = GetFileAttributes(path); + if(attrs == INVALID_FILE_ATTRIBUTES) { + DWORD error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND || + error == ERROR_PATH_NOT_FOUND || + error == ERROR_INVALID_NAME || + error == ERROR_BAD_NETPATH) + return 0; + } + + return 1; +} + +typedef DWORD(*tup_init_t)(remote_thread_t*); DWORD tup_inject_init(remote_thread_t* r) { static int initialised = 0; char filename[MAX_PATH]; + char vardict_env[64]; + int vardict_fd = -1; OSVERSIONINFO osinfo; - if (initialised) + if (initialised) { + DEBUG_HOOK("tup_inject_init ran twice..\n"); return 0; + } initialised = 1; - if (!GetModuleFileNameA(NULL, filename, sizeof(filename))) { + if (!GetProcessImageFileNameA(GetCurrentProcess(), filename, sizeof(filename))) { return 1; } - DEBUG_HOOK("Inside tup_dllinject_init '%s' '%s' '%s' '%s' '%s'\n", - filename, - r->execdir, - r->dll_name, - r->func_name, - r->depfilename); + if (r != NULL) { + DEBUG_HOOK("Inside tup_dllinject_init '%s' '%S' '%S' '%s' '%S'\n", + filename, + r->execdir, + r->dll_name, + r->func_name, + r->depfilename); + } else { + DEBUG_HOOK("Inside tup_dllinject_init 'tup.exe'\n"); + } DEBUG_HOOK(" - injected into %d: %s\n", GetCurrentProcessId(), GetCommandLineA()); - tup_inject_setexecdir(r->execdir); + if (r != NULL) { + //safewcpy(execdir, r->execdir); + ansi_to_wchar(r->execdir, execdir, countof(execdir)); - if (open_file(r->depfilename)) - return 1; - _putenv_s(TUP_VARDICT_NAME, r->vardict_file); + if (open_vardict_file(r->vardict_file)) + return 1; + + if (vardicth != INVALID_HANDLE_VALUE) { + vardict_fd = _open_osfhandle((intptr_t)vardicth, 0); + } + snprintf(vardict_env, sizeof(vardict_env), TUP_VARDICT_NAME "=%i", vardict_fd); + vardict_env[sizeof(vardict_env) - 1] = 0; + putenv(vardict_env); + //safewcpy(s_vardict_file, r->vardict_file); + ansi_to_wchar(r->vardict_file, s_vardict_file, countof(s_vardict_file)); + + handle_file(filename, NULL, ACCESS_READ); + + if (open_file(r->depfilename)) + return 1; + + //safewcpy(s_depfilename, r->depfilename); + ansi_to_wchar(r->depfilename, s_depfilename, countof(s_depfilename)); + + } + + /* Find top-level directory, start at CWD */ + GetCurrentDirectory(MAX_PATH, tuptopdir); + + WIN32_FIND_DATA ffd; + HANDLE hFind = INVALID_HANDLE_VALUE; + wchar_t pathBuffer[MAX_PATH]; + BOOL foundTopLevel = FALSE; + + while (foundTopLevel == FALSE) { + swprintf(pathBuffer, MAX_PATH, L"%S\\.tup", tuptopdir); + DEBUG_HOOK("Checking %S for tuptopdir\n", pathBuffer); + if (PathExists(pathBuffer)) { + foundTopLevel = TRUE; + } else { + // Possibly a variant? (Not a variant if there is only a tup.config at the root hence the else) + if (!HAS_VARIANTS()) { + swprintf(pathBuffer, MAX_PATH, L"%S\\tup.config", tuptopdir); + if (PathExists(pathBuffer)) { + if (!add_variant(tuptopdir)) { + DEBUG_HOOK("Unable to add variant\n"); + } + DEBUG_HOOK("%S in Variant: %S\n", filename, tuptopdir); + } + } + swprintf(tuptopdir, MAX_PATH, L"%.*ls", (int)(wcsrchr(tuptopdir, '\\') - tuptopdir), tuptopdir); + } + } - strcpy(s_depfilename, r->depfilename); - strcpy(s_vardict_file, r->vardict_file); + if (foundTopLevel) { + DEBUG_HOOK("Found Tup-Src dir at: %S\n", tuptopdir); + } else { + DEBUG_HOOK("FATAL-ERROR: Did not find Tup-Src dir\n"); + } - handle_file(filename, NULL, ACCESS_READ); + // tup.exe needs to find all variant directories + if (r == NULL) { + swprintf(pathBuffer, MAX_PATH, L"%S\\*", tuptopdir); + hFind = FindFirstFile(pathBuffer, &ffd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && ffd.cFileName[0] != '.') { + swprintf(pathBuffer, MAX_PATH, L"%S\\%S\\tup.config", tuptopdir, ffd.cFileName); + if (PathExists(pathBuffer)) { + swprintf(pathBuffer, MAX_PATH, L"%S\\%S", tuptopdir, ffd.cFileName); + DEBUG_HOOK("TUP: Found Variant Directory: %S\n", pathBuffer); + if (!add_variant(pathBuffer)) { + DEBUG_HOOK("Unable to add variant\n"); + } + } + } + } while (FindNextFile(hFind, &ffd) != 0); + } + } /* What a horrible API... */ osinfo.dwOSVersionInfoSize = sizeof(osinfo); GetVersionEx(&osinfo); - if(osinfo.dwMajorVersion >= 6) { + DEBUG_HOOK("Os Version: %X - %X\n", osinfo.dwMajorVersion, osinfo.dwMinorVersion); + + if (osinfo.dwMajorVersion >= 6) { /* Only hot patch for Windows Vista and above. Hot patching * here gets our hook for FindFirstFile, which iat patching * doesn't get for some reason. I also tried to just iat patch @@ -1596,205 +3237,143 @@ DWORD tup_inject_init(remote_thread_t* r) * hot patching breaks file removal for some reason, so for * example 'gcc -flto foo.o -o foo.exe' will fail. */ - hot_patch( patch_table, patch_table + patch_table_len ); + hot_patch(patch_table, patch_table + patch_table_len); } - iat_patch( patch_table, patch_table + patch_table_len ); + iat_patch(patch_table, patch_table + patch_table_len); return 0; } -#ifdef _WIN64 -int remote_stub(void); -__asm( - ".globl remote_stub\n" - "remote_stub:\n" - "subq $8, %rsp\n" - "movl $0x556677, (%rsp)\n" // return address, [0x7] - "movl $0x11223344, 4(%rsp)\n" // return address, [0xf] - "pushf\n" - "push %r15\n" - "push %r14\n" - "push %r13\n" - "push %r12\n" - "push %r11\n" - "push %r10\n" - "push %r9\n" - "push %r8\n" - "push %rbp\n" - "push %rdi\n" - "push %rsi\n" - "push %rdx\n" - "push %rcx\n" - "push %rbx\n" - "push %rax\n" - "xorq %rcx, %rcx\n" - "movq $0x1100000055667788, %rcx\n" // function parameter [0x30] - "xorq %rax, %rax\n" - "movq $0x9900000055667788, %rax\n" // function to call, [0x3d] - "call *%rax\n" - "pop %rax\n" - "pop %rbx\n" - "pop %rcx\n" - "pop %rdx\n" - "pop %rsi\n" - "pop %rdi\n" - "pop %rbp\n" - "pop %r8\n" - "pop %r9\n" - "pop %r10\n" - "pop %r11\n" - "pop %r12\n" - "pop %r13\n" - "pop %r14\n" - "pop %r15\n" - "popf\n" - "ret" -); - -static void WINAPI remote_init( remote_thread_t *r ) -{ - HMODULE h; - tup_init_t p; - h = r->load_library(r->dll_name); - if (!h) - return; - - p = (tup_init_t) r->get_proc_address(h, r->func_name); - if (!p) - return; - - p(r); -} - -static void remote_end(void) -{ -} -#endif - - -#if __DBG_W64 == 1 -static void printHex(const void *lpvbits, const unsigned int n) -{ - char* data = (char*) lpvbits; - unsigned int i = 0; - char line[17] = {}; - printf("%.8X | ", (unsigned char*)data); - while ( i < n ) { - line[i%16] = *(data+i); - if ((line[i%16] < 32) || (line[i%16] > 126)) { - line[i%16] = '.'; - } - printf("%.2X", (unsigned char)*(data+i)); - i++; - if (i%4 == 0) { - if (i%16 == 0) { - if (i < n-1) - printf(" | %s\n%.8X | ", &line, data+i); - } else { - printf(" "); - } - } - } - while (i%16 > 0) { - (i%4 == 0)?printf(" "):printf(" "); - line[i%16] = ' '; - i++; - } - printf(" | %s\n", &line); -} -#endif - -inline long long unsigned int low32(long long unsigned int tall) +inline long long unsigned int low32(long long unsigned int num) { - return tall & 0x00000000ffffffff; + return num & 0x00000000ffffffff; } -inline long long unsigned int high32(long long unsigned int tall) +inline long long unsigned int high32(long long unsigned int num) { - return tall >> 32; + return num >> 32; } -struct remote_stub_t { - uint8_t stub[23]; - uint8_t fileA_Hook[39]; - uint8_t fileW_Hook[39]; +struct remote_stub32_t { + uint8_t stub[22]; uint8_t remote_init[60]; }__attribute__((packed)); -static struct remote_stub_t remote_stub32 = { +static struct remote_stub32_t remote_stub32 = { .stub = { -0x68, 0x00, 0x00, 0x00, 0x00, -0x9c, -0x60, -0x68, 0xef, 0xbe, 0xad, 0xde, -0xb8, 0xef, 0xbe, 0xad, 0xde, -0xff, 0xd0, -0x61, -0x9d, -0xc3 -}, - .fileA_Hook = { -0x55, -0x89, 0xe5, -0x83, 0xec, 0x18, -0x8b, 0x45, 0x0c, -0x89, 0x44, 0x24, 0x04, -0x8b, 0x45, 0x08, -0x89, 0x04, 0x24, -0xff, 0x15, 0x78, 0x00, 0x00, 0x00, -0x85, 0xc0, -0x52, -0x0f, 0x95, 0xc0, -0x52, -0x0f, 0xb6, 0xc0, -0xc9, -0xc2, 0x08, 0x00 -}, - - .fileW_Hook = { -0x55, -0x89, 0xe5, -0x83, 0xec, 0x18, -0x8b, 0x45, 0x0c, -0x89, 0x44, 0x24, 0x04, -0x8b, 0x45, 0x08, -0x89, 0x04, 0x24, -0xff, 0x15, 0x7c, 0x00, 0x00, 0x00, -0x85, 0xc0, -0x51, -0x0f, 0x95, 0xc0, -0x51, -0x0f, 0xb6, 0xc0, -0xc9, -0xc2, 0x08, 0x00 -}, + 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x00000000 + 0x9c, // pushf + 0x60, // pusha + 0x68, 0xef, 0xbe, 0xad, 0xde, // push $0xdeadbeef + 0xb8, 0xef, 0xbe, 0xad, 0xde, // mov $0xdeadbeef,%eax + 0xff, 0xd0, // call *%eax + 0x61, // popa + 0x9d, // popf + 0xc3 // ret + }, + .remote_init = { + 0x55, // push %ebp + 0x89, 0xe5, // mov %esp,%ebp + 0x53, // push %ebx + 0x83, 0xec, 0x14, // sub $0x14,%esp + 0x8b, 0x5d, 0x08, // mov 0x8(%ebp),%ebx + 0x8d, 0x83, 0x14, 0x03, 0x00, 0x00, // lea 0x314(%ebx),%eax + 0x89, 0x04, 0x24, // mov %eax,(%esp) + 0xff, 0x13, // call *(%ebx) + 0x85, 0xc0, // test %eax,%eax + 0x51, // push %ecx + 0x74, 0x1b, // je 0x1b + 0x8d, 0x93, 0x18, 0x04, 0x00, 0x00, // lea 0x418(%ebx),%edx + 0x89, 0x54, 0x24, 0x04, // mov %edx,0x4(%esp) + 0x89, 0x04, 0x24, // mov %eax,(%esp) + 0xff, 0x53, 0x04, // call *0x4(%ebx) + 0x85, 0xc0, // test %eax,%eax + 0x52, // push %edx + 0x52, // push %edx + 0x74, 0x05, // je 0x05 + 0x89, 0x1c, 0x24, // mov %ebx,(%esp) + 0xff, 0xd0, // call *%eax + 0x8b, 0x5d, 0xfc, // mov -0x4(%ebp),%ebx + 0xc9, // leave + 0xc2, 0x04, 0x00 // ret $0x4 + } +}; + +#ifdef _WIN64 +struct remote_stub64_t { + uint8_t stub[96]; + uint8_t remote_init[56]; +}__attribute__((packed)); + +static struct remote_stub64_t remote_stub64 = { + .stub = { + 0x48, 0x83, 0xec, 0x08, // sub $0x8,%rsp + 0xc7, 0x04, 0x24, 0x77, 0x66, 0x55, 0x00, // movl $0x556677,(%rsp) + 0xc7, 0x44, 0x24, 0x04, 0x44, 0x33, 0x22, 0x11, // movl $0x11223344,0x4(%rsp) + 0x9c, // pushfq + 0x41, 0x57, // push %r15 + 0x41, 0x56, // push %r14 + 0x41, 0x55, // push %r13 + 0x41, 0x54, // push %r12 + 0x41, 0x53, // push %r11 + 0x41, 0x52, // push %r10 + 0x41, 0x51, // push %r9 + 0x41, 0x50, // push %r8 + 0x55, // push %rbp + 0x57, // push %rdi + 0x56, // push %rsi + 0x52, // push %rdx + 0x51, // push %rcx + 0x53, // push %rbx + 0x50, // push %rax + 0x48, 0x31, 0xc9, // xor %rcx,%rcx + 0x48, 0xb9, 0x88, 0x77, 0x66, 0x55, 0x00, 0x00, 0x00, 0x11, // movabs $0x1100000055667788,%rcx + 0x48, 0x31, 0xc0, // xor %rax,%rax + 0x48, 0xb8, 0x88, 0x77, 0x66, 0x55, 0x00, 0x00, 0x00, 0x99, // movabs $0x9900000055667788,%rax + 0xff, 0xd0, // callq *%rax + 0x58, // pop %rax + 0x5b, // pop %rbx + 0x59, // pop %rcx + 0x5a, // pop %rdx + 0x5e, // pop %rsi + 0x5f, // pop %rdi + 0x5d, // pop %rbp + 0x41, 0x58, // pop %r8 + 0x41, 0x59, // pop %r9 + 0x41, 0x5a, // pop %r10 + 0x41, 0x5b, // pop %r11 + 0x41, 0x5c, // pop %r12 + 0x41, 0x5d, // pop %r13 + 0x41, 0x5e, // pop %r14 + 0x41, 0x5f, // pop %r15 + 0x9d, // popfq + 0xc3, // retq + }, .remote_init = { -0x55, -0x89, 0xe5, -0x53, -0x83, 0xec, 0x14, -0x8b, 0x5d, 0x08, -0x8d, 0x83, 0x14, 0x03, 0x00, 0x00, -0x89, 0x04, 0x24, -0xff, 0x13, -0x85, 0xc0, -0x51, -0x74, 0x1b, // JE 0x1b -0x8d, 0x93, 0x18, 0x04, 0x00, 0x00, -0x89, 0x54, 0x24, 0x04, -0x89, 0x04, 0x24, -0xff, 0x53, 0x04, -0x85, 0xc0, -0x52, -0x52, -0x74, 0x05, // JE 0x05 -0x89, 0x1c, 0x24, -0xff, 0xd0, -0x8b, 0x5d, 0xfc, -0xc9, -0xc2, 0x04, 0x00} + 0x53, // push %rbx + 0x48, 0x83, 0xec, 0x20, // sub $0x20,%rsp + 0x48, 0x89, 0xcb, // mov %rcx,%rbx + 0x48, 0x8d, 0x89, 0x1c, 0x03, 0x00, 0x00, // lea 0x31c(%rcx),%rcx + 0xff, 0x13, // callq *(%rbx) + 0x48, 0x85, 0xc0, // test %rax,%rax + 0x74, 0x1c, // je 93 // jmpq version + 0x48, 0x8d, 0x93, 0x20, 0x04, 0x00, 0x00, // lea 0x420(%rbx),%rdx + 0x48, 0x89, 0xc1, // mov %rax,%rcx + 0xff, 0x53, 0x08, // callq *0x8(%rbx) + 0x48, 0x85, 0xc0, // test %rax,%rax + 0x74, 0x0a, // je 93 // jmpq version + 0x48, 0x89, 0xd9, // mov %rbx,%rcx + 0x48, 0x83, 0xc4, 0x20, // add $0x20,%rsp + 0x5b, // pop %rbx + 0xff, 0xe0, // jmpq *%rax + 0x48, 0x83, 0xc4, 0x20, // add $0x20,%rsp + 0x5b, // pop %rbx + 0xc3, // retq + } }; +#endif + static uint32_t LOAD_LIBRARY_32 = 0; static uint32_t GET_PROC_ADDRESS_32 = 0; @@ -1805,9 +3384,9 @@ BOOL get_wow64_addresses(void) DWORD dwRead; CHAR chBuf[BUFSIZE]; PROCESS_INFORMATION piProcInfo; - STARTUPINFOA siStartInfo; + STARTUPINFOW siStartInfo; BOOL ret; - char cmdline[MAX_PATH]; + wchar_t cmdline[MAX_PATH]; HANDLE g_hChildStd_OUT_Rd = NULL; HANDLE g_hChildStd_OUT_Wr = NULL; @@ -1833,14 +3412,14 @@ BOOL get_wow64_addresses(void) memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION)); - if(snprintf(cmdline, MAX_PATH, "%s\\%s", execdir, "tup32detect.exe") >= MAX_PATH) { + if(swprintf(cmdline, MAX_PATH, L"%S\\%S", execdir, L"tup32detect.exe") >= MAX_PATH) { fprintf(stderr, "tup error: cmdline is sized wrong for tup32detect.exe"); return FALSE; } // Detect and avoid inception! - if (CreateProcessA_orig != NULL) - ret = CreateProcessA_orig( + if (CreateProcessW_orig != NULL) + ret = CreateProcessW_orig( NULL, cmdline, NULL, @@ -1852,7 +3431,7 @@ BOOL get_wow64_addresses(void) &siStartInfo, &piProcInfo); else - ret = CreateProcessA( + ret = CreateProcessW( NULL, cmdline, NULL, @@ -1869,7 +3448,7 @@ BOOL get_wow64_addresses(void) return FALSE; } - ret = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL); + ret = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL); if (!ret || dwRead == 0) return FALSE; @@ -1883,29 +3462,33 @@ BOOL get_wow64_addresses(void) return TRUE; } +#ifdef _WIN64 - -int tup_inject_dll( +static int tup_inject_dll_w( LPPROCESS_INFORMATION lpProcessInformation, - const char *depfilename, - const char *vardict_file) + const wchar_t *depfilename, + const wchar_t *vardict_file) { char* remote_data; size_t code_size; DWORD old_protect; HANDLE process; - BOOL bWow64 = 0; + BOOL bWow64 = 0; IsWow64Process(lpProcessInformation->hProcess, &bWow64); - // WOW64 - DEBUG_HOOK("%s is WOW64: %i\n", GetCommandLineA(), bWow64); + CHAR buffer[1024]; + if (GetProcessImageFileNameA(lpProcessInformation->hProcess, buffer, 1024)) { + DEBUG_HOOK("%s is WOW64: %i\n", buffer, bWow64); + } + + // Loading 32bit application from 64bit application if (bWow64) { remote_thread32_t remote; if (GET_PROC_ADDRESS_32 == 0) { - if ( ! get_wow64_addresses() ) { - printf("Unable to retrieve WOW64 info\n"); + if (!get_wow64_addresses()) { + DEBUG_HOOK("Unable to retrieve WOW64 info\n"); return -1; } } @@ -1913,23 +3496,31 @@ int tup_inject_dll( memset(&remote, 0, sizeof(remote)); remote.load_library = LOAD_LIBRARY_32; remote.get_proc_address = GET_PROC_ADDRESS_32; - strcpy(remote.depfilename, depfilename); - strcpy(remote.vardict_file, vardict_file); - strcat(remote.execdir, execdir); - strcat(remote.dll_name, execdir); - strcat(remote.dll_name, "\\"); - strcat(remote.dll_name, "tup-dllinject32.dll"); - strcat(remote.func_name, "tup_inject_init"); - + #if USE_WIDE_PATHS_IN_REMOTE_THREAD + wcscpy(remote.depfilename, depfilename); + wcscpy(remote.vardict_file, vardict_file); + wcscpy(remote.execdir, execdir); + wcscpy(remote.dll_name, execdir); + wcscat(remote.dll_name, L"\\"); + wcscat(remote.dll_name, L"tup-dllinject32.dll"); + strcpy(remote.func_name, "tup_inject_init"); + #else + wchar_to_ansi(depfilename, remote.depfilename, MAX_PATH); + wchar_to_ansi(vardict_file, remote.vardict_file, MAX_PATH); + wchar_to_ansi(execdir, remote.execdir, MAX_PATH); + wchar_to_ansi(execdir, remote.dll_name, MAX_PATH); + strcat(remote.dll_name, "\\tup-dllinject32.dll"); + strcpy(remote.func_name, "tup_inject_init"); + #endif WOW64_CONTEXT ctx; ctx.ContextFlags = WOW64_CONTEXT_CONTROL; - if ( !Wow64GetThreadContext( lpProcessInformation->hThread, &ctx ) ) + if (!Wow64GetThreadContext(lpProcessInformation->hThread, &ctx)) return -1; /* Align code_size to a 16 byte boundary */ code_size = (sizeof(remote_stub32) + 0x0F) & ~0x0F; - DEBUG_HOOK("Injecting dll '%s' '%s' %s' '%s'\n", + DEBUG_HOOK("Injecting dll '%s' '%s' %s' '%s' '%s'\n", remote.execdir, remote.dll_name, remote.func_name, @@ -1941,72 +3532,94 @@ int tup_inject_dll( if (!WaitForInputIdle(process, INFINITE)) return -1; - remote_data = (char*) VirtualAllocEx( + remote_data = (char*)VirtualAllocEx( process, NULL, code_size + sizeof(remote), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (!remote_data) + if (!remote_data) { + DEBUG_HOOK("FAILURE to allocate remote process memory\n"); return -1; + } - if (!VirtualProtectEx(process, remote_data, code_size + sizeof(remote), PAGE_READWRITE, &old_protect)) + if (!VirtualProtectEx(process, remote_data, code_size + sizeof(remote), PAGE_READWRITE, &old_protect)) { + DEBUG_HOOK("FAILURE to set remote process memory to read/write\n"); return -1; + } unsigned char code[code_size]; + memset(code, 0, code_size); - memcpy( code, &remote_stub32, code_size ); + memcpy(code, &remote_stub32, sizeof(remote_stub32)); *(DWORD*)(code + 0x1) = ctx.Eip; // Return addr *(DWORD*)(code + 0x8) = (DWORD)((DWORD_PTR)remote_data + code_size); // Arg (ptr to remote (TCB)) *(DWORD*)(code + 0xd) = (DWORD)((DWORD_PTR)remote_data + ((DWORD_PTR)&remote_stub32.remote_init - (DWORD_PTR)&remote_stub32)); // Func (ptr to remote_init) - if (!WriteProcessMemory(process, remote_data, code, code_size, NULL)) + if (!WriteProcessMemory(process, remote_data, code, code_size, NULL)) { + DEBUG_HOOK("FAILURE to write code to remote process memory\n"); return -1; + } - if (!WriteProcessMemory(process, remote_data + code_size, &remote, sizeof(remote), NULL)) + if (!WriteProcessMemory(process, remote_data + code_size, &remote, sizeof(remote), NULL)) { + DEBUG_HOOK("FAILURE to write data to remote process memory\n"); return -1; + } - if (!VirtualProtectEx(process, remote_data, code_size + sizeof(remote), PAGE_EXECUTE_READ, &old_protect)) + if (!VirtualProtectEx(process, remote_data, code_size + sizeof(remote), PAGE_EXECUTE_READ, &old_protect)) { + DEBUG_HOOK("FAILURE to set remote process memory to executable\n"); return -1; + } - if (!FlushInstructionCache(process, remote_data, code_size + sizeof(remote))) + if (!FlushInstructionCache(process, remote_data, code_size + sizeof(remote))) { + DEBUG_HOOK("FAILURE to flush remote process instruction cache\n"); return -1; + } ctx.Eip = (DWORD_PTR)remote_data; ctx.ContextFlags = WOW64_CONTEXT_CONTROL; - if( !Wow64SetThreadContext( lpProcessInformation->hThread, &ctx ) ) + if (!Wow64SetThreadContext(lpProcessInformation->hThread, &ctx)) { + DEBUG_HOOK("FAILURE to set remote process thread context\n"); return -1; + } } else { -#ifdef _WIN64 HMODULE kernel32; remote_thread_t remote; memset(&remote, 0, sizeof(remote)); kernel32 = LoadLibraryA("kernel32.dll"); - remote.load_library = (LoadLibraryA_t) GetProcAddress(kernel32, "LoadLibraryA"); - remote.get_proc_address = (GetProcAddress_t) GetProcAddress(kernel32, "GetProcAddress"); - strcpy(remote.depfilename, depfilename); - strcpy(remote.vardict_file, vardict_file); - strcat(remote.execdir, execdir); - strcat(remote.dll_name, execdir); - strcat(remote.dll_name, "\\"); - strcat(remote.dll_name, "tup-dllinject.dll"); - strcat(remote.func_name, "tup_inject_init"); - + remote.load_library = (LoadLibraryA_t)GetProcAddress(kernel32, "LoadLibraryA"); + remote.get_proc_address = (GetProcAddress_t)GetProcAddress(kernel32, "GetProcAddress"); + +#if USE_WIDE_PATHS_IN_REMOTE_THREAD + wcscpy(remote.depfilename, depfilename); + wcscpy(remote.vardict_file, vardict_file); + wcscpy(remote.execdir, execdir); + wcscpy(remote.dll_name, execdir); + wcscat(remote.dll_name, L"\\"); + wcscat(remote.dll_name, L"tup-dllinject.dll"); + strcpy(remote.func_name, "tup_inject_init"); +#else + wchar_to_ansi(depfilename, remote.depfilename, MAX_PATH); + wchar_to_ansi(vardict_file, remote.vardict_file, MAX_PATH); + wchar_to_ansi(execdir, remote.execdir, MAX_PATH); + wchar_to_ansi(execdir, remote.dll_name, MAX_PATH); + strcat(remote.dll_name, "\\tup-dllinject.dll"); + strcpy(remote.func_name, "tup_inject_init"); +#endif CONTEXT ctx; ctx.ContextFlags = CONTEXT_CONTROL; - if( !GetThreadContext( lpProcessInformation->hThread, &ctx ) ) + if (!GetThreadContext(lpProcessInformation->hThread, &ctx)) { + DEBUG_HOOK("FAILURE to get thread context\n"); return -1; + } /* Align code_size to a 16 byte boundary */ - code_size = ( (uintptr_t) &remote_end - - (uintptr_t) &remote_stub + 0x0F) - & ~0x0F; + code_size = (sizeof(remote_stub64) + 0x0F) & ~0x0F; - - DEBUG_HOOK("Injecting dll '%s' '%s' %s' '%s'\n", + DEBUG_HOOK("Injecting dll '%s' '%s' %s' '%s' '%s'\n", remote.execdir, remote.dll_name, remote.func_name, @@ -2015,10 +3628,12 @@ int tup_inject_dll( process = lpProcessInformation->hProcess; - if (!WaitForInputIdle(process, INFINITE)) + if (!WaitForInputIdle(process, INFINITE)) { + DEBUG_HOOK("FAILURE from WaitForInputIdle\n"); return -1; + } - remote_data = (char*) VirtualAllocEx( + remote_data = (char*)VirtualAllocEx( process, NULL, code_size + sizeof(remote), @@ -2032,12 +3647,13 @@ int tup_inject_dll( return -1; unsigned char code[code_size]; + memset(code, 0, code_size); - memcpy( code, &remote_stub, code_size ); + memcpy(code, &remote_stub64, sizeof(remote_stub64)); *(DWORD*)(code + 0x7) = low32(ctx.Rip); *(DWORD*)(code + 0xf) = high32(ctx.Rip); *(DWORD64*)(code + 0x30) = (long long unsigned int)(remote_data + code_size); - *(DWORD64*)(code + 0x3d) = (long long unsigned int)(DWORD_PTR)remote_data + ((DWORD_PTR)&remote_init - (DWORD_PTR)&remote_stub); + *(DWORD64*)(code + 0x3d) = (long long unsigned int)(DWORD_PTR)remote_data + ((DWORD_PTR)&remote_stub64.remote_init - (DWORD_PTR)&remote_stub64); if (!WriteProcessMemory(process, remote_data, code, code_size, NULL)) return -1; @@ -2053,13 +3669,131 @@ int tup_inject_dll( ctx.Rip = (DWORD_PTR)remote_data; ctx.ContextFlags = CONTEXT_CONTROL; - if( !SetThreadContext( lpProcessInformation->hThread, &ctx ) ) + if (!SetThreadContext(lpProcessInformation->hThread, &ctx)) return -1; + } + + DEBUG_HOOK("DLL Injection successful\n"); + return 0; +} + #else - DEBUG_HOOK("Error: Shouldn't be hooking here for the 32-bit dll.\n"); + +static int tup_inject_dll_w( + LPPROCESS_INFORMATION lpProcessInformation, + const wchar_t *depfilename, + const wchar_t *vardict_file) +{ + char* remote_data; + size_t code_size; + DWORD old_protect; + HANDLE process; + HMODULE kernel32; + remote_thread_t remote; + BOOL bWow64 = 0; + + // Make sure we do not try to inject into 64bit processes + IsWow64Process(lpProcessInformation->hProcess, &bWow64); + if (!bWow64) { + fprintf(stderr, "tup error: Unable to start 64bit applications from 32bit\n"); + fflush(stderr); return -1; + } + + memset(&remote, 0, sizeof(remote)); + kernel32 = LoadLibraryA("kernel32.dll"); + remote.load_library = (LoadLibraryA_t)GetProcAddress(kernel32, "LoadLibraryA"); + remote.get_proc_address = (GetProcAddress_t)GetProcAddress(kernel32, "GetProcAddress"); +#if USE_WIDE_PATHS_IN_REMOTE_THREAD + wcscpy(remote.depfilename, depfilename); + wcscpy(remote.vardict_file, vardict_file); + wcscpy(remote.execdir, execdir); + wcscpy(remote.dll_name, execdir); + wcscat(remote.dll_name, L"\\"); + wcscat(remote.dll_name, L"tup-dllinject32.dll"); + strcpy(remote.func_name, "tup_inject_init"); +#else + wchar_to_ansi(depfilename, remote.depfilename, MAX_PATH); + wchar_to_ansi(vardict_file, remote.vardict_file, MAX_PATH); + wchar_to_ansi(execdir, remote.execdir, MAX_PATH); + wchar_to_ansi(execdir, remote.dll_name, MAX_PATH); + strcat(remote.dll_name, "\\tup-dllinject32.dll"); + strcpy(remote.func_name, "tup_inject_init"); #endif + CONTEXT ctx; + ctx.ContextFlags = CONTEXT_CONTROL; + if (!GetThreadContext(lpProcessInformation->hThread, &ctx)) { + DEBUG_HOOK("Unable to get thread context\n"); + return -1; } + /* Align code_size to a 16 byte boundary */ + code_size = (sizeof(remote_stub32) + 0x0F) & ~0x0F; + + DEBUG_HOOK("Injecting dll '%S' '%S' %s' '%S' '%S'\n", + remote.execdir, + remote.dll_name, + remote.func_name, + remote.depfilename, + remote.vardict_file); + + process = lpProcessInformation->hProcess; + + if (!WaitForInputIdle(process, INFINITE)) + return -1; + + remote_data = (char*)VirtualAllocEx( + process, + NULL, + code_size + sizeof(remote), + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + if (!remote_data) + return -1; + + if (!VirtualProtectEx(process, remote_data, code_size + sizeof(remote), PAGE_READWRITE, &old_protect)) + return -1; + + unsigned char code[code_size]; + memset(code, 0, code_size); + + memcpy(code, &remote_stub32, sizeof(remote_stub32)); + *(DWORD*)(code + 0x1) = ctx.Eip; // Return addr + *(DWORD*)(code + 0x8) = (DWORD)((DWORD_PTR)remote_data + code_size); // Arg (ptr to remote (TCB)) + *(DWORD*)(code + 0xd) = (DWORD)((DWORD_PTR)remote_data + ((DWORD_PTR)&remote_stub32.remote_init - (DWORD_PTR)&remote_stub32)); // Func (ptr to remote_init) + + if (!WriteProcessMemory(process, remote_data, code, code_size, NULL)) + return -1; + + if (!WriteProcessMemory(process, remote_data + code_size, &remote, sizeof(remote), NULL)) + return -1; + + if (!VirtualProtectEx(process, remote_data, code_size + sizeof(remote), PAGE_EXECUTE_READ, &old_protect)) + return -1; + + if (!FlushInstructionCache(process, remote_data, code_size + sizeof(remote))) + return -1; + + ctx.Eip = (DWORD_PTR)remote_data; + ctx.ContextFlags = CONTEXT_CONTROL; + if (!SetThreadContext(lpProcessInformation->hThread, &ctx)) + return -1; + return 0; } + +#endif + +int tup_inject_dll( + LPPROCESS_INFORMATION lpProcessInformation, + const char *depfilename_a, + const char *vardict_file_a) +{ + wchar_t depfilename[MAX_PATH]; + wchar_t vardict_file[MAX_PATH]; + ansi_to_wchar(depfilename_a, depfilename, MAX_PATH); + ansi_to_wchar(vardict_file_a, vardict_file, MAX_PATH); + return tup_inject_dll_w(lpProcessInformation, depfilename, vardict_file); +} + diff --git a/src/tup/server/windepfile.c b/src/tup/server/windepfile.c index e1b206d18..d2812db36 100644 --- a/src/tup/server/windepfile.c +++ b/src/tup/server/windepfile.c @@ -29,9 +29,14 @@ #include "compat/win32/dirpath.h" #include "compat/win32/open_notify.h" #include "compat/dir_mutex.h" +#include "tup/db.h" +#include "tup/parser.h" +#include "tup/fslurp.h" +#include "tup/option.h" #include #include #include +#include #define TUP_TMP ".tup/tmp" @@ -133,6 +138,9 @@ int server_init(enum server_mode mode) return -1; } + // Inject into self + tup_inject_init(NULL); + if(SetConsoleCtrlHandler(console_handler, TRUE) == 0) { perror("SetConsoleCtrlHandler"); fprintf(stderr, "tup error: Unable to set the CTRL-C handler.\n"); @@ -143,8 +151,133 @@ int server_init(enum server_mode mode) return 0; } +typedef struct slist slist; + +struct slist { + wchar_t *name; + slist *next; +}; + + +static void string_add(slist **list, const wchar_t *name) +{ + slist *ptr; + slist *item = calloc(sizeof(slist), 1); + if(name != NULL) + item->name = wcsdup(name); + + if(*list != NULL) { + ptr = *list; + while (ptr->next != NULL) ptr = ptr->next; + ptr->next = item; + } else { + *list = item; + } +} + int server_quit(void) { + if(!server_inited) + return 0; + + chdir(get_tup_top()); + + struct tup_entry *variant_tent, *normal_tent; + tupid_t src_tupid = DOT_DT; + struct tup_entry *src_tent = tup_entry_get(src_tupid); + + // No need to do in-src builds + if(tup_entry_variant_null(src_tent) != NULL) { + if(src_tent->variant->enabled) + return 0; + } + + int cnt = 0; + wchar_t cwd[PATH_MAX]; + _wgetcwd(cwd, PATH_MAX); + + HANDLE hfind; + WIN32_FIND_DATA find_data; + + wchar_t search_string[PATH_MAX]; + wchar_t path_name[PATH_MAX]; + char *path_fragment; + slist *dirs = NULL; + slist *tups = NULL, *tups_copy = NULL; + int link_exists; + + // Start with cwd + string_add(&dirs, L"."); + + do { + // search this directory + swprintf(search_string, PATH_MAX, L"%s\\%s\\*.*", cwd, dirs->name); + + hfind = FindFirstFile(search_string, &find_data); + if(hfind != INVALID_HANDLE_VALUE) { + do { + wsprintf(path_name, L"%s\\%s", dirs->name, find_data.cFileName); + if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && + find_data.cFileName[0] != '.') { + string_add(&dirs, path_name); + } else if(wcsncmp(find_data.cFileName, L"Tupfile", 7) == 0) { + string_add(&tups, path_name); + } + + } while (FindNextFile(hfind, &find_data)); + } + } while ((dirs = dirs->next) != NULL); + + tup_db_open(); + tup_db_begin(); + + // Look up variants + struct variant_head *variants = get_variant_list(); + struct variant *var = variants->lh_first; + + while (var != NULL) { + + if(var->enabled) { + tups_copy = tups; + + while (tups_copy != NULL) { + char utf8_filename[MAX_PATH]; + // First part should be the variant directory + variant_tent = tup_entry_get(var->tent->parent->tnode.tupid); + normal_tent = src_tent; + WideCharToMultiByte(CP_UTF8, 0, tups_copy->name, -1, utf8_filename, PATH_MAX, NULL, NULL); + + path_fragment = strtok(utf8_filename, "\\"); + // Next we resolve in-source Tupfile and variant directory + while ((path_fragment = strtok(NULL, "\\")) != NULL) { + tup_db_select_tent(normal_tent->tnode.tupid, path_fragment, &normal_tent); + // Only after directory for variant + if(strncmp(path_fragment, "Tupfile", 7) != 0) { + tup_db_select_tent(variant_tent->tnode.tupid, path_fragment, &variant_tent); + } + if(normal_tent == NULL || variant_tent == NULL) { + break; + } + } + + if(normal_tent != NULL && variant_tent != NULL) { + cnt++; + link_exists = 0; + tup_db_link_exists(normal_tent->tnode.tupid, variant_tent->tnode.tupid, TUP_LINK_NORMAL, &link_exists); + if(!link_exists) + tup_db_create_link(normal_tent->tnode.tupid, variant_tent->tnode.tupid, TUP_LINK_NORMAL); + } + + tups_copy = tups_copy->next; + } + } + var = var->list.le_next; + } + + tup_db_commit(); + + //fprintf(stderr, "Patched %d dependencies\n", cnt); + return 0; } @@ -232,7 +365,8 @@ static int create_process(struct server *s, int dfd, char *cmdline, #define SHSTR "sh -c '" #define BASHSTR "bash -e -o pipefail -c '" -#define CMDSTR "CMD.EXE /Q /C " +// /D disables potentially harmfull addons +#define CMDSTR "CMD.EXE /D /Q /C " int server_exec(struct server *s, int dfd, const char *cmd, struct tup_env *newenv, struct tup_entry *dtent, int need_namespacing, int run_in_bash) { @@ -251,9 +385,9 @@ int server_exec(struct server *s, int dfd, const char *cmd, struct tup_env *newe struct file_entry *fent; struct file_entry *tmp; - int have_shell = strncmp(cmd, "sh ", 3) == 0 - || strncmp(cmd, "bash ", 5) == 0 - || strncmp(cmd, "cmd ", 4) == 0; + int have_shell = strncasecmp(cmd, "sh ", 3) == 0 + || strncasecmp(cmd, "bash ", 5) == 0 + || strncasecmp(cmd, "cmd ", 4) == 0; int need_sh = 0; int need_cmd = 0; @@ -304,6 +438,15 @@ int server_exec(struct server *s, int dfd, const char *cmd, struct tup_env *newe strcat(cmdline, "'"); } + // Patch up directory slashes + char *slash = strchr(cmdline, '\\'); + while (slash != NULL) { + // Make sure we don't mess up escape characters + if(slash[1] != '\0' && (isalnum(slash[1]) != 0 || slash[1] == '.')) + slash[0] = '/'; + slash = strchr(slash + 1, '\\'); + } + pthread_mutex_lock(&dir_mutex); if(create_process(s, dfd, cmdline, newenv, &pi) < 0) { pthread_mutex_lock(s->error_mutex); @@ -448,7 +591,162 @@ int server_run_script(FILE *f, tupid_t tupid, const char *cmdline, struct tupid_entries *env_root, char **rules) { if(f || tupid || cmdline || env_root || rules) {/* unsupported */} - fprintf(stderr, "tup error: Run scripts are not yet supported on this platform.\n"); + + struct tup_entry *tent; + struct server s; + struct tup_env te; + int need_shell = 0, full_deps = 0, dfd; + CHAR final_cmdline[128]; + char *cr; + struct tup_entry *script_entry = NULL; + + tent = tup_entry_get(tupid); + + // Parse out name of script, without arguments and possibly './' + char *namebuf = strdup(cmdline); + char *name = strchr(namebuf, ' '); + if(name != NULL) { + name[0] = 0; + } + + // If name contains slashes, we assume it is a local + // script, and try to add a dependency. Otherwise + // it is a global script, and TUP can not track it. + if(strstr(namebuf, "/") != NULL && (namebuf[0] != '/' || strstr(namebuf, ":") != NULL)) { + + name = strtok(namebuf, "/"); + + tupid_t target_tupid = tupid; + struct tup_entry *target_tent = tent; + + do { + + // Up a directory + if(strncmp(name, "..", 2) == 0) { + do { + // ../out of source tree + if(target_tent->parent == NULL) + break; + + // Load parent... + target_tupid = target_tent->parent->tnode.tupid; + target_tent = tup_entry_get(target_tupid); + + // Break out when we have a real name + name = strtok(NULL, "/"); + if(strncmp(name, "..", 2) != 0) + break; + + } while (name != NULL); + } + // Skip single dot + else if(strncmp(name, ".", 1) == 0) { + name = strtok(NULL, "/"); + } + + if(tup_entry_variant_null(target_tent) != NULL) { + // Variant + if(target_tent->variant->tent->parent->dt != 0) { + tup_db_select_tent(target_tent->variant->tent->parent->dt, name, &script_entry); + } else { + tup_db_select_tent(target_tupid, name, &script_entry); + } + } + + if(script_entry != NULL) { + target_tupid = script_entry->tnode.tupid; + target_tent = tup_entry_get(target_tupid); + } + + } while ((name = strtok(NULL, "/")) != NULL && script_entry != NULL); + + // Failed. + if(script_entry == NULL) { + fprintf(f, "tup error: unable to locate run-script: '%s'\n", cmdline); + free(namebuf); + return -1; + } + + // Add dependency + struct tupfile *tf = (struct tupfile *) CONTAINING_RECORD(env_root, struct tupfile, env_root); + tupid_tree_add_dup(&tf->input_root, script_entry->tnode.tupid); + } + + // On windows, we invoke 'sh -c' only when using shell scripts, rest is parsed through cmd, + // should work with all kinds of scripts as long as they have a registered type + if(strstr(cmdline, ".sh") != NULL) + need_shell = 1; + + final_cmdline[0] = 0; + if(need_shell) + strcat(final_cmdline, SHSTR); + else + strcat(final_cmdline, CMDSTR); + + strcat(final_cmdline, cmdline); + if(need_shell) + strcat(final_cmdline, "'"); + + free(namebuf); + + if(tup_db_get_environ(env_root, NULL, &te) < 0) + return -1; + + full_deps = tup_option_get_int("updater.full_deps"); + + s.id = tupid; + s.output_fd = -1; + s.error_fd = -1; + s.exited = 0; + s.exit_status = 0; + s.signalled = 0; + s.error_mutex = NULL; + init_file_info(&s.finfo, tup_entry_variant(tent)->variant_dir); + + dfd = tup_entry_open(tent); + + if(server_exec(&s, dfd, final_cmdline, &te, tent, full_deps, 0) != 0) { + fprintf(f, "tup-error: Unable to execute run-script: %s\n", final_cmdline); + return -1; + } + + environ_free(&te); + + if(display_output(s.error_fd, 1, cmdline, 1, f) < 0) + return -1; + if(close(s.error_fd) < 0) { + perror("close(s.error_fd)"); + return -1; + } + + if(s.exited) { + if(s.exit_status == 0) { + struct buf b; + if(fslurp_null(s.output_fd, &b) < 0) + return -1; + if(close(s.output_fd) < 0) { + perror("close(s.output_fd)"); + return -1; + } + + // Remove all carriage return from output + cr = strchr(b.s, '\r'); + while (cr != NULL) { + cr[0] = ' '; + cr = strchr(cr, '\r'); + } + *rules = b.s; + return 0; + } + fprintf(f, "tup error: run-script exited with failure code: %i\n", s.exit_status); + } else { + if(s.signalled) { + fprintf(f, "tup error: run-script terminated with signal %i\n", s.exit_sig); + } else { + fprintf(f, "tup error: run-script terminated abnormally.\n"); + } + } + return -1; }