mirror of
https://github.com/HIllya51/LunaTranslator.git
synced 2025-01-01 10:04:12 +08:00
306 lines
8.5 KiB
C++
306 lines
8.5 KiB
C++
#include "TinkerBell.h"
|
|
bool InsertTinkerBellHook()
|
|
{
|
|
// DWORD s1,s2,i;
|
|
// DWORD ch=0x8141;
|
|
DWORD i;
|
|
WORD count;
|
|
count = 0;
|
|
HookParam hp;
|
|
hp.type = CODEC_ANSI_BE | NO_CONTEXT;
|
|
for (i = processStartAddress; i < processStopAddress - 4; i++)
|
|
{
|
|
if (*(DWORD *)i == 0x8141)
|
|
{
|
|
BYTE t = *(BYTE *)(i - 1);
|
|
if (t == 0x3d || t == 0x2d)
|
|
{
|
|
hp.offset = regoffset(eax);
|
|
hp.address = i - 1;
|
|
}
|
|
else if (*(BYTE *)(i - 2) == 0x81)
|
|
{
|
|
t &= 0xf8;
|
|
if (t == 0xf8 || t == 0xe8)
|
|
{
|
|
hp.offset = -8 - ((*(BYTE *)(i - 1) & 7) << 2);
|
|
hp.address = i - 2;
|
|
}
|
|
}
|
|
if (hp.address)
|
|
{
|
|
char hook_name[0x20];
|
|
::strcpy(hook_name, "TinkerBell"); // size = 0xa
|
|
hook_name[0xa] = '0' + count;
|
|
hook_name[0xb] = 0;
|
|
ConsoleOutput("INSERT TinkerBell");
|
|
count += NewHook(hp, hook_name);
|
|
hp.address = 0;
|
|
}
|
|
}
|
|
}
|
|
if (count)
|
|
return true;
|
|
ConsoleOutput("TinkerBell: failed");
|
|
return false;
|
|
}
|
|
|
|
// s1=SearchPattern(processStartAddress,processStopAddress-processStartAddress-4,&ch,4);
|
|
// if (s1)
|
|
// {
|
|
// for (i=s1;i>s1-0x400;i--)
|
|
// {
|
|
// if (*(WORD*)(processStartAddress+i)==0xec83)
|
|
// {
|
|
// hp.address=processStartAddress+i;
|
|
// NewHook(hp, "C.System");
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
// s2=s1+SearchPattern(processStartAddress+s1+4,processStopAddress-s1-8,&ch,4);
|
|
// if (s2)
|
|
// {
|
|
// for (i=s2;i>s2-0x400;i--)
|
|
// {
|
|
// if (*(WORD*)(processStartAddress+i)==0xec83)
|
|
// {
|
|
// hp.address=processStartAddress+i;
|
|
// NewHook(hp, "TinkerBell");
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
// //if (count)
|
|
// RegisterEngineType(ENGINE_TINKER);
|
|
namespace
|
|
{
|
|
void WendyBell_filter(TextBuffer *buffer, HookParam *hp)
|
|
{
|
|
|
|
auto wc = buffer->strW();
|
|
|
|
for (int i = 0; i < wc.size() - 1; i++)
|
|
{
|
|
if (wc[i] == L'\xff' && wc[i + 1] == L'\xff')
|
|
{
|
|
wc = wc.substr(0, i) + wc.substr(i + 3 + wc[i + 2]);
|
|
}
|
|
}
|
|
for (int i = 0; i < wc.size(); i++)
|
|
{
|
|
if (wc[i] < 10)
|
|
{
|
|
wc = wc.substr(0, i) + wc.substr(i + 1);
|
|
}
|
|
}
|
|
strReplace(wc, L"\xfe", L"");
|
|
buffer->from(wc);
|
|
}
|
|
}
|
|
|
|
namespace
|
|
{
|
|
std::wstring last = L"";
|
|
void tkbl_filter(TextBuffer *buffer, HookParam *hp)
|
|
{
|
|
StringFilter(buffer, L"\x26bc\x65\x25\xffff", 4); // 移除心形
|
|
|
|
WendyBell_filter(buffer, hp);
|
|
auto str = buffer->strW(); // 末尾存在一个换行符
|
|
str = str.substr(0, str.size());
|
|
if (last == str)
|
|
return buffer->clear();
|
|
last = str;
|
|
buffer->from(str);
|
|
}
|
|
bool tkbl()
|
|
{
|
|
// せをはやみ
|
|
const BYTE bytes[] = {
|
|
0x55, 0x8b, 0xec,
|
|
0x83, 0xec, 0x0c,
|
|
0x53, 0x56,
|
|
0x8b, 0xf1,
|
|
0x8b, 0x5e, 0x10,
|
|
0x8b, 0x4e, 0x14,
|
|
0x89, 0x5d, 0xf4,
|
|
0x89, 0x4d, 0xfc,
|
|
0x3b, 0xd9};
|
|
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
|
if (!addr)
|
|
return false;
|
|
|
|
HookParam hp;
|
|
hp.type = USING_STRING | CODEC_UTF16 | NO_CONTEXT;
|
|
hp.address = addr;
|
|
hp.filter_fun = tkbl_filter;
|
|
hp.text_fun = [](hook_context *context, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
|
|
{
|
|
auto str = (wchar_t *)context->ebx;
|
|
*split = (wcschr(str, 0x3010) != nullptr) && (wcschr(str, 0x3011) != nullptr);
|
|
buffer->from(str);
|
|
};
|
|
hp.offset = regoffset(ebx);
|
|
return NewHook(hp, "tkbl");
|
|
}
|
|
}
|
|
|
|
bool InsertWendyBellHook()
|
|
{
|
|
const BYTE bytes[] = {
|
|
|
|
0x83, 0xbe, XX4, 0x00,
|
|
0x8b, XX2,
|
|
0x0f, 0x85, XX4,
|
|
0x83, 0xbe, XX4, 0x00,
|
|
0x0f, 0x85, XX4,
|
|
0x83, 0xbe, XX4, 0x00,
|
|
0x0f, 0x84, XX4
|
|
/*.always:0048E4CA 83 BE F8 04 00 00 00 cmp dword ptr[esi + 4F8h], 0
|
|
.always : 0048E4D1 8B 5D 84 mov ebx,[ebp + Src]
|
|
.always : 0048E4D4 0F 85 86 F8 FF FF jnz loc_48DD60
|
|
.always : 0048E4D4
|
|
.always : 0048E4DA 83 BE F4 04 00 00 00 cmp dword ptr[esi + 4F4h], 0
|
|
.always : 0048E4E1 0F 85 79 F8 FF FF jnz loc_48DD60
|
|
.always : 0048E4E1
|
|
.always : 0048E4E7 83 BE 00 05 00 00 00 cmp dword ptr[esi + 500h], 0
|
|
.always : 0048E4EE 0F 84 6C F8 FF FF jz loc_48DD60*/
|
|
|
|
};
|
|
const BYTE bytes2[] = {
|
|
// 夢幻のさくら ~緋艶姫淫辱孕蝕譚~
|
|
// 妖花の園
|
|
0x8b, 0x86, XX4,
|
|
0x6a, 0x00,
|
|
0x8b, 0x80, XX4,
|
|
0x50,
|
|
0x8b, 0x08,
|
|
0xff, 0x91, XX4,
|
|
0x8b, 0x45, XX,
|
|
0x83, 0xF8, 0x08
|
|
//
|
|
//.always:0048E51D 8B 86 58 0A 00 00 mov eax,[esi + 0A58h]
|
|
//.always : 0048E523 6A 00 push 0
|
|
//.always : 0048E525 8B 80 B8 01 00 00 mov eax,[eax + 1B8h]
|
|
//.always : 0048E52B 50 push eax
|
|
//.always : 0048E52C 8B 08 mov ecx,[eax]
|
|
//.always:0048E52E FF 91 C4 00 00 00 call dword ptr[ecx + 0C4h]
|
|
//.always : 0048E52E
|
|
//.always : 0048E534 8B 45 DC mov eax,[ebp + var_24]
|
|
//.always : 0048E537 83 F8 08 cmp eax, 8
|
|
};
|
|
|
|
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress);
|
|
auto addrs2 = Util::SearchMemory(bytes2, sizeof(bytes2), PAGE_EXECUTE, processStartAddress, processStopAddress);
|
|
addrs.insert(addrs.end(), addrs2.begin(), addrs2.end());
|
|
auto succ = false;
|
|
for (auto addr : addrs)
|
|
{
|
|
HookParam hp;
|
|
hp.address = addr;
|
|
hp.offset = regoffset(ebx);
|
|
hp.filter_fun = WendyBell_filter;
|
|
hp.type = USING_STRING | CODEC_UTF16 | NO_CONTEXT;
|
|
ConsoleOutput("%p", addr);
|
|
succ |= NewHook(hp, "WendyBell");
|
|
if (*(WORD *)(6 + addr) == 0x006a)
|
|
{
|
|
// https://vndb.org/r94776
|
|
// 悪魔と夜と異世界と パッケージ版
|
|
hp.address = 6 + addr;
|
|
hp.offset = regoffset(edx);
|
|
succ |= NewHook(hp, "WendyBell");
|
|
}
|
|
}
|
|
|
|
return succ;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
bool _2()
|
|
{
|
|
|
|
const BYTE bytes[] = {
|
|
// 夢幻のさくら2
|
|
0x55, 0x8b, 0xec,
|
|
0x53,
|
|
0x8b, 0x5d, 0x08,
|
|
0x56, 0x8b, 0xf1,
|
|
0x57,
|
|
0x8b, 0x4e, 0x10,
|
|
0x8b, 0xc1,
|
|
0xf7, 0xd0,
|
|
0x3b, 0xc3};
|
|
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress);
|
|
auto succ = false;
|
|
for (auto addr : addrs)
|
|
{
|
|
HookParam hp;
|
|
hp.address = addr;
|
|
hp.offset = stackoffset(2);
|
|
hp.type = CODEC_UTF16 | USING_CHAR | NO_CONTEXT;
|
|
struct savecontext
|
|
{
|
|
int cnt = 0;
|
|
int cntx = 0;
|
|
};
|
|
hp.user_value = (uintptr_t) new savecontext;
|
|
hp.filter_fun = [](TextBuffer *buffer, HookParam *hp)
|
|
{
|
|
// ff ff 4 305f 305f 304b 304b 306a 306a 3057 3057 3 5c0f 5c0f 9ce5 9ce5 904a 904a
|
|
if (![=]()
|
|
{
|
|
auto wc = *(wchar_t *)buffer->buff;
|
|
switch (wc)
|
|
{
|
|
case L'\xfe':
|
|
return false; // 换行
|
|
case L'\xff':
|
|
((savecontext *)hp->user_value)->cnt += 1;
|
|
return false;
|
|
default:
|
|
if (((savecontext *)hp->user_value)->cntx == 0 && ((savecontext *)hp->user_value)->cnt)
|
|
{
|
|
((savecontext *)hp->user_value)->cntx = wc * 2;
|
|
((savecontext *)hp->user_value)->cnt -= 1;
|
|
return false;
|
|
}
|
|
if (((savecontext *)hp->user_value)->cntx && ((savecontext *)hp->user_value)->cnt == 1)
|
|
{
|
|
((savecontext *)hp->user_value)->cntx -= 1;
|
|
return false;
|
|
}
|
|
if (((savecontext *)hp->user_value)->cntx && ((savecontext *)hp->user_value)->cnt == 0)
|
|
{
|
|
((savecontext *)hp->user_value)->cntx -= 1;
|
|
if (((savecontext *)hp->user_value)->cntx % 2)
|
|
return true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}())
|
|
buffer->clear();
|
|
};
|
|
succ |= NewHook(hp, "TinkerBell");
|
|
}
|
|
return succ;
|
|
}
|
|
}
|
|
bool TinkerBell::attach_function()
|
|
{
|
|
return InsertTinkerBellHook() || tkbl() || (InsertWendyBellHook() | _2());
|
|
}
|
|
bool TinkerBellold::attach_function()
|
|
{
|
|
HookParam hp;
|
|
hp.address = (DWORD)ExtTextOutA;
|
|
|
|
hp.offset = stackoffset(6);
|
|
hp.type = USING_STRING | USING_SPLIT;
|
|
hp.split = stackoffset(5);
|
|
return NewHook(hp, "TinkerBell");
|
|
}
|