#define _MICE_FILES #include "files.h" HANDLE open_hook(file_hook_t* file_hook) { open_hook_t* opened = (open_hook_t*)malloc(sizeof(open_hook_t)); ZeroMemory(opened, sizeof *opened); opened->hook = file_hook; HANDLE handle = GetDummyHandle(); opened->ctx.m_Handle = handle; opened->ctx.m_HookData = file_hook->hook_data; SetDataForHandle(handle, HDATA_FILE, opened, TRUE); return handle; } file_hook_t* file_hook_list = NULL; file_hook_t* new_file_hook(LPCWSTR filename) { file_hook_t* hook = (file_hook_t*)malloc(sizeof(file_hook_t)); memset(hook, 0, sizeof *hook); hook->filename = filename; return hook; } void hook_file(file_hook_t* hook) { hook->next = NULL; if (file_hook_list == NULL) { file_hook_list = hook; return; } file_hook_t* hl = file_hook_list; while (hl->next != NULL) hl = hl->next; hl->next = hook; }; drive_redirect_t DRIVE_REDIRECT_TABLE[] = { // Note: Had to create last_shime.log { .drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\" }, // {.drive = "C:\\ProgramData/boost_interprocess/", .path = "\\\\.\\ipc\\"}, }; char _redirected_path[MAX_PATH]; file_hook_t* find_hook(LPCWSTR lpFileName) { file_hook_t* file_hook = file_hook_list; while (file_hook != NULL) { if (wcscmp(lpFileName, file_hook->filename) == 0 || (file_hook->altFilename != NULL && wcscmp(lpFileName, file_hook->altFilename) == 0)) { return file_hook; } file_hook = file_hook->next; } return NULL; }; void make_dirs(char* path) { int count = 0; size_t i; size_t len = strlen(path); while (1) { int n = 0; for (i = 0; i < len; i++) { if (path[i] == '\\' || path[i] == '/' || path[i] == '\0') { if (n++ == count) { path[i] = '\0'; count++; break; } path[i] = '\\'; } } if (i == len) return; CreateDirectory(path, NULL); } } char WORKING_DIR[MAX_PATH + 1] = { 0 }; char get_gamedata_drive() { if (WORKING_DIR[0] == 0x00) { GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR); } return WORKING_DIR[0]; } inline char char_lower(char value) { if ('A' <= value <= 'Z') return value - 'A' + 'a'; return value; } BOOL redirect_path(LPCSTR path, LPCSTR* redirected) { for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) { drive_redirect_t row = DRIVE_REDIRECT_TABLE[i]; if (strncmp(path, row.drive, strlen(row.drive)) == 0) { log_trace(HOOKS_LOGGER, "Redirecting '%s' to '%s'", path, row.path); size_t new_len = strlen(path) - strlen(row.drive) + strlen(row.path); strcpy_s(_redirected_path, new_len + 1, row.path); char* dst = _redirected_path + strlen(row.path); size_t len = strlen(path) - strlen(row.drive); const char* src = path + strlen(row.drive); for (; len > 0; len--) (dst++)[0] = (src++)[0]; dst[0] = 0; log_trace(HOOKS_LOGGER, "New filename: '%s'", _redirected_path); make_dirs(_redirected_path); *redirected = _redirected_path; return TRUE; } } if ((('a' <= path[0] && path[0] <= 'z') || ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) { // TODO: Ca if (char_lower(path[0]) == char_lower(get_gamedata_drive())) { return FALSE; } ZeroMemory(_redirected_path, sizeof _redirected_path); snprintf(_redirected_path, sizeof _redirected_path, "dev\\%c\\%s", char_lower(path[0]), path + 3); make_dirs(_redirected_path); *redirected = _redirected_path; return TRUE; } return FALSE; } BOOL redirect_path_w(LPCWSTR lpFileName, LPCSTR* redirected) { char cFileName[MAX_PATH] = { 0 }; WideCharToMultiByte(CP_ACP, 0, lpFileName, wcslen(lpFileName), cFileName, sizeof cFileName, NULL, NULL); return redirect_path(cFileName, redirected); } HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { file_hook_t* found_fh = find_hook(lpFileName); if (found_fh != NULL) { HANDLE handle = open_hook(found_fh); log_info(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle); return handle; } HANDLE handle; LPCSTR redirected; if (redirect_path_w(lpFileName, &redirected)) { handle = TrueCreateFileA(redirected, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); log_misc(HOOKS_LOGGER, "CreateFileW(%s) -> 0x%p", redirected, handle); } else { handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); log_misc(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle); } return handle; } HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { WCHAR wideFileName[MAX_PATH + 1]; MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, (LPWSTR)&wideFileName, MAX_PATH + 1); file_hook_t* found_fh = find_hook(wideFileName); if (found_fh != NULL) { HANDLE handle = open_hook(found_fh); log_info(HOOKS_LOGGER, "CreateFileA(%s) -> 0x%p", lpFileName, handle); return handle; } redirect_path(lpFileName, &lpFileName); HANDLE handle = TrueCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); log_misc(HOOKS_LOGGER, "CreateFileA(%s) -> 0x%p", lpFileName, handle); return handle; } BOOL WINAPI FakePathFileExistsA(LPCSTR pszPath) { redirect_path(pszPath, &pszPath); return TruePathFileExistsA(pszPath); } BOOL WINAPI FakePathFileExistsW(LPCWSTR pszPath) { LPCSTR redirected; if (redirect_path_w(pszPath, &redirected)) { return TruePathFileExistsA(redirected); } return TruePathFileExistsW(pszPath); } BOOL WINAPI FakeDeleteFileA(LPCSTR pszPath) { LPCSTR redirected; if (redirect_path(pszPath, &redirected)) { return TrueDeleteFileA(redirected); } return TrueDeleteFileA(pszPath); } BOOL WINAPI FakeDeleteFileW(LPCWSTR pszPath) { LPCSTR redirected; if (redirect_path_w(pszPath, &redirected)) { return TrueDeleteFileA(redirected); } return TrueDeleteFileW(pszPath); } BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { open_hook_t* pHData = GetDataForHandle(hDevice, HDATA_FILE); if (pHData == NULL) { log_trace(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, nOutBufferSize); return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); } file_hook_t* file_hook = pHData->hook; if (!file_hook->DeviceIoControl) { log_error(HOOKS_LOGGER, "DeviceIoControl(%ls) unimplemented", file_hook->filename); return FALSE; } BOOL ret = file_hook->DeviceIoControl(&(pHData->ctx), dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); if (lpOverlapped) { SetEvent(lpOverlapped->hEvent); if (ret && lpBytesReturned) { lpOverlapped->InternalHigh = *lpBytesReturned; } } return ret; } DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); if (pHData == NULL) return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod); if (dwMoveMethod == FILE_BEGIN) { if (*lpDistanceToMoveHigh) pHData->ctx.m_Pointer.HighPart = *lpDistanceToMoveHigh; else pHData->ctx.m_Pointer.HighPart = 0; pHData->ctx.m_Pointer.LowPart = lDistanceToMove; } else if (dwMoveMethod == FILE_END) { log_error("files", "FILE_END unimplemented"); return 0xFFFFFFFF; } else { if (lpDistanceToMoveHigh) pHData->ctx.m_Pointer.HighPart += *lpDistanceToMoveHigh; pHData->ctx.m_Pointer.LowPart += lDistanceToMove; } return pHData->ctx.m_Pointer.LowPart; } BOOL WINAPI FakeSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) { open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); if (pHData != NULL) { if (dwMoveMethod == FILE_BEGIN) { pHData->ctx.m_Pointer = liDistanceToMove; } else if (dwMoveMethod == FILE_END) { log_error("files", "FILE_END unimplemented"); return FALSE; } else { pHData->ctx.m_Pointer.QuadPart += liDistanceToMove.QuadPart; } if (lpNewFilePointer) lpNewFilePointer->QuadPart = pHData->ctx.m_Pointer.QuadPart; return TRUE; } return TrueSetFilePointerEx(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod); } DWORD WINAPI FakeGetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) { open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); if (pHData == NULL) { return TrueGetFileSizeEx(hFile, lpFileSize); } file_hook_t* file_hook = pHData->hook; if (!file_hook->GetFileSizeEx) { log_error(HOOKS_LOGGER, "GetFileSizeEx(%ls) unimplemented", file_hook->filename); return FALSE; } return file_hook->GetFileSizeEx(&(pHData->ctx), lpFileSize); } DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { if (hFile == GetStdHandle(STD_OUTPUT_HANDLE) || hFile == GetStdHandle(STD_ERROR_HANDLE)) { return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); } open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); if (pHData == NULL) { return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); } file_hook_t* file_hook = pHData->hook; if (!file_hook->WriteFile) { log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", file_hook->filename); return FALSE; } return file_hook->WriteFile(&(pHData->ctx), lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); } BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { if (hFile == GetStdHandle(STD_INPUT_HANDLE)) { return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); } open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE); if (pHData == NULL) { return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); } file_hook_t* file_hook = pHData->hook; if (!file_hook->ReadFile) { log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", file_hook->filename); return FALSE; } return file_hook->ReadFile(&(pHData->ctx), lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); } BOOL WINAPI FakeCloseHandle(HANDLE hObject) { RemoveDataForHandle(hObject, HDATA_ANY); return TrueCloseHandle(hObject); } int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) { redirect_path((char*)path, &path); return True_stat64i32(path, buffer); }; void hook_io() { hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl, 5); hook("Kernel32.dll", "CreateFileA", FakeCreateFileA, (void**)&TrueCreateFileA, 6); hook("Kernel32.dll", "CreateFileW", FakeCreateFileW, (void**)&TrueCreateFileW, 6); hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6); hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6); hook("Kernel32.dll", "SetFilePointerEx", FakeSetFilePointerEx, (void**)&TrueSetFilePointerEx, 6); hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile, 6); hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile, 6); hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx, 6); hook("Shlwapi.dll", "PathFileExistsA", FakePathFileExistsA, (void**)&TruePathFileExistsA, 5); hook("Shlwapi.dll", "PathFileExistsW", FakePathFileExistsW, (void**)&TruePathFileExistsW, 5); hook("Kernel32.dll", "DeleteFileA", FakeDeleteFileA, (void**)&TrueDeleteFileA, 7); hook("Kernel32.dll", "DeleteFileW", FakeDeleteFileW, (void**)&TrueDeleteFileW, 7); hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32, 5); }