From f7c2641d5889be3e5046616034b439aef3b08db1 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Tue, 18 Jun 2019 04:48:48 -0400 Subject: [PATCH] improve x64 mono --- include/types.h | 3 ++- texthook/engine/match64.cc | 18 ++++++++++++++---- texthook/texthook.cc | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/types.h b/include/types.h index e74cdaa..908e02c 100644 --- a/include/types.h +++ b/include/types.h @@ -40,12 +40,13 @@ struct HookParam DWORD type; // flags UINT codepage; // text encoding short length_offset; // index of the string length - uintptr_t padding; // padding + uintptr_t padding; // padding before string DWORD user_value; // 7/20/2014: jichi additional parameters for PSP games void(*text_fun)(DWORD stack, HookParam* hp, BYTE obsoleteAlwaysZero, DWORD* data, DWORD* split, DWORD* len); bool(*filter_fun)(void* data, DWORD* len, HookParam* hp, BYTE obsoleteAlwaysZero); // jichi 10/24/2014: Add filter function. Return true if skip the text bool(*hook_fun)(DWORD stack, HookParam* hp); // jichi 10/24/2014: Add generic hook function, return false if stop execution. + int(*length_fun)(uintptr_t stack, uintptr_t data); // data after padding added char name[HOOK_NAME_SIZE]; }; diff --git a/texthook/engine/match64.cc b/texthook/engine/match64.cc index d178b47..d4a35a8 100644 --- a/texthook/engine/match64.cc +++ b/texthook/engine/match64.cc @@ -63,7 +63,7 @@ namespace Engine How to hook Mono/Unity3D: Find all standard function prologs in memory with write/execute permission: these represent possible JIT compiled functions Then use Mono APIs to reflect what these functions are, and hook them if they are string member functions - Mono calling convention uses 'this' as first argument on stack + Mono calling convention uses 'this' as first argument Must be dynamic hook bootstrapped from other mono api or mono_domain_get won't work */ trigger_fun = [](LPVOID addr, DWORD, DWORD) @@ -74,8 +74,10 @@ namespace Engine if (!getDomain || !getName || !getJitInfo) goto failed; static auto domain = getDomain(); if (!domain) goto failed; - const BYTE prolog[] = { 0x55, 0x48, 0x8b, 0xec }; - for (auto addr : Util::SearchMemory(prolog, sizeof(prolog), PAGE_EXECUTE_READWRITE)) + const BYTE prolog1[] = { 0x55, 0x48, 0x8b, 0xec }; + const BYTE prolog2[] = { 0x48, 0x83, 0xec }; + for (auto [prolog, size] : Array>{ { prolog1, sizeof(prolog1) }, { prolog2, sizeof(prolog2) } }) + for (auto addr : Util::SearchMemory(prolog, size, PAGE_EXECUTE_READWRITE)) { [](uint64_t addr) { @@ -83,13 +85,21 @@ namespace Engine { if (getJitInfo(domain, addr)) if (char* name = getName(addr)) - if (strstr(name, "string:") && !strstr(name, "string:mem")) + if (strstr(name, "string:") && strstr(name, "+ 0x0") && !strstr(name, "string:mem")) { HookParam hp = {}; hp.address = addr; hp.type = USING_STRING | USING_UNICODE; hp.offset = -0x20; hp.padding = 20; + hp.length_fun = [](uintptr_t, uintptr_t data) + { + /* Artikash 6/18/2019: + even though this should get the true length mono uses internally + there's still some garbage picked up on https://vndb.org/v20403 demo, don't know why */ + int len = *(int*)(data - 4); + return len > 0 && len < 1000 ? len * 2 : 0; + }; NewHook(hp, name); } } diff --git a/texthook/texthook.cc b/texthook/texthook.cc index dc0ddde..95756f7 100644 --- a/texthook/texthook.cc +++ b/texthook/texthook.cc @@ -298,6 +298,7 @@ void TextHook::Clear() int TextHook::GetLength(uintptr_t base, uintptr_t in) { int len; + if (hp.length_fun) return hp.length_fun(base, in); switch (hp.length_offset) { default: // jichi 12/26/2013: I should not put this default branch to the end len = *((uintptr_t*)base + hp.length_offset);