From 4c0000870e93b970f0cfa6fc0f313278643476d2 Mon Sep 17 00:00:00 2001 From: CrazyRedMachine Date: Mon, 17 Jun 2024 20:49:27 +0200 Subject: [PATCH] wip patch gen --- libdisasm/Module.mk | 16 +-- popnhax/Module.mk | 3 +- popnhax/dllmain.cc | 2 + popnhax/omnimix_patch.cc | 300 +++++++++++++++++++++++++++++++++++++++ popnhax/omnimix_patch.h | 6 + util/bst.h | 2 + 6 files changed, 315 insertions(+), 14 deletions(-) create mode 100644 popnhax/omnimix_patch.cc create mode 100644 popnhax/omnimix_patch.h diff --git a/libdisasm/Module.mk b/libdisasm/Module.mk index ebdf7b2..4755f79 100644 --- a/libdisasm/Module.mk +++ b/libdisasm/Module.mk @@ -1,29 +1,19 @@ libs += libdisasm +cflags += -w + src_libdisasm := \ ia32_implicit.c \ - ia32_implicit.h \ ia32_insn.c \ - ia32_insn.h \ ia32_invariant.c \ - ia32_invariant.h \ ia32_modrm.c \ - ia32_modrm.h \ ia32_opcode_tables.c \ - ia32_opcode_tables.h \ ia32_operand.c \ - ia32_operand.h \ ia32_reg.c \ - ia32_reg.h \ ia32_settings.c \ - ia32_settings.h \ - libdis.h \ - qword.h \ x86_disasm.c \ x86_format.c \ x86_imm.c \ - x86_imm.h \ x86_insn.c \ x86_misc.c \ - x86_operand_list.c \ - x86_operand_list.h + x86_operand_list.c \ No newline at end of file diff --git a/popnhax/Module.mk b/popnhax/Module.mk index 281d440..aaf8e79 100644 --- a/popnhax/Module.mk +++ b/popnhax/Module.mk @@ -8,7 +8,8 @@ ldflags_popnhax := \ libs_popnhax := \ util \ - minhook + minhook \ + libdisasm srcpp_popnhax := \ dllmain.cc \ diff --git a/popnhax/dllmain.cc b/popnhax/dllmain.cc index 08d9235..551e454 100644 --- a/popnhax/dllmain.cc +++ b/popnhax/dllmain.cc @@ -7861,6 +7861,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv if (force_no_omni) config.patch_db = false; +make_omnimix_patch(g_game_dll_fn); + bool datecode_auto = (strcmp(config.force_datecode, "auto") == 0); if (!config.disable_multiboot) diff --git a/popnhax/omnimix_patch.cc b/popnhax/omnimix_patch.cc new file mode 100644 index 0000000..d65dcc0 --- /dev/null +++ b/popnhax/omnimix_patch.cc @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include +#include + +#include "util/bst.h" +#include "util/log.h" +#include "util/patch.h" +#include "util/search.h" +#include "libdisasm/libdis.h" + +#include "omnimix_patch.h" + +#define LINE_SIZE 512 + + +#define MUSIC_IDX 0 +#define CHART_IDX 1 +#define STYLE_IDX 2 +#define FLAVOR_IDX 3 +#define CHARA_IDX 4 +#define NUM_IDX 5 + +bst_t *g_xref_bst = NULL; + +typedef struct table_s { + char *name; + uint32_t *addr; + uint32_t size; // size of one entry + uint32_t limit; // number of entries +} table_t; + +table_t g_tables[NUM_IDX]; + +uint32_t *find_binary(char *data, DWORD dllSize, const char *search_pattern, uint32_t search_size, uint32_t search_head, int8_t search_idx) +{ + //fprintf(stderr, "find binary %.*s\n", search_size, search_pattern); + uint32_t *ea = 0; + int8_t found = -1; + while (true) + { + int64_t pattern_offset = search(data, dllSize -((uint32_t) ea)-1, search_pattern, search_size, ((uint32_t) ea)+1); + + if (pattern_offset == -1) + break; + + ea = (uint32_t *) (pattern_offset + search_head); + found++; + + if (found != search_idx) + continue; + + return (uint32_t *) ((int64_t) data + (int64_t) ea); + } + + return NULL; +} + +uint32_t *find_binary_xref(char *data, DWORD dllSize, const char *search_pattern, uint32_t search_size, uint32_t search_head, int8_t search_idx, int8_t xref_search_idx) +{ + + uint32_t* ea = find_binary(data, dllSize, search_pattern, search_size, search_head, search_idx); + + if (ea == NULL) + return NULL; + + char *as_hex = (char *) &ea; + + ea = find_binary(data, dllSize, as_hex, 4, 0, xref_search_idx); + + return ea; + +} + +uint32_t get_table_size_by_xref(char *data, DWORD dllSize, uint32_t *ea, uint32_t entry_size) +{ + fprintf(stderr, "get table size by xref\n"); + uint32_t *orig_ea = ea; + // Skip 10 entries because why not. We're looking for the end anyway + ea = (uint32_t*)((uint32_t)ea+(entry_size*10)); + + fprintf(stderr, "orig ea %p, entry size %u, ea %p\n", orig_ea, entry_size, ea); + bool found = false; + + while (!found) + { + uint32_t *as_int = (uint32_t*)&ea; + //fprintf(stderr, "looking for xref to %0X\n", *as_int); + + if ( bst_search(g_xref_bst, *as_int) != NULL ) + { + found=true; + } +/* uint32_t *xref = find_binary(data, dllSize, as_hex, 4, 0, 0); + if ( xref != NULL ) + { + fprintf(stderr, "found at addr %p\n", xref); + if ( xref != (uint32_t*)0x10169236 ) + { + found = true; + } + else + { + fprintf(stderr, "bad offset\n"); + } + } +*/ + if (!found) + ea = (uint32_t*)((uint32_t)ea+entry_size); + } + + fprintf(stderr, "found value %u (ea = %p, orig_ea = %p, entry size = %u)\n", ((((uint32_t)ea)-((uint32_t)orig_ea))/entry_size), ea, orig_ea, entry_size); + return (((uint32_t)ea)-((uint32_t)orig_ea))/entry_size; +} + +/* +def get_table_size_by_xref(ea, entry_size): + # Skip 10 entries because why not. We're looking for the end anyway + orig_ea = ea + ea += entry_size * 10 + + found_end = False + while not found_end: + for xref_idx, xref in enumerate(idautils.XrefsTo(ea)): + found_end = True + break + + if not found_end: + ea += entry_size + + return (ea - orig_ea) // entry_size +*/ + + +void print_cb(x86_insn_t *insn, void *arg) +{ + char line[LINE_SIZE]; /* buffer of line to print */ + x86_format_insn(insn, line, LINE_SIZE, intel_syntax); + fprintf(stderr,"%s\n", line); +} + +static void add_xref_to_bst(uint32_t addr) +{ + if ( bst_search(g_xref_bst, addr) == NULL ) + { + //LOG("added addr %0X to BST\n", addr); + g_xref_bst = bst_insert(g_xref_bst, addr); + } +} + +void add_xref(x86_insn_t *insn, void *arg) +{ + //char line[LINE_SIZE]; /* buffer of line to print */ + //x86_format_insn(insn, line, LINE_SIZE, intel_syntax); + //LOG("%s\n", line); + //LOG("it has %u operands\n", insn->operand_count); + + uint32_t addr = x86_get_address(insn); + if ( addr != 0 ) + { + add_xref_to_bst(addr); + //LOG("found ref to %0X at ea %0X\n", addr, insn->addr); + //fprintf(stderr, "\n"); + return; + } + + // doesn't have an address directly + x86_op_t *op = x86_operand_1st(insn); + if ( op != NULL && op->type == op_expression ) + { + x86_ea_t exp = op->data.expression; +// LOG("(expression) disp is %0X\n", exp.disp); + add_xref_to_bst(exp.disp); + } + + op = x86_operand_2nd(insn); + if ( op != NULL && op->type == op_expression ) + { + x86_ea_t exp = op->data.expression; +// LOG("(expression) disp is %0X\n", exp.disp); + add_xref_to_bst(exp.disp); + } + + op = x86_operand_3rd(insn); + if ( op != NULL && op->type == op_expression ) + { + x86_ea_t exp = op->data.expression; +// LOG("(expression) disp is %0X\n", exp.disp); + add_xref_to_bst(exp.disp); + } + + + /* bst_search(g_xref_bst, idx) == NULL */ + +} + +bool make_omnimix_patch(const char *dllFilename){ + + DWORD dllSize = 0; + char *buf = getDllData(dllFilename, &dllSize); +/* +const char *dummy_buf = "\x8b\x0c\x95\xfc\x28\x32\x10"; +DWORD dummy_size = 7; +*/ +/* build instruction table indexed by parameter */ + LOG("START DISASSEMBLY\n"); + + x86_init(opt_none, NULL, NULL); + + unsigned int num_insn = x86_disasm_range( (unsigned char *)buf, (uint32_t) buf, 0, dllSize, &add_xref, NULL); + + LOG("parsed %u instructions\n", num_insn); + LOG("END DISASSEMBLY\n"); + + x86_cleanup(); +/* instruction table is done */ + +LOG("\n"); +LOG("\n"); + +/* init tables */ +g_tables[MUSIC_IDX].name = strdup("music"); +g_tables[CHART_IDX].name = strdup("chart"); +g_tables[STYLE_IDX].name = strdup("style"); +g_tables[FLAVOR_IDX].name = strdup("flavor"); +g_tables[CHARA_IDX].name = strdup("chara"); + +// These all reference the first entry in their respective tables +g_tables[MUSIC_IDX].addr = find_binary_xref(buf, dllSize, "\x00\x83\x7C\x83\x62\x83\x76\x83\x58\x00", 10, 1, 0, 0); +g_tables[CHART_IDX].addr = find_binary_xref(buf, dllSize, "\x00\x70\x6F\x70\x6E\x31\x00\x00", 8, 1, 0, 1); +g_tables[STYLE_IDX].addr = find_binary(buf, dllSize, "\x01\x00\x00\x00\xFF\x54\x0C\x00\x1A\x00\x00\x00\x11\x00\x00\x00", 16, 0, 2); +g_tables[FLAVOR_IDX].addr = find_binary(buf, dllSize, "\x00\x82\xBB\x82\xEA\x82\xA2\x82\xAF\x81\x5B\x00\x00\x00\x82\xA4\x82", 17, 1, 0); +g_tables[CHARA_IDX].addr = find_binary_xref(buf, dllSize, "\x00\x62\x61\x6D\x62\x5F\x31\x61\x00", 9, 1, 0, 0); + +fprintf(stderr, "buffer addresses ok\n"); +// Modify the entry sizes as required +g_tables[MUSIC_IDX].size = 0xAC; +g_tables[CHART_IDX].size = 0x20; // Probably won't change? +g_tables[STYLE_IDX].size = 0x10; // Unlikely to change +g_tables[FLAVOR_IDX].size = 0x60; +g_tables[CHARA_IDX].size = 0x4C; + +// buffer_addr + (buffer_entry_size * limit) should give you the very end of the array (after the last entry) +g_tables[MUSIC_IDX].limit = get_table_size_by_xref(buf, dllSize, g_tables[MUSIC_IDX].addr, g_tables[MUSIC_IDX].size); +g_tables[CHART_IDX].limit = get_table_size_by_xref(buf, dllSize, g_tables[CHART_IDX].addr, g_tables[CHART_IDX].size); +g_tables[STYLE_IDX].limit = get_table_size_by_xref(buf, dllSize, g_tables[STYLE_IDX].addr, g_tables[STYLE_IDX].size); +g_tables[FLAVOR_IDX].limit = get_table_size_by_xref(buf, dllSize, g_tables[FLAVOR_IDX].addr, g_tables[FLAVOR_IDX].size); +g_tables[CHARA_IDX].limit = get_table_size_by_xref(buf, dllSize, g_tables[CHARA_IDX].addr, g_tables[CHARA_IDX].size); + +/* +# Modify the entry sizes as required +buffer_addrs = [ + # entry type, table address, entry size + [MUSIC_IDX, music_table_addr, 0xac], + [CHART_IDX, chart_table_addr, 0x20], # Probably won't change? + [STYLE_IDX, style_table_addr, 0x10], # Unlikely to change + [FLAVOR_IDX, flavor_table_addr, 0x60], + [CHARA_IDX, chara_table_addr, 0x4C], +] + +limit_info_list = [ + # buffer_addr + (buffer_entry_size * limit) should give you the very end of the array (after the last entry) + [MUSIC_IDX, get_table_size_by_xref(*buffer_addrs[MUSIC_IDX][1:])], + [CHART_IDX, get_table_size_by_xref(*buffer_addrs[CHART_IDX][1:])], + [STYLE_IDX, get_table_size_by_xref(*buffer_addrs[STYLE_IDX][1:])], + [FLAVOR_IDX, get_table_size_by_xref(*buffer_addrs[FLAVOR_IDX][1:])], + [CHARA_IDX, get_table_size_by_xref(*buffer_addrs[CHARA_IDX][1:])], +] + +for limit_info in limit_info_list: + patch_target, limit_value = limit_info + if TARGETS[patch_target] == "music": + music_limit = limit_value + LOG("\t\t<%s __type=\"u32\">%d\n", TARGETS[patch_target], limit_value, TARGETS[patch_target]); +LOG("\t\n"); +*/ + +LOG("\t\n"); +for (int i=0; i < NUM_IDX; i++) +{ + //patch_target, buffer_addr, entry_size = buffer_info + LOG("\t\t<%s __type=\"u32\">%d\n", g_tables[i].name, g_tables[i].limit, g_tables[i].name); +} +LOG("\t\n"); + +LOG("\t\n"); +for (int i=0; i < NUM_IDX; i++) +{ + //patch_target, buffer_addr, entry_size = buffer_info + LOG("\t\t<%s __type=\"str\">0x%p\n", g_tables[i].name, g_tables[i].addr, g_tables[i].name); +} +LOG("\t\n"); + + + getchar(); + exit(0); + return false; +} \ No newline at end of file diff --git a/popnhax/omnimix_patch.h b/popnhax/omnimix_patch.h new file mode 100644 index 0000000..d544603 --- /dev/null +++ b/popnhax/omnimix_patch.h @@ -0,0 +1,6 @@ +#ifndef __OMNIMIX_PATCH_H__ +#define __OMNIMIX_PATCH_H__ + +bool make_omnimix_patch(const char *dllFilename); + +#endif diff --git a/util/bst.h b/util/bst.h index c8338b2..ab3727d 100644 --- a/util/bst.h +++ b/util/bst.h @@ -1,6 +1,8 @@ #ifndef __BST_H__ #define __BST_H__ +#include + typedef struct bst_s { uint32_t data;