LunaHook-mirror/LunaHook/engine32/Malie.cpp
恍兮惚兮 6a43cd5b86 pch
2024-05-06 23:31:54 +08:00

1655 lines
70 KiB
C++
Raw Permalink 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"Malie.h"
namespace { // unnamed Malie
/********************************************************************************************
Malie hook:
Process name is malie.exe.
This is the most complicate code I have made. Malie engine store text string in
linked list. We need to insert a hook to where it travels the list. At that point
EBX should point to a structure. We can find character at -8 and font size at +10.
Also need to enable ITH suppress function.
********************************************************************************************/
bool InsertMalieHook1()
{
const DWORD sig1 = 0x05e3c1;
enum { sig1_size = 3 };
DWORD i = SearchPattern(processStartAddress, processStopAddress - processStartAddress, &sig1, sig1_size);
if (!i) {
ConsoleOutput("MalieHook1: pattern i not exist");
return false;
}
const WORD sig2 = 0xc383;
enum { sig2_size = 2 };
DWORD j = i + processStartAddress + sig1_size;
i = SearchPattern(j, processStopAddress - j, &sig2, sig2_size);
//if (!j)
if (!i) { // jichi 8/19/2013: Change the condition fro J to I
ConsoleOutput("MalieHook1: pattern j not exist");
return false;
}
HookParam hp;
hp.address = j + i;
hp.offset=get_reg(regs::ebx);
hp.index = -0x8;
hp.split = get_reg(regs::ebx);
hp.split_index = 0x10;
hp.type = CODEC_UTF16|USING_SPLIT|DATA_INDIRECT|SPLIT_INDIRECT;
ConsoleOutput("INSERT MalieHook1");
return NewHook(hp, "Malie");
//RegisterEngineType(ENGINE_MALIE);
}
DWORD malie_furi_flag_; // jichi 8/20/2013: Make it global so that it can be reset
void SpecialHookMalie(hook_stack* stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t*len)
{
DWORD ch = stack->eax & 0xffff,
ptr = stack->edi;
*data = ch;
*len = 2;
if (malie_furi_flag_) {
DWORD index = stack->edx;
if (*(WORD *)(ptr + index * 2 - 2) < 0xa)
malie_furi_flag_ = 0;
}
else if (ch == 0xa) {
malie_furi_flag_ = 1;
len = 0;
}
*split = malie_furi_flag_;
}
bool InsertMalieHook2() // jichi 8/20/2013: Change return type to boolean
{
const BYTE bytes[] = {0x66,0x3d,0x1,0x0};
DWORD start = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!start) {
ConsoleOutput("MalieHook2: pattern not exist");
return false;
}
BYTE *ptr = (BYTE *)start;
while (true) {
if (*(WORD *)ptr == 0x3d66) {
ptr += 4;
if (ptr[0] == 0x75) {
ptr += ptr[1]+2;
continue;
}
if (*(WORD *)ptr == 0x850f) {
ptr += *(DWORD *)(ptr + 2) + 6;
continue;
}
}
break;
}
malie_furi_flag_ = 0; // reset old malie flag
HookParam hp;
hp.address = (DWORD)ptr + 4;
hp.offset=get_reg(regs::eax);
hp.text_fun = SpecialHookMalie;
hp.type = USING_SPLIT|CODEC_UTF16|NO_CONTEXT|USING_CHAR;
ConsoleOutput("INSERT MalieHook2");
return NewHook(hp, "Malie");
//RegisterEngineType(ENGINE_MALIE);
}
/**
* jichi 12/17/2013: Added for Electro Arms
* Observations from Electro Arms:
* 1. split = 0xC can handle most texts and its dwRetn is always zero
* 2. The text containing furigana needed to split has non-zero dwRetn when split = 0
*
* 3/15/2015: logic modified as the plus operation would create so many threads
*/
void SpecialHookMalie2(hook_stack* stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t*len)
{
//CC_UNUSED(data);
//*len = GetHookDataLength(*hp, esp_base, (DWORD)data);
*len = 2;
DWORD s1 = stack->stack[3], // base split, which is stable
s2 = stack->stack[0]; // used to split out furigana, but un stable
// http://www.binaryhexconverter.com/decimal-to-binary-converter
//enum : DWORD { mask = 0x14 };
*split = s1 + (s2 ? 1 : 0);
}
// static DWORD last_split; // FIXME: This makes the special function stateful
// DWORD s1 = *(DWORD *)esp_base; // current split at 0x0
// if (!s1)
// *split = last_split;
// else {
// DWORD s2 = *(DWORD *)(esp_base + 0xc); // second split
// *split = last_split = s1 + s2; // not sure if plus is a good way
// }
/**
* jichi 8/20/2013: Add hook for sweet light BRAVA!!
* See: http://www.hongfire.com/forum/printthread.php?t=36807&pp=10&page=680
*
* BRAVA!! /H code: "/HWN-4:C@1A3DF4:malie.exe"
* - addr: 1719796 = 0x1a3df4
* - text_fun: 0x0
* - function: 0
* - hook_len: 0
* - ind: 0
* - length_offset: 1
* - module: 751199171 = 0x2cc663c3
* - off: 4294967288 = 0xfffffff8L = -0x8
* - recover_len: 0
* - split: 12 = 0xc
* - split_ind: 0
* - type: 1106 = 0x452
*/
bool InsertMalie2Hook()
{
// 001a3dee 6900 70000000 imul eax,dword ptr ds:[eax],70
// 001a3df4 0200 add al,byte ptr ds:[eax] ; this is the place to hook
// 001a3df6 50 push eax
// 001a3df7 0069 00 add byte ptr ds:[ecx],ch
// 001a3dfa 0000 add byte ptr ds:[eax],al
const BYTE bytes1[] = {
0x40, // inc eax
0x89,0x56, 0x08, // mov dword ptr ds:[esi+0x8],edx
0x33,0xd2, // xor edx,edx
0x89,0x46, 0x04 // mov dword ptr ds:[esi+0x4],eax
};
ULONG range1 = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes1, sizeof(bytes1), processStartAddress, processStartAddress + range1);
//reladdr = 0x1a3df4;
if (!addr) {
//ITH_MSG(0, "Wrong1", "t", 0);
//ConsoleOutput("Not malie2 engine");
ConsoleOutput("Malie2Hook: pattern p not exist");
return false;
}
addr += sizeof(bytes1); // skip bytes1
//const BYTE bytes2[] = { 0x85, 0xc0 }; // test eax,eax
const WORD bytes2 = 0xc085; // test eax,eax
enum { range2 = 0x200 };
addr = MemDbg::findBytes(&bytes2, sizeof(bytes2), addr, addr + range2);
if (!addr) {
//ConsoleOutput("Not malie2 engine");
ConsoleOutput("Malie2Hook: pattern q not exist");
return false;
}
HookParam hp;
hp.address = addr;
hp.offset=get_reg(regs::eax);
//hp.split = 0xc; // jichi 12/17/2013: Subcontext removed
//hp.split = -0xc; // jichi 12/17/2013: This could split the furigana, but will mess up the text
//hp.type = USING_SPLIT|CODEC_UTF16|NO_CONTEXT;
// jichi 12/17/2013: Need extern func for Electro Arms
// Though the hook parameter is quit similar to Malie, the original extern function does not work
hp.type = USING_SPLIT|NO_CONTEXT|CODEC_UTF16|USING_CHAR;
hp.text_fun = SpecialHookMalie2;
ConsoleOutput("INSERT Malie2");
return NewHook(hp, "Malie2");
//GROWL_DWORD2(hp.address, reladdr);
//RegisterEngineType(ENGINE_MALIE);
}
// jichi 2/8/3014: Return the beginning and the end of the text
// Remove the leading illegal characters
enum { _MALIE3_MAX_LENGTH = VNR_TEXT_CAPACITY };
LPCWSTR _Malie3LTrim(LPCWSTR p)
{
if (p)
for (int count = 0; count < _MALIE3_MAX_LENGTH; count++,
p++)
if (p[0] == L'v' && p[1] == L'_') { // ex. v_akr0001, v_mzk0001
p += 9;
return p; // must return otherwise trimming more will break the ITH repetition elimination
} else if (p[0] >= 0xa) // ltrim illegal characters less than 0xa
return p;
return nullptr;
}
// Remove the trailing illegal characters
LPCWSTR _Malie3RTrim(LPCWSTR p)
{
if (p)
for (int count = 0; count < _MALIE3_MAX_LENGTH; count++,
p--)
if (p[-1] >= 0xa) { // trim illegal characters less than 0xa
if (p[-1] >= L'0' && p[-1] <= L'9'&& p[-1-7] == L'_')
p -= 9;
else
return p;
}
return nullptr;
}
// Example section in memory:
// 0D7D7E00 07 00 08 00 76 00 5F 00 7A 00 65 00 70 00 30 00 v_zep0
// 0D7D7E10 30 00 37 00 35 00 00 00 0C 30 42 30 41 30 01 30 075.「あぁ<E38182>// 0D7D7E20 41 30 26 20 26 20 07 00 09 00 07 00 06 00 07 00 ぁ…….
// 0D7D7E30 08 00 76 00 5F 00 7A 00 65 00 70 00 30 00 30 00 v_zep00
// 0D7D7E40 37 00 36 00 00 00 46 30 01 30 42 30 01 30 41 30 76.぀<>あ、ぁ
// 0D7D7E50 41 30 41 30 26 20 26 20 26 20 26 20 01 30 63 30 ぁぁ…………、っ
// 0D7D7E60 07 00 09 00 0D 30 07 00 06 00 0A 00 0A 00 00 30 .<2E>..
// 0D7D7E70 16 60 44 30 01 30 16 60 44 30 01 30 4A 30 5E 30 怖い、怖い、お<E38081>// 0D7D7E80 7E 30 57 30 44 30 02 30 55 4F 4C 30 16 60 44 30 ましい。何が怖い
// 0D7D7E90 6E 30 4B 30 55 30 48 30 01 30 06 52 4B 30 89 30 のかさえ、<E38188>から
// 0D7D7EA0 6A 30 44 30 02 30 07 00 06 00 0A 00 00 30 8B 89 な぀. <>// 0D7D7EB0 8B 30 6A 30 88 30 02 30 8B 89 8B 30 6A 30 02 30 るなよ。見るな<E3828B>// 0D7D7EC0 07 00 06 00 8B 89 8B 30 6A 30 01 30 8B 89 8B 30 見るな、見る
// 0D7D7ED0 6A 30 8B 89 8B 30 6A 30 8B 89 8B 30 6A 30 01 30 な見るな見るな<E3828B>// 0D7D7EE0 1F 75 4D 30 66 30 66 30 AA 60 44 30 4B 30 88 30 生きてて悪ぁ<E682AA><E38181>// 0D7D7EF0 02 30 C5 60 51 30 6A 30 44 30 63 30 66 30 07 00 。情けなぁ<E381AA>
// 0D7D7F00 01 00 E4 55 0A 00 8F 30 89 30 00 00 46 30 6A 30 嗤.わら.ぁ<>
// 0D7D7F10 88 30 02 30 07 00 06 00 BE 7C 00 4E 6F 67 6A 30 よ<>精一杯な
// 0D7D7F20 93 30 60 30 8B 89 03 90 57 30 66 30 4F 30 8C 30 んだ見送<E8A68B>てくれ
// 0D7D7F30 02 30 4A 30 58 98 44 30 57 30 7E 30 59 30 01 30 。お願いします<E381BE>// 0D7D7F40 60 30 4B 30 89 30 69 30 46 30 4B 30 5D 30 6E 30 <20>からどぁ<E381A9><EFBFBD>
// 0D7D7F50 EE 76 92 30 84 30 81 30 66 30 01 30 4F 30 60 30 目をやめて、く<E38081>
// 0D7D7F60 55 30 44 30 01 30 5D 30 93 30 6A 30 02 30 07 00 さい、そんな<E38293>
// 0D7D7F70 06 00 0A 00 00 30 07 00 01 00 BA 87 50 5B 0A 00 . <>
// 0D7D7F80 59 30 4C 30 00 00 8B 30 88 30 46 30 6A 30 EE 76 すが.るよぁ<E38288>
// 0D7D7F90 67 30 00 25 00 25 07 00 06 00 BF 30 01 30 B9 30 で──タ、ス
// 0D7D7FA0 01 30 B1 30 01 30 C6 30 01 30 6A 30 93 30 66 30 、ケ、テ、なんて
// 0D7D7FB0 02 30 07 00 06 00 00 00 00 00 00 00 00 00 00 00 <20>.....
// 0D7D7FC0 FC D8 C0 22 00 00 00 80 74 00 00 00 00 00 00 00 .耀t...
//
// Return the end of the line
LPCWSTR _Malie3GetEOL(LPCWSTR p)
{
if (p)
for (int count = 0; count < _MALIE3_MAX_LENGTH; count++,
p++)
switch (*p) {
case 0:
case 0xa: // stop at \0, or \n where the text after 0xa is furigana
return p;
case 0x7:
// \x07\x00\x01\x00 is used to split furigana, which we want to keep
// \x07\x00\x04\x00 is used to split sentences, observed in シルヴァリオ ヴェンヂ<E383B3><EFBFBD>
// \x07\x00\x06\x00 is used to split paragraph, observed in シルヴァリオ ヴェンヂ<E383B3><EFBFBD>
if (p[1] < 0xa && p[1] != 0x1)
return p;
}
return nullptr;
}
/**
* jichi 3/8/2014: Add hook for 相州戦神館學<E9A4A8>八命陣
* See: http://sakuradite.com/topic/157
* check 0x5b51ed for ecx+edx*2
* Also need to skip furigana.
*/
void SpecialHookMalie3(hook_stack* stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t*len)
{
//CC_UNUSED(split);
DWORD ecx = stack->ecx, // *(DWORD *)(esp_base + pusha_ecx_off - 4),
edx = stack->edx; // *(DWORD *)(esp_base + pusha_edx_off - 4);
//*data = ecx + edx*2; // [ecx+edx*2];
//*len = wcslen((LPCWSTR)data) << 2;
// There are garbage characters
LPCWSTR start = _Malie3LTrim((LPCWSTR)(ecx + edx*2)),
stop = _Malie3RTrim(_Malie3GetEOL(start));
*data = (DWORD)start;
*len = max(0, stop - start) * 2;
*split = FIXED_SPLIT_VALUE;
//GROWL_DWORD5((DWORD)start, (DWORD)stop, *len, (DWORD)*start, (DWORD)_Malie3GetEOL(start));
}
/**
* jichi 8/20/2013: Add hook for 相州戦神館學<E9A4A8>八命陣
* See: http://sakuradite.com/topic/157
* Credits: @ok123
*
* Debugging method: insert hardware breakpoint into text
* There are four matches of text in the memory
*
* Sample game: シルヴァリオ ヴェンヂ<E383B3><EFBFBD>
* 0065478B 90 NOP
* 0065478C 90 NOP
* 0065478D 90 NOP
* 0065478E 90 NOP
* 0065478F 90 NOP
* 00654790 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+0x4]
* 00654794 56 PUSH ESI
* 00654795 57 PUSH EDI
* 00654796 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
* 00654799 8B08 MOV ECX,DWORD PTR DS:[EAX]
* 0065479B 33F6 XOR ESI,ESI
* 0065479D 66:8B3451 MOV SI,WORD PTR DS:[ECX+EDX*2] ; jichi: text accessed here
* 006547A1 42 INC EDX
* 006547A2 8970 04 MOV DWORD PTR DS:[EAX+0x4],ESI
* 006547A5 8950 08 MOV DWORD PTR DS:[EAX+0x8],EDX
* 006547A8 8B50 04 MOV EDX,DWORD PTR DS:[EAX+0x4]
* 006547AB 83FA 01 CMP EDX,0x1
* 006547AE 75 2C JNZ SHORT malie.006547DC
* 006547B0 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
* 006547B3 33F6 XOR ESI,ESI
* 006547B5 66:8B3451 MOV SI,WORD PTR DS:[ECX+EDX*2]
* 006547B9 42 INC EDX
* 006547BA 8970 04 MOV DWORD PTR DS:[EAX+0x4],ESI
* 006547BD 33F6 XOR ESI,ESI
* 006547BF 8950 08 MOV DWORD PTR DS:[EAX+0x8],EDX
* 006547C2 66:8B3451 MOV SI,WORD PTR DS:[ECX+EDX*2]
* 006547C6 8970 04 MOV DWORD PTR DS:[EAX+0x4],ESI
* 006547C9 42 INC EDX
* 006547CA 33F6 XOR ESI,ESI
* 006547CC 8950 08 MOV DWORD PTR DS:[EAX+0x8],EDX
* 006547CF 66:8B3451 MOV SI,WORD PTR DS:[ECX+EDX*2]
* 006547D3 42 INC EDX
* 006547D4 8970 04 MOV DWORD PTR DS:[EAX+0x4],ESI
* 006547D7 8950 08 MOV DWORD PTR DS:[EAX+0x8],EDX
* 006547DA ^EB BF JMP SHORT malie.0065479B
* 006547DC 83FA 02 CMP EDX,0x2
* 006547DF 0F84 59010000 JE malie.0065493E
* 006547E5 83FA 03 CMP EDX,0x3
* 006547E8 75 12 JNZ SHORT malie.006547FC
* 006547EA 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
* 006547ED 33F6 XOR ESI,ESI
* 006547EF 66:8B3451 MOV SI,WORD PTR DS:[ECX+EDX*2]
* 006547F3 42 INC EDX
* 006547F4 8970 04 MOV DWORD PTR DS:[EAX+0x4],ESI
* 006547F7 8950 08 MOV DWORD PTR DS:[EAX+0x8],EDX
* 006547FA ^EB 9F JMP SHORT malie.0065479B
* 006547FC 83FA 04 CMP EDX,0x4
* 006547FF 0F84 39010000 JE malie.0065493E
* 00654805 83FA 07 CMP EDX,0x7
* 00654808 0F85 27010000 JNZ malie.00654935
* 0065480E 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
* 00654811 33F6 XOR ESI,ESI
* 00654813 66:8B3451 MOV SI,WORD PTR DS:[ECX+EDX*2]
* 00654817 8970 04 MOV DWORD PTR DS:[EAX+0x4],ESI
* 0065481A 8D72 01 LEA ESI,DWORD PTR DS:[EDX+0x1]
* 0065481D 8B50 04 MOV EDX,DWORD PTR DS:[EAX+0x4]
* 00654820 8970 08 MOV DWORD PTR DS:[EAX+0x8],ESI
* 00654823 8D7A FF LEA EDI,DWORD PTR DS:[EDX-0x1]
* 00654826 83FF 3B CMP EDI,0x3B
* 00654829 ^0F87 79FFFFFF JA malie.006547A8
* 0065482F 33D2 XOR EDX,EDX
* 00654831 8A97 9C496500 MOV DL,BYTE PTR DS:[EDI+0x65499C]
* 00654837 FF2495 80496500 JMP DWORD PTR DS:[EDX*4+0x654980]
* 0065483E 8B50 0C MOV EDX,DWORD PTR DS:[EAX+0xC]
* 00654841 85D2 TEST EDX,EDX
* 00654843 0F8F 2B010000 JG malie.00654974
* 00654849 33D2 XOR EDX,EDX
* 0065484B 66:8B1471 MOV DX,WORD PTR DS:[ECX+ESI*2]
* 0065484F 46 INC ESI
* 00654850 85D2 TEST EDX,EDX
* 00654852 8950 04 MOV DWORD PTR DS:[EAX+0x4],EDX
* 00654855 8970 08 MOV DWORD PTR DS:[EAX+0x8],ESI
* 00654858 0F84 E0000000 JE malie.0065493E
* 0065485E 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
* 00654861 33F6 XOR ESI,ESI
* 00654863 66:8B3451 MOV SI,WORD PTR DS:[ECX+EDX*2]
* 00654867 42 INC EDX
* 00654868 8950 08 MOV DWORD PTR DS:[EAX+0x8],EDX
* 0065486B 8BD6 MOV EDX,ESI
* 0065486D 85D2 TEST EDX,EDX
* 0065486F 8970 04 MOV DWORD PTR DS:[EAX+0x4],ESI
* 00654872 ^75 EA JNZ SHORT malie.0065485E
* 00654874 8B50 08 MOV EDX,DWORD PTR DS:[EAX+0x8]
*/
bool InsertMalie3Hook()
{
// i.e. 8b44240456578b50088b0833f6668b345142
const BYTE bytes[] = {
// 0x90 nop
0x8b,0x44,0x24, 0x04, // 5b51e0 mov eax,dword ptr ss:[esp+0x4] ; jichi: function starts
0x56, // 5b51e4 push esi
0x57, // 5b51e5 push edi
0x8b,0x50, 0x08, // 5b51e6 mov edx,dword ptr ds:[eax+0x8]
0x8b,0x08, // 5b51e9 mov ecx,dword ptr ds:[eax]
0x33,0xf6, // 5b51eb xor esi,esi
0x66,0x8b,0x34,0x51, // 5b51ed mov si,word ptr ds:[ecx+edx*2] // jichi: hook here
0x42 // 5b51f1 inc edx
};
enum {addr_offset = 0x5b51ed - 0x5b51e0};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr) {
ConsoleOutput("Malie3: pattern not found");
return false;
}
HookParam hp;
hp.address = addr + addr_offset;
//GROWL(hp.address);
//hp.address = 0x5b51ed;
//hp.address = 0x5b51f1;
//hp.address = 0x5b51f2;
// jichi 3/15/2015: Remove 0704 in シルヴァリオ ヴェンッ<E383B3>
hp.filter_fun = IllegalCharsFilterW; // remove illegal control chars such as 0x07,0x01
hp.text_fun = SpecialHookMalie3;
hp.type = USING_SPLIT|NO_CONTEXT|CODEC_UTF16;
//hp.filter_fun = Malie3Filter;
ConsoleOutput("INSERT Malie3");
return NewHook(hp, "Malie3");
}
bool InsertMalie4Hook()
{
// i.e. 50 8B 45 10 D9 9F ?? ?? ?? ?? 0F B7 04 58 50 51 E8 ?? ?? ?? ?? 8B 45 14 83 C4 10
const BYTE bytes[] = {
0x50, // 65904E | 50 | push eax | mireado: pattern starts
0x8B,0x45,0x10, // 65904F | 8B 45 10 | mov eax,dword ptr ss:[ebp+10] |
0xD9,0x9F,XX4, // 659052 | D9 9F E8 6B 87 00 | fstp dword ptr ds:[edi+876BE8] |
0x0F,0xB7,0x04,0x58, // 659058 | 0F B7 04 58 | movzx eax,word ptr ds:[eax+ebx*2] |
0x50, // 65905C | 50 | push eax |
0x51, // 65905D | 51 | push ecx |
0xE8,XX4, // 65905E | E8 DD 1D EA FF | call malie.4FAE40 | mireado: hook here
0x8B,0x45,0x14, // 659063 | 8B 45 14 | mov eax,dword ptr ss:[ebp+14] |
0x83,0xC4,0x10 // 659066 | 83 C4 10 | add esp,10 |
};
enum {addr_offset = 0x65905E - 0x65904E};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr) {
ConsoleOutput("Malie4: pattern not found");
return false;
}
HookParam hp;
hp.address = addr + addr_offset;
hp.offset=get_reg(regs::eax); // pusha_eax_off - 4
//hp.split = 0xc; // jichi 12/17/2013: Subcontext removed
//hp.type = USING_SPLIT|CODEC_UTF16|NO_CONTEXT;
// jichi 12/17/2013: Need extern func for Electro Arms
// Though the hook parameter is quit similar to Malie, the original extern function does not work
hp.split = get_reg(regs::edx); // jichi 12/17/2013: This could split the furigana, but will mess up the text
hp.type = USING_SPLIT|NO_CONTEXT|CODEC_UTF16;
ConsoleOutput("INSERT Malie4");
return NewHook(hp, "Malie4");
//GROWL_DWORD2(hp.address, reladdr);
//RegisterEngineType(ENGINE_MALIE);
}
// Artikash 1/19/2019: works on https://vndb.org/r52326
bool InsertMalie5Hook()
{
const BYTE bytes[] = {
0x8b, 0x49, 0x10, // mov ecx,[ecx+10]
0x03, 0x08, // add ecx,[eax]
0x51 // push ecx
};
if (DWORD addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress))
{
ConsoleOutput("INSERT Malie5");
HookParam hp;
hp.address = addr + 5;
hp.offset=get_reg(regs::ecx);
hp.type = CODEC_UTF16 | USING_STRING | NO_CONTEXT;
return NewHook(hp, "Malie5");
}
ConsoleOutput("Malie5 pattern not found");
return false;
}
// jichi 3/12/2015: Return guessed Malie engine year
//int GetMalieYear()
//{
// if (Util::SearchResourceString(L"2013 light"))
// return 2013;
// if (Util::SearchResourceString(L"2014 light"))
// return 2014;
// return 2015;
//}
} // unnamed Malie
bool InsertMalieHook()
{
if (Util::CheckFile(L"tools.dll"))
return InsertMalieHook1(); // jichi 3/5/2015: For old light games such as Dies irae.
else { // For old Malie games before 2015
// jichi 8/20/2013: Add hook for sweet light engine
// Insert both malie and malie2 hook.
bool ok = false;
// jichi 3/12/2015: Disable MalieHook2 which will crash シルヴァリオ ヴェンッ<E383B3>
//if (!Util::CheckFile(L"gdiplus.dll"))
if (Util::CheckFile(L"System\\*")) { // Insert old Malie hook. There are usually System/cursor.cur
ok = InsertMalieHook2() || ok;
ok = InsertMalie2Hook() || ok; // jichi 8/20/2013
}
// The main disadvantage of Malie3 is that it cannot find character name
ok = InsertMalie3Hook() || ok; // jichi 3/7/2014
ok = InsertMalie4Hook() || ok;
ok = InsertMalie5Hook() || ok;
return ok;
}
}
namespace { // unnamed
namespace ScenarioHook {
namespace Private {
/**
* Sample game: シルヴァリオ ヴェンデッタ
*
* 0706: long pause, text separator
* 0704: short pause
* 0708: voice start.
* 0701: ruby start, 0a as separator
*
* Sample plain unvoiced text:
*
* 0706 is used as pause char.
*
* 01FFF184 00 30 2A 8A 8C 30 8B 30 21 6B 6E 30 27 59 75 65  訪れる次の大敵
* 01FFF194 00 25 00 25 21 6B 6E 30 0D 4E 78 5E 02 30 21 6B ──次の不幸。次
* 01FFF1A4 6E 30 E6 82 E3 96 02 30 21 6B 6E 30 34 78 C5 6E の苦難。次の破滅
* 01FFF1B4 02 30 07 00 06 00 0A 00 00 30 B4 63 7F 30 D6 53 。. 掴み取
* 01FFF1C4 63 30 5F 30 6F 30 5A 30 6E 30 2A 67 65 67 6F 30 ったはずの未来は
* 01FFF1D4 97 66 D2 9E 6B 30 55 87 7E 30 8C 30 5F 30 7E 30 暗黒に蝕まれたま
* 01FFF1E4 7E 30 9A 7D 4C 88 57 30 66 30 44 30 4F 30 02 30 ま続行していく。
* 01FFF1F4 07 00 06 00 0A 00 00 30 80 30 57 30 8D 30 4B 62 . むしろ手
* 01FFF204 6B 30 57 30 5F 30 47 59 E1 8D 92 30 7C 54 73 30 にした奇跡を呼び
* 01FFF214 34 6C 6B 30 01 30 88 30 8A 30 4A 30 5E 30 7E 30 水に、よりおぞま
* 01FFF224 57 30 44 30 B0 65 5F 30 6A 30 66 8A F4 7D 92 30 しい新たな試練を
* 01FFF234 44 7D 7F 30 BC 8F 93 30 67 30 4B 90 7D 54 92 30 組み込んで運命を
* 01FFF244 C6 99 D5 52 55 30 5B 30 8B 30 6E 30 60 30 02 30 駆動させるのだ。
* 01FFF254 07 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 ......
* 01FFF264 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
* 01FFF274 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
* 01FFF284 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
* 01FFF294 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
* 01FFF2A4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
*
* Mixed unvoiced text and voiced text list:
* 01FFF184 00 30 1C 20 DD 52 29 52 1D 20 4B 30 89 30 6F 30  “勝利”からは
* 01FFF194 03 90 52 30 89 30 8C 30 6A 30 44 30 02 30 07 00 逃げられない。
* 01FFF1A4 06 00 0A 00 00 30 1C 20 DD 52 29 52 1D 20 4B 30 . “勝利”か
* 01FFF1B4 89 30 6F 30 03 90 52 30 89 30 8C 30 6A 30 44 30 らは逃げられない
* 01FFF1C4 02 30 07 00 06 00 0A 00 00 30 1C 20 DD 52 29 52 。. “勝利
* 01FFF1D4 1D 20 4B 30 89 30 6F 30 03 90 52 30 89 30 8C 30 ”からは逃げられ
* 01FFF1E4 6A 30 44 30 02 30 07 00 06 00 0A 00 0A 00 07 00 ない。..
* 01FFF1F4 08 00 76 00 5F 00 76 00 6E 00 64 00 30 00 30 00 v_vnd00
* 01FFF204 30 00 31 00 00 00 0C 30 6A 30 89 30 70 30 00 25 01.「ならば─
* 01FFF214 00 25 00 25 00 25 0D 30 07 00 09 00 07 00 06 00 ───」.
* 01FFF224 0A 00 0A 00 00 30 00 25 00 25 55 30 42 30 01 30 .. ──さあ、
* 01FFF234 69 30 46 30 59 30 8B 30 4B 30 1F FF 07 00 06 00 どうするか?
* 01FFF244 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
* 01FFF254 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
* 01FFF264 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........
*
* Sample voiced text:
*
* 0269F184 07 00 08 00 76 00 5F 00 7A 00 65 00 70 00 30 00 v_zep0
* 0269F194 30 00 30 00 31 00 00 00 1C 20 DD 52 29 52 1D 20 001.“勝利”
* 0269F1A4 68 30 6F 30 01 30 55 4F 60 30 1F FF 07 00 09 00 とは、何だ?.
* 0269F1B4 07 00 06 00 0A 00 0A 00 07 00 08 00 76 00 5F 00 ..v_
* 0269F1C4 7A 00 65 00 70 00 30 00 30 00 30 00 32 00 00 00 zep0002.
* 0269F1D4 1C 20 04 68 49 51 1D 20 68 30 6F 30 01 30 55 4F “栄光”とは、何
* 0269F1E4 60 30 1F FF 07 00 09 00 07 00 06 00 0A 00 0A 00 だ?...
* 0269F1F4 07 00 08 00 76 00 5F 00 7A 00 65 00 70 00 30 00 v_zep0
* 0269F204 30 00 30 00 33 00 00 00 5D 30 8C 30 92 30 97 5F 003.それを得
* 0269F214 8C 30 70 30 01 30 55 4F 82 30 31 59 8F 30 5A 30 れば、何も失わず
* 0269F224 6B 30 08 6E 80 30 6E 30 60 30 8D 30 46 30 4B 30 に済むのだろうか
* 0269F234 07 00 09 00 07 00 06 00 0A 00 0A 00 07 00 08 00 ...
* 0269F244 76 00 5F 00 7A 00 65 00 70 00 30 00 30 00 30 00 v_zep000
* 0269F254 34 00 00 00 51 65 48 30 8B 30 6E 30 4B 30 02 30 4.救えるのか。
* 0269F264 88 5B 8C 30 8B 30 6E 30 4B 30 02 30 2C 67 53 5F 守れるのか。本当
* 0269F274 6B 30 01 30 78 5E 5B 30 6B 30 6A 30 8C 30 8B 30 に、幸せになれる
* 0269F284 6E 30 60 30 8D 30 46 30 4B 30 07 00 09 00 07 00 のだろうか.
* 0269F294 06 00 00 00 00 00 00 00 D1 01 00 00 8C F3 69 02 ...Ǒ.ɩ
*
* Ruby:
*
* 01FDF2B4 63 30 5F 30 07 00 01 00 14 90 EF 7A 0A 00 68 30 った途端.と
* 01FDF2C4 5F 30 93 30 00 00 01 30 06 90 6B 30 40 62 09 67 たん.、逆に所有
*
* Pause without 0a:
*
* 0271F184 07 00 08 00 76 00 5F 00 7A 00 65 00 70 00 30 00 v_zep0
* 0271F194 30 00 34 00 34 00 00 00 00 30 51 30 8C 30 69 30 044. けれど
* 0271F1A4 00 25 00 25 07 00 09 00 07 00 06 00 07 00 08 00 ──.
* 0271F1B4 76 00 5F 00 7A 00 65 00 70 00 30 00 30 00 34 00 v_zep004
* 0271F1C4 35 00 00 00 5D 30 8C 30 67 30 82 30 01 30 88 5B 5.それでも、守
* 0271F1D4 89 30 6A 30 51 30 8C 30 70 30 6A 30 89 30 6A 30 らなければならな
* 0271F1E4 44 30 50 5B 4C 30 FA 51 65 67 5F 30 4B 30 89 30 い子が出来たから
* 0271F1F4 02 30 07 00 09 00 07 00 06 00 07 00 04 00 00 30 。. 
* 0271F204 07 00 08 00 76 00 5F 00 7A 00 65 00 70 00 30 00 v_zep0
* 0271F214 30 00 34 00 36 00 00 00 7C 5F 73 59 92 30 51 65 046.彼女を救
* 0271F224 46 30 5F 30 81 30 6B 30 01 30 53 30 6E 30 61 30 うために、このち
* 0271F234 63 30 7D 30 51 30 6A 30 7D 54 92 30 F8 61 51 30 っぽけな命を懸け
* 0271F244 8B 30 68 30 93 8A 63 30 5F 30 02 30 86 30 48 30 ると誓った。ゆえ
*
* Scenario caller: 4637bf
*
* 0046377D 90 NOP
* 0046377E 90 NOP
* 0046377F 90 NOP
* 00463780 81EC 00080000 SUB ESP,0x800
* 00463786 56 PUSH ESI
* 00463787 8BB424 08080000 MOV ESI,DWORD PTR SS:[ESP+0x808]
* 0046378E 8B46 1C MOV EAX,DWORD PTR DS:[ESI+0x1C]
* 00463791 8B88 68020000 MOV ECX,DWORD PTR DS:[EAX+0x268]
* 00463797 57 PUSH EDI
* 00463798 51 PUSH ECX
* 00463799 E8 D200FFFF CALL malie.00453870
* 0046379E 8BBC24 14080000 MOV EDI,DWORD PTR SS:[ESP+0x814]
* 004637A5 68 C06C4100 PUSH malie.00416CC0
* 004637AA 8D5424 10 LEA EDX,DWORD PTR SS:[ESP+0x10]
* 004637AE 57 PUSH EDI
* 004637AF 52 PUSH EDX
* 004637B0 E8 AB041F00 CALL malie.00653C60
* 004637B5 8D4424 18 LEA EAX,DWORD PTR SS:[ESP+0x18]
* 004637B9 50 PUSH EAX
* 004637BA E8 21031F00 CALL malie.00653AE0 ; jichi: scenario caller
* 004637BF 8B4E 1C MOV ECX,DWORD PTR DS:[ESI+0x1C]
* 004637C2 57 PUSH EDI
* 004637C3 8981 68020000 MOV DWORD PTR DS:[ECX+0x268],EAX
* 004637C9 E8 32E61E00 CALL malie.00651E00
* 004637CE 83C4 18 ADD ESP,0x18
* 004637D1 33D2 XOR EDX,EDX
* 004637D3 85C0 TEST EAX,EAX
* 004637D5 8B46 1C MOV EAX,DWORD PTR DS:[ESI+0x1C]
* 004637D8 0F9FC2 SETG DL
* 004637DB 5F POP EDI
* 004637DC 5E POP ESI
* 004637DD 8990 7C020000 MOV DWORD PTR DS:[EAX+0x27C],EDX
* 004637E3 81C4 00080000 ADD ESP,0x800
* 004637E9 C3 RETN
* 004637EA 90 NOP
* 004637EB 90 NOP
* 004637EC 90 NOP
*
* Name caller: 46382e
*
* 004637EB 90 NOP
* 004637EC 90 NOP
* 004637ED 90 NOP
* 004637EE 90 NOP
* 004637EF 90 NOP
* 004637F0 81EC 00080000 SUB ESP,0x800
* 004637F6 56 PUSH ESI
* 004637F7 8BB424 08080000 MOV ESI,DWORD PTR SS:[ESP+0x808]
* 004637FE 8B46 1C MOV EAX,DWORD PTR DS:[ESI+0x1C]
* 00463801 8B88 6C020000 MOV ECX,DWORD PTR DS:[EAX+0x26C]
* 00463807 51 PUSH ECX
* 00463808 E8 6300FFFF CALL malie.00453870
* 0046380D 8B9424 10080000 MOV EDX,DWORD PTR SS:[ESP+0x810]
* 00463814 68 C06C4100 PUSH malie.00416CC0
* 00463819 52 PUSH EDX
* 0046381A 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+0x10]
* 0046381E 50 PUSH EAX
* 0046381F E8 3C041F00 CALL malie.00653C60
* 00463824 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+0x14]
* 00463828 51 PUSH ECX
* 00463829 E8 B2021F00 CALL malie.00653AE0 ; jichi: name
* 0046382E 8B56 1C MOV EDX,DWORD PTR DS:[ESI+0x1C]
* 00463831 83C4 14 ADD ESP,0x14
* 00463834 8982 6C020000 MOV DWORD PTR DS:[EDX+0x26C],EAX
* 0046383A 5E POP ESI
* 0046383B 81C4 00080000 ADD ESP,0x800
* 00463841 C3 RETN
* 00463842 90 NOP
* 00463843 90 NOP
* 00463844 90 NOP
*
* History caller: 418d0b
*
* 00418C9D 90 NOP
* 00418C9E 90 NOP
* 00418C9F 90 NOP
* 00418CA0 81EC 00080000 SUB ESP,0x800
* 00418CA6 53 PUSH EBX
* 00418CA7 56 PUSH ESI
* 00418CA8 57 PUSH EDI
* 00418CA9 6A 6C PUSH 0x6C
* 00418CAB FF15 20256900 CALL DWORD PTR DS:[<&MSVCRT.malloc>] ; msvcrt.malloc
* 00418CB1 8BD8 MOV EBX,EAX
* 00418CB3 83C4 04 ADD ESP,0x4
* 00418CB6 85DB TEST EBX,EBX
* 00418CB8 0F84 D1000000 JE malie.00418D8F
* 00418CBE 8BB424 10080000 MOV ESI,DWORD PTR SS:[ESP+0x810]
* 00418CC5 33C0 XOR EAX,EAX
* 00418CC7 B9 1B000000 MOV ECX,0x1B
* 00418CCC 8BFB MOV EDI,EBX
* 00418CCE F3:AB REP STOS DWORD PTR ES:[EDI]
* 00418CD0 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 00418CD2 68 C06C4100 PUSH malie.00416CC0
* 00418CD7 50 PUSH EAX
* 00418CD8 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+0x14]
* 00418CDC 51 PUSH ECX
* 00418CDD E8 7EAF2300 CALL malie.00653C60
* 00418CE2 8D5424 18 LEA EDX,DWORD PTR SS:[ESP+0x18]
* 00418CE6 52 PUSH EDX
* 00418CE7 E8 F4AD2300 CALL malie.00653AE0
* 00418CEC 8903 MOV DWORD PTR DS:[EBX],EAX
* 00418CEE 8B46 04 MOV EAX,DWORD PTR DS:[ESI+0x4]
* 00418CF1 68 C06C4100 PUSH malie.00416CC0
* 00418CF6 50 PUSH EAX
* 00418CF7 8D4C24 24 LEA ECX,DWORD PTR SS:[ESP+0x24]
* 00418CFB 51 PUSH ECX
* 00418CFC E8 5FAF2300 CALL malie.00653C60
* 00418D01 8D5424 28 LEA EDX,DWORD PTR SS:[ESP+0x28]
* 00418D05 52 PUSH EDX
* 00418D06 E8 D5AD2300 CALL malie.00653AE0 ; jichi: history caller
* 00418D0B 8943 04 MOV DWORD PTR DS:[EBX+0x4],EAX
* 00418D0E 8B46 08 MOV EAX,DWORD PTR DS:[ESI+0x8]
* 00418D11 83C4 20 ADD ESP,0x20
* 00418D14 85C0 TEST EAX,EAX
* 00418D16 75 05 JNZ SHORT malie.00418D1D
* 00418D18 B8 0CEF7000 MOV EAX,malie.0070EF0C
* 00418D1D 50 PUSH EAX
* 00418D1E E8 3D6F2300 CALL malie.0064FC60
* 00418D23 8943 08 MOV DWORD PTR DS:[EBX+0x8],EAX
* 00418D26 8B46 0C MOV EAX,DWORD PTR DS:[ESI+0xC]
* 00418D29 83C4 04 ADD ESP,0x4
* 00418D2C 85C0 TEST EAX,EAX
* 00418D2E 75 05 JNZ SHORT malie.00418D35
* 00418D30 B8 0CEF7000 MOV EAX,malie.0070EF0C
* 00418D35 50 PUSH EAX
* 00418D36 E8 256F2300 CALL malie.0064FC60
* 00418D3B 8943 0C MOV DWORD PTR DS:[EBX+0xC],EAX
* 00418D3E 8B46 60 MOV EAX,DWORD PTR DS:[ESI+0x60]
* 00418D41 8943 60 MOV DWORD PTR DS:[EBX+0x60],EAX
* 00418D44 8B4E 64 MOV ECX,DWORD PTR DS:[ESI+0x64]
* 00418D47 894B 64 MOV DWORD PTR DS:[EBX+0x64],ECX
* 00418D4A 8B56 68 MOV EDX,DWORD PTR DS:[ESI+0x68]
* 00418D4D 8D7E 10 LEA EDI,DWORD PTR DS:[ESI+0x10]
* 00418D50 83C4 04 ADD ESP,0x4
* 00418D53 85FF TEST EDI,EDI
* 00418D55 8953 68 MOV DWORD PTR DS:[EBX+0x68],EDX
* 00418D58 74 35 JE SHORT malie.00418D8F
* 00418D5A 55 PUSH EBP
* 00418D5B 8BEB MOV EBP,EBX
* 00418D5D 2BEE SUB EBP,ESI
* 00418D5F BE 14000000 MOV ESI,0x14
* 00418D64 8B07 MOV EAX,DWORD PTR DS:[EDI]
* 00418D66 66:8338 00 CMP WORD PTR DS:[EAX],0x0
* 00418D6A 75 04 JNZ SHORT malie.00418D70
* 00418D6C 33C0 XOR EAX,EAX
* 00418D6E EB 09 JMP SHORT malie.00418D79
* 00418D70 50 PUSH EAX
* 00418D71 E8 EA6E2300 CALL malie.0064FC60
* 00418D76 83C4 04 ADD ESP,0x4
* 00418D79 89042F MOV DWORD PTR DS:[EDI+EBP],EAX
* 00418D7C 83C7 04 ADD EDI,0x4
* 00418D7F 4E DEC ESI
* 00418D80 ^75 E2 JNZ SHORT malie.00418D64
* 00418D82 5D POP EBP
* 00418D83 5F POP EDI
* 00418D84 5E POP ESI
* 00418D85 8BC3 MOV EAX,EBX
* 00418D87 5B POP EBX
* 00418D88 81C4 00080000 ADD ESP,0x800
* 00418D8E C3 RETN
* 00418D8F 5F POP EDI
* 00418D90 5E POP ESI
* 00418D91 8BC3 MOV EAX,EBX
* 00418D93 5B POP EBX
* 00418D94 81C4 00080000 ADD ESP,0x800
* 00418D9A C3 RETN
* 00418D9B 90 NOP
* 00418D9C 90 NOP
*
* Exit dialog box caller:
* 00475A8D 90 NOP
* 00475A8E 90 NOP
* 00475A8F 90 NOP
* 00475A90 56 PUSH ESI
* 00475A91 68 B09C7500 PUSH malie.00759CB0
* 00475A96 FF15 F8206900 CALL DWORD PTR DS:[<&KERNEL32.EnterCriti>; ntdll.RtlEnterCriticalSection
* 00475A9C 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+0x8]
* 00475AA0 85F6 TEST ESI,ESI
* 00475AA2 74 4A JE SHORT malie.00475AEE
* 00475AA4 56 PUSH ESI
* 00475AA5 E8 56000000 CALL malie.00475B00
* 00475AAA 8B46 1C MOV EAX,DWORD PTR DS:[ESI+0x1C]
* 00475AAD 8B08 MOV ECX,DWORD PTR DS:[EAX]
* 00475AAF 51 PUSH ECX
* 00475AB0 E8 BBDDFDFF CALL malie.00453870
* 00475AB5 8B5424 14 MOV EDX,DWORD PTR SS:[ESP+0x14]
* 00475AB9 52 PUSH EDX
* 00475ABA E8 21E01D00 CALL malie.00653AE0 ; jichi: called here
* 00475ABF 8B4E 1C MOV ECX,DWORD PTR DS:[ESI+0x1C]
* 00475AC2 8901 MOV DWORD PTR DS:[ECX],EAX
* 00475AC4 8B56 1C MOV EDX,DWORD PTR DS:[ESI+0x1C]
* 00475AC7 C782 94000000 00>MOV DWORD PTR DS:[EDX+0x94],0x0
* 00475AD1 8B46 1C MOV EAX,DWORD PTR DS:[ESI+0x1C]
* 00475AD4 8B08 MOV ECX,DWORD PTR DS:[EAX]
* 00475AD6 51 PUSH ECX
* 00475AD7 E8 84C41D00 CALL malie.00651F60
* 00475ADC 8B56 1C MOV EDX,DWORD PTR DS:[ESI+0x1C]
* 00475ADF 56 PUSH ESI
* 00475AE0 8982 98000000 MOV DWORD PTR DS:[EDX+0x98],EAX
* 00475AE6 E8 C5000000 CALL malie.00475BB0
* 00475AEB 83C4 14 ADD ESP,0x14
* 00475AEE 68 B09C7500 PUSH malie.00759CB0
* 00475AF3 FF15 44226900 CALL DWORD PTR DS:[<&KERNEL32.LeaveCriti>; ntdll.RtlLeaveCriticalSection
* 00475AF9 5E POP ESI
* 00475AFA C3 RETN
* 00475AFB 90 NOP
* 00475AFC 90 NOP
* 00475AFD 90 NOP
*
* Sample game: 相州戦神館學園 八命陣 (older game0
* Scenario caller: 46314f
*
* 0046310B 90 NOP
* 0046310C 90 NOP
* 0046310D 90 NOP
* 0046310E 90 NOP
* 0046310F 90 NOP
* 00463110 81EC 00080000 SUB ESP,0x800
* 00463116 56 PUSH ESI
* 00463117 8BB424 08080000 MOV ESI,DWORD PTR SS:[ESP+0x808]
* 0046311E 8B46 20 MOV EAX,DWORD PTR DS:[ESI+0x20]
* 00463121 8B88 68020000 MOV ECX,DWORD PTR DS:[EAX+0x268]
* 00463127 57 PUSH EDI
* 00463128 51 PUSH ECX
* 00463129 E8 62240200 CALL .00485590
* 0046312E 8BBC24 14080000 MOV EDI,DWORD PTR SS:[ESP+0x814]
* 00463135 68 10634100 PUSH .00416310
* 0046313A 8D5424 10 LEA EDX,DWORD PTR SS:[ESP+0x10]
* 0046313E 57 PUSH EDI
* 0046313F 52 PUSH EDX
* 00463140 E8 AB841D00 CALL .0063B5F0
* 00463145 8D4424 18 LEA EAX,DWORD PTR SS:[ESP+0x18]
* 00463149 50 PUSH EAX
* 0046314A E8 41831D00 CALL .0063B490
* 0046314F 8B4E 20 MOV ECX,DWORD PTR DS:[ESI+0x20] ; jichi: scenario retaddr
* 00463152 57 PUSH EDI
* 00463153 8981 68020000 MOV DWORD PTR DS:[ECX+0x268],EAX
* 00463159 E8 82661D00 CALL .006397E0
* 0046315E 83C4 18 ADD ESP,0x18
* 00463161 33D2 XOR EDX,EDX
* 00463163 85C0 TEST EAX,EAX
* 00463165 8B46 20 MOV EAX,DWORD PTR DS:[ESI+0x20]
* 00463168 0F9FC2 SETG DL
* 0046316B 5F POP EDI
* 0046316C 5E POP ESI
* 0046316D 8990 7C020000 MOV DWORD PTR DS:[EAX+0x27C],EDX
* 00463173 81C4 00080000 ADD ESP,0x800
* 00463179 C3 RETN
* 0046317A 90 NOP
* 0046317B 90 NOP
* 0046317C 90 NOP
* 0046317D 90 NOP
* 0046317E 90 NOP
*
* Sample game: BRAVA!!
* Scenario retaddr: 42011f
*
* 004200FD 90 NOP
* 004200FE 90 NOP
* 004200FF 90 NOP
* 00420100 56 PUSH ESI
* 00420101 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+0x8]
* 00420105 8B46 20 MOV EAX,DWORD PTR DS:[ESI+0x20]
* 00420108 8B88 F0000000 MOV ECX,DWORD PTR DS:[EAX+0xF0]
* 0042010E 57 PUSH EDI
* 0042010F 51 PUSH ECX
* 00420110 E8 BB240200 CALL .004425D0
* 00420115 8B7C24 14 MOV EDI,DWORD PTR SS:[ESP+0x14]
* 00420119 57 PUSH EDI
* 0042011A E8 01031300 CALL .00550420
* 0042011F 8B56 20 MOV EDX,DWORD PTR DS:[ESI+0x20] ; jichi: scenario caller
* 00420122 57 PUSH EDI
* 00420123 8982 F0000000 MOV DWORD PTR DS:[EDX+0xF0],EAX
* 00420129 E8 B2E61200 CALL .0054E7E0
* 0042012E 8B56 20 MOV EDX,DWORD PTR DS:[ESI+0x20]
* 00420131 83C4 0C ADD ESP,0xC
* 00420134 33C9 XOR ECX,ECX
* 00420136 85C0 TEST EAX,EAX
* 00420138 0F9FC1 SETG CL
* 0042013B 5F POP EDI
* 0042013C 5E POP ESI
* 0042013D 898A FC000000 MOV DWORD PTR DS:[EDX+0xFC],ECX
* 00420143 C3 RETN
* 00420144 90 NOP
*
* Name retaddr: 415a2c
*
* 004159DD 90 NOP
* 004159DE 90 NOP
* 004159DF 90 NOP
* 004159E0 81EC 00080000 SUB ESP,0x800
* 004159E6 53 PUSH EBX
* 004159E7 56 PUSH ESI
* 004159E8 57 PUSH EDI
* 004159E9 6A 6C PUSH 0x6C
* 004159EB FF15 40D45800 CALL DWORD PTR DS:[0x58D440] ; msvcrt.malloc
* 004159F1 8BD8 MOV EBX,EAX
* 004159F3 83C4 04 ADD ESP,0x4
* 004159F6 85DB TEST EBX,EBX
* 004159F8 0F84 D1000000 JE .00415ACF
* 004159FE 8BB424 10080000 MOV ESI,DWORD PTR SS:[ESP+0x810]
* 00415A05 33C0 XOR EAX,EAX
* 00415A07 B9 1B000000 MOV ECX,0x1B
* 00415A0C 8BFB MOV EDI,EBX
* 00415A0E F3:AB REP STOS DWORD PTR ES:[EDI]
* 00415A10 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 00415A12 68 003B4100 PUSH .00413B00
* 00415A17 50 PUSH EAX
* 00415A18 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+0x14]
* 00415A1C 51 PUSH ECX
* 00415A1D E8 5EAB1300 CALL .00550580
* 00415A22 8D5424 18 LEA EDX,DWORD PTR SS:[ESP+0x18]
* 00415A26 52 PUSH EDX
* 00415A27 E8 F4A91300 CALL .00550420
* 00415A2C 8903 MOV DWORD PTR DS:[EBX],EAX ; jichi: name caller
* 00415A2E 8B46 04 MOV EAX,DWORD PTR DS:[ESI+0x4]
* 00415A31 68 003B4100 PUSH .00413B00
* 00415A36 50 PUSH EAX
* 00415A37 8D4C24 24 LEA ECX,DWORD PTR SS:[ESP+0x24]
* 00415A3B 51 PUSH ECX
* 00415A3C E8 3FAB1300 CALL .00550580
* 00415A41 8D5424 28 LEA EDX,DWORD PTR SS:[ESP+0x28]
* 00415A45 52 PUSH EDX
* 00415A46 E8 D5A91300 CALL .00550420
* 00415A4B 8943 04 MOV DWORD PTR DS:[EBX+0x4],EAX
* 00415A4E 8B46 08 MOV EAX,DWORD PTR DS:[ESI+0x8]
* 00415A51 83C4 20 ADD ESP,0x20
* 00415A54 85C0 TEST EAX,EAX
* 00415A56 75 05 JNZ SHORT .00415A5D
* 00415A58 B8 6C285E00 MOV EAX,.005E286C
* 00415A5D 50 PUSH EAX
* 00415A5E E8 DD691300 CALL .0054C440
* 00415A63 8943 08 MOV DWORD PTR DS:[EBX+0x8],EAX
* 00415A66 8B46 0C MOV EAX,DWORD PTR DS:[ESI+0xC]
* 00415A69 83C4 04 ADD ESP,0x4
* 00415A6C 85C0 TEST EAX,EAX
* 00415A6E 75 05 JNZ SHORT .00415A75
* 00415A70 B8 6C285E00 MOV EAX,.005E286C
* 00415A75 50 PUSH EAX
* 00415A76 E8 C5691300 CALL .0054C440
* 00415A7B 8943 0C MOV DWORD PTR DS:[EBX+0xC],EAX
* 00415A7E 8B46 60 MOV EAX,DWORD PTR DS:[ESI+0x60]
* 00415A81 8943 60 MOV DWORD PTR DS:[EBX+0x60],EAX
* 00415A84 8B4E 64 MOV ECX,DWORD PTR DS:[ESI+0x64]
* 00415A87 894B 64 MOV DWORD PTR DS:[EBX+0x64],ECX
* 00415A8A 8B56 68 MOV EDX,DWORD PTR DS:[ESI+0x68]
* 00415A8D 8D7E 10 LEA EDI,DWORD PTR DS:[ESI+0x10]
* 00415A90 83C4 04 ADD ESP,0x4
* 00415A93 85FF TEST EDI,EDI
* 00415A95 8953 68 MOV DWORD PTR DS:[EBX+0x68],EDX
* 00415A98 74 35 JE SHORT .00415ACF
* 00415A9A 55 PUSH EBP
* 00415A9B 8BEB MOV EBP,EBX
* 00415A9D 2BEE SUB EBP,ESI
* 00415A9F BE 14000000 MOV ESI,0x14
* 00415AA4 8B07 MOV EAX,DWORD PTR DS:[EDI]
* 00415AA6 66:8338 00 CMP WORD PTR DS:[EAX],0x0
* 00415AAA 75 04 JNZ SHORT .00415AB0
* 00415AAC 33C0 XOR EAX,EAX
* 00415AAE EB 09 JMP SHORT .00415AB9
* 00415AB0 50 PUSH EAX
* 00415AB1 E8 8A691300 CALL .0054C440
* 00415AB6 83C4 04 ADD ESP,0x4
* 00415AB9 89042F MOV DWORD PTR DS:[EDI+EBP],EAX
* 00415ABC 83C7 04 ADD EDI,0x4
* 00415ABF 4E DEC ESI
* 00415AC0 ^75 E2 JNZ SHORT .00415AA4
* 00415AC2 5D POP EBP
* 00415AC3 5F POP EDI
* 00415AC4 5E POP ESI
* 00415AC5 8BC3 MOV EAX,EBX
* 00415AC7 5B POP EBX
* 00415AC8 81C4 00080000 ADD ESP,0x800
* 00415ACE C3 RETN
* 00415ACF 5F POP EDI
* 00415AD0 5E POP ESI
* 00415AD1 8BC3 MOV EAX,EBX
* 00415AD3 5B POP EBX
* 00415AD4 81C4 00080000 ADD ESP,0x800
* 00415ADA C3 RETN
* 00415ADB 90 NOP
* 00415ADC 90 NOP
* 00415ADD 90 NOP
* 00415ADE 90 NOP
*/
size_t parseTextSize(LPCWSTR text)
{
size_t count = 0;
bool skipNull = false;
for (; *text || skipNull; text++, count++)
if (text[0] == 0)
skipNull = false;
else if (text[0] == 0x7)
switch (text[1]) {
case 0x1: // ruby
skipNull = true;
break;
case 0x8: // voice
return count;
case 0x6: // pause
return count + 2;
}
return count;
}
size_t rtrim(LPCWSTR text, size_t size)
{
while (size && (text[size - 1] <= 32 || text[size - 1] == 0x3000)) // trim trailing non-printable characters
size--;
return size;
}
std::string parseTextData(LPCWSTR text)
{
std::string ret;
if (!wcschr(text, 0x7)) {
ret=std::string((LPCSTR)text, ::wcslen(text) * sizeof(wchar_t));
return ret;
}
for (; *text; text++) {
if (text[0] == 0x7)
switch (text[1]) {
case 0x1: // ruby
if (LPCWSTR p = ::wcschr(text + 2, 0xa)) {
ret.append(LPCSTR(text + 2), (p - text - 2) * sizeof(wchar_t));
text = p + ::wcslen(p); // text now point to zero
continue;
} // mismatched ruby that should never happen
return std::string();
case 0x8: // voice
return ret;
case 0x6: // pause
ret.append((LPCSTR)text, 2 * sizeof(wchar_t));
return ret;
}
ret.append((LPCSTR)text, sizeof(wchar_t));
}
return ret;
}
#define MALIE_0 L"[0]" // represent \0
void filterTextData(std::string &text)
{
// remove short pause
static std::string shortPause((LPCSTR)L"\x07\x04", 2 * sizeof(wchar_t));
//text.replace(shortPause, ""); // there is no remove method in std::string
strReplace(text, shortPause, "");
}
// I need a cache retainer here to make sure same text result in same result
void hookafter(hook_stack*s,void* data1, size_t len)
{
static std::string data_;
static std::unordered_set<uint64_t> hashes_;
auto text = (LPCWSTR)s->stack[1];
if (!text || !*text
|| !(text[0] == 0x7 && text[1] == 0x8) && all_ascii(text) )
return ;
std::string data;
bool update = false;
for (size_t size; *text; text += size) {
if (text[0] == 0x7 && text[1] == 0x8) { // voiced
size_t len = ::wcslen(text);
data.append((LPCSTR)text, (len + 1) * sizeof(wchar_t));
text += len + 1;
}
size = parseTextSize(text);
std::string oldData = parseTextData(text);
filterTextData(oldData);
if (oldData.empty()) // this should never happen
return ;
auto oldTextAddress = (LPCWSTR)oldData.c_str();
size_t oldTextSize = oldData.size() / sizeof(wchar_t),
trimmedSize = rtrim(oldTextAddress, oldTextSize);
if (trimmedSize == 0 || all_ascii(oldTextAddress, trimmedSize))
data.append(oldData);
else {
std::wstring oldText = std::wstring(oldTextAddress, trimmedSize),
newText = std::wstring((LPWSTR)data1,len/2) ;
if (newText.empty() || newText == oldText)
data.append(oldData);
else {
update = true;
data.append((LPCSTR)newText.c_str(), newText.size() * sizeof(wchar_t));
if (trimmedSize != oldTextSize)
data.append(LPCSTR(oldTextAddress + trimmedSize), (oldTextSize - trimmedSize) * sizeof(wchar_t));
}
}
}
if (update) {
{
static const std::string zero_bytes(sizeof(wchar_t), '\0'),
zero_repr((LPCSTR)MALIE_0, sizeof(MALIE_0) - sizeof(wchar_t)); // - \0's size
//data.replace(zero_repr, zero_bytes);
strReplace(data, zero_repr, zero_bytes);
}
// make sure there are 5 zeros at the end
data.push_back(0); data.push_back(0); data.push_back(0); data.push_back(0); data.push_back(0);
data_ = data;
text = (LPCWSTR)data_.c_str();
s->stack[1] = (ULONG)text;
}
}
bool hookBefore(hook_stack*s,void* data1, size_t* len,uintptr_t*role)
{
static std::string data_;
static std::unordered_set<uint64_t> hashes_;
auto text = (LPCWSTR)s->stack[1];
if (!text || !*text
|| !(text[0] == 0x7 && text[1] == 0x8) && all_ascii(text) )
return false;
//if (::wcsstr(text, L"\x30DC\x30BF\x30F3")) // ボタン
// return true;
//if (::wcsstr(text, L"\x30A4\x30E1\x30FC")) // イメージ
// return true;
// Scenario caller:
// 004637BA E8 21031F00 CALL malie.00653AE0 ; jichi: scenario caller
// 004637BF 8B4E 1C MOV ECX,DWORD PTR DS:[ESI+0x1C]
// 004637C2 57 PUSH EDI
//
// 0046314A E8 41831D00 CALL .0063B490
// 0046314F 8B4E 20 MOV ECX,DWORD PTR DS:[ESI+0x20] ; jichi: scenario retaddr
// 00463152 57 PUSH EDI
//
// (balloon-like)
// 0042011F 8B56 20 MOV EDX,DWORD PTR DS:[ESI+0x20] ; jichi: scenario caller
// 00420122 57 PUSH EDI
//
// Name caller:
// 00463829 E8 B2021F00 CALL malie.00653AE0 ; jichi: name
// 0046382E 8B56 1C MOV EDX,DWORD PTR DS:[ESI+0x1C]
// 00463831 83C4 14 ADD ESP,0x14
//
// (balloon-like)
// 00415A2C 8903 MOV DWORD PTR DS:[EBX],EAX ; jichi: name caller
// 00415A2E 8B46 04 MOV EAX,DWORD PTR DS:[ESI+0x4]
// 00415A31 68 003B4100 PUSH .00413B00
* role = Engine::OtherRole;
auto retaddr = s->stack[0];
switch (*(DWORD *)retaddr & 0xff0000ff) {
case 0x5700008b: *role = Engine::ScenarioRole; break;
case 0x8300008b:
case 0x46000089: *role = Engine::NameRole; break;
}
//auto sig = Engine::hashThreadSignature(role, retaddr); // this is not needed as the retaddr is used as split
auto sig = retaddr;
std::string data;
bool update = false;
for (size_t size; *text; text += size) {
if (text[0] == 0x7 && text[1] == 0x8) { // voiced
size_t len = ::wcslen(text);
data.append((LPCSTR)text, (len + 1) * sizeof(wchar_t));
text += len + 1;
}
size = parseTextSize(text);
std::string oldData = parseTextData(text);
filterTextData(oldData);
if (oldData.empty()) // this should never happen
return false;
auto oldTextAddress = (LPCWSTR)oldData.c_str();
size_t oldTextSize = oldData.size() / sizeof(wchar_t),
trimmedSize = rtrim(oldTextAddress, oldTextSize);
if (trimmedSize == 0 || all_ascii(oldTextAddress, trimmedSize))
data.append(oldData);
else {
std::wstring oldText = std::wstring(oldTextAddress, trimmedSize);
write_string_overwrite(data1,len,oldText);
update=true;
}
}
return update;
}
} // namespace Private
/**
* Sample game: シルヴァリオ ヴェンデッタ
*
* Text in arg1.
* Function found by debugging the text being accessed.
* It is the same as one of the parent call of Malie2.
*
* The target text arg1 is on this function's caller's stack.
*
* 00653ADC 90 NOP
* 00653ADD 90 NOP
* 00653ADE 90 NOP
* 00653ADF 90 NOP
* 00653AE0 56 PUSH ESI
* 00653AE1 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+0x8]
* 00653AE5 33C0 XOR EAX,EAX
* 00653AE7 85F6 TEST ESI,ESI
* 00653AE9 74 47 JE SHORT malie.00653B32
* 00653AEB 53 PUSH EBX
* 00653AEC 57 PUSH EDI
* 00653AED 68 00C47F00 PUSH malie.007FC400
* 00653AF2 FF15 F8206900 CALL DWORD PTR DS:[<&KERNEL32.EnterCriti>; ntdll.RtlEnterCriticalSection
* 00653AF8 56 PUSH ESI
* 00653AF9 E8 C2E4FFFF CALL malie.00651FC0
* 00653AFE 8D78 02 LEA EDI,DWORD PTR DS:[EAX+0x2]
* 00653B01 57 PUSH EDI
* 00653B02 FF15 20256900 CALL DWORD PTR DS:[<&MSVCRT.malloc>] ; msvcrt.malloc
* 00653B08 8BD8 MOV EBX,EAX
* 00653B0A 83C4 08 ADD ESP,0x8
* 00653B0D 85DB TEST EBX,EBX
* 00653B0F 74 12 JE SHORT malie.00653B23
* 00653B11 8BCF MOV ECX,EDI
* 00653B13 8BFB MOV EDI,EBX
* 00653B15 8BC1 MOV EAX,ECX
* 00653B17 C1E9 02 SHR ECX,0x2
* 00653B1A F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
* 00653B1C 8BC8 MOV ECX,EAX
* 00653B1E 83E1 03 AND ECX,0x3
* 00653B21 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
* 00653B23 68 00C47F00 PUSH malie.007FC400
* 00653B28 FF15 44226900 CALL DWORD PTR DS:[<&KERNEL32.LeaveCriti>; ntdll.RtlLeaveCriticalSection
* 00653B2E 8BC3 MOV EAX,EBX
* 00653B30 5F POP EDI
* 00653B31 5B POP EBX
* 00653B32 5E POP ESI
* 00653B33 C3 RETN
* 00653B34 90 NOP
* 00653B35 90 NOP
* 00653B36 90 NOP
* 00653B37 90 NOP
* 00653B38 90 NOP
*
* Malie2's pattern: 4089560833d2894604
*
* const BYTE bytes1[] = {
* 0x40, // inc eax
* 0x89,0x56, 0x08, // mov dword ptr ds:[esi+0x8],edx
* 0x33,0xd2, // xor edx,edx
* 0x89,0x46, 0x04 // mov dword ptr ds:[esi+0x4],eax
* };
*
* Malie2 not used as it produces too many garbage
*
* Malie2's call stack:
*
* 026DF0D8 026DF0E0
* 026DF0DC 026DF184 ; jichi: source text
* 026DF0E0 026DF184
* 026DF0E4 00000000
* 026DF0E8 000000B8
* 026DF0EC 0627DFE8
* 026DF0F0 016F0000
* 026DF0F4 0627DFE0
* 026DF0F8 0180B5E0
* 026DF0FC 00000001
* 026DF100 0180B8F0 ASCII ""=VH"
* 026DF104 /026DF11C
* 026DF108 |77492CE8 RETURN to ntdll.77492CE8 from ntdll.77492D0B
* 026DF10C |0180B8F8
* 026DF110 |FFFFFFFF
* 026DF114 |04A9103C
* 026DF118 |0180B8F0 ASCII ""=VH"
* 026DF11C \026DF168
* 026DF120 771B98CD RETURN to msvcrt.771B98CD from ntdll.RtlFreeHeap
* 026DF124 018B0000
* 026DF128 00000000
* 026DF12C 00000006
* 026DF130 FFFFFFFF
* 026DF134 FFFFFFFF
* 026DF138 00000000
* 026DF13C 026DF184 ; jichi: text
* 026DF140 0000000C
* 026DF144 062671D8
* 026DF148 00000000
* 026DF14C /026DFA08
* 026DF150 |00653AFE RETURN to malie.00653AFE from malie.00651FC0
* 026DF154 |026DF184 ; jichi: text
* 026DF158 |007272A8 malie.007272A8
* 026DF15C |04A9103C
* 026DF160 |0183DFE8
* 026DF164 |004637BF RETURN to malie.004637BF from malie.00653AE0
* 026DF168 |026DF184 ; jichi: text, two continous scenario text
* 026DF16C |026DF184 ; jichi: text
* 026DF170 |007272A8 malie.007272A8
* 026DF174 |00416CC0 malie.00416CC0
* 026DF178 |0180B8F8
* 026DF17C |FFFFFFFF
* 026DF180 |0183DFE8
* 026DF184 |00080007
* 026DF188 |005F0076 malie.005F0076
* 026DF18C |0065007A malie.0065007A
* 026DF190 |00300070
* 026DF194 |00300030
*
* Sample game: 相州戦神館學園 八命陣 (older game without critical sections)
* 0063B48D 90 NOP
* 0063B48E 90 NOP
* 0063B48F 90 NOP
* 0063B490 56 PUSH ESI
* 0063B491 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+0x8]
* 0063B495 33C0 XOR EAX,EAX
* 0063B497 57 PUSH EDI
* 0063B498 85F6 TEST ESI,ESI
* 0063B49A 74 29 JE SHORT .0063B4C5
* 0063B49C 56 PUSH ESI
* 0063B49D E8 FEE4FFFF CALL .006399A0
* 0063B4A2 8D78 02 LEA EDI,DWORD PTR DS:[EAX+0x2]
* 0063B4A5 57 PUSH EDI
* 0063B4A6 FF15 94946700 CALL DWORD PTR DS:[0x679494] ; msvcrt.malloc
* 0063B4AC 83C4 08 ADD ESP,0x8
* 0063B4AF 85C0 TEST EAX,EAX
* 0063B4B1 74 12 JE SHORT .0063B4C5
* 0063B4B3 8BCF MOV ECX,EDI
* 0063B4B5 8BF8 MOV EDI,EAX
* 0063B4B7 8BD1 MOV EDX,ECX
* 0063B4B9 C1E9 02 SHR ECX,0x2
* 0063B4BC F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
* 0063B4BE 8BCA MOV ECX,EDX
* 0063B4C0 83E1 03 AND ECX,0x3
* 0063B4C3 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
* 0063B4C5 5F POP EDI
* 0063B4C6 5E POP ESI
* 0063B4C7 C3 RETN
* 0063B4C8 90 NOP
* 0063B4C9 90 NOP
* 0063B4CA 90 NOP
* 0063B4CB 90 NOP
*
* Sample game: 神咒神威神楽WEB体験版
* FIXME: Texts get disappeared
* 00517A8D 90 NOP
* 00517A8E 90 NOP
* 00517A8F 90 NOP
* 00517A90 56 PUSH ESI
* 00517A91 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+0x8]
* 00517A95 57 PUSH EDI
* 00517A96 56 PUSH ESI
* 00517A97 E8 64E5FFFF CALL .00516000
* 00517A9C 8D78 02 LEA EDI,DWORD PTR DS:[EAX+0x2]
* 00517A9F 57 PUSH EDI
* 00517AA0 FF15 40745500 CALL DWORD PTR DS:[0x557440] ; msvcrt.malloc
* 00517AA6 83C4 08 ADD ESP,0x8
* 00517AA9 85C0 TEST EAX,EAX
* 00517AAB 74 12 JE SHORT .00517ABF
* 00517AAD 8BCF MOV ECX,EDI
* 00517AAF 8BF8 MOV EDI,EAX
* 00517AB1 8BD1 MOV EDX,ECX
* 00517AB3 C1E9 02 SHR ECX,0x2
* 00517AB6 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
* 00517AB8 8BCA MOV ECX,EDX
* 00517ABA 83E1 03 AND ECX,0x3
* 00517ABD F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
* 00517ABF 5F POP EDI
* 00517AC0 5E POP ESI
* 00517AC1 C3 RETN
* 00517AC2 90 NOP
* 00517AC3 90 NOP
* 00517AC4 90 NOP
*/
bool attach(ULONG startAddress, ULONG stopAddress)
{
const uint8_t bytes[] = {
//FF15 20256900 // 00653B02 FF15 20256900 CALL DWORD PTR DS:[<&MSVCRT.malloc>] ; msvcrt.malloc
//8BD8 // 00653B08 8BD8 MOV EBX,EAX
0x83,0xC4, 0x08, // 00653B0A 83C4 08 ADD ESP,0x8
0x85,XX, // 00653B0D 85DB TEST EBX,EBX
0x74, 0x12, // 00653B0F 74 12 JE SHORT malie.00653B23
0x8B,XX, // 00653B11 8BCF MOV ECX,EDI
0x8B,XX, // 00653B13 8BFB MOV EDI,EBX
0x8B,XX, // 00653B15 8BC1 MOV EAX,ECX
0xC1,0xE9, 0x02, // 00653B17 C1E9 02 SHR ECX,0x2
0xF3,0xA5, // 00653B1A F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
0x8B,XX, // 00653B1C 8BC8 MOV ECX,EAX
0x83,0xE1, 0x03, // 00653B1E 83E1 03 AND ECX,0x3
0xF3,0xA4 // 00653B21 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
//DOUT(addr);
if (!addr)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
return false;
//addr = 0x00653AE0; // the actual hooked grant parent call function, text in arg1
// Sample game: シルヴァリオ ヴェンデッタ
// If there are untranslated function, hook to the following location and debug the function stack to find text address
//addr = 0x006519B0; // the callee function, text in arg2, function called by two functions, including the callee. Hooking to this function causing history to crash
//return winhook::hook_before(addr, Private::hookBefore);
HookParam hp;
hp.address=addr;
hp.hook_before=Private::hookBefore;
hp.hook_after=Private::hookafter;
hp.type=CODEC_UTF16|EMBED_ABLE;
return NewHook(hp,"EmbedMalie");
}
} // namespace ScenarioHook
namespace Patch {
namespace Private {
bool hookBefore(hook_stack*s,void* data1, size_t* len,uintptr_t*role)
{
static std::wstring fontFace_;
auto fontFamily=std::wstring(embedsharedmem->fontFamily);
if (!fontFamily.empty()) {
if (fontFace_ != fontFamily)
fontFace_ = fontFamily;
s->stack[1] = (ULONG)fontFace_.c_str();
//::memcpy((LPVOID)s->stack[2], fontFace_.utf16(), fontFace_.size() * sizeof(wchar_t));
}
return false;
}
} // namespace Private
/**
* Sample game: シルヴァリオ ヴェンデッタ
* Force changing font face, otherwise CreateFontIndirectW won't be invoked.
*
* Default font is TelopMinPro.
*
* There are two fonts that are needed to be changed for Malie engine.
* - Text font: can be changed in registry as "FontFace"
* - UI font: canb be changed in malie.ini using SystemFont
* Example:
*
* ;フォント種類指定
* ;SystemFont=SimSun
* ;FONT01=SimSun
* SystemFont=TelopMinPro
* FONT01=TelopMinPro
*
* This function is found by debugging CreateFontIndirectW.
* Font face in both arg1 and arg2.
*
* 0043A82C 90 NOP
* 0043A82D 90 NOP
* 0043A82E 90 NOP
* 0043A82F 90 NOP
* 0043A830 53 PUSH EBX
* 0043A831 55 PUSH EBP
* 0043A832 56 PUSH ESI
* 0043A833 57 PUSH EDI
* 0043A834 E8 C7FFFFFF CALL malie.0043A800
* 0043A839 8BF8 MOV EDI,EAX
* 0043A83B 33F6 XOR ESI,ESI
* 0043A83D 85FF TEST EDI,EDI
* 0043A83F 7E 20 JLE SHORT malie.0043A861
* 0043A841 8B5C24 14 MOV EBX,DWORD PTR SS:[ESP+0x14]
* 0043A845 8B2D 14256900 MOV EBP,DWORD PTR DS:[<&MSVCRT._wcsicmp>>; msvcrt._wcsicmp
* 0043A84B 56 /PUSH ESI
* 0043A84C E8 6FFFFFFF |CALL malie.0043A7C0
* 0043A851 50 |PUSH EAX
* 0043A852 53 |PUSH EBX
* 0043A853 FFD5 |CALL EBP
* 0043A855 83C4 0C |ADD ESP,0xC
* 0043A858 85C0 |TEST EAX,EAX
* 0043A85A 74 0D |JE SHORT malie.0043A869
* 0043A85C 46 |INC ESI
* 0043A85D 3BF7 |CMP ESI,EDI
* 0043A85F ^7C EA \JL SHORT malie.0043A84B
* 0043A861 5F POP EDI
* 0043A862 5E POP ESI
* 0043A863 5D POP EBP
* 0043A864 83C8 FF OR EAX,0xFFFFFFFF
* 0043A867 5B POP EBX
* 0043A868 C3 RETN
* 0043A869 5F POP EDI
* 0043A86A 8BC6 MOV EAX,ESI
* 0043A86C 5E POP ESI
* 0043A86D 5D POP EBP
* 0043A86E 5B POP EBX
* 0043A86F C3 RETN
* 0043A870 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+0x4]
* 0043A874 83F8 FF CMP EAX,-0x1
* 0043A877 75 05 JNZ SHORT malie.0043A87E
* 0043A879 E8 92FFFFFF CALL malie.0043A810
* 0043A87E 50 PUSH EAX
* 0043A87F E8 3CFFFFFF CALL malie.0043A7C0
* 0043A884 33C9 XOR ECX,ECX
* 0043A886 83C4 04 ADD ESP,0x4
* 0043A889 66:8338 40 CMP WORD PTR DS:[EAX],0x40
* 0043A88D 0F94C1 SETE CL
* 0043A890 8BC1 MOV EAX,ECX
* 0043A892 C3 RETN
* 0043A893 90 NOP
* 0043A894 90 NOP
* 0043A895 90 NOP
* 0043A896 90 NOP
* 0043A897 90 NOP
* 0043A898 90 NOP
*
* 0278F138 0043AB90 RETURN to malie.0043AB90 from malie.0043A830
* 0278F13C 0278F154 UNICODE "telopminpro"
* 0278F140 0278F154 UNICODE "telopminpro"
* 0278F144 006D2AE8 UNICODE "%s"
* 0278F148 0192C990 UNICODE "telopminpro"
* 0278F14C 00000000
* 0278F150 0A33AAE0
* 0278F154 00650074 malie.00650074
* 0278F158 006F006C malie.006F006C
* 0278F15C 006D0070 ASCII "Context"
* 0278F160 006E0069 malie.006E0069
* 0278F164 00720070 malie.00720070
* 0278F168 0000006F
* 0278F16C 3F088850
* 0278F170 00000000
* 0278F174 00000000
*
*/
bool attachFont(ULONG startAddress, ULONG stopAddress)
{
const uint8_t bytes[] = {
0x50, // 0043A851 50 |PUSH EAX
0x53, // 0043A852 53 |PUSH EBX
0xFF,0xD5, // 0043A853 FFD5 |CALL EBP
0x83,0xC4, 0x0C, // 0043A855 83C4 0C |ADD ESP,0xC
0x85,0xC0, // 0043A858 85C0 |TEST EAX,EAX
0x74, 0x0D, // 0043A85A 74 0D |JE SHORT malie.0043A869
0x46, // 0043A85C 46 |INC ESI
0x3B,0xF7 // 0043A85D 3BF7 |CMP ESI,EDI
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
if (!addr)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
return false;
HookParam hp;
hp.address=addr;
hp.type=EMBED_ABLE|HOOK_EMPTY;
hp.hook_before= Private::hookBefore;
return NewHook(hp,"PatchMalieFont");
}
} // namespace Patch
} // unnamed namespace
namespace{
//Dies irae ~Acta est Fabula~ HD
//Dies irae ~Interview with Kaziklu Bey~
std::wstring readString(DWORD address) {
std::wstring s = L"";
uint16_t c;
//console.log(hexdump(address))
while ((c = *(uint16_t*)address) != 0) {
// utf-16 characters
if (c >= 0x20) {
s += (wchar_t)c;// String.fromCharCode(c);
address = address+2;//.add(2);
}
else {
// start command
if (c == 0x7) {
address = address+2;//.add(2);
//let cmd = address.readU16();
auto cmd=*(uint16_t*)address;
address = address+2;//.add(2); // skip cmd
// voice id --> skip
if (cmd == 0x8) {
while ((c = *(uint16_t*)address) != 0) {
address = address+2;//.add(2);
}
address = address+2;//.add(2);
}
// end line --> return string
if (cmd == 0x6) {
return s;
}
// ruby
if (cmd == 0x1) {
while ((c = *(uint16_t*)address) != 0) {
// when we reach 0xa we have the kanji part
if (c == 0xa) {
address = address+2;//.add(2);
//let rubi = '';
while ((c = *(uint16_t*)address) != 0) {
// rubi += String.fromCharCode(c);
address = address+2;//.add(2);
}
//console.log('rubi: ' + rubi);
break;
}
else {
s += (wchar_t)c;// String.fromCharCode(c);
address = address+2;//.add(2);
}
}
address = address+2;//.add(2);
}
}
else {
address = address+2;//.add(2);
}
}
}
return {};
}
void textfun_light(hook_stack* stack, HookParam*, uintptr_t* data, uintptr_t* split, size_t* len){
DWORD eax = stack->eax;
DWORD ecx=*(DWORD*)eax;
DWORD edx = stack->edx ;
auto str = readString(ecx+edx*2);
static std::wstring _ws;
if(_ws==str)return;
_ws=str;
write_string_new(data,len,str);
*split=0;
}
bool malie_light(){
BYTE pattern[]={
0x8b,0x08,//往前两个字节否则jump到下个指令被hook截断会崩溃
0x0f,XX,XX,XX,0x89,XX,XX,0x8d,XX,XX,0x89,XX,XX,0x8d,XX,XX,0x00,0x00,0x00,0x00
};
ULONG addr = MemDbg::findBytes(pattern, sizeof(pattern), processStartAddress, processStopAddress);
if (!addr)
return false;
HookParam hp{};
hp.address=addr;
hp.text_fun=textfun_light;
hp.type=CODEC_UTF16|USING_STRING|NO_CONTEXT;
return NewHook(hp,"malie_6");
}
}
bool Malie::attach_function() {
bool embed=ScenarioHook::attach(processStartAddress,processStopAddress);
// if(embed)Patch::attachFont(processStartAddress,processStopAddress); 导致闪退,放弃
auto b1= InsertMalieHook()||embed;
b1=malie_light()||b1;
return b1;
}