From 2262cc5871fe456bfeabc2c7dbf5f7f709afd186 Mon Sep 17 00:00:00 2001 From: 32th-System Date: Mon, 15 Sep 2025 00:48:18 +0200 Subject: [PATCH 1/2] thcrap: POC user home folder censoring --- thcrap/src/init.cpp | 11 +++-- thcrap/src/log.cpp | 88 +++++++++++++++++++++++++++++++++++++++- thcrap/src/patchfile.cpp | 16 +++++++- thcrap/src/stack.cpp | 12 +++++- thcrap/src/util.cpp | 69 +++++++++++++++++++++++++++++++ thcrap/src/util.h | 8 ++++ thcrap/thcrap.vcxproj | 2 +- 7 files changed, 194 insertions(+), 12 deletions(-) diff --git a/thcrap/src/init.cpp b/thcrap/src/init.cpp index 99360eff..dea1c175 100644 --- a/thcrap/src/init.cpp +++ b/thcrap/src/init.cpp @@ -272,13 +272,12 @@ json_t* identify(const char *exe_fn) void thcrap_detour(HMODULE hProc) { - DWORD mod_name_len = GetModuleFileNameU(hProc, NULL, 0) + 1; - VLA(char, mod_name, mod_name_len); - GetModuleFileNameU(hProc, mod_name, mod_name_len); - log_printf("Applying %s detours to %s...\n", PROJECT_NAME_SHORT, mod_name); - + wchar_t* mod_name = PathFindFileNameW(CurrentPeb()->ProcessParameters->ImagePathName.Buffer); + UTF8_DEC(mod_name); + UTF8_CONV(mod_name); + log_printf("Applying %s detours to %s...\n", PROJECT_NAME_SHORT, mod_name_utf8); + UTF8_FREE(mod_name); iat_detour_apply(hProc); - VLA_FREE(mod_name); } int thcrap_init(const char *run_cfg) diff --git a/thcrap/src/log.cpp b/thcrap/src/log.cpp index c23aa0bf..1970ad7e 100644 --- a/thcrap/src/log.cpp +++ b/thcrap/src/log.cpp @@ -8,6 +8,7 @@ */ #include "thcrap.h" +#include #include #include @@ -101,14 +102,75 @@ void log_rotate(void) } // -------- -static void log_print_real(const char* str, uint32_t n, bool is_n) { - static DWORD byteRet; +const char* user_home_win = 0; +uint32_t user_home_win_len = 0; +//const char* user_home_unx = "C:\\Users\\thc"; +//uint32_t user_home_unx_len = strlen(user_home_unx); + +void log_write(const char* str, uint32_t n) { + DWORD byteRet; if unexpected(console_open) { WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, n, &byteRet, NULL); } if (HANDLE file = log_file) { WriteFile(file, str, n, &byteRet, NULL); } +} + +void log_write_censored(const char* str, uint32_t n) { + const char* p = str; + + uint32_t len_to_use; + + for (;;) { + //const char* p_new = nullptr; + // + //size_t p_new_win_len = 0; + //size_t p_new_unx_len = 0; + // + //const char* p_new_win = find_path_substring(p, n - (p - str), user_home_win, user_home_win_len, &p_new_win_len); + //const char* p_new_unx = find_path_substring(p, n - (p - str), user_home_unx, user_home_unx_len, &p_new_unx_len); + // + //if(p_new_win < p_new_unx) { + // if (p_new_unx == nullptr) { + // p_new = p_new_win; + // len_to_use = p_new_win_len; + // } else { + // p_new = p_new_unx; + // len_to_use = p_new_unx_len; + // } + //} else if (p_new_win > p_new_unx) { + // if (p_new_unx == nullptr) { + // p_new = p_new_win; + // len_to_use = p_new_win_len; + // } else { + // p_new = p_new_unx; + // len_to_use = p_new_unx_len; + // } + //} + + size_t p_new_len = 0; + const char* p_new = find_path_substring(p, n - (p - str), user_home_win, user_home_win_len, &p_new_len); + + if (p_new) { + log_write(p, p_new - p); + log_write("%USERPROFILE%", strlen("%USERPROFILE%")); + p = p_new + p_new_len; + } + else { + no_censoring_needed: + log_write(p, n - (p - str)); + return; + } + } +} + +static void log_print_real(const char* str, uint32_t n, bool is_n) { + if (user_home_win) { + log_write_censored(str, n); + } else { + log_write(str, n); + } if (!is_n) { if (auto func = log_print_hook) { func(str); @@ -368,6 +430,28 @@ void log_init(int console) } #endif + + + // Figure out user's home + HANDLE hToken; + // GetCurrentProcess is just { return 0xFFFFFFFF } because 0xFFFFFFFF is a pseudo handle to the current process + OpenProcessToken(INVALID_HANDLE_VALUE, TOKEN_QUERY, &hToken); + + DWORD profLen_w; + GetUserProfileDirectoryW(hToken, nullptr, &profLen_w); + VLA(wchar_t, profDir_w, profLen_w); + GetUserProfileDirectoryW(hToken, profDir_w, &profLen_w); + + size_t profLen_u = StringToUTF8(nullptr, profDir_w, 0); + + char* profDir_u = (char*)malloc(profLen_u + 1); + StringToUTF8(profDir_u, profDir_w, profLen_u + 1); + + user_home_win = profDir_u; + user_home_win_len = profLen_u; + + CloseHandle(hToken); + log_printf( "%s\n" "%s logfile\n" diff --git a/thcrap/src/patchfile.cpp b/thcrap/src/patchfile.cpp index 32658edb..a9ceee59 100644 --- a/thcrap/src/patchfile.cpp +++ b/thcrap/src/patchfile.cpp @@ -160,8 +160,20 @@ TH_CALLER_FREE char* fn_for_game(const char *fn) void patch_print_fn(const patch_t *patch_info, const char *fn) { if (patch_info && fn) { - const char* archive = patch_info->archive; - char end_char = archive[patch_info->archive_length - 1]; + char end_char = patch_info->archive[patch_info->archive_length - 1]; + + std::string_view& thcrap_dir = runconfig_thcrap_dir_get_view(); + + size_t out_len = 0; + const char* archive = find_path_substring(patch_info->archive, patch_info->archive_length, thcrap_dir.data(), thcrap_dir.length(), &out_len); + + if (!archive) { + archive = patch_info->archive; + } + else { + archive += out_len; + } + log_printf( (end_char == '/') || (end_char == '\\') ? "\n%*s+ %s%s" : "\n%*s+ %s/%s" , patch_info->level, "", archive, fn diff --git a/thcrap/src/stack.cpp b/thcrap/src/stack.cpp index 0e62ce60..976d3e75 100644 --- a/thcrap/src/stack.cpp +++ b/thcrap/src/stack.cpp @@ -347,7 +347,17 @@ void stack_print() } log_print("\n"); + std::string_view& thcrap_dir = runconfig_thcrap_dir_get_view(); + for (const patch_t& patch : stack) { + size_t out_len = 0; + const char* archive = find_path_substring(patch.archive, patch.archive_length, thcrap_dir.data(), thcrap_dir.length(), &out_len); + if (!archive) { + archive = patch.archive; + } + else { + archive += out_len; + } log_printf( "\n" @@ -356,7 +366,7 @@ void stack_print() " title: %s\n" " update: %s\n" , patch.level, patch.id - , patch.archive + , archive , patch.title , BoolStr(patch.update) ); diff --git a/thcrap/src/util.cpp b/thcrap/src/util.cpp index 446c6d28..9435b673 100644 --- a/thcrap/src/util.cpp +++ b/thcrap/src/util.cpp @@ -101,3 +101,72 @@ int _asprintf(char** buffer_ret, const char* format, ...) { va_end(va); return ret; } + +bool path_cmp_n(const char* const p1, const char* const p2, size_t n) { + for (size_t i = 0; i < n; i++) { + if (p1[i] != p2[i]) { + if ((p1[i] == '\\' || p1[i] == '/') && (p2[i] == '\\' || p2[i] == '/')) { + continue; + } + return false; + } + } + return true; +} + +static inline bool is_separator(char c) { + return c == '/' || c == '\\'; +}; + +static inline size_t skip_separators(const char* str, size_t str_len, size_t pos) { + while (pos < str_len && is_separator(str[pos])) { + pos++; + } + return pos; +}; + +const char* find_path_substring(const char* haystack, size_t h_len, const char* needle, size_t n_len, size_t* out_len) { + if (haystack == nullptr || needle == nullptr) { + return nullptr; + } + + // Empty needle matches at position 0 with length 0 + if (n_len == 0) { + return haystack; + } + + for (size_t h_pos = 0; h_pos < h_len;) { + size_t h_current = h_pos; + size_t n_current = 0; + size_t match_start = h_pos; + + // Try to match the needle starting at this position + while (h_current < h_len && n_current < n_len) { + // Handle separator matching + if (is_separator(needle[n_current]) && is_separator(haystack[h_current])) { + // Both are separators (skip all consecutive separators in both strings) + h_current = skip_separators(haystack, h_len, h_current); + n_current = skip_separators(needle, n_len, n_current); + } + else { + // Regular (case insensitive) character matching + if (tolower(haystack[h_current]) != tolower(needle[n_current])) { + break; + } + h_current++; + n_current++; + } + } + + if (n_current == n_len) { + if (out_len) + *out_len = h_current - match_start; + return haystack + match_start; + } + else { + h_pos = h_current + 1; + } + } + + return nullptr; +} diff --git a/thcrap/src/util.h b/thcrap/src/util.h index 0ecf8dd7..1bf6f262 100644 --- a/thcrap/src/util.h +++ b/thcrap/src/util.h @@ -541,6 +541,14 @@ inline int8_t hex_value_inline(char c) { #define hex_value(c) hex_value_inline(c) +/** + * Finds any instance of a filesystem path in any (counted) string + * - / and \ are treated as the same + * - Repeated path separators are ignore + * Returns a pair with position and length + */ +const char* find_path_substring(const char* haystack, size_t h_len, const char* needle, size_t n_len, size_t* out_len); + #ifdef __cplusplus extern "C++" { diff --git a/thcrap/thcrap.vcxproj b/thcrap/thcrap.vcxproj index 91696c3b..c63545f8 100644 --- a/thcrap/thcrap.vcxproj +++ b/thcrap/thcrap.vcxproj @@ -39,7 +39,7 @@ Windows - jansson$(Suffix).lib;shlwapi.lib;psapi.lib;%(AdditionalDependencies) + jansson$(Suffix).lib;shlwapi.lib;psapi.lib;userenv.lib;%(AdditionalDependencies) thcrap_x64_injector$(DebugSuffix).lib;%(AdditionalDependencies) thcrap_x86.def thcrap_x64.def From f96d5945881eade9ae3a98f4345551615fe20986 Mon Sep 17 00:00:00 2001 From: 32th-System Date: Fri, 19 Sep 2025 17:15:54 +0200 Subject: [PATCH 2/2] thcrap: replace mentions of 'censoring' with 'filtering' it just seems more appropriate --- thcrap/src/log.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/thcrap/src/log.cpp b/thcrap/src/log.cpp index 1970ad7e..93ae9f88 100644 --- a/thcrap/src/log.cpp +++ b/thcrap/src/log.cpp @@ -117,7 +117,7 @@ void log_write(const char* str, uint32_t n) { } } -void log_write_censored(const char* str, uint32_t n) { +void log_write_filtered(const char* str, uint32_t n) { const char* p = str; uint32_t len_to_use; @@ -158,7 +158,7 @@ void log_write_censored(const char* str, uint32_t n) { p = p_new + p_new_len; } else { - no_censoring_needed: + no_filtering_needed: log_write(p, n - (p - str)); return; } @@ -167,7 +167,7 @@ void log_write_censored(const char* str, uint32_t n) { static void log_print_real(const char* str, uint32_t n, bool is_n) { if (user_home_win) { - log_write_censored(str, n); + log_write_filtered(str, n); } else { log_write(str, n); }