From f0daa9e7616bc05e17d99db01026431bff58b040 Mon Sep 17 00:00:00 2001 From: CrazyRedMachine Date: Mon, 29 Apr 2024 21:17:11 +0200 Subject: [PATCH] rework exclude code, add options to xml --- dist/popnhax/popnhax.xml | 22 +- popnhax/config.h | 6 + popnhax/custom_categs.cc | 120 ++++++----- popnhax/custom_categs.h | 4 +- popnhax/dllmain.cc | 29 ++- popnhax/loader.cc | 30 ++- popnhax/loader.h | 3 +- popnhax/translation.cc | 428 +++++++++++++++++++-------------------- 8 files changed, 362 insertions(+), 280 deletions(-) diff --git a/dist/popnhax/popnhax.xml b/dist/popnhax/popnhax.xml index 8f21a63..fda72de 100644 --- a/dist/popnhax/popnhax.xml +++ b/dist/popnhax/popnhax.xml @@ -7,6 +7,16 @@ 0 0 + + 0 + + 0 + + + + 0 + + 0 @@ -29,10 +39,6 @@ 0 - - - 0 - 0 @@ -134,10 +140,18 @@ 0 0 + + 4000 0 + + Customs + + [ol:4][olc:d92f0d]%s + + diff --git a/popnhax/config.h b/popnhax/config.h index 5397ef7..b5aad2c 100644 --- a/popnhax/config.h +++ b/popnhax/config.h @@ -17,6 +17,8 @@ struct popnhax_config { uint8_t custom_categ; uint16_t custom_categ_min_songid; uint16_t custom_categ_max_songid; + bool custom_exclude_from_version; + bool custom_exclude_from_level; bool force_hd_timing; uint8_t force_hd_resolution; bool force_unlocks; @@ -29,6 +31,7 @@ struct popnhax_config { bool force_full_opt; bool netvs_off; bool guidese_off; + bool local_favorites; bool patch_db; bool disable_expansions; @@ -55,6 +58,9 @@ struct popnhax_config { bool survival_iidx; bool survival_spicy; int8_t base_offset; + char custom_category_title[16]; + char custom_category_format[64]; + char custom_track_title_format[64]; }; #endif diff --git a/popnhax/custom_categs.cc b/popnhax/custom_categs.cc index b2976b5..181040d 100644 --- a/popnhax/custom_categs.cc +++ b/popnhax/custom_categs.cc @@ -35,10 +35,10 @@ bool g_subcategmode = false; uint32_t g_min_id = 4000; uint32_t g_max_id = 0; -const char *g_categname = "Customs"; +char *g_categname; const char *g_categicon = "cate_cc"; -const char *g_categformat = "[ol:4][olc:d92f0d]%s"; -const char *g_customformat = " [rz:3][c:d92f0d]%s[/rz][/c]"; +char *g_categformat; +char *g_customformat; char *g_string_addr; uint8_t idx = 0; @@ -116,12 +116,7 @@ void commit_favorites() if ( file == NULL ) { - file = fopen("data_mods\\default.fav", "w"); - - if (file == NULL) - { - return; - } + return; } for (uint32_t i = 0; i < favorites_count; i++) @@ -626,7 +621,7 @@ void hook_artist_printf() real_artist_printf(); } -static bool patch_custom_highlight(const char *game_dll_fn) { +static bool patch_custom_track_format(const char *game_dll_fn) { DWORD dllSize = 0; char *data = getDllData(game_dll_fn, &dllSize); @@ -634,7 +629,7 @@ static bool patch_custom_highlight(const char *game_dll_fn) { { int64_t pattern_offset = search(data, dllSize, "\x83\xC4\x08\x8B\x44\x24\x50\x50\x68", 9, 0); if (pattern_offset == -1) { - LOG("popnhax: custom_highlight: cannot find song/genre print function\n"); + LOG("popnhax: custom_track_format: cannot find song/genre print function\n"); return false; } @@ -648,7 +643,7 @@ static bool patch_custom_highlight(const char *game_dll_fn) { { int64_t pattern_offset = search(data, dllSize, "\x83\xC4\x08\x33\xFF\x8B\x43\x0C\x8B\x70\x04\x83\xC0\x04", 14, 0); if (pattern_offset == -1) { - LOG("popnhax: custom_highlight: cannot find artist print function\n"); + LOG("popnhax: custom_track_format: cannot find artist print function\n"); return false; } @@ -658,6 +653,7 @@ static bool patch_custom_highlight(const char *game_dll_fn) { (void **)&real_artist_printf); } + LOG("popnhax: custom_track_format: custom format injected\n"); return true; } @@ -669,7 +665,7 @@ static bool patch_favorite_categ(const char *game_dll_fn) { if (add_song_in_list == NULL) { int64_t pattern_offset = search(data, dllSize, "\x8B\x4D\x10\x8B\x5D\x0C\x8B\xF1", 8, 0); if (pattern_offset == -1) { - LOG("popnhax: custom_favorites: cannot find add_song_in_list function\n"); + LOG("popnhax: local_favorites: cannot find add_song_in_list function\n"); return false; } @@ -681,7 +677,7 @@ static bool patch_favorite_categ(const char *game_dll_fn) { { int64_t pattern_offset = search(data, dllSize, "\x83\xF8\x10\x77\x75\xFF\x24\x85", 8, 0); if (pattern_offset == -1) { - LOG("popnhax: custom_favorites: cannot find category jump table\n"); + LOG("popnhax: local_favorites: cannot find category jump table\n"); return false; } @@ -697,7 +693,7 @@ static bool patch_favorite_categ(const char *game_dll_fn) { //this is the same function used in score challenge patch, checking if we're logged in... but now we just directly retrieve the address int64_t pattern_offset = search(data, dllSize, "\x8B\x01\x8B\x50\x14\xFF\xE2\xC3\xCC\xCC\xCC\xCC", 12, 0); if (pattern_offset == -1) { - LOG("popnhax: custom_favorites: cannot find check if logged function\n"); + LOG("popnhax: local_favorites: cannot find check if logged function\n"); return false; } @@ -706,35 +702,50 @@ static bool patch_favorite_categ(const char *game_dll_fn) { //hook result screen to replace 3 functions { - int64_t pattern_offset = search(data, dllSize, "\xBF\x07\x00\x00\x00\xC6\x85\x61\xD3", 9, 0); - if (pattern_offset == -1) { - LOG("popnhax: custom_favorites: cannot find result screen function\n"); + int64_t first_loc = search(data, dllSize, "\xBF\x07\x00\x00\x00\xC6\x85\x61\xD3", 9, 0); + if (first_loc == -1) { + LOG("popnhax: local_favorites: cannot find result screen function\n"); return false; } //song is in favorite - uint64_t function_call_addr = (int64_t)(data + pattern_offset + 0x5F); - uint32_t function_offset = *((uint32_t*)(function_call_addr +0x01)); - uint64_t function_addr = function_call_addr+5+function_offset; - MH_CreateHook((LPVOID)function_addr, (LPVOID)hook_song_is_in_favorite, + int64_t second_loc = search(data, 1000, "\x8B\xC8\xE8", 3, first_loc); + if (second_loc == -1) { + LOG("popnhax: local_favorites: cannot retrieve is song in favorites call\n"); + return false; + } + uint64_t function_call_addr = (int64_t)(data + second_loc + 0x02); + uint32_t function_offset = *((uint32_t*)(function_call_addr +0x01)); + uint64_t function_addr = function_call_addr+5+function_offset; + MH_CreateHook((LPVOID)function_addr, (LPVOID)hook_song_is_in_favorite, (void **)&real_song_is_in_favorite); -//add to favorites - uint64_t function2_call_addr = (int64_t)(data + pattern_offset + 0xBA); - uint32_t function2_offset = *((uint32_t*)(function2_call_addr +0x01)); - uint64_t function2_addr = function2_call_addr+5+function2_offset; - MH_CreateHook((LPVOID)function2_addr, (LPVOID)hook_add_to_favorite, - (void **)&real_add_to_favorite); - //remove from favorites - uint64_t function3_call_addr = (int64_t)(data + pattern_offset + 0x89); - uint32_t function3_offset = *((uint32_t*)(function3_call_addr +0x01)); - uint64_t function3_addr = function3_call_addr+5+function3_offset; - MH_CreateHook((LPVOID)function3_addr, (LPVOID)hook_remove_from_favorite, + int64_t third_loc = search(data, 1000, "\x6A\x01\x6A\x00\x68", 5, second_loc); + if (third_loc == -1) { + LOG("popnhax: local_favorites: cannot retrieve remove from favorites call\n"); + return false; + } + uint64_t function2_call_addr = (int64_t)(data + third_loc - 0x05); + uint32_t function2_offset = *((uint32_t*)(function2_call_addr +0x01)); + uint64_t function2_addr = function2_call_addr+5+function2_offset; + MH_CreateHook((LPVOID)function2_addr, (LPVOID)hook_remove_from_favorite, (void **)&real_remove_from_favorite); +//add to favorites + int64_t fourth_loc = search(data, 1000, "\x6A\x01\x6A\x00\x68", 5, third_loc+2); + if (fourth_loc == -1) { + LOG("popnhax: local_favorites: cannot retrieve add to favorites call\n"); + return false; + } + uint64_t function3_call_addr = (int64_t)(data + fourth_loc - 0x05); + uint32_t function3_offset = *((uint32_t*)(function3_call_addr +0x01)); + uint64_t function3_addr = function3_call_addr+5+function3_offset; + MH_CreateHook((LPVOID)function3_addr, (LPVOID)hook_add_to_favorite, + (void **)&real_add_to_favorite); + } - LOG("popnhax: custom_favorites: favorite category handling replaced\n"); + LOG("popnhax: local_favorites: favorite category handling replaced\n"); return true; } @@ -997,7 +1008,6 @@ void hook_getversion() __asm("force_version_0:\n"); __asm("mov eax, 0x00\n"); - //__asm("mov ecx, 0x138E\n"); __asm("ret\n"); __asm("real_version:\n"); @@ -1016,7 +1026,6 @@ void hook_getcsversion() __asm("force_csversion_0:\n"); __asm("mov eax, 0x00\n"); - //__asm("mov ecx, 0x138E\n"); __asm("ret\n"); __asm("real_csversion:\n"); @@ -1043,7 +1052,8 @@ bool patch_exclude(const char *game_dll_fn) MH_CreateHook((LPVOID)function_addr, (LPVOID)hook_getversion, (void **)&real_getversion); } - + /* + //exclude from CS version category too { int64_t pattern_offset = search(data, dllSize, "\xB8\x13\x05\x00\x00\x66\x3B\xF0", 8, 0); if (pattern_offset == -1) { @@ -1057,16 +1067,26 @@ bool patch_exclude(const char *game_dll_fn) MH_CreateHook((LPVOID)function_addr, (LPVOID)hook_getcsversion, (void **)&real_getcsversion); - } + }*/ LOG("popnhax: exclude_customs: Custom songs excluded from version listings\n"); return true; } -bool patch_custom_categs(const char *dllFilename, uint8_t mode, uint16_t min, uint16_t max) +bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config) { - g_min_id = min; - g_max_id = max; +LOG("config is %p\n", (void*)config); + g_min_id = config->custom_categ_min_songid; + g_max_id = config->custom_categ_max_songid; + uint8_t mode = config->custom_categ; + + g_categname = config->custom_category_title; + g_categformat = config->custom_category_format; + +LOG("custom songid range is [%d;%d]\n", g_min_id, g_max_id); +LOG("category name is %s\n", g_categname); +LOG("category format is %s\n", g_categformat); + #if SIMPLE_CATEG_ALLOC == 1 songlist = (uint32_t*)calloc(1,5); #endif @@ -1076,12 +1096,18 @@ bool patch_custom_categs(const char *dllFilename, uint8_t mode, uint16_t min, ui load_databases(); } -patch_exclude(dllFilename); - - patch_custom_highlight(dllFilename); - -load_favorites(); -patch_favorite_categ(dllFilename); + if ( config->custom_track_title_format[0] != '\0' ) + { + g_customformat = config->custom_track_title_format; +LOG("custom title format is %s\n", g_customformat); + patch_custom_track_format(dllFilename); + } return patch_custom_categ(dllFilename); +} + +bool patch_local_favorites(const char *dllFilename) +{ + //load_favorites(); + return patch_favorite_categ(dllFilename); } \ No newline at end of file diff --git a/popnhax/custom_categs.h b/popnhax/custom_categs.h index 15d48d3..c27929b 100644 --- a/popnhax/custom_categs.h +++ b/popnhax/custom_categs.h @@ -2,7 +2,9 @@ #define __CUSTOM_CATEGS_H__ #include +#include "popnhax/config.h" -bool patch_custom_categs(const char *dllFilename, uint8_t mode, uint16_t min, uint16_t max); +bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config); +bool patch_local_favorites(const char *dllFilename); #endif diff --git a/popnhax/dllmain.cc b/popnhax/dllmain.cc index 9b67792..eca8228 100644 --- a/popnhax/dllmain.cc +++ b/popnhax/dllmain.cc @@ -191,6 +191,18 @@ PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_U16, struct popnhax_config, custom_categ_mi "/popnhax/custom_categ_min_songid") PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_U16, struct popnhax_config, custom_categ_max_songid, "/popnhax/custom_categ_max_songid") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, custom_exclude_from_version, + "/popnhax/custom_exclude_from_version") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, custom_exclude_from_level, + "/popnhax/custom_exclude_from_level") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_STR, struct popnhax_config, custom_category_title, + "/popnhax/custom_category_title") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_STR, struct popnhax_config, custom_category_format, + "/popnhax/custom_category_format") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_STR, struct popnhax_config, custom_track_title_format, + "/popnhax/custom_track_title_format") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, local_favorites, + "/popnhax/local_favorites") PSMAP_END enum BufferIndexes { @@ -1441,7 +1453,7 @@ static bool patch_datecode(char *datecode) { return true; } -static bool patch_database(uint8_t force_unlocks) { +static bool patch_database() { DWORD dllSize = 0; char *data = getDllData(g_game_dll_fn, &dllSize); @@ -1519,10 +1531,7 @@ static bool patch_database(uint8_t force_unlocks) { config.disable_expansions = true; } - musichax_core_init( - force_unlocks, - !config.disable_expansions, - !config.disable_redirection, + musichax_core_init(&config, target, data, @@ -1554,6 +1563,9 @@ static bool patch_database(uint8_t force_unlocks) { ); limit_table[STYLE_TABLE_IDX] = new_limit_table[STYLE_TABLE_IDX]; + if (config.custom_exclude_from_version) + LOG("popnhax: custom_exclude_from_version: customs excluded from version folders\n"); //musichax_core_init took care of it + if (config.disable_redirection) { LOG("Redirection-related code is disabled, buffer address, buffer size and related patches will not be applied"); printf("Redirection-related code is disabled, buffer address, buffer size and related patches will not be applied"); @@ -5589,8 +5601,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv patch_db_power_points(); patch_db_fix_cursor(); if (config.custom_categ) - patch_custom_categs(g_game_dll_fn, config.custom_categ, config.custom_categ_min_songid, config.custom_categ_max_songid); - patch_database(config.force_unlocks); + patch_custom_categs(g_game_dll_fn, &config); + patch_database(); } if (config.force_unlocks) { @@ -5603,6 +5615,9 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv force_unlock_deco_parts(); } + if (config.local_favorites) + patch_local_favorites(g_game_dll_fn); + if (config.force_full_opt) option_full(); diff --git a/popnhax/loader.cc b/popnhax/loader.cc index aecde91..cf9cd50 100644 --- a/popnhax/loader.cc +++ b/popnhax/loader.cc @@ -5,6 +5,7 @@ #include "imports/avs.h" #include "util/patch.h" +#include "util/log.h" #include "xmlhelper.h" #include "tableinfo.h" @@ -66,7 +67,7 @@ uint32_t add_chart(uint32_t cur_idx, uint8_t *folder, uint8_t *filename, int32_t uint32_t file_type, uint16_t used_keys, bool override_idx); void parse_charadb(const char *input_filename, const char *target); -void parse_musicdb(const char *input_filename, const char *target); +void parse_musicdb(const char *input_filename, const char *target, struct popnhax_config *config); std::map chart_type_overrides; @@ -818,7 +819,7 @@ void parse_charadb(const char *input_filename, const char *target) { free(config_xml); } -void parse_musicdb(const char *input_filename, const char *target) { +void parse_musicdb(const char *input_filename, const char *target, struct popnhax_config *config) { if (!file_exists(input_filename)) { printf("Couldn't find %s, skipping...\n", input_filename); return; @@ -915,6 +916,18 @@ void parse_musicdb(const char *input_filename, const char *target) { } } + //force loading background for unilab + m->mask |= 0x100; + + if ( config->custom_categ + && config->custom_exclude_from_version + && idx >= config->custom_categ_min_songid + && (config->custom_categ_max_songid == 0 || idx <= config->custom_categ_max_songid) ) + { + m->cs_version = 0; + m->folder = 0; + } + if ((prop_chart = property_search(config_xml, prop, "charts/chart"))) { for (; prop_chart != NULL; prop_chart = property_node_traversal( prop_chart, TRAVERSE_NEXT_SEARCH_RESULT)) { @@ -992,7 +1005,7 @@ void parse_musicdb(const char *input_filename, const char *target) { free(config_xml); } -void load_databases(const char *target_datecode) { +void load_databases(const char *target_datecode, struct popnhax_config *config) { SearchFile s; printf("XML db files search...\n"); @@ -1013,11 +1026,11 @@ void load_databases(const char *target_datecode) { if ( strstr(result[i].c_str(), "musicdb") == NULL ) continue; printf("(musicdb) Loading %s...\n", result[i].c_str()); - parse_musicdb(result[i].c_str(), target_datecode); + parse_musicdb(result[i].c_str(), target_datecode, config); } } -void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_redirection_allowed, +void musichax_core_init(struct popnhax_config *config, char *target_datecode, char *base_data, @@ -1036,6 +1049,11 @@ void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_r uint64_t chara_size, uint64_t *new_chara_size, char *orig_chara_data, uint8_t **new_chara_table) { + + bool force_unlocks = config->force_unlocks; + bool is_expansion_allowed = !config->disable_expansions; + bool is_redirection_allowed = !config->disable_redirection; + if (style_size > fontstyle_table_size) { fontstyle_table_size = style_size; } @@ -1181,7 +1199,7 @@ void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_r cur->chara_x, cur->chara_y, cur->unk1, cur->display_bpm, cur->hold_flags, true); } - load_databases((const char *)target_datecode); + load_databases((const char *)target_datecode, config); // Add some filler charts to fix some bugs (hack) for (int i = 0; i < 10; i++) { diff --git a/popnhax/loader.h b/popnhax/loader.h index 4d91185..161a83c 100644 --- a/popnhax/loader.h +++ b/popnhax/loader.h @@ -2,10 +2,11 @@ #define __LOADER_H__ #include +#include "popnhax/config.h" int8_t get_chart_type_override(uint8_t *, uint32_t, uint32_t); -void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_redirection_allowed, +void musichax_core_init(struct popnhax_config *config, char *target_datecode, char *base_data, uint64_t music_size, uint64_t *new_music_size, char *orig_music_data, uint8_t **new_music_table, uint64_t chart_size, uint64_t *new_chart_size, char *orig_chart_data, diff --git a/popnhax/translation.cc b/popnhax/translation.cc index dff5f1f..31e40e2 100644 --- a/popnhax/translation.cc +++ b/popnhax/translation.cc @@ -56,10 +56,10 @@ bool patch_sjis(const char *dllFilename, const char *find, uint8_t find_size, in } while (valid_sjis); if (dump_dict) - { + { //fprintf(g_dict_applied_fp,"0x%x;%s;%s\n",rva_to_offset(dllFilename, (uint32_t)*offset),(char*)find,(char*)replace); fprintf(g_dict_applied_fp,";%s;%s\n",(char*)find,(char*)replace); - } + } /* safety check replace is not too big */ uint8_t free_size = find_size-1; do @@ -83,41 +83,41 @@ bool patch_sjis(const char *dllFilename, const char *find, uint8_t find_size, in #define RELOC_HIGHLOW 0x3 static void perform_reloc(char *data, int32_t delta, uint32_t ext_base, uint32_t ext_delta) -{ - PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew); - PIMAGE_DATA_DIRECTORY datadir = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; - PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)(data + datadir->VirtualAddress); +{ + PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew); + PIMAGE_DATA_DIRECTORY datadir = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)(data + datadir->VirtualAddress); - while(reloc->VirtualAddress != 0) - { - if (reloc->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION)) - { - DWORD relocDescNb = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); - LPWORD relocDescList = (LPWORD)((LPBYTE)reloc + sizeof(IMAGE_BASE_RELOCATION)); + while(reloc->VirtualAddress != 0) + { + if (reloc->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION)) + { + DWORD relocDescNb = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); + LPWORD relocDescList = (LPWORD)((LPBYTE)reloc + sizeof(IMAGE_BASE_RELOCATION)); - for (DWORD i = 0; i < relocDescNb; i++) - { - if ( ((relocDescList[i])>>12) == RELOC_HIGHLOW ) - { - DWORD_PTR *p = (DWORD_PTR *)( data + (reloc->VirtualAddress + ((relocDescList[i])&0x0FFF)) ); - /* Change the offset to adapt to injected module base address */ - - DWORD old_prot; - VirtualProtect((LPVOID)p, 4, PAGE_EXECUTE_READWRITE, &old_prot); - *p += delta; - if ( ext_base > 0 && *p >= ((int64_t)data+ext_base) ) - { - //fprintf(stderr,"reloc rva %lx to ext ", *p); - *p += ext_delta; - //fprintf(stderr," %lx\n", *p); - } - VirtualProtect((LPVOID)p, 4, old_prot, &old_prot); - } - } - } - /* Set reloc pointer to the next relocation block */ - reloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)reloc + reloc->SizeOfBlock); - } + for (DWORD i = 0; i < relocDescNb; i++) + { + if ( ((relocDescList[i])>>12) == RELOC_HIGHLOW ) + { + DWORD_PTR *p = (DWORD_PTR *)( data + (reloc->VirtualAddress + ((relocDescList[i])&0x0FFF)) ); + /* Change the offset to adapt to injected module base address */ + + DWORD old_prot; + VirtualProtect((LPVOID)p, 4, PAGE_EXECUTE_READWRITE, &old_prot); + *p += delta; + if ( ext_base > 0 && *p >= ((int64_t)data+ext_base) ) + { + //fprintf(stderr,"reloc rva %lx to ext ", *p); + *p += ext_delta; + //fprintf(stderr," %lx\n", *p); + } + VirtualProtect((LPVOID)p, 4, old_prot, &old_prot); + } + } + } + /* Set reloc pointer to the next relocation block */ + reloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)reloc + reloc->SizeOfBlock); + } } #define BYTE3_TO_UINT(bp) \ @@ -134,191 +134,191 @@ static void perform_reloc(char *data, int32_t delta, uint32_t ext_base, uint32_t static bool patch_translation_ips(const char *dllFilename, const char *foldername, bool dump_dll) { #define IPS_READ(_ips_read_dest, _ips_read_size, _ips_read_name) do {\ - if ( fread(_ips_read_dest, 1, _ips_read_size, ips_fp) != _ips_read_size )\ - {\ - LOG("CANNOT READ %s\n", _ips_read_name);\ - return false;\ - }\ + if ( fread(_ips_read_dest, 1, _ips_read_size, ips_fp) != _ips_read_size )\ + {\ + LOG("CANNOT READ %s\n", _ips_read_name);\ + return false;\ + }\ } while (0) - DWORD dllSize = 0; + DWORD dllSize = 0; char *data = getDllData(dllFilename, &dllSize); - char dict_filepath[64]; + char dict_filepath[64]; sprintf(dict_filepath, "%s%s%s", "data_mods\\", foldername, "\\popn22.ips"); - FILE *ips_fp = fopen(dict_filepath, "rb"); + FILE *ips_fp = fopen(dict_filepath, "rb"); if (ips_fp == NULL) - { + { return false; - } + } - LOG("popnhax: translation: popn22.ips found\n"); + LOG("popnhax: translation: popn22.ips found\n"); - /* check .ips header */ - uint8_t buffer[8]; - if (fread(&buffer, 1, 5, ips_fp) != 5) - return false; - - if (memcmp(buffer, "PATCH", 5) != 0) - { - LOG("popnhax: translation: invalid .ips header\n"); - return false; - } + /* check .ips header */ + uint8_t buffer[8]; + if (fread(&buffer, 1, 5, ips_fp) != 5) + return false; - if (dump_dll) - { - LOG("popnhax: translation debug: dump dll before patch\n"); - FILE* dllrtp = fopen("dllruntime.dll", "wb"); - fwrite(data, 1, dllSize, dllrtp); - fclose(dllrtp); - LOG("popnhax: translation debug: dllruntime.dll generated\n"); - } + if (memcmp(buffer, "PATCH", 5) != 0) + { + LOG("popnhax: translation: invalid .ips header\n"); + return false; + } - /* undo all relocation so you can apply ips patch with correct values, we'll reapply them later */ - PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew); - DWORD_PTR reloc_delta = (DWORD_PTR)((int64_t)data - headers->OptionalHeader.ImageBase); - perform_reloc(data, -1*reloc_delta, 0, 0); + if (dump_dll) + { + LOG("popnhax: translation debug: dump dll before patch\n"); + FILE* dllrtp = fopen("dllruntime.dll", "wb"); + fwrite(data, 1, dllSize, dllrtp); + fclose(dllrtp); + LOG("popnhax: translation debug: dllruntime.dll generated\n"); + } - uint32_t trans_base = 0; /* eclale patch adds new section header which I'm relocating */ - uint32_t trans_base_offset = 0; - uint32_t trans_rebase = 0; + /* undo all relocation so you can apply ips patch with correct values, we'll reapply them later */ + PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew); + DWORD_PTR reloc_delta = (DWORD_PTR)((int64_t)data - headers->OptionalHeader.ImageBase); + perform_reloc(data, -1*reloc_delta, 0, 0); - uint32_t offset = 0; - uint16_t size = 0; - uint16_t count = 0; - uint8_t replace[MAX_REPLACE_SIZE] = {0}; - - while ( fread(&offset, 1, 3, ips_fp) == 3 && offset != IPS_EOF ) - { - bool skip = false; - - /* need to convert offset to rva before applying patch since the dll is already in memory */ - uint8_t *bp = (uint8_t *)&offset; - offset = BYTE3_TO_UINT(bp); - uint32_t rva; + uint32_t trans_base = 0; /* eclale patch adds new section header which I'm relocating */ + uint32_t trans_base_offset = 0; + uint32_t trans_rebase = 0; - if (offset < 0x400) - { - rva = offset; - } - else if ( !offset_to_rva(dllFilename, offset, &rva) ) - { - LOG("Invalid offset %x conversion. Skip this patch\n", offset); - skip = true; - /* still need to go through the loop to increase read pointer accordingly */ - } - - IPS_READ(&size, 2, "SIZE"); - bp = (uint8_t *)&size; - size = BYTE2_TO_UINT(bp); - ++count; - - //LOG("%03d: offset %x converted to %x\nsize %d\n", count, offset, rva,size); - if ( size == 0 ) - { - uint8_t value; - - IPS_READ(&size, 2, "RLE SIZE"); - bp = (uint8_t *)&size; - size = BYTE2_TO_UINT(bp); + uint32_t offset = 0; + uint16_t size = 0; + uint16_t count = 0; + uint8_t replace[MAX_REPLACE_SIZE] = {0}; - IPS_READ(&value, 1, "RLE VALUE"); - - //LOG("RLE PATCH! size %d value %d\n", size, value); - //fprintf(stderr, "rle value %d (%d bytes)\n",value, size); - if ( size > MAX_REPLACE_SIZE ) - { - LOG("RLE replacement too big.\n"); - return false; - } - memset(replace, value, size); - } - else - { - if ( size > MAX_REPLACE_SIZE ) - { - - uint16_t remaining = size; - uint32_t chunk_rva = rva; - - do { - /* patch in multiple chunks */ - LOG("multipart patch: rva %x, %d remaining\n", chunk_rva, remaining); - IPS_READ(&replace, MAX_REPLACE_SIZE, "DATA"); - - if ( !skip ) - patch_memory((int64_t)data+chunk_rva, (char *)replace, MAX_REPLACE_SIZE); - - remaining -= MAX_REPLACE_SIZE; - chunk_rva += MAX_REPLACE_SIZE; - - } while (remaining > MAX_REPLACE_SIZE); - - size = remaining; - rva = chunk_rva; - - } - - IPS_READ(&replace, size, "DATA"); - } - - /* eclale woes */ - if ( trans_base == 0 && rva < 0x400 ) - { - if (memcmp(replace, ".trans", 6) == 0) - { - trans_base = *(uint32_t*)(replace+0x0C); - trans_base_offset = *(uint32_t*)(replace+0x14); - //LOG("found .trans section at offset %x rva %x\n", trans_base_offset, trans_base); - } - } + while ( fread(&offset, 1, 3, ips_fp) == 3 && offset != IPS_EOF ) + { + bool skip = false; - if ( trans_base_offset != 0 && offset >= trans_base_offset ) - { - /* patching into new section */ - if ( trans_rebase == 0 ) - { - HANDLE hProc = GetCurrentProcess(); - LPVOID myAlloc = VirtualAllocEx(hProc, NULL, 16384, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (myAlloc == NULL) - { - LOG("Failed to allocate memory in target process. Error: 0x%lX\n", GetLastError()); - exit(0); - } - trans_rebase = (uint32_t)myAlloc - (uint32_t)data; - //LOG( "virtualalloc worked; address %x (%p)\n", trans_rebase, myAlloc); + /* need to convert offset to rva before applying patch since the dll is already in memory */ + uint8_t *bp = (uint8_t *)&offset; + offset = BYTE3_TO_UINT(bp); + uint32_t rva; - /* seems useless */ - //memcpy(replace, &trans_rebase, 4); - //patch_memory((int64_t)data+0x02d4, (char *)replace, 4); - //LOG( "patched .trans section address to %02x %02x %02x %02x\n", replace[0], replace[1], replace[2], replace[3]); - } - rva = (offset - trans_base_offset) + trans_rebase; - //LOG( "off %x - base %x + rebase %x = %x\n\n", offset, trans_base_offset, trans_rebase, rva); - //LOG( "offset %x relocated to rva %x.", offset, rva); - } - - if ( !skip ) - { - patch_memory((int64_t)data+rva, (char *)replace, size); - } - } + if (offset < 0x400) + { + rva = offset; + } + else if ( !offset_to_rva(dllFilename, offset, &rva) ) + { + LOG("Invalid offset %x conversion. Skip this patch\n", offset); + skip = true; + /* still need to go through the loop to increase read pointer accordingly */ + } - /* redo all relocation now the dll is patched */ - perform_reloc(data, reloc_delta, trans_base, trans_rebase-trans_base); + IPS_READ(&size, 2, "SIZE"); + bp = (uint8_t *)&size; + size = BYTE2_TO_UINT(bp); + ++count; - LOG("popnhax: translation: IPS patch applied.\n"); - - if (dump_dll) - { - LOG("popnhax: translation debug: dump dll after patch\n"); - FILE* dllrtp = fopen("dllruntime_patched.dll", "wb"); - fwrite(data, 1, dllSize, dllrtp); - fclose(dllrtp); - } + //LOG("%03d: offset %x converted to %x\nsize %d\n", count, offset, rva,size); + if ( size == 0 ) + { + uint8_t value; - fclose(ips_fp); - return true; + IPS_READ(&size, 2, "RLE SIZE"); + bp = (uint8_t *)&size; + size = BYTE2_TO_UINT(bp); + + IPS_READ(&value, 1, "RLE VALUE"); + + //LOG("RLE PATCH! size %d value %d\n", size, value); + //fprintf(stderr, "rle value %d (%d bytes)\n",value, size); + if ( size > MAX_REPLACE_SIZE ) + { + LOG("RLE replacement too big.\n"); + return false; + } + memset(replace, value, size); + } + else + { + if ( size > MAX_REPLACE_SIZE ) + { + + uint16_t remaining = size; + uint32_t chunk_rva = rva; + + do { + /* patch in multiple chunks */ + LOG("multipart patch: rva %x, %d remaining\n", chunk_rva, remaining); + IPS_READ(&replace, MAX_REPLACE_SIZE, "DATA"); + + if ( !skip ) + patch_memory((int64_t)data+chunk_rva, (char *)replace, MAX_REPLACE_SIZE); + + remaining -= MAX_REPLACE_SIZE; + chunk_rva += MAX_REPLACE_SIZE; + + } while (remaining > MAX_REPLACE_SIZE); + + size = remaining; + rva = chunk_rva; + + } + + IPS_READ(&replace, size, "DATA"); + } + + /* eclale woes */ + if ( trans_base == 0 && rva < 0x400 ) + { + if (memcmp(replace, ".trans", 6) == 0) + { + trans_base = *(uint32_t*)(replace+0x0C); + trans_base_offset = *(uint32_t*)(replace+0x14); + //LOG("found .trans section at offset %x rva %x\n", trans_base_offset, trans_base); + } + } + + if ( trans_base_offset != 0 && offset >= trans_base_offset ) + { + /* patching into new section */ + if ( trans_rebase == 0 ) + { + HANDLE hProc = GetCurrentProcess(); + LPVOID myAlloc = VirtualAllocEx(hProc, NULL, 16384, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (myAlloc == NULL) + { + LOG("Failed to allocate memory in target process. Error: 0x%lX\n", GetLastError()); + exit(0); + } + trans_rebase = (uint32_t)myAlloc - (uint32_t)data; + //LOG( "virtualalloc worked; address %x (%p)\n", trans_rebase, myAlloc); + + /* seems useless */ + //memcpy(replace, &trans_rebase, 4); + //patch_memory((int64_t)data+0x02d4, (char *)replace, 4); + //LOG( "patched .trans section address to %02x %02x %02x %02x\n", replace[0], replace[1], replace[2], replace[3]); + } + rva = (offset - trans_base_offset) + trans_rebase; + //LOG( "off %x - base %x + rebase %x = %x\n\n", offset, trans_base_offset, trans_rebase, rva); + //LOG( "offset %x relocated to rva %x.", offset, rva); + } + + if ( !skip ) + { + patch_memory((int64_t)data+rva, (char *)replace, size); + } + } + + /* redo all relocation now the dll is patched */ + perform_reloc(data, reloc_delta, trans_base, trans_rebase-trans_base); + + LOG("popnhax: translation: IPS patch applied.\n"); + + if (dump_dll) + { + LOG("popnhax: translation debug: dump dll after patch\n"); + FILE* dllrtp = fopen("dllruntime_patched.dll", "wb"); + fwrite(data, 1, dllSize, dllrtp); + fclose(dllrtp); + } + + fclose(ips_fp); + return true; #undef IPS_READ } @@ -331,16 +331,16 @@ static bool patch_translation_dict(const char *dllFilename, const char *folderna uint8_t word_count = 0; uint8_t orig_size = 0; - char dict_filepath[64]; + char dict_filepath[64]; sprintf(dict_filepath, "%s%s%s", "data_mods\\", foldername, "\\popn22.dict"); - FILE *dict_fp = fopen(dict_filepath, "rb"); - + FILE *dict_fp = fopen(dict_filepath, "rb"); + if (dict_fp == NULL) - { - return false; - } - - LOG("popnhax: translation: popn22.dict file found\n"); + { + return false; + } + + LOG("popnhax: translation: popn22.dict file found\n"); #define STATE_WAITING 0 #define STATE_ORIGINAL 1 @@ -435,11 +435,11 @@ static bool patch_translation_dict(const char *dllFilename, const char *folderna bool patch_translate(const char *dllFilename, const char *folder, bool debug) { - bool ips_done = false; - bool dict_done = false; + bool ips_done = false; + bool dict_done = false; - ips_done = patch_translation_ips(dllFilename, folder, debug); - dict_done = patch_translation_dict(dllFilename, folder, debug); - - return ips_done || dict_done; + ips_done = patch_translation_ips(dllFilename, folder, debug); + dict_done = patch_translation_dict(dllFilename, folder, debug); + + return ips_done || dict_done; } \ No newline at end of file