LunaHook-mirror/LunaHook/engine32/Escude.cpp
恍兮惚兮 eb123790e6 refactor
2024-03-21 18:29:50 +08:00

263 lines
11 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include"Escude.h"
#include"embed_util.h"
/** jichi 7/23/2015 Escude
* Sample game: Re;Lord <20><>ルフォルト<E383AB>魔女とぬぁ<E381AC>るみ * See: http://capita.tistory.com/m/post/210
*
* ENCODEKOR,FORCEFONT(5),HOOK(0x0042CB40,TRANS([[ESP+0x4]+0x20],PTRCHEAT,PTRBACKUP,SAFE),RETNPOS(SOURCE)),FONT(Malgun Gothic,-13)
*
* GDI functions: TextOutA, GetTextExtentPoint32A
* It requires changing function to MS Gothic using configure.exe
*
* Text in arg1 + 0x20
*
* 0042CB3C CC INT3
* 0042CB3D CC INT3
* 0042CB3E CC INT3
* 0042CB3F CC INT3
* 0042CB40 56 PUSH ESI
* 0042CB41 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+0x8]
* 0042CB45 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 0042CB47 50 PUSH EAX
* 0042CB48 E8 53FC0A00 CALL .004DC7A0
* 0042CB4D 8B56 04 MOV EDX,DWORD PTR DS:[ESI+0x4]
* 0042CB50 83C4 04 ADD ESP,0x4
* 0042CB53 5E POP ESI
* 0042CB54 85D2 TEST EDX,EDX
* 0042CB56 74 7E JE SHORT .0042CBD6
* 0042CB58 85C0 TEST EAX,EAX
* 0042CB5A 74 07 JE SHORT .0042CB63
* 0042CB5C 8B08 MOV ECX,DWORD PTR DS:[EAX]
* 0042CB5E 8B49 04 MOV ECX,DWORD PTR DS:[ECX+0x4]
* 0042CB61 EB 02 JMP SHORT .0042CB65
* 0042CB63 33C9 XOR ECX,ECX
* 0042CB65 890A MOV DWORD PTR DS:[EDX],ECX
* 0042CB67 85C0 TEST EAX,EAX
* 0042CB69 74 07 JE SHORT .0042CB72
* 0042CB6B 8B08 MOV ECX,DWORD PTR DS:[EAX]
* 0042CB6D 8B49 08 MOV ECX,DWORD PTR DS:[ECX+0x8]
* 0042CB70 EB 02 JMP SHORT .0042CB74
* 0042CB72 33C9 XOR ECX,ECX
* 0042CB74 894A 04 MOV DWORD PTR DS:[EDX+0x4],ECX
* 0042CB77 85C0 TEST EAX,EAX
* 0042CB79 74 08 JE SHORT .0042CB83
* 0042CB7B 8B08 MOV ECX,DWORD PTR DS:[EAX]
* 0042CB7D 0FB749 0E MOVZX ECX,WORD PTR DS:[ECX+0xE]
* 0042CB81 EB 02 JMP SHORT .0042CB85
* 0042CB83 33C9 XOR ECX,ECX
* 0042CB85 0FB7C9 MOVZX ECX,CX
* 0042CB88 894A 08 MOV DWORD PTR DS:[EDX+0x8],ECX
* 0042CB8B 85C0 TEST EAX,EAX
* 0042CB8D 74 19 JE SHORT .0042CBA8
* 0042CB8F 8B08 MOV ECX,DWORD PTR DS:[EAX]
* 0042CB91 8379 04 00 CMP DWORD PTR DS:[ECX+0x4],0x0
* 0042CB95 76 11 JBE SHORT .0042CBA8
* 0042CB97 8B49 08 MOV ECX,DWORD PTR DS:[ECX+0x8]
* 0042CB9A 85C9 TEST ECX,ECX
* 0042CB9C 76 0A JBE SHORT .0042CBA8
* 0042CB9E 49 DEC ECX
* 0042CB9F 0FAF48 0C IMUL ECX,DWORD PTR DS:[EAX+0xC]
* 0042CBA3 0348 04 ADD ECX,DWORD PTR DS:[EAX+0x4]
* 0042CBA6 EB 02 JMP SHORT .0042CBAA
* 0042CBA8 33C9 XOR ECX,ECX
* 0042CBAA 894A 0C MOV DWORD PTR DS:[EDX+0xC],ECX
* 0042CBAD 85C0 TEST EAX,EAX
* 0042CBAF 74 16 JE SHORT .0042CBC7
* 0042CBB1 8B48 0C MOV ECX,DWORD PTR DS:[EAX+0xC]
* 0042CBB4 F7D9 NEG ECX
* 0042CBB6 894A 10 MOV DWORD PTR DS:[EDX+0x10],ECX
* 0042CBB9 8B00 MOV EAX,DWORD PTR DS:[EAX]
* 0042CBBB 83C0 28 ADD EAX,0x28
* 0042CBBE 8942 14 MOV DWORD PTR DS:[EDX+0x14],EAX
* 0042CBC1 B8 01000000 MOV EAX,0x1
* 0042CBC6 C3 RETN
* 0042CBC7 33C9 XOR ECX,ECX
* 0042CBC9 F7D9 NEG ECX
* 0042CBCB 894A 10 MOV DWORD PTR DS:[EDX+0x10],ECX
* 0042CBCE 8B00 MOV EAX,DWORD PTR DS:[EAX]
* 0042CBD0 83C0 28 ADD EAX,0x28
* 0042CBD3 8942 14 MOV DWORD PTR DS:[EDX+0x14],EAX
* 0042CBD6 B8 01000000 MOV EAX,0x1
* 0042CBDB C3 RETN
* 0042CBDC CC INT3
* 0042CBDD CC INT3
* 0042CBDE CC INT3
* 0042CBDF CC INT3
* 0042CBE0 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+0x4]
* 0042CBE4 8B48 10 MOV ECX,DWORD PTR DS:[EAX+0x10]
* 0042CBE7 8B50 0C MOV EDX,DWORD PTR DS:[EAX+0xC]
* 0042CBEA 51 PUSH ECX
* 0042CBEB 8B48 08 MOV ECX,DWORD PTR DS:[EAX+0x8]
* 0042CBEE 52 PUSH EDX
* 0042CBEF 8B50 04 MOV EDX,DWORD PTR DS:[EAX+0x4]
* 0042CBF2 8B00 MOV EAX,DWORD PTR DS:[EAX]
* 0042CBF4 51 PUSH ECX
* 0042CBF5 52 PUSH EDX
* 0042CBF6 50 PUSH EAX
* 0042CBF7 E8 E4FD0A00 CALL .004DC9E0
* 0042CBFC 83C4 14 ADD ESP,0x14
* 0042CBFF C3 RETN
* 0042CC00 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+0x4]
* 0042CC04 8B48 10 MOV ECX,DWORD PTR DS:[EAX+0x10]
* 0042CC07 8B50 0C MOV EDX,DWORD PTR DS:[EAX+0xC]
* 0042CC0A 51 PUSH ECX
* 0042CC0B 8B48 08 MOV ECX,DWORD PTR DS:[EAX+0x8]
* 0042CC0E 52 PUSH EDX
* 0042CC0F 8B50 04 MOV EDX,DWORD PTR DS:[EAX+0x4]
* 0042CC12 8B00 MOV EAX,DWORD PTR DS:[EAX]
* 0042CC14 51 PUSH ECX
* 0042CC15 52 PUSH EDX
* 0042CC16 50 PUSH EAX
* 0042CC17 E8 C4FF0A00 CALL .004DCBE0
* 0042CC1C 83C4 14 ADD ESP,0x14
* 0042CC1F C3 RETN
* 0042CC20 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+0x4]
* 0042CC24 8B08 MOV ECX,DWORD PTR DS:[EAX]
* 0042CC26 894C24 04 MOV DWORD PTR SS:[ESP+0x4],ECX
* 0042CC2A E9 71FB0A00 JMP .004DC7A0
* 0042CC2F CC INT3
* 0042CC30 56 PUSH ESI
* 0042CC31 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+0x8]
* 0042CC35 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 0042CC37 50 PUSH EAX
* 0042CC38 E8 63FB0A00 CALL .004DC7A0
* 0042CC3D D946 0C FLD DWORD PTR DS:[ESI+0xC]
* 0042CC40 D91C24 FSTP DWORD PTR SS:[ESP]
* 0042CC43 83EC 08 SUB ESP,0x8
* 0042CC46 D946 08 FLD DWORD PTR DS:[ESI+0x8]
* 0042CC49 D95C24 04 FSTP DWORD PTR SS:[ESP+0x4]
* 0042CC4D D946 04 FLD DWORD PTR DS:[ESI+0x4]
* 0042CC50 D91C24 FSTP DWORD PTR SS:[ESP]
* 0042CC53 50 PUSH EAX
* 0042CC54 E8 27680400 CALL .00473480
* 0042CC59 83C4 10 ADD ESP,0x10
* 0042CC5C B8 01000000 MOV EAX,0x1
* 0042CC61 5E POP ESI
* 0042CC62 C3 RETN
* 0042CC63 CC INT3
* 0042CC64 CC INT3
* 0042CC65 CC INT3
* 0042CC66 CC INT3
* 0042CC67 CC INT3
* 0042CC68 CC INT3
* 0042CC69 CC INT3 *
*/
namespace { // unnamed
/**
* Handle new lines and ruby.
*
* そ<>日、彼の言葉に耳を傾ける<E38191><EFBFBD>かった<E381A3> * ザールラント歴丹<E6ADB4><EFBFBD> 月二十日<r>グローセン州 ヘルフォルト区郊<E58CBA> *
* 僁<>な霋<E381AA>の後<E381AE>r><ruby text='まぶ<E381BE>>瞼</ruby>の裏を焼く陽光に気付いた<E38184> *
* 気<>く重<E3818F>ruby text='まぶ<E381BE>>瞼</ruby>を開け<E9968B><E38191>r>見覚えのある輪郭が瞳に<E79EB3>り込む<E8BEBC> *
* そ<>日、彼の言葉に耳を傾ける<E38191><EFBFBD>かった。――尊厳を捨てて媚<E381A6>る。それが生きることか――<E28095><E28095><EFBFBD>敗北したのた誰しも少年の声を聞かず、蔑み、そして冷笑してぁ<E381A6>。安寧の世がぁ<E3818C>までも続くと信じてぁ<E381A6>から。それでも、私<E38081>――。ザールラント歴丹<E6ADB4><EFBFBD> 月二十日<r>グローセン州 ヘルフォルト区郊外僅かな霋<E381AA>の後<E381AE>r><ruby text='まぶ<E381BE>>瞼</ruby>の裏を焼く陽光に気付いた。気<E38082>く重<E3818F>ruby text='まぶ<E381BE>>瞼</ruby>を開け<E9968B><E38191>r>見覚えのある輪郭が瞳に<E79EB3>り込む
*/
bool EscudeFilter(LPVOID data, size_t *size, HookParam *)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t *>(size);
StringCharReplacer(text, len, "<r>", 3, '\n');
if (cpp_strnstr(text, "<ruby", *len)) {
StringFilter(text, len, "</ruby>", 7);
StringFilterBetween(text, len, "<ruby", 5, "'>", 2);
}
return true;
}
LPCSTR _escudeltrim(LPCSTR text)
{
if (text && *text == '<')
for (auto p = text; (signed char)*p > 0; p++)
if (*p == '>')
return p + 1;
return text;
}
void SpecialHookEscude(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD arg1 = stack->stack[1];
if (!arg1 || (LONG)arg1 == -1 || ::IsBadWritePtr((LPVOID)arg1, 4)) // this is indispensable
return;
LPCSTR text = (LPCSTR)*(DWORD *)(arg1 + 0x20);
if (!text || ::IsBadWritePtr((LPVOID)text, 1) || !*text) // this is indispensable
return;
text = _escudeltrim(text);
if (!text)
return;
*data = (DWORD)text;
*len = ::strlen(text);
*split = *(DWORD *)arg1;
}
struct HookArgument
{
ULONG split;
//ULONG unknown1[3];
//LPCSTR text1; // 0x10 only for old games
ULONG unknown[7];
LPCSTR text; // 0x20
bool isValid() const { return Engine::isAddressWritable(text) && *text; }
Engine::TextRole role() const
{
if (split >= 0xff)
return Engine::OtherRole;
static ULONG maxSplit_ = 0;
if (split > maxSplit_)
maxSplit_ = split;
if (split == maxSplit_)
return Engine::ScenarioRole;
return Engine::NameRole; // scenario role is larger than name role
}
};
LPCSTR trimmedText;
bool hook_before(hook_stack*s,void* data, size_t* len,uintptr_t*role){
auto arg = (HookArgument *)s->stack[1];
if ((long)arg == -1 || !Engine::isAddressWritable(arg) || !arg->isValid())
return false;
trimmedText = _escudeltrim(arg->text);
* role = arg->role();
return write_string_overwrite(data,len,trimmedText);
}
void hook_after(hook_stack*s,void* data, size_t len){
static std::string data_;
data_=std::string((char*)data,len);
auto arg = (HookArgument *)s->stack[1];
if(trimmedText!=arg->text)
data_.insert(0,std::string(arg->text, trimmedText - arg->text));
arg->text=data_.c_str();
}
} // unnamed namespace
bool InsertEscudeHook()
{
const BYTE bytes[] = {
0x76, 0x0a, // 0042cb9c 76 0a jbe short .0042cba8
0x49, // 0042cb9e 49 dec ecx
0x0f,0xaf,0x48, 0x0c // 0042cb9f 0faf48 0c imul ecx,dword ptr ds:[eax+0xc]
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
//GROWL(addr);
if (!addr) {
ConsoleOutput("Escude: pattern not found");
return false;
}
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr) {
ConsoleOutput("Escude: enclosing function not found");
return false;
}
HookParam hp;
hp.address = addr;
hp.hook_before=hook_before;
hp.hook_after=hook_after;
hp.hook_font=F_TextOutA|F_GetTextExtentPoint32A;
hp.text_fun = SpecialHookEscude;
hp.filter_fun = EscudeFilter;
hp.type = USING_STRING|USING_SPLIT|NO_CONTEXT|EMBED_ABLE|EMBED_DYNA_SJIS; // NO_CONTEXT as this function is only called by one caller anyway
hp.newlineseperator=L"<r>";
ConsoleOutput("INSERT Escude");
return NewHook(hp, "Escude");
}
bool Escude::attach_function() {
return InsertEscudeHook();
}