This commit is contained in:
恍兮惚兮 2024-10-22 00:49:26 +08:00
parent a5986fe7dd
commit 44ad71eb81

View File

@ -109,8 +109,8 @@
* 0012ed64 00951d88 ascii "2015/01/18" * 0012ed64 00951d88 ascii "2015/01/18"
*/ */
namespace { // unnamed namespace
{ // unnamed
void SpecialHookWillPlus(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) void SpecialHookWillPlus(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{ {
@ -118,14 +118,16 @@ void SpecialHookWillPlus(hook_stack* stack, HookParam *hp, uintptr_t *data, uin
// if (detect_offset) // if (detect_offset)
// return; // return;
DWORD i, l; DWORD i, l;
union { union
{
DWORD retn; DWORD retn;
WORD *pw; WORD *pw;
BYTE *pb; BYTE *pb;
}; };
retn = stack->retaddr; // jichi 1/18/2015: dynamically find function return address retn = stack->retaddr; // jichi 1/18/2015: dynamically find function return address
i = 0; i = 0;
while (*pw != 0xc483) { // add esp, $ while (*pw != 0xc483)
{ // add esp, $
l = ::disasm(pb); l = ::disasm(pb);
if (++i == 5) if (++i == 5)
// ConsoleOutput("Fail to detect offset."); // ConsoleOutput("Fail to detect offset.");
@ -133,7 +135,8 @@ void SpecialHookWillPlus(hook_stack* stack, HookParam *hp, uintptr_t *data, uin
retn += l; retn += l;
} }
// jichi 2/11/2015: Check baddaddr which might crash the game on Windows XP. // jichi 2/11/2015: Check baddaddr which might crash the game on Windows XP.
if (*pw == 0xc483 && !::IsBadReadPtr((LPCVOID)(pb + 2), 1) && !::IsBadReadPtr((LPCVOID)(*(pb + 2) - 8), 1)) { if (*pw == 0xc483 && !::IsBadReadPtr((LPCVOID)(pb + 2), 1) && !::IsBadReadPtr((LPCVOID)(*(pb + 2) - 8), 1))
{
ConsoleOutput("WillPlus1 pattern found"); ConsoleOutput("WillPlus1 pattern found");
// jichi 1/18/2015: // jichi 1/18/2015:
// By studying [honeybee] RE:BIRTHDAY SONG, it seems the scenario text is at fixed address // By studying [honeybee] RE:BIRTHDAY SONG, it seems the scenario text is at fixed address
@ -147,8 +150,9 @@ void SpecialHookWillPlus(hook_stack* stack, HookParam *hp, uintptr_t *data, uin
*data = (DWORD)str; *data = (DWORD)str;
*len = ::strlen(str); *len = ::strlen(str);
*split = 0; // 8/3/2014 jichi: use return address as split *split = 0; // 8/3/2014 jichi: use return address as split
}
} else { // jichi 1/19/2015: Try willplus2 else
{ // jichi 1/19/2015: Try willplus2
ConsoleOutput("WillPlus1 pattern not found, try WillPlus2 instead"); ConsoleOutput("WillPlus1 pattern not found, try WillPlus2 instead");
hp->offset = 4 * 8; // arg8, address of text hp->offset = 4 * 8; // arg8, address of text
hp->type = USING_STRING | NO_CONTEXT | USING_SPLIT; // merge different scenario threads hp->type = USING_STRING | NO_CONTEXT | USING_SPLIT; // merge different scenario threads
@ -166,9 +170,13 @@ void SpecialHookWillPlus(hook_stack* stack, HookParam *hp, uintptr_t *data, uin
bool InsertOldWillPlusHook() bool InsertOldWillPlusHook()
{ {
//__debugbreak(); //__debugbreak();
enum { sub_esp = 0xec81 }; // jichi: caller pattern: sub esp = 0x81,0xec byte enum
{
sub_esp = 0xec81
}; // jichi: caller pattern: sub esp = 0x81,0xec byte
ULONG addr = MemDbg::findCallerAddress((ULONG)::GetGlyphOutlineA, sub_esp, processStartAddress, processStopAddress); ULONG addr = MemDbg::findCallerAddress((ULONG)::GetGlyphOutlineA, sub_esp, processStartAddress, processStopAddress);
if (!addr) { if (!addr)
{
ConsoleOutput("WillPlus: function call not found"); ConsoleOutput("WillPlus: function call not found");
return false; return false;
} }
@ -185,8 +193,10 @@ const char *_willplus_trim_a(const char *text, size_t *size)
{ {
int textSize = ::strlen(text); int textSize = ::strlen(text);
int prefix = 0; int prefix = 0;
if (text[0] == '%') { if (text[0] == '%')
while (prefix < textSize - 1 && text[prefix] == '%' && ::isupper(text[prefix+1])) { {
while (prefix < textSize - 1 && text[prefix] == '%' && ::isupper(text[prefix + 1]))
{
prefix += 2; prefix += 2;
while (::isupper(text[prefix])) while (::isupper(text[prefix]))
prefix++; prefix++;
@ -194,7 +204,8 @@ const char *_willplus_trim_a(const char *text, size_t *size)
} }
{ {
int pos = textSize; int pos = textSize;
for (int i = textSize - 1; i >= prefix; i--) { for (int i = textSize - 1; i >= prefix; i--)
{
char ch = text[i]; char ch = text[i];
if (::isupper(ch)) if (::isupper(ch))
; ;
@ -214,8 +225,10 @@ const wchar_t *_willplus_trim_w(const wchar_t *text, size_t *size)
{ {
int textSize = ::wcslen(text); int textSize = ::wcslen(text);
int prefix = 0; int prefix = 0;
if (text[0] == '%') { if (text[0] == '%')
while (prefix < textSize - 1 && text[prefix] == '%' && ::isupper(text[prefix+1])) { {
while (prefix < textSize - 1 && text[prefix] == '%' && ::isupper(text[prefix + 1]))
{
prefix += 2; prefix += 2;
while (::isupper(text[prefix])) while (::isupper(text[prefix]))
prefix++; prefix++;
@ -223,7 +236,8 @@ const wchar_t *_willplus_trim_w(const wchar_t *text, size_t *size)
} }
{ {
int pos = textSize; int pos = textSize;
for (int i = textSize - 1; i >= prefix; i--) { for (int i = textSize - 1; i >= prefix; i--)
{
wchar_t ch = text[i]; wchar_t ch = text[i];
if (::isupper(ch)) if (::isupper(ch))
; ;
@ -253,7 +267,8 @@ void SpecialHookWillPlusA(hook_stack* stack, HookParam *hp, uintptr_t *data, ui
*data = (DWORD)text; *data = (DWORD)text;
*split = FIXED_SPLIT_VALUE << index; *split = FIXED_SPLIT_VALUE << index;
} }
bool WillPlus_extra_filter(void* data, size_t* size, HookParam*) { bool WillPlus_extra_filter(void *data, size_t *size, HookParam *)
{
auto text = reinterpret_cast<LPWSTR>(data); auto text = reinterpret_cast<LPWSTR>(data);
StringFilter(text, size, L"%XS", 5); // remove %XS followed by 2 chars StringFilter(text, size, L"%XS", 5); // remove %XS followed by 2 chars
@ -278,7 +293,8 @@ bool InsertWillPlusAHook()
const BYTE bytes2[] = {0x8B, 0x00, 0xFF, 0x76, 0xFC, 0x8B, 0xCF, 0x50}; const BYTE bytes2[] = {0x8B, 0x00, 0xFF, 0x76, 0xFC, 0x8B, 0xCF, 0x50};
ULONG range2 = min(processStopAddress - processStartAddress, MAX_REL_ADDR); ULONG range2 = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr2 = MemDbg::findBytes(bytes2, sizeof(bytes2), processStartAddress, processStartAddress + range2); ULONG addr2 = MemDbg::findBytes(bytes2, sizeof(bytes2), processStartAddress, processStartAddress + range2);
if (addr2) { if (addr2)
{
HookParam myhp; HookParam myhp;
myhp.address = addr2 + 2; myhp.address = addr2 + 2;
@ -296,7 +312,8 @@ bool InsertWillPlusAHook()
0x81, 0xec, 0x14, 0x08, 0x00, 0x00 // 0042B5E0 81EC 14080000 SUB ESP,0x814 ; jichi: text in eax, name in eax - 1024, able to copy 0x81, 0xec, 0x14, 0x08, 0x00, 0x00 // 0042B5E0 81EC 14080000 SUB ESP,0x814 ; jichi: text in eax, name in eax - 1024, able to copy
}; };
DWORD addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); DWORD addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr) { if (!addr)
{
ConsoleOutput("WillPlusA: pattern not found"); ConsoleOutput("WillPlusA: pattern not found");
return false; return false;
} }
@ -322,14 +339,16 @@ void SpecialHookWillPlusW(hook_stack* stack, HookParam *hp, uintptr_t *data, ui
bool InsertWillPlusWHook() bool InsertWillPlusWHook()
{ {
const BYTE bytes1[] = { // scenario const BYTE bytes1[] = {
// scenario
0x83, 0xc0, 0x20, // 00452b02 83c0 20 add eax,0x20 ; jichi: hook before here, text in ecx 0x83, 0xc0, 0x20, // 00452b02 83c0 20 add eax,0x20 ; jichi: hook before here, text in ecx
0x33, 0xd2, // 00452b05 33d2 xor edx,edx 0x33, 0xd2, // 00452b05 33d2 xor edx,edx
0x8b, 0xc1, // 00452b07 8bc1 mov eax,ecx 0x8b, 0xc1, // 00452b07 8bc1 mov eax,ecx
0xc7, 0x84, 0x24, 0xe0, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00 // 00452b09 c78424 e0010000 07000000 mov dword ptr ss:[esp+0x1e0],0x7 0xc7, 0x84, 0x24, 0xe0, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00 // 00452b09 c78424 e0010000 07000000 mov dword ptr ss:[esp+0x1e0],0x7
// 00452b14 c78424 dc010000 00000000 mov dword ptr ss:[esp+0x1dc],0x0 // 00452b14 c78424 dc010000 00000000 mov dword ptr ss:[esp+0x1dc],0x0
}; };
const BYTE bytes2[] = { // name const BYTE bytes2[] = {
// name
0x33, 0xdb, // 00453521 33db xor ebx,ebx ; jichi: hook here, text in ecx 0x33, 0xdb, // 00453521 33db xor ebx,ebx ; jichi: hook here, text in ecx
0x33, 0xd2, // 00453523 33d2 xor edx,edx 0x33, 0xd2, // 00453523 33d2 xor edx,edx
0x8b, 0xc1, // 00453525 8bc1 mov eax,ecx 0x8b, 0xc1, // 00453525 8bc1 mov eax,ecx
@ -339,9 +358,11 @@ bool InsertWillPlusWHook()
const BYTE *bytes[] = {bytes1, bytes2}; const BYTE *bytes[] = {bytes1, bytes2};
const size_t sizes[] = {sizeof(bytes1), sizeof(bytes2)}; const size_t sizes[] = {sizeof(bytes1), sizeof(bytes2)};
auto succ = false; auto succ = false;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++)
{
DWORD addr = MemDbg::findBytes(bytes[i], sizes[i], processStartAddress, processStopAddress); DWORD addr = MemDbg::findBytes(bytes[i], sizes[i], processStartAddress, processStopAddress);
if (!addr) { if (!addr)
{
ConsoleOutput("WillPlusW: pattern not found"); ConsoleOutput("WillPlusW: pattern not found");
return false; return false;
} }
@ -450,7 +471,8 @@ static bool InsertNewWillPlusHook()
BYTE byte = *(BYTE *)(addr + 1); BYTE byte = *(BYTE *)(addr + 1);
regs offset = regs::invalid; regs offset = regs::invalid;
switch (byte) { switch (byte)
{
case 0xf9: case 0xf9:
offset = regs::ecx; offset = regs::ecx;
break; break;
@ -473,7 +495,8 @@ static bool InsertNewWillPlusHook()
offset = regs::edi; offset = regs::edi;
break; break;
}; };
if (offset!=regs::invalid) { if (offset != regs::invalid)
{
HookParam hp; HookParam hp;
hp.address = addr + 8; hp.address = addr + 8;
hp.type = CODEC_UTF16; hp.type = CODEC_UTF16;
@ -481,7 +504,8 @@ static bool InsertNewWillPlusHook()
found |= NewHook(hp, "WillPlus3"); found |= NewHook(hp, "WillPlus3");
} }
} }
if (!found) ConsoleOutput("WillPlus: failed to find instructions"); if (!found)
ConsoleOutput("WillPlus: failed to find instructions");
return found; return found;
} }
@ -493,9 +517,12 @@ bool InsertWillPlusHook()
ok = InsertWillPlusWHook() || InsertNewWillPlusHook() || InsertWillPlusAHook() || ok; ok = InsertWillPlusWHook() || InsertNewWillPlusHook() || InsertWillPlusAHook() || ok;
return ok; return ok;
} }
namespace will3{ namespace will3
{
int kp = 0;int lf=0;int lc=0; int kp = 0;
int lf = 0;
int lc = 0;
bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role) bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role)
{ {
// DOUT(QString::fromUtf16((LPWSTR)s->stack[6]));//"MS UI Gothic" // DOUT(QString::fromUtf16((LPWSTR)s->stack[6]));//"MS UI Gothic"
@ -507,17 +534,21 @@ bool hookBefore(hook_stack*s,void* data, size_t* len,uintptr_t*role)
auto split = s->stack[0]; // retaddr auto split = s->stack[0]; // retaddr
std::wstring str = ((LPWSTR)s->stack[7]); std::wstring str = ((LPWSTR)s->stack[7]);
kp=0;lf=0; kp = 0;
if (endWith(str,L"%K%P")){ lf = 0;
if (endWith(str, L"%K%P"))
{
kp = 1; kp = 1;
str = str.substr(0, str.size() - 4); str = str.substr(0, str.size() - 4);
} }
if(startWith(str,L"%LF")){ if (startWith(str, L"%LF"))
{
lf = 1; lf = 1;
str = str.substr(3); str = str.substr(3);
} }
if(startWith(str,L"%LC")){ if (startWith(str, L"%LC"))
{
lc = 1; lc = 1;
str = str.substr(3); str = str.substr(3);
} }
@ -530,35 +561,41 @@ bool hookBefore(hook_stack*s,void* data, size_t* len,uintptr_t*role)
write_string_overwrite(data, len, str); write_string_overwrite(data, len, str);
return true; return true;
} }
void hookafter(hook_stack*s,void* data, size_t len){ void hookafter(hook_stack *s, void *data, size_t len)
{
auto data_ = std::wstring((wchar_t *)data, len / 2); // EngineController::instance()->dispatchTextWSTD(innner, Engine::ScenarioRole, 0); auto data_ = std::wstring((wchar_t *)data, len / 2); // EngineController::instance()->dispatchTextWSTD(innner, Engine::ScenarioRole, 0);
if (kp) { if (kp)
{
data_.append(L"%K%P"); data_.append(L"%K%P");
} }
if(lf){ if (lf)
{
data_ = L"%LF" + data_; data_ = L"%LF" + data_;
}if(lc){ }
if (lc)
{
data_ = L"%LC" + data_; data_ = L"%LC" + data_;
} }
s->stack[7] = (ULONG)(data_.c_str()); s->stack[7] = (ULONG)(data_.c_str());
} }
} }
bool InsertWillPlus4Hook() { bool InsertWillPlus4Hook()
{
// 星の乙女と六華の姉妹 // 星の乙女と六華の姉妹
const BYTE bytes[] = { const BYTE bytes[] = {
0xc7, 0x45, 0xfc, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xfc, 0x00, 0x00, 0x00, 0x00,
0x33, 0xc9, 0x33, 0xc9,
0xc7,0x47,0x78,0x00,0x00,0x00,0x00 0xc7, 0x47, 0x78, 0x00, 0x00, 0x00, 0x00};
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (addr == 0)return false; if (addr == 0)
return false;
addr = MemDbg::findEnclosingFunctionBeforeDword(0x83dc8b53, addr, MemDbg::MaximumFunctionSize, 1); addr = MemDbg::findEnclosingFunctionBeforeDword(0x83dc8b53, addr, MemDbg::MaximumFunctionSize, 1);
if (addr == 0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.offset = get_stack(7); hp.offset = get_stack(7);
@ -569,15 +606,15 @@ bool InsertWillPlus4Hook() {
hp.hook_after = will3::hookafter; hp.hook_after = will3::hookafter;
return NewHook(hp, "EmbedWillplus3"); return NewHook(hp, "EmbedWillplus3");
} }
bool InsertWillPlus5Hook() { bool InsertWillPlus5Hook()
{
// ensemble 29th Project『乙女の剣と秘めごとコンチェルト』オフィシャルサイト 体验版 // ensemble 29th Project『乙女の剣と秘めごとコンチェルト』オフィシャルサイト 体验版
const BYTE bytes[] = { const BYTE bytes[] = {
0x3d, XX2, 0x00, 0x00, 0x3d, XX2, 0x00, 0x00,
0x72, XX, 0x72, XX,
0x3d, XX2, 0x00, 0x00, 0x3d, XX2, 0x00, 0x00,
0x77 0x77};
};
/*if (v26 >= 0xE63E) /*if (v26 >= 0xE63E)
{ {
if (v26 <= 0xE757)*/ if (v26 <= 0xE757)*/
@ -589,7 +626,8 @@ bool InsertWillPlus5Hook() {
bool ok = false; bool ok = false;
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress); auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress);
for (auto addr : addrs) { for (auto addr : addrs)
{
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.offset = get_reg(regs::eax); hp.offset = get_reg(regs::eax);
@ -599,7 +637,8 @@ bool InsertWillPlus5Hook() {
} }
return ok; return ok;
} }
bool insertwillplus6(){ bool insertwillplus6()
{
/* 0x00492870 /* 0x00492870
0: 50 push eax 0: 50 push eax
@ -636,11 +675,11 @@ f: 6a 01 push 0x1
0x8b, 0xd6, 0x8b, 0xd6,
0xe8, XX4, 0xe8, XX4,
0x83, 0xf8, 0x83, 0xf8,
0xff,0x75,0xdc 0xff, 0x75, 0xdc};
};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
addr += sizeof(bytes); addr += sizeof(bytes);
ConsoleOutput("%p %p %p", addr, processStartAddress, processStopAddress); ConsoleOutput("%p %p %p", addr, processStartAddress, processStopAddress);
HookParam hp; HookParam hp;
@ -650,7 +689,8 @@ f: 6a 01 push 0x1
ConsoleOutput("INSERT WillPlus6"); ConsoleOutput("INSERT WillPlus6");
return NewHook(hp, "WillPlus6"); return NewHook(hp, "WillPlus6");
} }
bool willX(){ bool willX()
{
// 世界でいちばんNGな恋 // 世界でいちばんNGな恋
// .text:0040EAE9 81 FE 94 81 00 00 cmp esi, 8194h // .text:0040EAE9 81 FE 94 81 00 00 cmp esi, 8194h
// .text:0040EAEF 74 2C jz short loc_40EB1D // .text:0040EAEF 74 2C jz short loc_40EB1D
@ -680,11 +720,11 @@ bool willX(){
0x74, XX, 0x74, XX,
0x81, 0xFE, 0x59, 0x81, 0x00, 0x00, 0x81, 0xFE, 0x59, 0x81, 0x00, 0x00,
0x74, XX, 0x74, XX,
0x81,0xFE,0x96,0x81,0x00,0x00 0x81, 0xFE, 0x96, 0x81, 0x00, 0x00};
};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
auto succ = false; auto succ = false;
{ {
HookParam hp; HookParam hp;
@ -707,12 +747,8 @@ bool willX(){
return succ; return succ;
} }
namespace
{ // unnamed
namespace { // unnamed
// Sample prefix: %LF // Sample prefix: %LF
// Sample suffix: %L%P%W // Sample suffix: %L%P%W
@ -720,21 +756,25 @@ template <typename strT>
strT trim(strT text, int *size) strT trim(strT text, int *size)
{ {
int length = *size; int length = *size;
if (text[0] == '%') { // handle prefix if (text[0] == '%')
{ // handle prefix
int pos = 0; int pos = 0;
while (pos < length - 1 && text[pos] == '%' && ::isupper(text[pos+1])) { while (pos < length - 1 && text[pos] == '%' && ::isupper(text[pos + 1]))
{
pos += 2; pos += 2;
while (::isupper(text[pos])) while (::isupper(text[pos]))
pos++; pos++;
} }
if (pos) { if (pos)
{
length -= pos; length -= pos;
text += pos; text += pos;
} }
} }
{ // handle suffix { // handle suffix
int pos = length; int pos = length;
for (int i = length - 1; i >= 0; i--) { for (int i = length - 1; i >= 0; i--)
{
if (::isupper(text[i])) if (::isupper(text[i]))
; ;
else if (text[i] == '%' && ::isupper(text[i + 1])) else if (text[i] == '%' && ::isupper(text[i + 1]))
@ -747,7 +787,8 @@ strT trim(strT text, int *size)
*size = length; *size = length;
return text; return text;
} }
struct textinfo{ struct textinfo
{
std::wstring text_; std::wstring text_;
int stackIndex_; int stackIndex_;
int role_; int role_;
@ -762,7 +803,10 @@ namespace TextHookW
bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role) bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role)
{ {
auto info = savetyperef.at(idx); auto info = savetyperef.at(idx);
enum { sig = 0 }; enum
{
sig = 0
};
auto text = (LPCWSTR)s->stack[info->stackIndex_]; auto text = (LPCWSTR)s->stack[info->stackIndex_];
if (!text || !*text) if (!text || !*text)
return false; return false;
@ -776,10 +820,14 @@ namespace TextHookW
return true; return true;
} }
template <int idx> template <int idx>
void hookafter(hook_stack*s,void* data, size_t len){ void hookafter(hook_stack *s, void *data, size_t len)
{
auto newText = std::wstring((LPWSTR)data, len / 2); auto newText = std::wstring((LPWSTR)data, len / 2);
auto info = savetyperef.at(idx); auto info = savetyperef.at(idx);
enum { sig = 0 }; enum
{
sig = 0
};
auto text = (LPCWSTR)s->stack[info->stackIndex_]; auto text = (LPCWSTR)s->stack[info->stackIndex_];
if (!text || !*text) if (!text || !*text)
return; return;
@ -805,7 +853,8 @@ namespace TextHookW
bool attach(const uint8_t *pattern, size_t patternSize, ULONG startAddress, ULONG stopAddress, int hookStackIndex, int role = Engine::UnknownRole) bool attach(const uint8_t *pattern, size_t patternSize, ULONG startAddress, ULONG stopAddress, int hookStackIndex, int role = Engine::UnknownRole)
{ {
ULONG addr = MemDbg::findBytes(pattern, patternSize, startAddress, stopAddress); ULONG addr = MemDbg::findBytes(pattern, patternSize, startAddress, stopAddress);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
auto _tinfo = new textinfo{}; auto _tinfo = new textinfo{};
@ -958,7 +1007,6 @@ bool attachScenarioHookW2(ULONG startAddress, ULONG stopAddress)
}; };
int edi = get_reg(regs::edi) / 4; int edi = get_reg(regs::edi) / 4;
return TextHookW::attach<2>(bytes, sizeof(bytes), startAddress, stopAddress, edi, Engine::ScenarioRole); return TextHookW::attach<2>(bytes, sizeof(bytes), startAddress, stopAddress, edi, Engine::ScenarioRole);
} }
/** /**
* Sample game: * Sample game:
@ -1028,7 +1076,6 @@ bool attachNameHookW(ULONG startAddress, ULONG stopAddress)
int ecx = get_reg(regs::ecx) / 4; int ecx = get_reg(regs::ecx) / 4;
return TextHookW::attach<3>(bytes, sizeof(bytes), startAddress, stopAddress, ecx, Engine::NameRole); return TextHookW::attach<3>(bytes, sizeof(bytes), startAddress, stopAddress, ecx, Engine::NameRole);
} }
/** /**
@ -1096,12 +1143,13 @@ bool attachOtherHookW(ULONG startAddress, ULONG stopAddress)
int edx = get_reg(regs::edx) / 4; int edx = get_reg(regs::edx) / 4;
return TextHookW::attach<4>(bytes, sizeof(bytes), startAddress, stopAddress, edx, Engine::OtherRole); return TextHookW::attach<4>(bytes, sizeof(bytes), startAddress, stopAddress, edx, Engine::OtherRole);
} }
namespace PatchA { namespace PatchA
{
namespace Private { namespace Private
{
// The second argument is always 0 and not used // The second argument is always 0 and not used
bool isLeadByteChar(int ch, int) bool isLeadByteChar(int ch, int)
{ {
@ -1181,7 +1229,8 @@ bool csmemcpy(void *dst, const void *src, size_t size)
ulong replace_near_call(ulong addr, ulong val) ulong replace_near_call(ulong addr, ulong val)
{ {
DWORD ret; DWORD ret;
switch (::disasm((LPCVOID)addr)) { switch (::disasm((LPCVOID)addr))
{
case 5: // near call / short jmp: relative address case 5: // near call / short jmp: relative address
ret = *(DWORD *)(addr + 1) + (addr + 5); ret = *(DWORD *)(addr + 1) + (addr + 5);
val -= addr + 5; val -= addr + 5;
@ -1195,7 +1244,8 @@ ulong replace_near_call(ulong addr, ulong val)
*(DWORD *)(data + 1) = val - (addr + 5); *(DWORD *)(data + 1) = val - (addr + 5);
return csmemcpy((LPVOID)addr, data, sizeof(data)) ? ret : 0; return csmemcpy((LPVOID)addr, data, sizeof(data)) ? ret : 0;
} }
default: return 0; default:
return 0;
} }
} }
ULONG patchEncoding(ULONG startAddress, ULONG stopAddress) ULONG patchEncoding(ULONG startAddress, ULONG stopAddress)
@ -1205,7 +1255,10 @@ ULONG patchEncoding(ULONG startAddress, ULONG stopAddress)
0xff, 0x75, 0x08, // 00487fe1 ff75 08 push dword ptr ss:[ebp+0x8] 0xff, 0x75, 0x08, // 00487fe1 ff75 08 push dword ptr ss:[ebp+0x8]
0xe8, 0xaa, 0xff, 0xff, 0xff // 00487fe4 e8 aaffffff call .00487f93 ; jichi: called here 0xe8, 0xaa, 0xff, 0xff, 0xff // 00487fe4 e8 aaffffff call .00487f93 ; jichi: called here
}; };
enum { addr_offset = 5 }; enum
{
addr_offset = 5
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress); ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
return addr; //&& replace_near_call(addr + addr_offset, (ULONG)Private::isLeadByteChar); return addr; //&& replace_near_call(addr + addr_offset, (ULONG)Private::isLeadByteChar);
@ -1213,9 +1266,11 @@ ULONG patchEncoding(ULONG startAddress, ULONG stopAddress)
} // namespace PatchA } // namespace PatchA
namespace ScenarioHookA { namespace ScenarioHookA
{
namespace Private { namespace Private
{
/* /*
void dispatch(LPSTR text, int role) void dispatch(LPSTR text, int role)
{ {
@ -1244,7 +1299,10 @@ namespace Private {
// dispatch(text - 1024, Engine::NameRole); // dispatch(text - 1024, Engine::NameRole);
// dispatch(text, Engine::ScenarioRole); // dispatch(text, Engine::ScenarioRole);
enum { sig = 0 }; enum
{
sig = 0
};
if (!Engine::isAddressWritable(text) || !*text) // isAddressWritable is not needed for correct games if (!Engine::isAddressWritable(text) || !*text) // isAddressWritable is not needed for correct games
return false; return false;
int size = ::strlen(text), int size = ::strlen(text),
@ -1263,7 +1321,8 @@ namespace Private {
::strcpy(text, newData.c_str()); ::strcpy(text, newData.c_str());
return true;*/ return true;*/
} }
void hookafter(hook_stack*s,void* data, size_t len){ void hookafter(hook_stack *s, void *data, size_t len)
{
auto newData = std::string((char *)data, len); auto newData = std::string((char *)data, len);
auto text = (LPSTR)s->eax; auto text = (LPSTR)s->eax;
@ -1510,7 +1569,8 @@ bool attach(ULONG startAddress, ULONG stopAddress)
0x81, 0xec, 0x14, 0x08, 0x00, 0x00 // 0042B5E0 81EC 14080000 SUB ESP,0x814 ; jichi: text in eax, name in eax - 1024, able to copy 0x81, 0xec, 0x14, 0x08, 0x00, 0x00 // 0042B5E0 81EC 14080000 SUB ESP,0x814 ; jichi: text in eax, name in eax - 1024, able to copy
}; };
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress); ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
@ -1521,12 +1581,13 @@ bool attach(ULONG startAddress, ULONG stopAddress)
hp.hook_font = F_GetGlyphOutlineA | F_TextOutA; hp.hook_font = F_GetGlyphOutlineA | F_TextOutA;
static ULONG paddr = (PatchA::patchEncoding(startAddress, stopAddress)); static ULONG paddr = (PatchA::patchEncoding(startAddress, stopAddress));
ConsoleOutput("%p", paddr); ConsoleOutput("%p", paddr);
if(paddr){ if (paddr)
{
hp.type |= EMBED_DYNA_SJIS; hp.type |= EMBED_DYNA_SJIS;
hp.hook_font = F_GetGlyphOutlineA | F_TextOutA; hp.hook_font = F_GetGlyphOutlineA | F_TextOutA;
patch_fun=[](){ patch_fun = []()
{
PatchA::replace_near_call(paddr + 5, (ULONG)PatchA::Private::isLeadByteChar); PatchA::replace_near_call(paddr + 5, (ULONG)PatchA::Private::isLeadByteChar);
}; };
} }
return NewHook(hp, "EmbedWillplusA"); return NewHook(hp, "EmbedWillplusA");
@ -1534,9 +1595,11 @@ bool attach(ULONG startAddress, ULONG stopAddress)
} // namespace ScenarioHookA } // namespace ScenarioHookA
namespace OtherHookA { namespace OtherHookA
{
namespace Private { namespace Private
{
bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role) bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role)
{ {
@ -1563,7 +1626,8 @@ namespace Private {
bool attach(ULONG startAddress, ULONG stopAddress) bool attach(ULONG startAddress, ULONG stopAddress)
{ {
ULONG addr = MemDbg::findCallerAddressAfterInt3((ULONG)::GetGlyphOutlineA, startAddress, stopAddress); ULONG addr = MemDbg::findCallerAddressAfterInt3((ULONG)::GetGlyphOutlineA, startAddress, stopAddress);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.hook_before = Private::hookBefore; hp.hook_before = Private::hookBefore;
@ -1577,21 +1641,23 @@ bool attach(ULONG startAddress, ULONG stopAddress)
} // unnamed namespace } // unnamed namespace
/** Public class */ /** Public class */
namespace WillPlusEngine{ namespace WillPlusEngine
{
bool attach() bool attach()
{ {
ULONG startAddress = processStartAddress, stopAddress = processStopAddress; ULONG startAddress = processStartAddress, stopAddress = processStopAddress;
if (::attachScenarioHookW1(startAddress, stopAddress) || ::attachScenarioHookW2(startAddress, stopAddress))
if (::attachScenarioHookW1(startAddress, stopAddress) || ::attachScenarioHookW2(startAddress, stopAddress)) { {
(::attachNameHookW(startAddress, stopAddress)); (::attachNameHookW(startAddress, stopAddress));
(::attachOtherHookW(startAddress, stopAddress)); (::attachOtherHookW(startAddress, stopAddress));
return true; return true;
}
} else if (ScenarioHookA::attach(startAddress, stopAddress)) { // try widechar pattern first, which is more unique else if (ScenarioHookA::attach(startAddress, stopAddress))
{ // try widechar pattern first, which is more unique
(OtherHookA::attach(startAddress, stopAddress)); (OtherHookA::attach(startAddress, stopAddress));
// HijackManager::instance()->attachFunction((ULONG)::GetGlyphOutlineA); // HijackManager::instance()->attachFunction((ULONG)::GetGlyphOutlineA);
@ -1603,7 +1669,8 @@ bool attach()
} }
} }
namespace{ namespace
{
static bool InsertWillPlus4() static bool InsertWillPlus4()
{ {
@ -1620,7 +1687,8 @@ static bool InsertWillPlus4()
}; };
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR); ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range); ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr) { if (!addr)
{
ConsoleOutput("WillPlus4: pattern not found"); ConsoleOutput("WillPlus4: pattern not found");
return false; return false;
} }
@ -1651,7 +1719,8 @@ static bool InsertWillPlus5()
}; };
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR); ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range); ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr) { if (!addr)
{
ConsoleOutput("WillPlus5: pattern not found"); ConsoleOutput("WillPlus5: pattern not found");
return false; return false;
} }
@ -1669,7 +1738,8 @@ static bool InsertWillPlus5()
return true; return true;
} }
bool _xxx(){ bool _xxx()
{
bool ok = false; bool ok = false;
ok = InsertWillPlus4() || ok; ok = InsertWillPlus4() || ok;
ok = InsertWillPlus5() || ok; ok = InsertWillPlus5() || ok;
@ -1677,7 +1747,8 @@ bool ok=false;
} }
} }
bool WillPlus::attach_function() { bool WillPlus::attach_function()
{
bool succ = WillPlusEngine::attach(); bool succ = WillPlusEngine::attach();
succ |= InsertWillPlusHook(); succ |= InsertWillPlusHook();
succ |= InsertWillPlus4Hook(); succ |= InsertWillPlus4Hook();
@ -1689,17 +1760,19 @@ bool WillPlus::attach_function() {
return succ; return succ;
} }
bool Willold::attach_function()
{
bool Willold::attach_function() {
// https://vndb.org/v17755 // https://vndb.org/v17755
// 凌辱鬼 // 凌辱鬼
auto addr = MemDbg::findLongJumpAddress((ULONG)TextOutA, processStartAddress, processStopAddress); auto addr = MemDbg::findLongJumpAddress((ULONG)TextOutA, processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
addr = MemDbg::findNearCallAddress(addr, processStartAddress, processStopAddress); addr = MemDbg::findNearCallAddress(addr, processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
addr = findfuncstart(addr, 0x200); addr = findfuncstart(addr, 0x200);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.type = USING_CHAR | CODEC_ANSI_BE; hp.type = USING_CHAR | CODEC_ANSI_BE;