2024-02-07 20:59:24 +08:00

698 lines
30 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.

#include"Minori.h"
#include"util/textunion.h"
bool Minori1EngFilter(LPVOID data, size_t* size, HookParam*)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
StringCharReplacer(text, len, "\\n", 2, ' ');
StringFilter(text, len, "\\a", 2);
StringFilter(text, len, "\\v", 2);
CharReplacer(text, len, '\xC4', '-');
CharReplacer(text, len, '\x93', '"');
CharReplacer(text, len, '\x94', '"');
CharReplacer(text, len, '\x92', '\'');
StringCharReplacer(text, len, "\\I", 2, '\'');
StringCharReplacer(text, len, "\\P", 2, '\'');
return true;
}
bool Minori1JapFilter(LPVOID data, size_t* size, HookParam*)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
StringFilter(text, len, "\\a", 2);
StringFilter(text, len, "\\v", 2);
StringFilter(text, len, "\\N", 2);
if (cpp_strnstr(text, "{", *len)) {
StringFilterBetween(text, len, "{", 1, "}", 1);
}
return true;
}
bool InsertMinori1Hook()
{
/*
* Sample games:
* https://vndb.org/v19644
* https://vndb.org/v12562
*/
const BYTE bytes[] = {
0x84, 0xC0, // test al,al << hook here
0x0F, 0x85, XX4, // jne trinoline_en_AA.exe+243E1
0x68, XX4, // push trinoline_en_AA.exe+118BF8 << alt eng hook
0x33, 0xFF // xor edi,edi
};
enum { alt_addr_offset = 8 };
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr) {
ConsoleOutput("Minori1: pattern not found");
return false;
}
HookParam hp;
hp.address = addr;
hp.offset =get_reg(regs::edx);
hp.codepage = 932;
hp.type = USING_STRING;
hp.filter_fun = Minori1JapFilter;
ConsoleOutput(" INSERT Minori1");
auto succ=NewHook(hp, "Minori1");
hp.address = addr + alt_addr_offset;
hp.filter_fun = Minori1EngFilter;
ConsoleOutput(" INSERT Minori1eng");
succ|=NewHook(hp, "Minori1eng");
return succ;
}
bool Minori2Filter(LPVOID data, size_t* size, HookParam*)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
StringCharReplacer(text, len, "\\n", 2, ' ');
if (cpp_strnstr(text, "{", *len)) {
StringFilterBetween(text, len, "{", 1, "}", 1);
}
return true;
}
bool InsertMinori2Hook()
{
/*
* Sample games:
* https://vndb.org/v35
*/
const BYTE bytes[] = {
0x80, 0x38, 0x00, // cmp byte ptr [eax],00 << hook here
0x0F, 0x84, XX4, // je WindRP.exe+2832A
0xB8, 0x20, 0x03, 0x00, 0x00, // mov eax,00000320
0x89, 0x44, 0x24, 0x10, // mov [esp+10],eax
0x89, 0x44, 0x24, 0x14, // mov [esp+14],eax
0x8B, 0x47, 0x20 // mov eax,[edi+20]
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr) {
ConsoleOutput("Minori2: pattern not found");
return false;
}
ConsoleOutput(" INSERT Minori2");
HookParam hp;
hp.address = addr;
hp.offset=get_reg(regs::eax);
hp.type = USING_STRING;
hp.filter_fun = Minori2Filter;
ConsoleOutput(" INSERT Minori2");
ConsoleOutput("Minori2: Please, set text to max speed");
return NewHook(hp, "Minori2");
}
bool InsertMinoriHooks()
{
return InsertMinori1Hook() || InsertMinori2Hook();
}
namespace { // unnamed
namespace ScenarioHook {
namespace Private {
/**
* Sample game: 12の月のイヴ
* Remove \tag and leading #.
*/
LPCSTR trim(LPCSTR text, int *size)
{
int length = *size;
// handle prefix
while (text[0] == '#' || text[0] == '@') {
text++;
length--;
}
while (text[0] == '\\' && ::isalpha(text[1])) {
text += 2;
length -= 2;
}
// handle suffix
while (length >= 2 && text[length - 2] == '\\' && ::isalpha(text[length - 1]))
length -= 2;
*size = length;
return text;
}
/**
* Sample game: ソレヨリノ前奏詩
*
* 013BEFAE CC INT3
* 013BEFAF CC INT3
* 013BEFB0 55 PUSH EBP
* 013BEFB1 8BEC MOV EBP,ESP
* 013BEFB3 6A FF PUSH -0x1
* 013BEFB5 68 78654401 PUSH yorino_t.01446578
* 013BEFBA 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
* 013BEFC0 50 PUSH EAX
* 013BEFC1 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
* 013BEFC8 83EC 54 SUB ESP,0x54
* 013BEFCB 53 PUSH EBX
* 013BEFCC 8B5D 08 MOV EBX,DWORD PTR SS:[EBP+0x8]
* 013BEFCF 56 PUSH ESI
* 013BEFD0 57 PUSH EDI
* 013BEFD1 8BF3 MOV ESI,EBX
* 013BEFD3 E8 68FFFFFF CALL yorino_t.013BEF40
* 013BEFD8 8883 6C2A0000 MOV BYTE PTR DS:[EBX+0x2A6C],AL
* 013BEFDE 8B45 14 MOV EAX,DWORD PTR SS:[EBP+0x14]
* 013BEFE1 33F6 XOR ESI,ESI
* 013BEFE3 56 PUSH ESI
* 013BEFE4 50 PUSH EAX
* 013BEFE5 BF 0F000000 MOV EDI,0xF
* 013BEFEA 83C8 FF OR EAX,0xFFFFFFFF
* 013BEFED 8D4D BC LEA ECX,DWORD PTR SS:[EBP-0x44]
* 013BEFF0 897D D0 MOV DWORD PTR SS:[EBP-0x30],EDI
* 013BEFF3 8975 CC MOV DWORD PTR SS:[EBP-0x34],ESI
* 013BEFF6 C645 BC 00 MOV BYTE PTR SS:[EBP-0x44],0x0
* 013BEFFA E8 313AFAFF CALL yorino_t.01362A30 ; jichi: name call
* 013BEFFF 8B4D 18 MOV ECX,DWORD PTR SS:[EBP+0x18]
* 013BF002 56 PUSH ESI
* 013BF003 8975 FC MOV DWORD PTR SS:[EBP-0x4],ESI
* 013BF006 51 PUSH ECX
* 013BF007 83C8 FF OR EAX,0xFFFFFFFF
* 013BF00A 8D4D D8 LEA ECX,DWORD PTR SS:[EBP-0x28]
* 013BF00D 897D EC MOV DWORD PTR SS:[EBP-0x14],EDI
* 013BF010 8975 E8 MOV DWORD PTR SS:[EBP-0x18],ESI
* 013BF013 C645 D8 00 MOV BYTE PTR SS:[EBP-0x28],0x0
* 013BF017 E8 143AFAFF CALL yorino_t.01362A30 ; jichi: scenario call
* 013BF01C C645 FC 01 MOV BYTE PTR SS:[EBP-0x4],0x1
* 013BF020 8B8B 7C2A0000 MOV ECX,DWORD PTR DS:[EBX+0x2A7C]
* 013BF026 3BCE CMP ECX,ESI
* 013BF028 74 1C JE SHORT yorino_t.013BF046
* 013BF02A 8B11 MOV EDX,DWORD PTR DS:[ECX]
* 013BF02C 8B52 0C MOV EDX,DWORD PTR DS:[EDX+0xC]
* 013BF02F 8D45 BC LEA EAX,DWORD PTR SS:[EBP-0x44]
* 013BF032 50 PUSH EAX
* 013BF033 FFD2 CALL EDX
* 013BF035 8B8B 7C2A0000 MOV ECX,DWORD PTR DS:[EBX+0x2A7C]
* 013BF03B 8B01 MOV EAX,DWORD PTR DS:[ECX]
* 013BF03D 8B40 0C MOV EAX,DWORD PTR DS:[EAX+0xC]
* 013BF040 8D55 D8 LEA EDX,DWORD PTR SS:[EBP-0x28]
* 013BF043 52 PUSH EDX
* 013BF044 FFD0 CALL EAX
* 013BF046 8B8B 1C130000 MOV ECX,DWORD PTR DS:[EBX+0x131C]
* 013BF04C 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+0xC]
* 013BF04F 3BCF CMP ECX,EDI
* 013BF051 0F95C0 SETNE AL
* 013BF054 C683 411A0000 00 MOV BYTE PTR DS:[EBX+0x1A41],0x0
* 013BF05B 8845 08 MOV BYTE PTR SS:[EBP+0x8],AL
* 013BF05E 84C0 TEST AL,AL
* 013BF060 74 15 JE SHORT yorino_t.013BF077
* 013BF062 3BCE CMP ECX,ESI
* 013BF064 7C 11 JL SHORT yorino_t.013BF077
* 013BF066 8BB3 0C1A0000 MOV ESI,DWORD PTR DS:[EBX+0x1A0C]
* 013BF06C 85F6 TEST ESI,ESI
* 013BF06E 74 05 JE SHORT yorino_t.013BF075
* 013BF070 E8 8B500100 CALL yorino_t.013D4100
* 013BF075 33F6 XOR ESI,ESI
* 013BF077 56 PUSH ESI
* 013BF078 8D4D D8 LEA ECX,DWORD PTR SS:[EBP-0x28]
* 013BF07B 51 PUSH ECX
* 013BF07C 8D8B 00130000 LEA ECX,DWORD PTR DS:[EBX+0x1300]
* 013BF082 83C8 FF OR EAX,0xFFFFFFFF
* 013BF085 E8 A639FAFF CALL yorino_t.01362A30
* 013BF08A 56 PUSH ESI
* 013BF08B 8D55 BC LEA EDX,DWORD PTR SS:[EBP-0x44]
* 013BF08E 52 PUSH EDX
* 013BF08F 8D8B 20130000 LEA ECX,DWORD PTR DS:[EBX+0x1320]
* 013BF095 83C8 FF OR EAX,0xFFFFFFFF
* 013BF098 89BB 1C130000 MOV DWORD PTR DS:[EBX+0x131C],EDI
* 013BF09E E8 8D39FAFF CALL yorino_t.01362A30
* 013BF0A3 8B45 10 MOV EAX,DWORD PTR SS:[EBP+0x10]
* 013BF0A6 56 PUSH ESI
* 013BF0A7 50 PUSH EAX
* 013BF0A8 8D8B 3C130000 LEA ECX,DWORD PTR DS:[EBX+0x133C]
* 013BF0AE 83C8 FF OR EAX,0xFFFFFFFF
* 013BF0B1 E8 7A39FAFF CALL yorino_t.01362A30
* 013BF0B6 8B15 00A74B01 MOV EDX,DWORD PTR DS:[0x14BA700] ; yorino_t.0146603C
* 013BF0BC 8B82 CC000000 MOV EAX,DWORD PTR DS:[EDX+0xCC]
* 013BF0C2 B9 00A74B01 MOV ECX,yorino_t.014BA700
* 013BF0C7 FFD0 CALL EAX
* 013BF0C9 3BC6 CMP EAX,ESI
* 013BF0CB 7E 15 JLE SHORT yorino_t.013BF0E2
* 013BF0CD 3983 CC290000 CMP DWORD PTR DS:[EBX+0x29CC],EAX
* 013BF0D3 7C 0D JL SHORT yorino_t.013BF0E2
* 013BF0D5 8BCB MOV ECX,EBX
* 013BF0D7 E8 14650000 CALL yorino_t.013C55F0
* 013BF0DC 89B3 CC290000 MOV DWORD PTR DS:[EBX+0x29CC],ESI
* 013BF0E2 8A45 1C MOV AL,BYTE PTR SS:[EBP+0x1C]
* 013BF0E5 8883 421A0000 MOV BYTE PTR DS:[EBX+0x1A42],AL
* 013BF0EB 84C0 TEST AL,AL
* 013BF0ED 75 1F JNZ SHORT yorino_t.013BF10E
* 013BF0EF 83BB A0120000 02 CMP DWORD PTR DS:[EBX+0x12A0],0x2
* 013BF0F6 75 16 JNZ SHORT yorino_t.013BF10E
* 013BF0F8 89B3 A0120000 MOV DWORD PTR DS:[EBX+0x12A0],ESI
* 013BF0FE 8B15 00A74B01 MOV EDX,DWORD PTR DS:[0x14BA700] ; yorino_t.0146603C
* 013BF104 8B42 2C MOV EAX,DWORD PTR DS:[EDX+0x2C]
* 013BF107 B9 00A74B01 MOV ECX,yorino_t.014BA700
* 013BF10C FFD0 CALL EAX
* 013BF10E 8B45 08 MOV EAX,DWORD PTR SS:[EBP+0x8]
* 013BF111 8B53 10 MOV EDX,DWORD PTR DS:[EBX+0x10]
* 013BF114 8B52 3C MOV EDX,DWORD PTR DS:[EDX+0x3C]
* 013BF117 6A 00 PUSH 0x0
* 013BF119 6A 01 PUSH 0x1
* 013BF11B 50 PUSH EAX
* 013BF11C 8D4D D8 LEA ECX,DWORD PTR SS:[EBP-0x28]
* 013BF11F 51 PUSH ECX
* 013BF120 8D45 BC LEA EAX,DWORD PTR SS:[EBP-0x44]
* 013BF123 50 PUSH EAX
* 013BF124 8D4B 10 LEA ECX,DWORD PTR DS:[EBX+0x10]
* 013BF127 FFD2 CALL EDX
* 013BF129 8B43 10 MOV EAX,DWORD PTR DS:[EBX+0x10]
* 013BF12C 8BB3 0C1A0000 MOV ESI,DWORD PTR DS:[EBX+0x1A0C]
* 013BF132 8945 1C MOV DWORD PTR SS:[EBP+0x1C],EAX
* 013BF135 8B83 141A0000 MOV EAX,DWORD PTR DS:[EBX+0x1A14]
* 013BF13B E8 204B0100 CALL yorino_t.013D3C60
* 013BF140 8B55 1C MOV EDX,DWORD PTR SS:[EBP+0x1C]
* 013BF143 50 PUSH EAX
* 013BF144 8B42 4C MOV EAX,DWORD PTR DS:[EDX+0x4C]
* 013BF147 8BCF MOV ECX,EDI
* 013BF149 51 PUSH ECX
* 013BF14A 8D4B 10 LEA ECX,DWORD PTR DS:[EBX+0x10]
* 013BF14D FFD0 CALL EAX
* 013BF14F 8B53 10 MOV EDX,DWORD PTR DS:[EBX+0x10]
* 013BF152 8B42 78 MOV EAX,DWORD PTR DS:[EDX+0x78]
* 013BF155 8D4B 10 LEA ECX,DWORD PTR DS:[EBX+0x10]
* 013BF158 FFD0 CALL EAX
* 013BF15A 8BF3 MOV ESI,EBX
* 013BF15C 8983 64130000 MOV DWORD PTR DS:[EBX+0x1364],EAX
* 013BF162 E8 B9B0FFFF CALL yorino_t.013BA220
* 013BF167 84C0 TEST AL,AL
* 013BF169 74 6D JE SHORT yorino_t.013BF1D8
* 013BF16B 8B53 10 MOV EDX,DWORD PTR DS:[EBX+0x10]
* 013BF16E 8B42 40 MOV EAX,DWORD PTR DS:[EDX+0x40]
* 013BF171 6A 00 PUSH 0x0
* 013BF173 6A 01 PUSH 0x1
* 013BF175 8D4B 10 LEA ECX,DWORD PTR DS:[EBX+0x10]
* 013BF178 FFD0 CALL EAX
* 013BF17A E8 C1FDFFFF CALL yorino_t.013BEF40
* 013BF17F 33C9 XOR ECX,ECX
* 013BF181 8BFB MOV EDI,EBX
* 013BF183 E8 C8B8FFFF CALL yorino_t.013BAA50
* 013BF188 33FF XOR EDI,EDI
* 013BF18A 89BB 181A0000 MOV DWORD PTR DS:[EBX+0x1A18],EDI
* 013BF190 E8 3BF0FFFF CALL yorino_t.013BE1D0
* 013BF195 68 78CB4401 PUSH yorino_t.0144CB78
* 013BF19A 8D75 A0 LEA ESI,DWORD PTR SS:[EBP-0x60]
* 013BF19D C745 B4 0F000000 MOV DWORD PTR SS:[EBP-0x4C],0xF
* 013BF1A4 897D B0 MOV DWORD PTR SS:[EBP-0x50],EDI
* 013BF1A7 C645 A0 00 MOV BYTE PTR SS:[EBP-0x60],0x0
* 013BF1AB E8 A065FAFF CALL yorino_t.01365750
* 013BF1B0 C645 FC 02 MOV BYTE PTR SS:[EBP-0x4],0x2
* 013BF1B4 8B53 10 MOV EDX,DWORD PTR DS:[EBX+0x10]
* 013BF1B7 8B52 6C MOV EDX,DWORD PTR DS:[EDX+0x6C]
* 013BF1BA 8D4B 10 LEA ECX,DWORD PTR DS:[EBX+0x10]
* 013BF1BD 6A 01 PUSH 0x1
* 013BF1BF 8BC6 MOV EAX,ESI
* 013BF1C1 50 PUSH EAX
* 013BF1C2 FFD2 CALL EDX
* 013BF1C4 837D B4 10 CMP DWORD PTR SS:[EBP-0x4C],0x10
* 013BF1C8 72 56 JB SHORT yorino_t.013BF220
* 013BF1CA 8B45 A0 MOV EAX,DWORD PTR SS:[EBP-0x60]
* 013BF1CD 50 PUSH EAX
* 013BF1CE E8 28B50500 CALL yorino_t.0141A6FB
* 013BF1D3 83C4 04 ADD ESP,0x4
* 013BF1D6 EB 48 JMP SHORT yorino_t.013BF220
* 013BF1D8 8B7D 10 MOV EDI,DWORD PTR SS:[EBP+0x10]
* 013BF1DB C783 181A0000 04>MOV DWORD PTR DS:[EBX+0x1A18],0x4
* 013BF1E5 837F 10 00 CMP DWORD PTR DS:[EDI+0x10],0x0
* 013BF1E9 C705 64514801 00>MOV DWORD PTR DS:[0x1485164],0x0
* 013BF1F3 76 2B JBE SHORT yorino_t.013BF220
* 013BF1F5 8BF3 MOV ESI,EBX
* 013BF1F7 E8 D4EFFFFF CALL yorino_t.013BE1D0
* 013BF1FC 8B15 00A74B01 MOV EDX,DWORD PTR DS:[0x14BA700] ; yorino_t.0146603C
* 013BF202 8B82 8C000000 MOV EAX,DWORD PTR DS:[EDX+0x8C]
* 013BF208 B9 00A74B01 MOV ECX,yorino_t.014BA700
* 013BF20D FFD0 CALL EAX
* 013BF20F 84C0 TEST AL,AL
* 013BF211 75 0D JNZ SHORT yorino_t.013BF220
* 013BF213 837F 10 00 CMP DWORD PTR DS:[EDI+0x10],0x0
* 013BF217 76 07 JBE SHORT yorino_t.013BF220
* 013BF219 57 PUSH EDI
* 013BF21A 53 PUSH EBX
* 013BF21B E8 A0EAFFFF CALL yorino_t.013BDCC0
* 013BF220 BE 10000000 MOV ESI,0x10
* 013BF225 C683 C8290000 00 MOV BYTE PTR DS:[EBX+0x29C8],0x0
* 013BF22C 3975 EC CMP DWORD PTR SS:[EBP-0x14],ESI
* 013BF22F 72 0C JB SHORT yorino_t.013BF23D
* 013BF231 8B4D D8 MOV ECX,DWORD PTR SS:[EBP-0x28]
* 013BF234 51 PUSH ECX
* 013BF235 E8 C1B40500 CALL yorino_t.0141A6FB
* 013BF23A 83C4 04 ADD ESP,0x4
* 013BF23D 3975 D0 CMP DWORD PTR SS:[EBP-0x30],ESI
* 013BF240 5F POP EDI
* 013BF241 5E POP ESI
* 013BF242 C745 EC 0F000000 MOV DWORD PTR SS:[EBP-0x14],0xF
* 013BF249 C745 E8 00000000 MOV DWORD PTR SS:[EBP-0x18],0x0
* 013BF250 C645 D8 00 MOV BYTE PTR SS:[EBP-0x28],0x0
* 013BF254 5B POP EBX
* 013BF255 72 0C JB SHORT yorino_t.013BF263
* 013BF257 8B55 BC MOV EDX,DWORD PTR SS:[EBP-0x44]
* 013BF25A 52 PUSH EDX
* 013BF25B E8 9BB40500 CALL yorino_t.0141A6FB
* 013BF260 83C4 04 ADD ESP,0x4
* 013BF263 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-0xC]
* 013BF266 64:890D 00000000 MOV DWORD PTR FS:[0],ECX
* 013BF26D 8BE5 MOV ESP,EBP
* 013BF26F 5D POP EBP
* 013BF270 C2 1800 RETN 0x18
* 013BF273 CC INT3
* 013BF274 CC INT3
* 013BF275 CC INT3
* 013BF276 CC INT3
* 013BF277 CC INT3
* 013BF278 CC INT3
* 013BF279 CC INT3
* 013BF27A CC INT3
* 013BF27B CC INT3
* 013BF27C CC INT3
* 013BF27D CC INT3
* 013BF27E CC INT3
* 013BF27F CC INT3
*
* Sample text:
* 00C3091C 57 48 49 54 45 2E 70 6E 67 00 00 00 00 00 00 00 WHITE.png.......
* 00C3092C 09 00 00 00 0F 00 00 00 00 00 00 00 00 00 00 00 ...............
*/
TextUnionA *arg_,
argValue_;
std::unordered_map<uintptr_t,int>addr_role;
bool hookBeforehookBefore(hook_stack*s,void* data1, size_t* len,uintptr_t*role)
{
static std::string data_;
//auto arg = (TextUnionA *)s->ecx;
auto arg = (TextUnionA *)s->stack[0]; // arg1
if (!arg || !arg->isValid())
return false;
auto text = arg->getText();
if (all_ascii(text))
return false;
int size = arg->size,
trimmedSize = size;
auto trimmedText = trim(text, &trimmedSize);
if (!trimmedSize || !*trimmedText)
return false;
//auto sig = Engine::hashThreadSignature(role, retaddr);
std::string oldData(trimmedText, trimmedSize);
auto retaddr=s->stack[0];
*role=addr_role[retaddr];
if (*role == Engine::NameRole)
strReplace(oldData,"\x81\x40", ""); // remove spaces in the middle of names
strcpy((char*)data1,oldData.c_str());
*len=oldData.size();return true;
}
void hookafter(hook_stack*s,void* data1, size_t len){
std::string newData = std::string((LPSTR)data1,len);
auto arg = (TextUnionA *)s->stack[0]; // arg1
auto text = arg->getText();
int size = arg->size,
trimmedSize = size;
auto trimmedText = trim(text, &trimmedSize);
int prefixSize = trimmedText - text,
suffixSize = size - prefixSize - trimmedSize;
if (prefixSize)
newData.insert(0,std::string(text, prefixSize));
if (suffixSize)
newData.append(trimmedText + trimmedSize, suffixSize);
arg_ = arg;
argValue_ = *arg;
static std::string data_;
data_ = newData;
arg->setText(data_);
}
bool hookAfter(hook_stack*s,void* data1, size_t* len,uintptr_t*role)
{
if (arg_) {
*arg_ = argValue_;
arg_ = nullptr;
}
return 0;
}
} // namespace Private
/**
* Sample game: ソレヨリノ前奏詩
* arg1 is source, ecx is target.
*
* 01052A2D CC INT3
* 01052A2E CC INT3
* 01052A2F CC INT3
* 01052A30 55 PUSH EBP
* 01052A31 8BEC MOV EBP,ESP
* 01052A33 53 PUSH EBX
* 01052A34 8B5D 0C MOV EBX,DWORD PTR SS:[EBP+0xC]
* 01052A37 56 PUSH ESI
* 01052A38 8BF1 MOV ESI,ECX ; jichi: ecx is target address?
* 01052A3A 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+0x8]
* 01052A3D 57 PUSH EDI
* 01052A3E 8B79 10 MOV EDI,DWORD PTR DS:[ECX+0x10] ; jichi: source size
* 01052A41 3BFB CMP EDI,EBX
* 01052A43 73 0A JNB SHORT yorino_t.01052A4F
* 01052A45 68 88CA1301 PUSH yorino_t.0113CA88 ; ASCII "invalid string position"
* 01052A4A E8 337C0B00 CALL yorino_t.0110A682
* 01052A4F 2BFB SUB EDI,EBX
* 01052A51 3BC7 CMP EAX,EDI
* 01052A53 0F42F8 CMOVB EDI,EAX
* 01052A56 3BF1 CMP ESI,ECX
* 01052A58 75 1D JNZ SHORT yorino_t.01052A77
* 01052A5A 8D0C1F LEA ECX,DWORD PTR DS:[EDI+EBX]
* 01052A5D 83C8 FF OR EAX,0xFFFFFFFF
* 01052A60 E8 EBFCFFFF CALL yorino_t.01052750
* 01052A65 8BC3 MOV EAX,EBX
* 01052A67 33C9 XOR ECX,ECX
* 01052A69 E8 E2FCFFFF CALL yorino_t.01052750
* 01052A6E 5F POP EDI
* 01052A6F 8BC6 MOV EAX,ESI
* 01052A71 5E POP ESI
* 01052A72 5B POP EBX
* 01052A73 5D POP EBP
* 01052A74 C2 0800 RETN 0x8
* 01052A77 83FF FE CMP EDI,-0x2
* 01052A7A 76 0A JBE SHORT yorino_t.01052A86
* 01052A7C 68 B4CA1301 PUSH yorino_t.0113CAB4 ; ASCII "string too long"
* 01052A81 E8 AF7B0B00 CALL yorino_t.0110A635
* 01052A86 8B46 14 MOV EAX,DWORD PTR DS:[ESI+0x14]
* 01052A89 3BC7 CMP EAX,EDI
* 01052A8B 73 27 JNB SHORT yorino_t.01052AB4
* 01052A8D 8B46 10 MOV EAX,DWORD PTR DS:[ESI+0x10]
* 01052A90 50 PUSH EAX
* 01052A91 57 PUSH EDI
* 01052A92 56 PUSH ESI
* 01052A93 E8 88FDFFFF CALL yorino_t.01052820
* 01052A98 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+0x8]
* 01052A9B 85FF TEST EDI,EDI
* 01052A9D 74 68 JE SHORT yorino_t.01052B07
* 01052A9F B8 10000000 MOV EAX,0x10
* 01052AA4 3941 14 CMP DWORD PTR DS:[ECX+0x14],EAX
* 01052AA7 72 02 JB SHORT yorino_t.01052AAB
* 01052AA9 8B09 MOV ECX,DWORD PTR DS:[ECX]
* 01052AAB 3946 14 CMP DWORD PTR DS:[ESI+0x14],EAX
* 01052AAE 72 2A JB SHORT yorino_t.01052ADA
* 01052AB0 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 01052AB2 EB 28 JMP SHORT yorino_t.01052ADC
* 01052AB4 85FF TEST EDI,EDI
* 01052AB6 ^75 E7 JNZ SHORT yorino_t.01052A9F
* 01052AB8 897E 10 MOV DWORD PTR DS:[ESI+0x10],EDI
* 01052ABB 83F8 10 CMP EAX,0x10
* 01052ABE 72 0E JB SHORT yorino_t.01052ACE
* 01052AC0 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 01052AC2 5F POP EDI
* 01052AC3 C600 00 MOV BYTE PTR DS:[EAX],0x0
* 01052AC6 8BC6 MOV EAX,ESI
* 01052AC8 5E POP ESI
* 01052AC9 5B POP EBX
* 01052ACA 5D POP EBP
* 01052ACB C2 0800 RETN 0x8
* 01052ACE 5F POP EDI
* 01052ACF 8BC6 MOV EAX,ESI
* 01052AD1 5E POP ESI
* 01052AD2 C600 00 MOV BYTE PTR DS:[EAX],0x0
* 01052AD5 5B POP EBX
* 01052AD6 5D POP EBP
* 01052AD7 C2 0800 RETN 0x8
* 01052ADA 8BC6 MOV EAX,ESI ; jichi: esi is target address
* 01052ADC 57 PUSH EDI ; jichi: source size
* 01052ADD 03CB ADD ECX,EBX
* 01052ADF 51 PUSH ECX ; jichi: source
* 01052AE0 50 PUSH EAX ; jichi: target
* 01052AE1 E8 9AC80B00 CALL yorino_t.0110F380 ; jichi: called here
* 01052AE6 83C4 0C ADD ESP,0xC
* 01052AE9 837E 14 10 CMP DWORD PTR DS:[ESI+0x14],0x10
* 01052AED 897E 10 MOV DWORD PTR DS:[ESI+0x10],EDI
* 01052AF0 72 0F JB SHORT yorino_t.01052B01
* 01052AF2 8B06 MOV EAX,DWORD PTR DS:[ESI]
* 01052AF4 C60438 00 MOV BYTE PTR DS:[EAX+EDI],0x0
* 01052AF8 5F POP EDI
* 01052AF9 8BC6 MOV EAX,ESI
* 01052AFB 5E POP ESI
* 01052AFC 5B POP EBX
* 01052AFD 5D POP EBP
* 01052AFE C2 0800 RETN 0x8
* 01052B01 8BC6 MOV EAX,ESI
* 01052B03 C60438 00 MOV BYTE PTR DS:[EAX+EDI],0x0
* 01052B07 5F POP EDI
* 01052B08 8BC6 MOV EAX,ESI
* 01052B0A 5E POP ESI
* 01052B0B 5B POP EBX
* 01052B0C 5D POP EBP
* 01052B0D C2 0800 RETN 0x8
* 01052B10 6A 00 PUSH 0x0
* 01052B12 50 PUSH EAX
* 01052B13 C746 14 0F000000 MOV DWORD PTR DS:[ESI+0x14],0xF
* 01052B1A C746 10 00000000 MOV DWORD PTR DS:[ESI+0x10],0x0
* 01052B21 83C8 FF OR EAX,0xFFFFFFFF
* 01052B24 8BCE MOV ECX,ESI
* 01052B26 C606 00 MOV BYTE PTR DS:[ESI],0x0
* 01052B29 E8 02FFFFFF CALL yorino_t.01052A30
* 01052B2E 8BC6 MOV EAX,ESI
* 01052B30 C3 RETN
* 01052B31 CC INT3
* 01052B32 CC INT3
* 01052B33 CC INT3
* 01052B34 CC INT3
* 01052B35 CC INT3
* 01052B36 CC INT3
* 01052B37 CC INT3
* 01052B38 CC INT3
* 01052B39 CC INT3
* 01052B3A CC INT3
* 01052B3B CC INT3
* 01052B3C CC INT3
*
* 005CF5C4 01C17D68
* 005CF5C8 00000026
* 005CF5CC /005CF5EC
* 005CF5D0 |00172AE6 RETURN to yorino_t.00172AE6 from yorino_t.0022F380
* 005CF5D4 |01C154F0 ; jichi: target text
* 005CF5D8 |01C15608 ; jcihi: source text
* 005CF5DC |00000026 ; jichi: source size
* 005CF5E0 |00000082 ; jichi: capacity? not sure
* 005CF5E4 |00000000
* 005CF5E8 |01C16A68
* 005CF5EC ]005CF668
* 005CF5F0 |001CF08A RETURN to yorino_t.001CF08A from yorino_t.00172A30
* 005CF5F4 |005CF640
* 005CF5F8 |00000000
* 005CF5FC |01C19500
*/
bool attach(ULONG startAddress, ULONG stopAddress)
{
const uint8_t bytes[] = {
0x8b,0xc6, // 01052ada 8bc6 mov eax,esi ; jichi: esi is target address
0x57, // 01052adc 57 push edi ; jichi: source size
0x03,0xcb, // 01052add 03cb add ecx,ebx
0x51, // 01052adf 51 push ecx ; jichi: source
0x50 // 01052ae0 50 push eax ; jichi: target
//0xe8, XX4, // 01052ae1 e8 9ac80b00 call yorino_t.0110f380 ; jichi: called here
//0x83,0xc4, 0x0c // 01052ae6 83c4 0c add esp,0xc
};
//enum { addr_offset = sizeof(bytes) - 8 };
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
if (!addr)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
return false;
//return winhook::hook_before(addr, Private::hookBefore);
bool count = false;
auto fun = [&count](ULONG addr) -> bool {
// Sample game: ソレヨリノ前奏詩
// 013BEFFA E8 313AFAFF CALL yorino_t.01362A30 ; jichi: name call
// 013BEFFF 8B4D 18 MOV ECX,DWORD PTR SS:[EBP+0x18]
// 013BF002 56 PUSH ESI
// 013BF003 8975 FC MOV DWORD PTR SS:[EBP-0x4],ESI
// 013BF006 51 PUSH ECX
// 013BF007 83C8 FF OR EAX,0xFFFFFFFF
// 013BF00A 8D4D D8 LEA ECX,DWORD PTR SS:[EBP-0x28]
// 013BF00D 897D EC MOV DWORD PTR SS:[EBP-0x14],EDI
// 013BF010 8975 E8 MOV DWORD PTR SS:[EBP-0x18],ESI
// 013BF013 C645 D8 00 MOV BYTE PTR SS:[EBP-0x28],0x0
// 013BF017 E8 143AFAFF CALL yorino_t.01362A30 ; jichi: scenario call
// 013BF01C C645 FC 01 MOV BYTE PTR SS:[EBP-0x4],0x1
// 013BF020 8B8B 7C2A0000 MOV ECX,DWORD PTR DS:[EBX+0x2A7C]
// 013BF026 3BCE CMP ECX,ESI
//
// Bad scenario to skip:
//
// 0035A9A3 C745 E4 0F000000 MOV DWORD PTR SS:[EBP-0x1C],0xF
// 0035A9AA C745 E0 00000000 MOV DWORD PTR SS:[EBP-0x20],0x0
// 0035A9B1 C645 D0 00 MOV BYTE PTR SS:[EBP-0x30],0x0
// 0035A9B5 -E9 4656D001 JMP 02060000 ; jichi: here
// 0035A9BA C645 FC 01 MOV BYTE PTR SS:[EBP-0x4],0x1
// 0035A9BE 8B7D E0 MOV EDI,DWORD PTR SS:[EBP-0x20]
// 0035A9C1 83FF 01 CMP EDI,0x1
// 0035A9C4 0F86 B0000000 JBE .0035AA7A
auto retaddr = addr + 5;
auto role = Engine::OtherRole;
switch (*(DWORD *)retaddr) {
case 0x56184d8b:
// 013BEFFF 8B4D 18 MOV ECX,DWORD PTR SS:[EBP+0x18]
// 013BF002 56 PUSH ESI
role = Engine::NameRole;
break;
case 0x01fc45c6: // 013BF01C C645 FC 01 MOV BYTE PTR SS:[EBP-0x4],0x1
if (*(DWORD *)(retaddr - 5 - sizeof(DWORD)) == 0x00D845C6) { // previous instruction
role = Engine::ScenarioRole;
break;
}
default: return true;
}
Private::addr_role[retaddr]=role;
{
HookParam hp;
hp.address=addr;
hp.hook_before=Private::hookBeforehookBefore;
hp.hook_after=Private::hookafter;
hp.type=EMBED_ABLE|USING_STRING|EMBED_DYNA_SJIS;
hp.hook_font=F_GetGlyphOutlineA;
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){
static std::regex rx("\\{.*?\\}");
auto _=std::regex_replace(std::string((char*)data,*len), rx, "");
strcpy((char*)data,_.c_str());*len=_.size();return true;
};
count|=NewHook(hp,"EmbedMinori");
}
{
HookParam hp;
hp.address=addr+5;
hp.hook_before=Private::hookAfter;
hp.hook_after=Private::hookafter;
hp.type=EMBED_ABLE|HOOK_EMPTY;
count|=NewHook(hp,"EmbedMinori");
}
return true; // replace all functions
};
MemDbg::iterNearCallAddress(fun, addr, startAddress, stopAddress);
return count;
}
} // namespace ScenarioHook
} // unnamed namespace
bool Minori::attach_function() {
bool embed=ScenarioHook::attach(processStartAddress,processStopAddress);
return InsertMinoriHooks()||embed;
}