forked from Popn_Tools/popnhax
Compare commits
3 Commits
7c8248e00d
...
a4a4e53da1
Author | SHA1 | Date | |
---|---|---|---|
a4a4e53da1 | |||
fd529834b5 | |||
0cb685ef4b |
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#include "SearchFile.h"
|
#include "SearchFile.h"
|
||||||
|
|
||||||
#define PROGRAM_VERSION "1.10.dev"
|
#define PROGRAM_VERSION "1.11.beta1"
|
||||||
|
|
||||||
const char *g_game_dll_fn = NULL;
|
const char *g_game_dll_fn = NULL;
|
||||||
const char *g_config_fn = NULL;
|
const char *g_config_fn = NULL;
|
||||||
@ -607,13 +607,13 @@ bool patch_hispeed_auto(uint8_t mode, uint16_t default_bpm)
|
|||||||
/* write new hispeed according to target bpm */
|
/* write new hispeed according to target bpm */
|
||||||
{
|
{
|
||||||
/* improve compatibility with newer games */
|
/* improve compatibility with newer games */
|
||||||
int64_t pattern_offset = search(data, dllSize, "\xEB\x57\x8B\xBC\x24\x50\x01\x00\x00\x66\x8B\x85", 12, 0);
|
int64_t pattern_offset = search(data, dllSize, "\x0B\x00\x83\xC4\x04\xEB\x57\x8B\xBC\x24", 10, 0);
|
||||||
if (pattern_offset == -1) {
|
if (pattern_offset == -1) {
|
||||||
LOG("popnhax: auto hi-speed: cannot find chart BPM address offset\n");
|
LOG("popnhax: auto hi-speed: cannot find chart BPM address offset\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t patch_addr = (int64_t)data + pattern_offset + 0x1C;
|
uint64_t patch_addr = (int64_t)data + pattern_offset + 0x21;
|
||||||
g_low_bpm_ebp_offset = *((uint16_t *)(patch_addr));
|
g_low_bpm_ebp_offset = *((uint16_t *)(patch_addr));
|
||||||
|
|
||||||
if (g_low_bpm_ebp_offset != 0x0A1A && g_low_bpm_ebp_offset != 0x0A1E)
|
if (g_low_bpm_ebp_offset != 0x0A1A && g_low_bpm_ebp_offset != 0x0A1E)
|
||||||
@ -2677,13 +2677,6 @@ pfree_apply:
|
|||||||
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_pfree_pplist_inject,
|
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_pfree_pplist_inject,
|
||||||
(void **)&real_pfree_pplist_inject);
|
(void **)&real_pfree_pplist_inject);
|
||||||
}
|
}
|
||||||
/* prevent crash when playing only customs in a credit */
|
|
||||||
{
|
|
||||||
if (!find_and_patch_hex(g_game_dll_fn, "\x0F\x8E\x5C\xFF\xFF\xFF\xEB\x04", 8, 6, "\x90\x90", 2))
|
|
||||||
{
|
|
||||||
LOG("popnhax: pfree: cannot patch end list pointer\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* restore pp_list pointer so that it is freed at end of credit */
|
/* restore pp_list pointer so that it is freed at end of credit */
|
||||||
{
|
{
|
||||||
@ -5116,6 +5109,33 @@ static bool patch_db_fix_cursor(){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void (*real_pp_mean_compute)();
|
||||||
|
void hook_pp_mean_compute()
|
||||||
|
{
|
||||||
|
__asm("test ecx, ecx\n");
|
||||||
|
__asm("jnz divide_list\n");
|
||||||
|
__asm("mov eax, 0\n");
|
||||||
|
__asm("jmp skip_divide\n");
|
||||||
|
__asm("divide_list:\n");
|
||||||
|
__asm("div ecx\n");
|
||||||
|
__asm("skip_divide:\n");
|
||||||
|
real_pp_mean_compute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*real_pp_convergence_loop)();
|
||||||
|
void hook_pp_convergence_loop()
|
||||||
|
{
|
||||||
|
__asm("movzx eax, word ptr[ebx]\n");
|
||||||
|
__asm("cmp eax, 0xBB8\n");
|
||||||
|
__asm("jl conv_loop_rearm\n");
|
||||||
|
__asm("mov al, 0\n");
|
||||||
|
__asm("jmp conv_loop_leave\n");
|
||||||
|
__asm("conv_loop_rearm:\n");
|
||||||
|
__asm("mov al, 1\n");
|
||||||
|
__asm("conv_loop_leave:\n");
|
||||||
|
real_pp_convergence_loop();
|
||||||
|
}
|
||||||
|
|
||||||
bool patch_db_power_points()
|
bool patch_db_power_points()
|
||||||
{
|
{
|
||||||
DWORD dllSize = 0;
|
DWORD dllSize = 0;
|
||||||
@ -5145,7 +5165,20 @@ bool patch_db_power_points()
|
|||||||
g_pfree_song_offset = *(uint8_t *) ((int64_t)data + pattern_offset + 0x03);
|
g_pfree_song_offset = *(uint8_t *) ((int64_t)data + pattern_offset + 0x03);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adapt convergence value computation (skip cs_omni and customs) */
|
/* skip cs_omni and customs in power point convergence value */
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, dllSize, "\x8B\x6C\x24\x30\x8B\x4C\x24\x2C", 8, 0);
|
||||||
|
if (pattern_offset == -1) {
|
||||||
|
LOG("popnhax: patch_db: cannot find power point convergence value computation loop\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t patch_addr = (int64_t)data + pattern_offset - 0x08;
|
||||||
|
MH_CreateHook((LPVOID)(patch_addr), (LPVOID)hook_pp_convergence_loop,
|
||||||
|
(void **)&real_pp_convergence_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure they cannot count (sanity check) */
|
||||||
{
|
{
|
||||||
int64_t pattern_offset = search(data, dllSize, "\x84\xC0\x75\x11\x8D\x44\x24\x38", 8, 0);
|
int64_t pattern_offset = search(data, dllSize, "\x84\xC0\x75\x11\x8D\x44\x24\x38", 8, 0);
|
||||||
if (pattern_offset == -1) {
|
if (pattern_offset == -1) {
|
||||||
@ -5179,9 +5212,33 @@ bool patch_db_power_points()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
skip_pp_list_elem = (void(*)()) ((int64_t)data + jump_addr_offset);
|
skip_pp_list_elem = (void(*)()) ((int64_t)data + jump_addr_offset);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* prevent crash when playing only customs in a credit */
|
||||||
|
{
|
||||||
|
if (!find_and_patch_hex(g_game_dll_fn, "\x0F\x8E\x5C\xFF\xFF\xFF\xEB\x04", 8, 6, "\x90\x90", 2))
|
||||||
|
{
|
||||||
|
LOG("popnhax: patch_db: cannot patch end list pointer\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prevent another crash when playing only customs in a credit (sanity check) */
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, dllSize, "\xC1\xF9\x02\x33\xD2\xF7\xF1\x8B\xC8", 9, 0);
|
||||||
|
if (pattern_offset == -1) {
|
||||||
|
LOG("popnhax: patch_db: cannot find power point mean computation\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t patch_addr = (int64_t)data + pattern_offset + 0x05;
|
||||||
|
patch_memory(patch_addr, (char*)"\x90\x90", 2); // erase original div ecx (is taken care of in hook_pp_mean_compute)
|
||||||
|
|
||||||
|
/* fix possible divide by zero error */
|
||||||
|
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_pp_mean_compute,
|
||||||
|
(void **)&real_pp_mean_compute);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG("popnhax: patch_db: power point computation fixed\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5227,6 +5284,204 @@ static bool option_net_ojama_off(){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *g_categname = "Custom Tracks";
|
||||||
|
const char *g_categicon = "cate_13";
|
||||||
|
const char *g_categformat = "[ol:4][olc:d92f0d]%s";
|
||||||
|
|
||||||
|
uint32_t songlist[4096] = {0};
|
||||||
|
uint32_t songlist_addr = (uint32_t)&songlist;
|
||||||
|
uint32_t songlist_count = 0;
|
||||||
|
|
||||||
|
struct songlist_struct_s {
|
||||||
|
uint32_t dummy[3];
|
||||||
|
uint32_t array_start;
|
||||||
|
uint32_t array_end;
|
||||||
|
} songlist_struct;
|
||||||
|
|
||||||
|
uint32_t songlist_struct_addr = (uint32_t)&songlist_struct;
|
||||||
|
|
||||||
|
void (*add_song_in_list)();
|
||||||
|
void (*categ_inject_songlist)();
|
||||||
|
|
||||||
|
void categ_inject_songlist_impl()
|
||||||
|
{
|
||||||
|
__asm("push edx\n");
|
||||||
|
songlist_struct.array_start = (uint32_t)&songlist;
|
||||||
|
songlist_struct.array_end = (uint32_t)&(songlist[songlist_count]);
|
||||||
|
__asm("pop edx\n");
|
||||||
|
__asm("push ecx\n");
|
||||||
|
__asm("push _songlist_struct_addr\n");
|
||||||
|
__asm("lea eax, dword ptr [ecx+0x24]\n");
|
||||||
|
__asm("call [_add_song_in_list]\n");
|
||||||
|
__asm("pop ecx\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*real_categ_reinit_songlist)();
|
||||||
|
void hook_categ_reinit_songlist()
|
||||||
|
{
|
||||||
|
songlist_count = 0;
|
||||||
|
real_categ_reinit_songlist();
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*real_categ_build_songlist)();
|
||||||
|
void hook_categ_build_songlist()
|
||||||
|
{
|
||||||
|
__asm("cmp eax, 0xFA0\n");
|
||||||
|
__asm("jb categ_skip_add\n");
|
||||||
|
__asm("push eax\n");
|
||||||
|
__asm("push ebx\n");
|
||||||
|
__asm("mov eax, [_songlist_count]\n");
|
||||||
|
__asm("sal eax, 2\n");
|
||||||
|
__asm("add eax, _songlist_addr\n");
|
||||||
|
__asm("mov ebx, [edx]\n");
|
||||||
|
__asm("mov dword ptr [eax], ebx\n");
|
||||||
|
songlist_count++;
|
||||||
|
__asm("pop ebx\n");
|
||||||
|
__asm("pop eax\n");
|
||||||
|
__asm("categ_skip_add:\n");
|
||||||
|
real_categ_build_songlist();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void (*real_categ_printf_call)();
|
||||||
|
void (*real_categ_title_printf)();
|
||||||
|
void hook_categ_title_printf()
|
||||||
|
{
|
||||||
|
__asm("cmp edi, 0x10\n");
|
||||||
|
__asm("jle categ_title_printf_ok\n");
|
||||||
|
__asm("mov eax, _g_categformat\n");
|
||||||
|
__asm("push eax\n");
|
||||||
|
__asm("jmp [_real_categ_printf_call]\n");
|
||||||
|
__asm("categ_title_printf_ok:\n");
|
||||||
|
real_categ_title_printf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*categ_listing_newsongs)();
|
||||||
|
void (*real_categ_listing)();
|
||||||
|
void hook_categ_listing()
|
||||||
|
{
|
||||||
|
__asm("cmp eax, 0x11\n");
|
||||||
|
__asm("jne categ_listing_ok\n");
|
||||||
|
__asm("call [_categ_inject_songlist]\n");
|
||||||
|
__asm("categ_listing_ok:\n");
|
||||||
|
real_categ_listing();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool patch_custom_categ() {
|
||||||
|
|
||||||
|
DWORD dllSize = 0;
|
||||||
|
char *data = getDllData(g_game_dll_fn, &dllSize);
|
||||||
|
|
||||||
|
//patch format string for any category above 16 (prevent crash)
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, dllSize, "\x6A\xFF\x8B\xCB\xFF\xD2\x50", 7, 0);
|
||||||
|
if (pattern_offset == -1) {
|
||||||
|
LOG("popnhax: custom_categ: cannot find category title format string function\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t patch_addr = (int64_t)data + pattern_offset + 0x07;
|
||||||
|
real_categ_printf_call = (void (*)())(patch_addr + 0x08);
|
||||||
|
|
||||||
|
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_categ_title_printf,
|
||||||
|
(void **)&real_categ_title_printf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//add new category processing in jump table
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, dllSize, "\x8B\x4D\x10\x8B\x5D\x0C\x8B\xF1", 8, 0);
|
||||||
|
if (pattern_offset == -1) {
|
||||||
|
LOG("popnhax: custom_categ: cannot find add_song_in_list function\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_song_in_list = (void (*)())(data + pattern_offset - 0x12);
|
||||||
|
categ_inject_songlist = &categ_inject_songlist_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, dllSize, "\x83\xF8\x10\x77\x75\xFF\x24\x85", 8, 0);
|
||||||
|
if (pattern_offset == -1) {
|
||||||
|
LOG("popnhax: custom_categ: cannot find category jump table\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t patch_addr = (int64_t)data + pattern_offset + 0x05 + 0x75;
|
||||||
|
//categ_listing_newsongs = (void (*)())(data + pattern_offset + 0x05 + 0x0E); //TODO: replace this with my own function
|
||||||
|
|
||||||
|
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_categ_listing,
|
||||||
|
(void **)&real_categ_listing);
|
||||||
|
}
|
||||||
|
|
||||||
|
//create new song list
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, dllSize, "\x00\x8B\x56\x04\x0F\xB7\x02\xE8", 8, 0);
|
||||||
|
if (pattern_offset == -1) {
|
||||||
|
LOG("popnhax: custom_categ: cannot find songlist processing table\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t patch_addr = (int64_t)data + pattern_offset + 0x07;
|
||||||
|
|
||||||
|
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_categ_build_songlist,
|
||||||
|
(void **)&real_categ_build_songlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
//create new song list
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, dllSize, "\x33\xC9\xB8\x12\x00\x00\x00\xBA", 8, 0);
|
||||||
|
if (pattern_offset == -1) {
|
||||||
|
LOG("popnhax: custom_categ: cannot find category generation function\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t patch_addr = (int64_t)data + pattern_offset;
|
||||||
|
|
||||||
|
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_categ_reinit_songlist,
|
||||||
|
(void **)&real_categ_reinit_songlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//bump category number from 16 to 17
|
||||||
|
if (!find_and_patch_hex(g_game_dll_fn, "\x83\xFE\x11\x0F\x82\x59\xFE\xFF\xFF", 9, 2, "\x12", 1))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//patch getCategName for a 17th entry
|
||||||
|
//make array one cell larger
|
||||||
|
if (!find_and_patch_hex(g_game_dll_fn, "\x83\xEC\x44\x98\xC7\x04\x24", 7, 2, "\x48", 1))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t categname_str_addr = (uint32_t)g_categname;
|
||||||
|
char categname_patch_string[] = "\xC7\x44\x24\x44\x20\x00\x28\x10\x8B\x04\x84\x83\xC4\x48\xC3";
|
||||||
|
memcpy(categname_patch_string+4, &categname_str_addr, 4);
|
||||||
|
if (!find_and_patch_hex(g_game_dll_fn, "\x8B\x04\x84\x83\xC4\x44\xC3\xCC", 8, 0, categname_patch_string, 15))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//patch getIconName for a 17th entry
|
||||||
|
if (!find_and_patch_hex(g_game_dll_fn, "\x83\xEC\x44\x98\xC7\x04\x24", 7, 2, "\x48", 1)) //2nd occurrence since first one just got patched
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t categicon_str_addr = (uint32_t)g_categicon;
|
||||||
|
char categicon_patch_string[] = "\xC7\x44\x24\x44\xDC\x00\x28\x10\x8B\x04\x84\x83\xC4\x48\xC3";
|
||||||
|
memcpy(categicon_patch_string+4, &categicon_str_addr, 4);
|
||||||
|
if (!find_and_patch_hex(g_game_dll_fn, "\x8B\x04\x84\x83\xC4\x44\xC3\xCC", 8, 0, categicon_patch_string, 15))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG("popnhax: custom category injected\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||||
switch (ul_reason_for_call) {
|
switch (ul_reason_for_call) {
|
||||||
case DLL_PROCESS_ATTACH: {
|
case DLL_PROCESS_ATTACH: {
|
||||||
@ -5522,6 +5777,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
|||||||
/* must be called after force_datecode */
|
/* must be called after force_datecode */
|
||||||
patch_db_power_points();
|
patch_db_power_points();
|
||||||
patch_db_fix_cursor();
|
patch_db_fix_cursor();
|
||||||
|
patch_custom_categ();
|
||||||
patch_database(config.force_unlocks);
|
patch_database(config.force_unlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user