forked from Popn_Tools/popnhax
wip
This commit is contained in:
parent
3c459addea
commit
7f146dc5e9
@ -19,6 +19,9 @@
|
|||||||
#include "minhook/hde32.h"
|
#include "minhook/hde32.h"
|
||||||
#include "minhook/include/MinHook.h"
|
#include "minhook/include/MinHook.h"
|
||||||
|
|
||||||
|
uint8_t g_subcateg_count = 5;
|
||||||
|
|
||||||
|
bool g_subcategmode = false;
|
||||||
const char *g_categname = "Custom Tracks";
|
const char *g_categname = "Custom Tracks";
|
||||||
const char *g_categicon = "cate_13";
|
const char *g_categicon = "cate_13";
|
||||||
const char *g_categformat = "[ol:4][olc:d92f0d]%s";
|
const char *g_categformat = "[ol:4][olc:d92f0d]%s";
|
||||||
@ -38,6 +41,140 @@ uint32_t songlist_struct_addr = (uint32_t)&songlist_struct;
|
|||||||
void (*add_song_in_list)();
|
void (*add_song_in_list)();
|
||||||
void (*categ_inject_songlist)();
|
void (*categ_inject_songlist)();
|
||||||
|
|
||||||
|
|
||||||
|
void get_subcateg_size_impl()
|
||||||
|
{
|
||||||
|
__asm("mov eax, 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
char g_test_string[9] = "TOTOMCDO";
|
||||||
|
void get_subcateg_name_impl()
|
||||||
|
{
|
||||||
|
__asm("mov eax, _g_test_string");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t reimpl_value_1;
|
||||||
|
uint32_t reimpl_value_2;
|
||||||
|
void (*get_subcateg_size)() = &get_subcateg_size_impl;
|
||||||
|
void (*get_subcateg_name)() = &get_subcateg_name_impl;
|
||||||
|
void (*reimpl_func_1)();
|
||||||
|
void (*reimpl_func_2)();
|
||||||
|
void (*reimpl_func_3)();
|
||||||
|
void (*reimpl_func_4)();
|
||||||
|
|
||||||
|
//this is a reimplementation of the event category generation function, modded to use popnhax internal subcategories
|
||||||
|
void categ_inject_songlist_reimpl()
|
||||||
|
{
|
||||||
|
__asm("add esp, 0xC"); // cancel a sub esp 0xC that is added by this code for no reason
|
||||||
|
__asm("push 0xFFFFFFFF\n");
|
||||||
|
__asm("push [_reimpl_value_1]\n");
|
||||||
|
__asm("mov eax, dword ptr fs:[0]\n");
|
||||||
|
__asm("push eax\n");
|
||||||
|
__asm("sub esp, 0x10\n");
|
||||||
|
__asm("push ebx\n");
|
||||||
|
__asm("push ebp\n");
|
||||||
|
__asm("push esi\n");
|
||||||
|
__asm("push edi\n");
|
||||||
|
__asm("mov eax, dword ptr ds:[_reimpl_value_2]\n");
|
||||||
|
__asm("xor eax,esp\n");
|
||||||
|
__asm("push eax\n");
|
||||||
|
__asm("lea eax, dword ptr ss:[esp+0x24]\n");
|
||||||
|
__asm("mov dword ptr fs:[0], eax\n");
|
||||||
|
__asm("lea ebp, dword ptr ss:[esp+0x34]\n");
|
||||||
|
__asm("xor ebx, ebx\n");
|
||||||
|
__asm("mov dword ptr ss:[esp+0x34], ebx\n");
|
||||||
|
__asm("subcateg_loop:\n");
|
||||||
|
__asm("mov ecx, dword ptr ss:[ebp+0x08]\n");
|
||||||
|
__asm("mov eax, ebx\n");
|
||||||
|
|
||||||
|
get_subcateg_size();
|
||||||
|
|
||||||
|
__asm("test eax, eax\n");
|
||||||
|
__asm("je next_iter\n");
|
||||||
|
__asm("push 0xD8\n");
|
||||||
|
|
||||||
|
reimpl_func_1();
|
||||||
|
|
||||||
|
__asm("mov ecx, eax\n");
|
||||||
|
__asm("add esp, 0x04\n");
|
||||||
|
__asm("mov dword ptr ss:[esp+0x14], ecx\n");
|
||||||
|
__asm("xor eax, eax\n");
|
||||||
|
__asm("mov dword ptr ss:[esp+0x2C], eax\n");
|
||||||
|
__asm("cmp ecx, eax\n");
|
||||||
|
__asm("je jump_point_1\n");
|
||||||
|
__asm("mov eax, ebx\n");
|
||||||
|
|
||||||
|
get_subcateg_name();
|
||||||
|
|
||||||
|
__asm("mov edi, dword ptr ss:[ebp+0x04]\n");
|
||||||
|
__asm("mov edx, dword ptr ss:[ebp+0x0C]\n");
|
||||||
|
__asm("push eax\n");
|
||||||
|
__asm("push ecx\n");
|
||||||
|
__asm("mov ecx, dword ptr ss:[ebp+0x44]\n");
|
||||||
|
|
||||||
|
reimpl_func_2();
|
||||||
|
|
||||||
|
__asm("jump_point_1:\n");
|
||||||
|
__asm("mov dword ptr ss:[esp+0x2C], 0xFFFFFFFF\n");
|
||||||
|
__asm("mov ecx, dword ptr ss:[ebp+0xB4]\n");
|
||||||
|
__asm("lea esi, dword ptr ss:[ebp+0xA8]\n");
|
||||||
|
__asm("mov dword ptr ss:[esp+0x14], eax\n");
|
||||||
|
__asm("test ecx, ecx\n");
|
||||||
|
__asm("jne jump_point_2\n");
|
||||||
|
__asm("xor edx, edx\n");
|
||||||
|
__asm("jmp jump_point_3\n");
|
||||||
|
__asm("jump_point_2:\n");
|
||||||
|
__asm("mov edx, dword ptr ds:[esi+0x14]\n");
|
||||||
|
__asm("sub edx, ecx\n");
|
||||||
|
__asm("sar edx, 0x02\n");
|
||||||
|
__asm("jump_point_3:\n");
|
||||||
|
__asm("mov edi, dword ptr ds:[esi+0x10]\n");
|
||||||
|
__asm("mov ebx, edi\n");
|
||||||
|
__asm("sub ebx, ecx\n");
|
||||||
|
__asm("sar ebx, 0x02\n");
|
||||||
|
__asm("cmp ebx, edx\n");
|
||||||
|
__asm("jae jump_point_4\n");
|
||||||
|
__asm("mov dword ptr ds:[edi], eax\n");
|
||||||
|
__asm("add edi, 0x04\n");
|
||||||
|
__asm("mov dword ptr ds:[esi+0x10], edi\n");
|
||||||
|
__asm("jmp jump_point_5\n");
|
||||||
|
__asm("jump_point_4:\n");
|
||||||
|
__asm("cmp ecx, edi\n");
|
||||||
|
__asm("jbe jump_point_6\n");
|
||||||
|
|
||||||
|
reimpl_func_3();
|
||||||
|
|
||||||
|
__asm("jump_point_6:\n");
|
||||||
|
__asm("mov eax, dword ptr ds:[esi]\n");
|
||||||
|
__asm("push edi\n");
|
||||||
|
__asm("push eax\n");
|
||||||
|
__asm("lea eax, dword ptr ss:[esp+0x1C]\n");
|
||||||
|
__asm("push eax\n");
|
||||||
|
__asm("lea ecx, dword ptr ss:[esp+0x24]\n");
|
||||||
|
__asm("push ecx\n");
|
||||||
|
__asm("mov eax, esi\n");
|
||||||
|
|
||||||
|
reimpl_func_4();
|
||||||
|
|
||||||
|
__asm("jump_point_5:\n");
|
||||||
|
__asm("mov ebx, dword ptr ss:[esp+0x34]\n");
|
||||||
|
__asm("next_iter:\n");
|
||||||
|
__asm("inc ebx\n");
|
||||||
|
__asm("mov dword ptr ss:[esp+0x34], ebx\n");
|
||||||
|
__asm("cmp ebx, [_g_subcateg_count]\n");
|
||||||
|
__asm("jb subcateg_loop\n");
|
||||||
|
__asm("mov ecx, dword ptr ss:[esp+0x24]\n");
|
||||||
|
__asm("mov dword ptr fs:[0], ecx\n");
|
||||||
|
__asm("pop ecx\n");
|
||||||
|
__asm("pop edi\n");
|
||||||
|
__asm("pop esi\n");
|
||||||
|
__asm("pop ebp\n");
|
||||||
|
__asm("pop ebx\n");
|
||||||
|
__asm("add esp, 0x1C\n");
|
||||||
|
__asm("ret 4\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//this replaces the category handling function ( add_song_in_list is a subroutine called by the game )
|
||||||
void categ_inject_songlist_impl()
|
void categ_inject_songlist_impl()
|
||||||
{
|
{
|
||||||
__asm("push edx\n");
|
__asm("push edx\n");
|
||||||
@ -91,21 +228,25 @@ void hook_categ_title_printf()
|
|||||||
real_categ_title_printf();
|
real_categ_title_printf();
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*categ_listing_newsongs)();
|
void (*categ_listing_event)();
|
||||||
void (*real_categ_listing)();
|
void (*real_categ_listing)();
|
||||||
void hook_categ_listing()
|
void hook_categ_listing()
|
||||||
{
|
{
|
||||||
__asm("cmp eax, 0x11\n");
|
__asm("cmp eax, 0x11\n");
|
||||||
__asm("jne categ_listing_ok\n");
|
__asm("jne categ_listing_ok\n");
|
||||||
__asm("call [_categ_inject_songlist]\n");
|
__asm("cmp byte ptr ds:[_g_subcategmode], 1\n");
|
||||||
|
__asm("jne skip_push\n");
|
||||||
|
__asm("push esi\n"); //push esi to prepare for subcategory mode (categ_inject_songlist points to the correct function)
|
||||||
|
__asm("skip_push:\n");
|
||||||
|
__asm("call [_categ_inject_songlist]\n"); //
|
||||||
__asm("categ_listing_ok:\n");
|
__asm("categ_listing_ok:\n");
|
||||||
real_categ_listing();
|
real_categ_listing();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool patch_custom_categ_simple(const char *g_game_dll_fn) {
|
static bool patch_custom_categ_simple(const char *game_dll_fn) {
|
||||||
|
|
||||||
DWORD dllSize = 0;
|
DWORD dllSize = 0;
|
||||||
char *data = getDllData(g_game_dll_fn, &dllSize);
|
char *data = getDllData(game_dll_fn, &dllSize);
|
||||||
|
|
||||||
//patch format string for any category above 16 (prevent crash)
|
//patch format string for any category above 16 (prevent crash)
|
||||||
{
|
{
|
||||||
@ -122,6 +263,31 @@ static bool patch_custom_categ_simple(const char *g_game_dll_fn) {
|
|||||||
(void **)&real_categ_title_printf);
|
(void **)&real_categ_title_printf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
uint64_t function_call_addr = (int64_t)(data + pattern_offset + 0x05 + 69);
|
||||||
|
uint32_t function_offset = *((uint32_t*)(function_call_addr +0x01));
|
||||||
|
uint64_t function_addr = function_call_addr+5+function_offset;
|
||||||
|
categ_listing_event = (void (*)())(function_addr);
|
||||||
|
|
||||||
|
/* retrieve useful values from this function */
|
||||||
|
reimpl_value_1 = *((uint32_t*)(function_addr +0x03));
|
||||||
|
reimpl_value_2 = *((uint32_t*)(function_addr +0x16));
|
||||||
|
reimpl_func_1 = (void (*)())( *((uint32_t*)(function_addr +0x49)) + (uint32_t)(function_addr +0x04 +0x49) );
|
||||||
|
reimpl_func_2 = (void (*)())( *((uint32_t*)(function_addr +0x73)) + (uint32_t)(function_addr +0x04 +0x73) );
|
||||||
|
reimpl_func_3 = (void (*)())( *((uint32_t*)(function_addr +0xBC)) + (uint32_t)(function_addr +0x04 +0xBC) );
|
||||||
|
reimpl_func_4 = (void (*)())( *((uint32_t*)(function_addr +0xD1)) + (uint32_t)(function_addr +0x04 +0xD1) );
|
||||||
|
|
||||||
|
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_categ_listing,
|
||||||
|
(void **)&real_categ_listing);
|
||||||
|
}
|
||||||
|
|
||||||
//add new category processing in jump table
|
//add new category processing in jump table
|
||||||
{
|
{
|
||||||
int64_t pattern_offset = search(data, dllSize, "\x8B\x4D\x10\x8B\x5D\x0C\x8B\xF1", 8, 0);
|
int64_t pattern_offset = search(data, dllSize, "\x8B\x4D\x10\x8B\x5D\x0C\x8B\xF1", 8, 0);
|
||||||
@ -131,21 +297,25 @@ static bool patch_custom_categ_simple(const char *g_game_dll_fn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add_song_in_list = (void (*)())(data + pattern_offset - 0x12);
|
add_song_in_list = (void (*)())(data + pattern_offset - 0x12);
|
||||||
categ_inject_songlist = &categ_inject_songlist_impl;
|
|
||||||
}
|
if (g_subcategmode)
|
||||||
|
{
|
||||||
{
|
categ_inject_songlist = &categ_inject_songlist_reimpl;
|
||||||
int64_t pattern_offset = search(data, dllSize, "\x83\xF8\x10\x77\x75\xFF\x24\x85", 8, 0);
|
//categ_inject_songlist = categ_listing_event;
|
||||||
if (pattern_offset == -1) {
|
/*
|
||||||
LOG("popnhax: custom_categ: cannot find category jump table\n");
|
//create a copy of event categ handling function then mod it
|
||||||
return false;
|
categ_inject_songlist = (void(*)())malloc(256);
|
||||||
}
|
DWORD old_prot;
|
||||||
|
VirtualProtect((LPVOID)categ_inject_songlist, 256, PAGE_EXECUTE_READWRITE, &old_prot);
|
||||||
uint64_t patch_addr = (int64_t)data + pattern_offset + 0x05 + 0x75;
|
memcpy((LPVOID)categ_inject_songlist, (uint64_t*)categ_listing_event, 256);
|
||||||
//categ_listing_newsongs = (void (*)())(data + pattern_offset + 0x05 + 0x0E); //TODO: replace this with my own function
|
VirtualProtect((LPVOID)categ_inject_songlist, 256, old_prot, &old_prot);
|
||||||
|
|
||||||
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_categ_listing,
|
uint32_t call_offset = (uint32_t*)categ_inject_songlist - (uint32_t*)categ_listing_event;
|
||||||
(void **)&real_categ_listing);
|
LOG("popnhax: call offset is %x\n",call_offset);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
categ_inject_songlist = &categ_inject_songlist_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//create new song list
|
//create new song list
|
||||||
@ -178,14 +348,14 @@ static bool patch_custom_categ_simple(const char *g_game_dll_fn) {
|
|||||||
|
|
||||||
|
|
||||||
//bump category number from 16 to 17
|
//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))
|
if (!find_and_patch_hex(game_dll_fn, "\x83\xFE\x11\x0F\x82\x59\xFE\xFF\xFF", 9, 2, "\x12", 1))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//patch getCategName for a 17th entry
|
//patch getCategName for a 17th entry
|
||||||
//make array one cell larger
|
//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))
|
if (!find_and_patch_hex(game_dll_fn, "\x83\xEC\x44\x98\xC7\x04\x24", 7, 2, "\x48", 1))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -193,13 +363,13 @@ static bool patch_custom_categ_simple(const char *g_game_dll_fn) {
|
|||||||
uint32_t categname_str_addr = (uint32_t)g_categname;
|
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";
|
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);
|
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))
|
if (!find_and_patch_hex(game_dll_fn, "\x8B\x04\x84\x83\xC4\x44\xC3\xCC", 8, 0, categname_patch_string, 15))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//patch getIconName for a 17th entry
|
//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
|
if (!find_and_patch_hex(game_dll_fn, "\x83\xEC\x44\x98\xC7\x04\x24", 7, 2, "\x48", 1)) //2nd occurrence since first one just got patched
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -207,7 +377,7 @@ static bool patch_custom_categ_simple(const char *g_game_dll_fn) {
|
|||||||
uint32_t categicon_str_addr = (uint32_t)g_categicon;
|
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";
|
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);
|
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))
|
if (!find_and_patch_hex(game_dll_fn, "\x8B\x04\x84\x83\xC4\x44\xC3\xCC", 8, 0, categicon_patch_string, 15))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -316,11 +486,13 @@ bool patch_custom_categs(const char *dllFilename, uint8_t mode)
|
|||||||
{
|
{
|
||||||
if (mode == 1)
|
if (mode == 1)
|
||||||
{
|
{
|
||||||
|
g_subcategmode = true;
|
||||||
return patch_custom_categ_simple(dllFilename);
|
return patch_custom_categ_simple(dllFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 2)
|
if (mode == 2)
|
||||||
{
|
{
|
||||||
|
g_subcategmode = true;
|
||||||
subcateg_count = 0;
|
subcateg_count = 0;
|
||||||
load_databases();
|
load_databases();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user