refactor: Soundbank runtime hooking improvement
> change default behaviour to pattern based patch for hooks::soundbank, see #13 > fix broken check for hooks::soundbank unsupported game version
This commit is contained in:
+8
-34
@@ -901,7 +901,7 @@ void init(HINSTANCE hmodule, const char *model, const char *ext)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override .text .data per datacode _REV: prefer runtime offset lookup based on universal asm pattern
|
// Override .text .data per datacode (pattern match)
|
||||||
long extl = strtol(ext, nullptr, 10);
|
long extl = strtol(ext, nullptr, 10);
|
||||||
if (extl < 2019100800)
|
if (extl < 2019100800)
|
||||||
{
|
{
|
||||||
@@ -925,42 +925,16 @@ void init(HINSTANCE hmodule, const char *model, const char *ext)
|
|||||||
offset_.DAT_song_id = 0x67c;
|
offset_.DAT_song_id = 0x67c;
|
||||||
offset_.is_lstr_wchar = true;
|
offset_.is_lstr_wchar = true;
|
||||||
}
|
}
|
||||||
switch (to_hash(ext))
|
intptr_t beg, match;
|
||||||
|
offset_.TX_EnumValidSoundbanks = beg = match = find_asm_leacstr_from(hmodule, R8, "%05d/%05d.2dx");
|
||||||
|
while (beg > sizeof(void *) && match >= offset_.TX_EnumValidSoundbanks) //_REV: probably should be sigscan helper due to find_pattern_from performance, unify with wmischook
|
||||||
{
|
{
|
||||||
case to_hash("2018091900"):
|
beg -= sizeof(void *);
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0x1170b0;
|
match = find_pattern_from(hmodule, "4057", "XX", 0, 0, beg - reinterpret_cast<intptr_t>(hmodule));
|
||||||
break;
|
|
||||||
case to_hash("2019090200"):
|
|
||||||
case to_hash("2019100700"):
|
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0x37a540;
|
|
||||||
break;
|
|
||||||
case to_hash("2020092900"):
|
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0x5ac460;
|
|
||||||
break;
|
|
||||||
case to_hash("2021083000"):
|
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0x766bc0;
|
|
||||||
break;
|
|
||||||
case to_hash("2021091500"):
|
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0x766c60;
|
|
||||||
break;
|
|
||||||
case to_hash("2022082400"):
|
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0x46e160;
|
|
||||||
break;
|
|
||||||
case to_hash("2023090500"):
|
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0xafd780;
|
|
||||||
break;
|
|
||||||
case to_hash("2024082600"):
|
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0x8eae40;
|
|
||||||
break;
|
|
||||||
case to_hash("2025082500"):
|
|
||||||
offset_.TX_EnumValidSoundbanks = (intptr_t) hmodule + 0x969fb0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
snd_bank::resampler_ = avcodec::BmswTranscoderResampler() == avcodec::bmswac_resampler_none ? snd_bank::resampler_ : avcodec::BmswTranscoderResampler();
|
snd_bank::resampler_ = avcodec::BmswTranscoderResampler() == avcodec::bmswac_resampler_none ? snd_bank::resampler_ : avcodec::BmswTranscoderResampler();
|
||||||
offset_.TX_EnumValidSoundbanks = avcodec::BmswTranscoderEnumValidSoundbanksAddr() == 0x0 ? offset_.TX_EnumValidSoundbanks : (intptr_t) hmodule + (int64_t) avcodec::BmswTranscoderEnumValidSoundbanksAddr();
|
offset_.TX_EnumValidSoundbanks = avcodec::BmswTranscoderEnumValidSoundbanksAddr() == 0x0 ? match : (intptr_t) hmodule + (int64_t) avcodec::BmswTranscoderEnumValidSoundbanksAddr();
|
||||||
if (offset_.TX_EnumValidSoundbanks == (intptr_t) hmodule)
|
if (!offset_.TX_EnumValidSoundbanks)
|
||||||
{
|
{
|
||||||
log_warning("hooks::soundbank", "Unsupported game version({}), skipping..", ext);
|
log_warning("hooks::soundbank", "Unsupported game version({}), skipping..", ext);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -249,3 +249,52 @@ bool get_pe_identifier(const std::filesystem::path& dll_path, uint32_t* time_dat
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intptr_t find_asm_leacstr_from(HMODULE module, reg_t reg, const char *cstr)
|
||||||
|
{
|
||||||
|
// get module information
|
||||||
|
MODULEINFO module_info{};
|
||||||
|
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(module_info)))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const unsigned char *modbegp = reinterpret_cast<unsigned char *>(module);
|
||||||
|
const unsigned char *modendp = reinterpret_cast<unsigned char *>(module) + static_cast<size_t>(module_info.SizeOfImage);
|
||||||
|
|
||||||
|
// search cstr
|
||||||
|
const unsigned char *cstr_addr = std::search(
|
||||||
|
modbegp,
|
||||||
|
modendp,
|
||||||
|
reinterpret_cast<const unsigned char *>(cstr),
|
||||||
|
reinterpret_cast<const unsigned char *>(cstr) + strlen(cstr)
|
||||||
|
);
|
||||||
|
if (cstr_addr == modendp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
// find LEA REG, [abs32]
|
||||||
|
unsigned char asmop[6] = { 0x8D, reg.v, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
int32_t dist32 = reinterpret_cast<int32_t>(cstr_addr);
|
||||||
|
memcpy(asmop + (sizeof(asmop) - 4), &dist32, 4);
|
||||||
|
return reinterpret_cast<intptr_t>(std::search(
|
||||||
|
modbegp,
|
||||||
|
modendp,
|
||||||
|
asmop,
|
||||||
|
asmop + sizeof(asmop)
|
||||||
|
));
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
// find LEA REG, [RIP + rel32]
|
||||||
|
unsigned char rex = reg.t == GPR_EXT ? 0x4C : 0x48;
|
||||||
|
unsigned char asmop[7] = {rex, 0x8D, reg.v, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
for (const unsigned char *addr = modbegp; addr < modendp - sizeof(asmop); addr++)
|
||||||
|
{
|
||||||
|
auto dist32 = static_cast<int32_t>(reinterpret_cast<intptr_t>(cstr_addr) - reinterpret_cast<intptr_t>(addr + sizeof(asmop)));
|
||||||
|
memcpy(asmop + (sizeof(asmop) - 4), &dist32, 4);
|
||||||
|
if (memcmp(addr, asmop, sizeof(asmop)) == 0) return reinterpret_cast<intptr_t>(addr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
+51
-1
@@ -89,4 +89,54 @@ intptr_t replace_pattern_from(
|
|||||||
intptr_t usage,
|
intptr_t usage,
|
||||||
intptr_t start_from);
|
intptr_t start_from);
|
||||||
|
|
||||||
bool get_pe_identifier(const std::filesystem::path& dll_path, uint32_t* time_date_stamp, uint32_t* address_of_entry_point);
|
bool get_pe_identifier(const std::filesystem::path& dll_path, uint32_t* time_date_stamp, uint32_t* address_of_entry_point);
|
||||||
|
|
||||||
|
union reg_t{
|
||||||
|
struct{
|
||||||
|
unsigned char t;
|
||||||
|
unsigned char v;
|
||||||
|
};
|
||||||
|
unsigned short s;
|
||||||
|
constexpr reg_t(unsigned char t, unsigned char v) : s(v << 8 | t) {}
|
||||||
|
constexpr reg_t(unsigned short s) : s(s) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum REGTYPE : unsigned char
|
||||||
|
{
|
||||||
|
GPR_32,
|
||||||
|
GPR_64,
|
||||||
|
GPR_EXT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum REG : unsigned short
|
||||||
|
{
|
||||||
|
EAX = reg_t(GPR_32, 0x05).s,
|
||||||
|
ECX = reg_t(GPR_32, 0x0D).s,
|
||||||
|
EDX = reg_t(GPR_32, 0x15).s,
|
||||||
|
EBX = reg_t(GPR_32, 0x1D).s,
|
||||||
|
ESP = reg_t(GPR_32, 0x25).s,
|
||||||
|
EBP = reg_t(GPR_32, 0x2D).s,
|
||||||
|
ESI = reg_t(GPR_32, 0x35).s,
|
||||||
|
EDI = reg_t(GPR_32, 0x3D).s,
|
||||||
|
RAX = reg_t(GPR_64, 0x05).s,
|
||||||
|
RCX = reg_t(GPR_64, 0x0D).s,
|
||||||
|
RDX = reg_t(GPR_64, 0x15).s,
|
||||||
|
RBX = reg_t(GPR_64, 0x1D).s,
|
||||||
|
RSP = reg_t(GPR_64, 0x25).s,
|
||||||
|
RBP = reg_t(GPR_64, 0x2D).s,
|
||||||
|
RSI = reg_t(GPR_64, 0x35).s,
|
||||||
|
RDI = reg_t(GPR_64, 0x3D).s,
|
||||||
|
R8 = reg_t(GPR_EXT, 0x05).s,
|
||||||
|
R9 = reg_t(GPR_EXT, 0x0D).s,
|
||||||
|
R10 = reg_t(GPR_EXT, 0x15).s,
|
||||||
|
R11 = reg_t(GPR_EXT, 0x1D).s,
|
||||||
|
R12 = reg_t(GPR_EXT, 0x25).s,
|
||||||
|
R13 = reg_t(GPR_EXT, 0x2D).s,
|
||||||
|
R14 = reg_t(GPR_EXT, 0x35).s,
|
||||||
|
R15 = reg_t(GPR_EXT, 0x3D).s
|
||||||
|
};
|
||||||
|
|
||||||
|
intptr_t find_asm_leacstr_from(
|
||||||
|
HMODULE module,
|
||||||
|
reg_t reg,
|
||||||
|
const char *cstr);
|
||||||
Reference in New Issue
Block a user