#include #include #include #include const char *HSR_NAME = "StarRail"; const char *HSR_ASSEMBLY_PATH = "GameAssembly.dll"; const char *HSR_TP6_SECTION_NAME = ".ace"; const char *HSR_TVM_SECTION_NAME = ".tvm0"; struct crc_id_pair { uint32_t crc; enum game_id id; }; const struct crc_id_pair HSR_REGIONS[] = { // It may be possible to get rid of region-specific data altogether in the future { 0x9eb3084e, GAME_HSR_OS }, // os v1.2.0 { 0x14be07e9, GAME_HSR_CN } // cn v1.2.0 }; #define JUMP_SIZE (6 + sizeof(void*)) // Temporarily hardcoded offset // v1.2.0, same for os and cn #define WTSUD_PATCH_OFFSET 0x16430 char wtsud_original_bytes[JUMP_SIZE]; char *wtsud_patch_addr; static void _wtsud_stub() { // Recover original bytes DWORD oldProtect; VirtualProtect(wtsud_patch_addr, JUMP_SIZE, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(wtsud_patch_addr, wtsud_original_bytes, JUMP_SIZE); VirtualProtect(wtsud_patch_addr, JUMP_SIZE, oldProtect, &oldProtect); unload_ctr_dec(); } static void _unityplayer_callback(HMODULE unityModule) { if (utils_env_enabled("SRFIX_DISABLE")) { msg_info_a("Shared resources fix disabled. The game may not work"); return; } // Remove dependency on shared resources by patching WriteTextureStatisticUserData unload_ctr_inc(); wtsud_patch_addr = ((char*)unityModule) + WTSUD_PATCH_OFFSET; DWORD oldProtect; VirtualProtect(wtsud_patch_addr, JUMP_SIZE, PAGE_EXECUTE_READWRITE, &oldProtect); // Save original bytes memcpy(wtsud_original_bytes, wtsud_patch_addr, JUMP_SIZE); // Write jump const char JUMP_INST[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp [$ + 6] memcpy(wtsud_patch_addr, JUMP_INST, sizeof(JUMP_INST)); // Write destination address void *destAddr = &_wtsud_stub; memcpy(wtsud_patch_addr + sizeof(JUMP_INST), &destAddr, sizeof(destAddr)); VirtualProtect(wtsud_patch_addr, JUMP_SIZE, oldProtect, &oldProtect); } void hsr_fill_data(struct game_data *buf) { uint32_t crc = utils_file_crc32c("UnityPlayer.dll"); enum game_id id = GAME_INVALID; for (size_t i = 0; i < sizeof(HSR_REGIONS) / sizeof(struct crc_id_pair); i++) { if (HSR_REGIONS[i].crc == crc) { id = HSR_REGIONS[i].id; } } if (id == GAME_INVALID) { msg_err_a("Invalid UnityPlayer.dll checksum: %x", crc); } buf->id = id; buf->name = HSR_NAME; buf->assembly_path = HSR_ASSEMBLY_PATH; buf->tp6_section_name = HSR_TP6_SECTION_NAME; buf->tvm_section_name = HSR_TVM_SECTION_NAME; buf->unityplayer_callback = &_unityplayer_callback; }