Compare commits

...

47 Commits
main ... wip

Author SHA1 Message Date
ceffcc049d assets + build rework 2024-05-02 20:40:18 +02:00
b936ae00d3 custom track title format2 (and gotta find where i messed with customs) 2024-05-02 02:46:21 +02:00
c3f4f9b93e fix N 0 appearing on song select 2024-05-02 00:04:07 +02:00
b282cfa8f4 auto_diag 2024-05-01 20:29:47 +02:00
44fddc67ee cleanup 2024-05-01 14:28:47 +02:00
25fa51d831 datecode auto uses xml target 2024-05-01 12:31:14 +02:00
11ee17f48b force_datecode auto 2024-05-01 05:36:04 +02:00
dc63a6df08 cleanup for music limit check 2024-05-01 04:55:37 +02:00
1f630edb10 music limit check 2024-05-01 04:09:11 +02:00
c18656658c wip cleanup 2024-04-30 01:58:01 +02:00
d1c1d8a13f wip exclude from level 2024-04-30 00:52:22 +02:00
0b88b1253d different favorite files per game version 2024-04-29 22:31:32 +02:00
f0daa9e761 rework exclude code, add options to xml 2024-04-29 21:31:42 +02:00
d6ca83d076 exclude from versions,CS + default fav rework 2024-04-29 14:51:46 +02:00
5e57926b58 fav working 2024-04-28 22:42:04 +02:00
e838d88269 wip favorites, multiple .fav working, force fav handling on result screen 2024-04-28 15:01:49 +02:00
ed6a3a23f0 poc favorite 2024-04-28 01:58:15 +02:00
badd6535b3 poc favorite 2024-04-28 01:43:34 +02:00
2dcc503eca remove custom_is_new 2024-04-27 23:13:03 +02:00
94b7eb014d test new_is_custom (not good enough, will discard) 2024-04-27 23:04:42 +02:00
a7bf74962b wip custom highlight 2024-04-27 21:45:04 +02:00
f2320cdf07 add warning for back to song select without quick retire 2024-04-27 21:31:22 +02:00
30ba232511 wip custom highlight 2024-04-25 00:09:33 +02:00
de69af2d66 ALL SONGS subcategory 2024-04-22 01:28:04 +02:00
4f22fd29be fix crash 2024-04-22 00:20:41 +02:00
2543d2632f simple categ malloc 2024-04-21 21:40:48 +02:00
46ec71b83b cleanup, expose options 2024-04-21 18:15:03 +02:00
5f2a9d7bc0 cleanup 2024-04-21 16:09:33 +02:00
75ca8ba050 working 2024-04-21 15:56:55 +02:00
06957c8340 no more crash in menu, only once you select a song :( 2024-04-21 01:38:15 +02:00
2e94df0984 no more crash, but still event categ songlists dafuq 2024-04-21 00:35:48 +02:00
d0ea7fcc00 wip, folder names 2024-04-20 16:43:31 +02:00
298842bd61 wip, event function copy works 2024-04-20 15:17:22 +02:00
ea0d9487b2 wip marche pas 2024-04-20 15:09:55 +02:00
a7d65e2c72 wip marche pas 2024-04-20 15:09:27 +02:00
4761082536 wip 2024-04-20 14:25:00 +02:00
7f146dc5e9 wip 2024-04-20 14:21:26 +02:00
3c459addea wip categ 2024-04-20 10:32:49 +02:00
a4a4e53da1 inject custom category 2024-04-17 21:00:57 +02:00
fd529834b5 fix autohispeed for kaimei- 2024-04-17 20:55:22 +02:00
0cb685ef4b fix power point convergence value with customs 2024-01-05 22:32:22 +01:00
dc987c46ac expose base_offset as an option 2024-01-03 14:38:50 +01:00
4706d117a1 auto hispeed soflan retry 2024-01-03 14:11:34 +01:00
2535fba8d6 fix autohispeed 2024-01-03 00:41:21 +01:00
ccf3a4c8f8 rewrite patch pattern for back_to_song_select, render loop (enhanced_polling_stats and practice mode) 2023-12-30 00:49:24 +01:00
c3e8eb5f13 display version in log, rewrite patch pattern for quick retire, auto hispeed 2023-12-30 00:49:09 +01:00
783dafbe97 fix WSL compilation 2023-12-29 23:24:47 +01:00
18 changed files with 2368 additions and 699 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*:Zone.Identifier

View File

@ -232,8 +232,8 @@ $$(dll_$1_$2_$3) $$(implib_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) \
$(ccache) $$(toolchain_$1)gcc -shared $$(srcdir_$3)/$3.def \ $(ccache) $$(toolchain_$1)gcc -shared $$(srcdir_$3)/$3.def \
-o $$(dll_$1_$2_$3) -Wl,--out-implib,$$(implib_$1_$2_$3) \ -o $$(dll_$1_$2_$3) -Wl,--out-implib,$$(implib_$1_$2_$3) \
$$^ $$(ldflags_$3) $(optflags_$1) $$^ $$(ldflags_$3) $(optflags_$1)
strip -s $$(dll_$1_$2_$3) $$(toolchain_$1)strip -s $$(dll_$1_$2_$3)
ranlib $$(implib_$1_$2_$3) $$(toolchain_$1)ranlib $$(implib_$1_$2_$3)
endef endef
@ -248,7 +248,7 @@ exe_$1_$2_$3 := $$(bindir_$1_$2)/$3.exe
$$(exe_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) $$(absdpl_$1_$2_$3) \ $$(exe_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) $$(absdpl_$1_$2_$3) \
| $$(bindir_$1_$2) | $$(bindir_$1_$2)
$(ccache) $$(toolchain_$1)gcc -o $$@ $$^ $$(ldflags_$3) $(optflags_$1) $(ccache) $$(toolchain_$1)gcc -o $$@ $$^ $$(ldflags_$3) $(optflags_$1)
strip -s $$@ $$(toolchain_$1)strip -s $$@
endef endef
@ -259,7 +259,7 @@ define t_import
impdef_$1_$2_$3 ?= imports/import_$1_$2_$3.def impdef_$1_$2_$3 ?= imports/import_$1_$2_$3.def
$$(bindir_$1_$2)/lib$3.a: $$(impdef_$1_$2_$3) | $$(bindir_$1_$2) $$(bindir_$1_$2)/lib$3.a: $$(impdef_$1_$2_$3) | $$(bindir_$1_$2)
dlltool -l $$@ -d $$< $$(toolchain_$1)dlltool -l $$@ -d $$<
endef endef

View File

@ -14,17 +14,15 @@ include popnhax/Module.mk
# #
zipdir := $(BUILDDIR)/zip zipdir := $(BUILDDIR)/zip
popnhax_version := $(shell grep "define PROGRAM_VERSION" popnhax/dllmain.cc | cut -d'"' -f2)
$(zipdir)/: $(BUILDDIR)/popnhax_$(popnhax_version).zip: \
mkdir -p $@ build/bin/avs2_1508-32/popnhax.dll
@echo ... $@
@mkdir -p $(zipdir)
@cp -a -p build/bin/avs2_1508-32/popnhax.dll $(zipdir)
@cp -r -a -p dist/popnhax/* $(zipdir)
@cd $(zipdir) \
&& zip -r ../popnhax_$(popnhax_version).zip ./*
$(BUILDDIR)/popnhax.zip: \ all: $(BUILDDIR)/popnhax_$(popnhax_version).zip
build/bin/avs2_1508-32/popnhax.dll \
dist/popnhax/popnhax.xml \
dist/popnhax/D3d9.dll \
dist/popnhax/ifs_hook.dll \
| $(zipdir)/
echo ... $@
zip -j $@ $^
all: $(BUILDDIR)/popnhax.zip

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -5,6 +5,18 @@
<patch_db __type="bool">0</patch_db> <patch_db __type="bool">0</patch_db>
<!-- Force unlock music, charts, characters, and deco parts when applicable --> <!-- Force unlock music, charts, characters, and deco parts when applicable -->
<force_unlocks __type="bool">0</force_unlocks> <force_unlocks __type="bool">0</force_unlocks>
<!-- Put customs into their own category (0: no, 1: simple category with all customs, 2: subcategories by folder name) -->
<custom_categ __type="u8">2</custom_categ>
<!-- Prevent customs from showing up in version folders -->
<custom_exclude_from_version __type="bool">1</custom_exclude_from_version>
<!-- Prevent customs from showing up in level folders -->
<custom_exclude_from_level __type="bool">0</custom_exclude_from_level>
<!-- Other categories -->
<!-- Bring back score challenge in the game for servers supporting it (only for kaimei onwards) -->
<score_challenge __type="bool">0</score_challenge>
<!-- Handle favorites through data_mods/<game>.<friendID>.fav files (Note: allows UNLIMITED favorites as well as favorites without an account/server) -->
<local_favorites __type="bool">0</local_favorites>
<!-- Classic patches --> <!-- Classic patches -->
<!-- Prevent crash on boot when using a different default audio source (aka HDMI audio patch) --> <!-- Prevent crash on boot when using a different default audio source (aka HDMI audio patch) -->
@ -27,10 +39,6 @@
<!-- quick_retire with pfree also enables quick retry: press numpad 8 during song or on result screen to retry (keep holding to skip option select) --> <!-- quick_retire with pfree also enables quick retry: press numpad 8 during song or on result screen to retry (keep holding to skip option select) -->
<quick_retire __type="bool">0</quick_retire> <quick_retire __type="bool">0</quick_retire>
<!-- Network features -->
<!-- Bring back score challenge in the game for servers supporting it (only for kaimei onwards) -->
<score_challenge __type="bool">0</score_challenge>
<!-- Audio offset --> <!-- Audio offset -->
<!-- Offset the audio by x ms (negative plays audio earlier). This will disable keysounds --> <!-- Offset the audio by x ms (negative plays audio earlier). This will disable keysounds -->
<audio_offset __type="s8">0</audio_offset> <audio_offset __type="s8">0</audio_offset>
@ -49,7 +57,7 @@
<hispeed_default_bpm __type="u16">0</hispeed_default_bpm> <hispeed_default_bpm __type="u16">0</hispeed_default_bpm>
<!-- IIDX-like hard gauge (start with full gauge, instant fail if gauge drops to 0) --> <!-- IIDX-like hard gauge (start with full gauge, instant fail if gauge drops to 0) -->
<!-- Gauge details: increment: +0.1% for each cool/great/good (like spicy gauge), decrement: -9% for each bad, or -4.5% if gauge <=30% ) --> <!-- Gauge details: increment: +0.1% for each cool/great/good (like spicy gauge), decrement: -9% for each bad, or -4.5% if gauge <=30% (like IIDX) -->
<iidx_hard_gauge __type="bool">0</iidx_hard_gauge> <iidx_hard_gauge __type="bool">0</iidx_hard_gauge>
<!-- Force full options by default (useful when no numpad is available) --> <!-- Force full options by default (useful when no numpad is available) -->
<force_full_opt __type="bool">0</force_full_opt> <force_full_opt __type="bool">0</force_full_opt>
@ -96,14 +104,16 @@
======================================================================================== --> ======================================================================================== -->
<!-- Datecode and Multiboot --> <!-- Datecode and Multiboot -->
<!-- Force a different datecode than the one found in ea3-config (yyyymmdd00) --> <!-- Force a different datecode than the one found in ea3-config (yyyymmdd00), or use "auto" to let music limit decide for you if patch_db is on -->
<force_datecode __type="str"></force_datecode> <force_datecode __type="str">auto</force_datecode>
<!-- Also apply force_datecode to network packets --> <!-- Also apply force_datecode to network packets -->
<network_datecode __type="bool">1</network_datecode> <network_datecode __type="bool">1</network_datecode>
<!-- Disable multiboot auto conf tuning (which takes place when using popn22_yyyymmddrr.dll format and an xml without force_datecode option) --> <!-- Disable multiboot auto conf tuning (which takes place when using popn22_yyyymmddrr.dll format and an xml without another datecode in force_datecode) -->
<disable_multiboot __type="bool">0</disable_multiboot> <disable_multiboot __type="bool">0</disable_multiboot>
<!-- Timing and lanes --> <!-- Timing and lanes -->
<!-- Base visual offset (value will be added to the base SD (-60) and base HD (-76) values) -->
<base_offset __type="s8">0</base_offset>
<!-- Automatically play keysounds during songs --> <!-- Automatically play keysounds during songs -->
<disable_keysounds __type="bool">0</disable_keysounds> <disable_keysounds __type="bool">0</disable_keysounds>
<!-- Offset the keysounds by x ms (negative is earlier). With disable_keysounds, becomes an audio offset --> <!-- Offset the keysounds by x ms (negative is earlier). With disable_keysounds, becomes an audio offset -->
@ -122,14 +132,30 @@
<enhanced_polling_priority __type="s8">1</enhanced_polling_priority> <enhanced_polling_priority __type="s8">1</enhanced_polling_priority>
<!-- Song db patches --> <!-- Song db patches -->
<!-- Auto select patch file from data_mods folder (will detect datecode from ea3-config or force_datecode option) --> <!-- Auto select patch file from data_mods folder based on music limit, or datecode otherwise (will detect datecode from ea3-config or force_datecode option) -->
<patch_xml_auto __type="bool">1</patch_xml_auto> <patch_xml_auto __type="bool">1</patch_xml_auto>
<!-- Manually set XML file containing patches (requires patch_xml_auto to be disabled) --> <!-- Manually set XML file containing patches (requires patch_xml_auto to be disabled) -->
<patch_xml_filename __type="str"></patch_xml_filename> <patch_xml_filename __type="str"></patch_xml_filename>
<!-- Force the newly created buffers to be the same size as the original buffers --> <!-- Force the newly created buffers to be the same size as the original buffers (not recommended) -->
<disable_expansions __type="bool">0</disable_expansions> <disable_expansions __type="bool">0</disable_expansions>
<!-- Copy the new table information over top the old tables (automatically enables disable_expansions) --> <!-- Copy the new table information over top the old tables (automatically enables disable_expansions) (not recommended) -->
<disable_redirection __type="bool">0</disable_redirection> <disable_redirection __type="bool">0</disable_redirection>
<!-- Do not perform music limit checks for patch_xml_auto (not recommended) -->
<ignore_music_limit __type="bool">0</ignore_music_limit>
<!-- Custom category options -->
<!-- minimum songid for a song to be seen as "custom" -->
<custom_categ_min_songid __type="u16">4000</custom_categ_min_songid>
<!-- maximum songid for a song to be seen as "custom" (0 = no limit) -->
<custom_categ_max_songid __type="u16">0</custom_categ_max_songid>
<!-- Category title for customs -->
<custom_category_title __type="str">Customs</custom_category_title>
<!-- Format used for category title (in BM2DXFontScript format, refer to popnhax_tools documentation) -->
<custom_category_format __type="str">[ol:4][olc:d92f0d]%s</custom_category_format>
<!-- Format used for custom song titles on song select (Note: colors not working for kaimei and above, but rotation does, e.g. "* [rz:3]%s[/rz]" ) -->
<custom_track_title_format __type="str"></custom_track_title_format>
<!-- Optional secondary format used for older games only (Full colors supported, e.g. "[ol:4][olc:d92f0d]%s") -->
<custom_track_title_format2 __type="str"></custom_track_title_format2>
<!-- Translation --> <!-- Translation -->
<!-- Disable .dict string replacements and .ips patches --> <!-- Disable .dict string replacements and .ips patches -->

View File

@ -14,4 +14,5 @@ srcpp_popnhax := \
dllmain.cc \ dllmain.cc \
loader.cc \ loader.cc \
SearchFile.cc \ SearchFile.cc \
translation.cc translation.cc \
custom_categs.cc

View File

@ -4,6 +4,7 @@
#include <stdbool.h> #include <stdbool.h>
struct popnhax_config { struct popnhax_config {
uint8_t game_version;
bool practice_mode; bool practice_mode;
bool hidden_is_offset; bool hidden_is_offset;
bool iidx_hard_gauge; bool iidx_hard_gauge;
@ -14,6 +15,11 @@ struct popnhax_config {
bool quick_retire; bool quick_retire;
bool back_to_song_select; bool back_to_song_select;
bool score_challenge; bool score_challenge;
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; bool force_hd_timing;
uint8_t force_hd_resolution; uint8_t force_hd_resolution;
bool force_unlocks; bool force_unlocks;
@ -26,12 +32,14 @@ struct popnhax_config {
bool force_full_opt; bool force_full_opt;
bool netvs_off; bool netvs_off;
bool guidese_off; bool guidese_off;
bool local_favorites;
bool patch_db; bool patch_db;
bool disable_expansions; bool disable_expansions;
bool disable_redirection; bool disable_redirection;
bool disable_multiboot; bool disable_multiboot;
bool patch_xml_auto; bool patch_xml_auto;
bool ignore_music_limit;
char patch_xml_filename[MAX_PATH]; char patch_xml_filename[MAX_PATH];
char force_datecode[11]; char force_datecode[11];
bool network_datecode; bool network_datecode;
@ -51,6 +59,11 @@ struct popnhax_config {
uint8_t survival_gauge; uint8_t survival_gauge;
bool survival_iidx; bool survival_iidx;
bool survival_spicy; bool survival_spicy;
int8_t base_offset;
char custom_category_title[16];
char custom_category_format[64];
char custom_track_title_format[64];
char custom_track_title_format2[64];
}; };
#endif #endif

1069
popnhax/custom_categs.cc Normal file

File diff suppressed because it is too large Load Diff

10
popnhax/custom_categs.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __CUSTOM_CATEGS_H__
#define __CUSTOM_CATEGS_H__
#include <stdint.h>
#include "popnhax/config.h"
bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config);
bool patch_local_favorites(const char *dllFilename, uint8_t version);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#include "imports/avs.h" #include "imports/avs.h"
#include "util/patch.h" #include "util/patch.h"
#include "util/log.h"
#include "xmlhelper.h" #include "xmlhelper.h"
#include "tableinfo.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); uint32_t file_type, uint16_t used_keys, bool override_idx);
void parse_charadb(const char *input_filename, const char *target); 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<uint32_t, int8_t> chart_type_overrides; std::map<uint32_t, int8_t> chart_type_overrides;
@ -818,7 +819,7 @@ void parse_charadb(const char *input_filename, const char *target) {
free(config_xml); 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)) { if (!file_exists(input_filename)) {
printf("Couldn't find %s, skipping...\n", input_filename); printf("Couldn't find %s, skipping...\n", input_filename);
return; 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"))) { if ((prop_chart = property_search(config_xml, prop, "charts/chart"))) {
for (; prop_chart != NULL; prop_chart = property_node_traversal( for (; prop_chart != NULL; prop_chart = property_node_traversal(
prop_chart, TRAVERSE_NEXT_SEARCH_RESULT)) { prop_chart, TRAVERSE_NEXT_SEARCH_RESULT)) {
@ -992,7 +1005,7 @@ void parse_musicdb(const char *input_filename, const char *target) {
free(config_xml); free(config_xml);
} }
void load_databases(const char *target_datecode) { void load_databases(const char *target_datecode, struct popnhax_config *config) {
SearchFile s; SearchFile s;
printf("XML db files search...\n"); 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 ) if ( strstr(result[i].c_str(), "musicdb") == NULL )
continue; continue;
printf("(musicdb) Loading %s...\n", result[i].c_str()); 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 *target_datecode,
char *base_data, char *base_data,
@ -1036,6 +1049,10 @@ 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, uint64_t chara_size, uint64_t *new_chara_size, char *orig_chara_data,
uint8_t **new_chara_table) { 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) { if (style_size > fontstyle_table_size) {
fontstyle_table_size = style_size; fontstyle_table_size = style_size;
} }
@ -1181,7 +1198,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); 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) // Add some filler charts to fix some bugs (hack)
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {

View File

@ -2,10 +2,11 @@
#define __LOADER_H__ #define __LOADER_H__
#include <stdint.h> #include <stdint.h>
#include "popnhax/config.h"
int8_t get_chart_type_override(uint8_t *, uint32_t, uint32_t); 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, 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 *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, uint64_t chart_size, uint64_t *new_chart_size, char *orig_chart_data,

View File

@ -56,10 +56,10 @@ bool patch_sjis(const char *dllFilename, const char *find, uint8_t find_size, in
} while (valid_sjis); } while (valid_sjis);
if (dump_dict) 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,"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); fprintf(g_dict_applied_fp,";%s;%s\n",(char*)find,(char*)replace);
} }
/* safety check replace is not too big */ /* safety check replace is not too big */
uint8_t free_size = find_size-1; uint8_t free_size = find_size-1;
do do
@ -83,41 +83,41 @@ bool patch_sjis(const char *dllFilename, const char *find, uint8_t find_size, in
#define RELOC_HIGHLOW 0x3 #define RELOC_HIGHLOW 0x3
static void perform_reloc(char *data, int32_t delta, uint32_t ext_base, uint32_t ext_delta) 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_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_DATA_DIRECTORY datadir = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)(data + datadir->VirtualAddress); PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)(data + datadir->VirtualAddress);
while(reloc->VirtualAddress != 0) while(reloc->VirtualAddress != 0)
{ {
if (reloc->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION)) if (reloc->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION))
{ {
DWORD relocDescNb = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); DWORD relocDescNb = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
LPWORD relocDescList = (LPWORD)((LPBYTE)reloc + sizeof(IMAGE_BASE_RELOCATION)); LPWORD relocDescList = (LPWORD)((LPBYTE)reloc + sizeof(IMAGE_BASE_RELOCATION));
for (DWORD i = 0; i < relocDescNb; i++) for (DWORD i = 0; i < relocDescNb; i++)
{ {
if ( ((relocDescList[i])>>12) == RELOC_HIGHLOW ) if ( ((relocDescList[i])>>12) == RELOC_HIGHLOW )
{ {
DWORD_PTR *p = (DWORD_PTR *)( data + (reloc->VirtualAddress + ((relocDescList[i])&0x0FFF)) ); DWORD_PTR *p = (DWORD_PTR *)( data + (reloc->VirtualAddress + ((relocDescList[i])&0x0FFF)) );
/* Change the offset to adapt to injected module base address */ /* Change the offset to adapt to injected module base address */
DWORD old_prot; DWORD old_prot;
VirtualProtect((LPVOID)p, 4, PAGE_EXECUTE_READWRITE, &old_prot); VirtualProtect((LPVOID)p, 4, PAGE_EXECUTE_READWRITE, &old_prot);
*p += delta; *p += delta;
if ( ext_base > 0 && *p >= ((int64_t)data+ext_base) ) if ( ext_base > 0 && *p >= ((int64_t)data+ext_base) )
{ {
//fprintf(stderr,"reloc rva %lx to ext ", *p); //fprintf(stderr,"reloc rva %lx to ext ", *p);
*p += ext_delta; *p += ext_delta;
//fprintf(stderr," %lx\n", *p); //fprintf(stderr," %lx\n", *p);
} }
VirtualProtect((LPVOID)p, 4, old_prot, &old_prot); VirtualProtect((LPVOID)p, 4, old_prot, &old_prot);
} }
} }
} }
/* Set reloc pointer to the next relocation block */ /* Set reloc pointer to the next relocation block */
reloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)reloc + reloc->SizeOfBlock); reloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)reloc + reloc->SizeOfBlock);
} }
} }
#define BYTE3_TO_UINT(bp) \ #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) 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 {\ #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 )\ if ( fread(_ips_read_dest, 1, _ips_read_size, ips_fp) != _ips_read_size )\
{\ {\
LOG("CANNOT READ %s\n", _ips_read_name);\ LOG("CANNOT READ %s\n", _ips_read_name);\
return false;\ return false;\
}\ }\
} while (0) } while (0)
DWORD dllSize = 0; DWORD dllSize = 0;
char *data = getDllData(dllFilename, &dllSize); char *data = getDllData(dllFilename, &dllSize);
char dict_filepath[64]; char dict_filepath[64];
sprintf(dict_filepath, "%s%s%s", "data_mods\\", foldername, "\\popn22.ips"); 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) if (ips_fp == NULL)
{ {
return false; return false;
} }
LOG("popnhax: translation: popn22.ips found\n"); LOG("popnhax: translation: popn22.ips found\n");
/* check .ips header */ /* check .ips header */
uint8_t buffer[8]; uint8_t buffer[8];
if (fread(&buffer, 1, 5, ips_fp) != 5) if (fread(&buffer, 1, 5, ips_fp) != 5)
return false; return false;
if (memcmp(buffer, "PATCH", 5) != 0)
{
LOG("popnhax: translation: invalid .ips header\n");
return false;
}
if (dump_dll) if (memcmp(buffer, "PATCH", 5) != 0)
{ {
LOG("popnhax: translation debug: dump dll before patch\n"); LOG("popnhax: translation: invalid .ips header\n");
FILE* dllrtp = fopen("dllruntime.dll", "wb"); return false;
fwrite(data, 1, dllSize, dllrtp); }
fclose(dllrtp);
LOG("popnhax: translation debug: dllruntime.dll generated\n");
}
/* undo all relocation so you can apply ips patch with correct values, we'll reapply them later */ if (dump_dll)
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); LOG("popnhax: translation debug: dump dll before patch\n");
perform_reloc(data, -1*reloc_delta, 0, 0); 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 */ /* undo all relocation so you can apply ips patch with correct values, we'll reapply them later */
uint32_t trans_base_offset = 0; PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew);
uint32_t trans_rebase = 0; DWORD_PTR reloc_delta = (DWORD_PTR)((int64_t)data - headers->OptionalHeader.ImageBase);
perform_reloc(data, -1*reloc_delta, 0, 0);
uint32_t offset = 0; uint32_t trans_base = 0; /* eclale patch adds new section header which I'm relocating */
uint16_t size = 0; uint32_t trans_base_offset = 0;
uint16_t count = 0; uint32_t trans_rebase = 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;
if (offset < 0x400) uint32_t offset = 0;
{ uint16_t size = 0;
rva = offset; uint16_t count = 0;
} uint8_t replace[MAX_REPLACE_SIZE] = {0};
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);
IPS_READ(&value, 1, "RLE VALUE"); while ( fread(&offset, 1, 3, ips_fp) == 3 && offset != IPS_EOF )
{
//LOG("RLE PATCH! size %d value %d\n", size, value); bool skip = false;
//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 ) /* need to convert offset to rva before applying patch since the dll is already in memory */
{ uint8_t *bp = (uint8_t *)&offset;
/* patching into new section */ offset = BYTE3_TO_UINT(bp);
if ( trans_rebase == 0 ) uint32_t rva;
{
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 */ if (offset < 0x400)
//memcpy(replace, &trans_rebase, 4); {
//patch_memory((int64_t)data+0x02d4, (char *)replace, 4); rva = offset;
//LOG( "patched .trans section address to %02x %02x %02x %02x\n", replace[0], replace[1], replace[2], replace[3]); }
} else if ( !offset_to_rva(dllFilename, offset, &rva) )
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("Invalid offset %x conversion. Skip this patch\n", offset);
//LOG( "offset %x relocated to rva %x.", offset, rva); skip = true;
} /* still need to go through the loop to increase read pointer accordingly */
}
if ( !skip )
{
patch_memory((int64_t)data+rva, (char *)replace, size);
}
}
/* redo all relocation now the dll is patched */ IPS_READ(&size, 2, "SIZE");
perform_reloc(data, reloc_delta, trans_base, trans_rebase-trans_base); bp = (uint8_t *)&size;
size = BYTE2_TO_UINT(bp);
++count;
LOG("popnhax: translation: IPS patch applied.\n"); //LOG("%03d: offset %x converted to %x\nsize %d\n", count, offset, rva,size);
if ( size == 0 )
if (dump_dll) {
{ uint8_t value;
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); IPS_READ(&size, 2, "RLE SIZE");
return true; 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 #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 word_count = 0;
uint8_t orig_size = 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"); 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) if (dict_fp == NULL)
{ {
return false; return false;
} }
LOG("popnhax: translation: popn22.dict file found\n"); LOG("popnhax: translation: popn22.dict file found\n");
#define STATE_WAITING 0 #define STATE_WAITING 0
#define STATE_ORIGINAL 1 #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 patch_translate(const char *dllFilename, const char *folder, bool debug)
{ {
bool ips_done = false; bool ips_done = false;
bool dict_done = false; bool dict_done = false;
ips_done = patch_translation_ips(dllFilename, folder, debug); ips_done = patch_translation_ips(dllFilename, folder, debug);
dict_done = patch_translation_dict(dllFilename, folder, debug); dict_done = patch_translation_dict(dllFilename, folder, debug);
return ips_done || dict_done; return ips_done || dict_done;
} }

View File

@ -72,4 +72,9 @@ int _search(unsigned char *haystack, size_t haystack_size, const unsigned char *
int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) { int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) {
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, 0); int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, 0);
return res; return res;
}
int search_debug(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) {
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, 2);
return res;
} }

View File

@ -2,5 +2,6 @@
#define __SEARCH_H__ #define __SEARCH_H__
int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset); int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
int search_debug(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
#endif #endif