wip patch gen

This commit is contained in:
CrazyRedMachine 2024-06-17 20:49:27 +02:00
parent 3d8d6a83ad
commit 4c0000870e
6 changed files with 315 additions and 14 deletions

View File

@ -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

View File

@ -8,7 +8,8 @@ ldflags_popnhax := \
libs_popnhax := \
util \
minhook
minhook \
libdisasm
srcpp_popnhax := \
dllmain.cc \

View File

@ -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)

300
popnhax/omnimix_patch.cc Normal file
View File

@ -0,0 +1,300 @@
#include <cstdio>
#include <cstring>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#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("<?xml version='1.0' encoding='shift-jis'?>\n");
LOG("<patches target=\"20xxxxxx00\">\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</%s>\n", TARGETS[patch_target], limit_value, TARGETS[patch_target]);
LOG("\t</limits>\n");
*/
LOG("\t<limits>\n");
for (int i=0; i < NUM_IDX; i++)
{
//patch_target, buffer_addr, entry_size = buffer_info
LOG("\t\t<%s __type=\"u32\">%d</%s>\n", g_tables[i].name, g_tables[i].limit, g_tables[i].name);
}
LOG("\t</limits>\n");
LOG("\t<buffer_base_addrs>\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</%s>\n", g_tables[i].name, g_tables[i].addr, g_tables[i].name);
}
LOG("\t</buffer_base_addrs>\n");
getchar();
exit(0);
return false;
}

6
popnhax/omnimix_patch.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef __OMNIMIX_PATCH_H__
#define __OMNIMIX_PATCH_H__
bool make_omnimix_patch(const char *dllFilename);
#endif

View File

@ -1,6 +1,8 @@
#ifndef __BST_H__
#define __BST_H__
#include <stdint.h>
typedef struct bst_s
{
uint32_t data;