LunaHook-mirror/LunaHook/engine32/Silkys.cpp
恍兮惚兮 7de41ab004 Aisystem6
2024-09-24 23:25:45 +08:00

774 lines
26 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

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 "Silkys.h"
#include "util/textunion.h"
/** jichi: 6/17/2015
* Sample games
* - 堕ちてぁ<E381A6>新妻 trial
* - 根雪の幻影 trial
*
* This function is found by backtracking GetGlyphOutlineA.
* There are two GetGlyphOutlineA, which are in the same function.
* That function are called by two other functions.
* The second function is hooked.
*
* 堕ちてぁ<E381A6>新妻
* baseaddr = 08e0000
*
* 0096652E CC INT3
* 0096652F CC INT3
* 00966530 55 PUSH EBP
* 00966531 8BEC MOV EBP,ESP
* 00966533 83EC 18 SUB ESP,0x18
* 00966536 A1 00109F00 MOV EAX,DWORD PTR DS:[0x9F1000]
* 0096653B 33C5 XOR EAX,EBP
* 0096653D 8945 FC MOV DWORD PTR SS:[EBP-0x4],EAX
* 00966540 53 PUSH EBX
* 00966541 8B5D 0C MOV EBX,DWORD PTR SS:[EBP+0xC]
* 00966544 56 PUSH ESI
* 00966545 8B75 08 MOV ESI,DWORD PTR SS:[EBP+0x8]
* 00966548 57 PUSH EDI
* 00966549 6A 00 PUSH 0x0
* 0096654B 894D EC MOV DWORD PTR SS:[EBP-0x14],ECX
* 0096654E 8B0D FCB7A200 MOV ECX,DWORD PTR DS:[0xA2B7FC]
* 00966554 68 90D29D00 PUSH .009DD290 ; ASCII "/Config/SceneSkip"
* 00966559 895D F0 MOV DWORD PTR SS:[EBP-0x10],EBX
* 0096655C E8 2F4A0100 CALL .0097AF90
* 00966561 83F8 01 CMP EAX,0x1
* 00966564 0F84 E0010000 JE .0096674A
* 0096656A 8B55 EC MOV EDX,DWORD PTR SS:[EBP-0x14]
* 0096656D 85DB TEST EBX,EBX
* 0096656F 75 09 JNZ SHORT .0096657A
* 00966571 8B42 04 MOV EAX,DWORD PTR DS:[EDX+0x4]
* 00966574 8B40 38 MOV EAX,DWORD PTR DS:[EAX+0x38]
* 00966577 8945 F0 MOV DWORD PTR SS:[EBP-0x10],EAX
* 0096657A 33C0 XOR EAX,EAX
* 0096657C C645 F8 00 MOV BYTE PTR SS:[EBP-0x8],0x0
* 00966580 33C9 XOR ECX,ECX
* 00966582 66:8945 F9 MOV WORD PTR SS:[EBP-0x7],AX
* 00966586 3946 14 CMP DWORD PTR DS:[ESI+0x14],EAX
* 00966589 0F86 BB010000 JBE .0096674A
*
* Scenario stack:
*
* 002FF9DC 00955659 RETURN to .00955659 from .00966530
* 002FF9E0 002FFA10 ; jichi: text in [arg1+4]
* 002FF9E4 00000000 ; arg2 is zero
* 002FF9E8 00000001
* 002FF9EC 784B8FC7
*
* Name stack:
*
* 002FF59C 00930A76 RETURN to .00930A76 from .00966530
* 002FF5A0 002FF5D0 ; jichi: text in [arg1+4]
* 002FF5A4 004DDEC0 ; arg2 is a pointer
* 002FF5A8 00000001
* 002FF5AC 784B8387
* 002FF5B0 00000182
* 002FF5B4 00000000
*
* Scenario and Name are called by different callers.
*
* 根雪の幻影
*
* 00A1A00E CC INT3
* 00A1A00F CC INT3
* 00A1A010 55 PUSH EBP
* 00A1A011 8BEC MOV EBP,ESP
* 00A1A013 83EC 18 SUB ESP,0x18
* 00A1A016 A1 0050AA00 MOV EAX,DWORD PTR DS:[0xAA5000]
* 00A1A01B 33C5 XOR EAX,EBP
* 00A1A01D 8945 FC MOV DWORD PTR SS:[EBP-0x4],EAX
* 00A1A020 53 PUSH EBX
* 00A1A021 56 PUSH ESI
* 00A1A022 8B75 0C MOV ESI,DWORD PTR SS:[EBP+0xC]
* 00A1A025 57 PUSH EDI
* 00A1A026 8B7D 08 MOV EDI,DWORD PTR SS:[EBP+0x8]
* 00A1A029 6A 00 PUSH 0x0
* 00A1A02B 894D F0 MOV DWORD PTR SS:[EBP-0x10],ECX
* 00A1A02E 8B0D C434AE00 MOV ECX,DWORD PTR DS:[0xAE34C4]
* 00A1A034 68 F816A900 PUSH .00A916F8 ; ASCII "/Config/SceneSkip"
* 00A1A039 8975 EC MOV DWORD PTR SS:[EBP-0x14],ESI
* 00A1A03C E8 7F510100 CALL .00A2F1C0
* 00A1A041 83F8 01 CMP EAX,0x1
* 00A1A044 0F84 3A010000 JE .00A1A184
* 00A1A04A 8B4D F0 MOV ECX,DWORD PTR SS:[EBP-0x10]
* 00A1A04D 85F6 TEST ESI,ESI
* 00A1A04F 75 09 JNZ SHORT .00A1A05A
* 00A1A051 8B41 04 MOV EAX,DWORD PTR DS:[ECX+0x4]
* 00A1A054 8B40 38 MOV EAX,DWORD PTR DS:[EAX+0x38]
* 00A1A057 8945 EC MOV DWORD PTR SS:[EBP-0x14],EAX
* 00A1A05A 33C0 XOR EAX,EAX
* 00A1A05C C645 F8 00 MOV BYTE PTR SS:[EBP-0x8],0x0
* 00A1A060 33DB XOR EBX,EBX
* 00A1A062 66:8945 F9 MOV WORD PTR SS:[EBP-0x7],AX
* 00A1A066 3947 14 CMP DWORD PTR DS:[EDI+0x14],EAX
* 00A1A069 0F86 15010000 JBE .00A1A184
* 00A1A06F 90 NOP
* 00A1A070 837F 18 10 CMP DWORD PTR DS:[EDI+0x18],0x10
* 00A1A074 72 05 JB SHORT .00A1A07B
* 00A1A076 8B47 04 MOV EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A079 EB 03 JMP SHORT .00A1A07E
* 00A1A07B 8D47 04 LEA EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A07E 803C18 00 CMP BYTE PTR DS:[EAX+EBX],0x0
* 00A1A082 0F84 FC000000 JE .00A1A184
* 00A1A088 837F 18 10 CMP DWORD PTR DS:[EDI+0x18],0x10
* 00A1A08C 72 05 JB SHORT .00A1A093
* 00A1A08E 8B47 04 MOV EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A091 EB 03 JMP SHORT .00A1A096
* 00A1A093 8D47 04 LEA EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A096 8A0418 MOV AL,BYTE PTR DS:[EAX+EBX]
* 00A1A099 3C 81 CMP AL,0x81
* 00A1A09B 72 04 JB SHORT .00A1A0A1
* 00A1A09D 3C 9F CMP AL,0x9F
* 00A1A09F 76 06 JBE SHORT .00A1A0A7
* 00A1A0A1 04 20 ADD AL,0x20
* 00A1A0A3 3C 0F CMP AL,0xF
* 00A1A0A5 77 40 JA SHORT .00A1A0E7
* 00A1A0A7 837F 18 10 CMP DWORD PTR DS:[EDI+0x18],0x10
* 00A1A0AB 72 05 JB SHORT .00A1A0B2
* 00A1A0AD 8B47 04 MOV EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A0B0 EB 03 JMP SHORT .00A1A0B5
* 00A1A0B2 8D47 04 LEA EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A0B5 837F 18 10 CMP DWORD PTR DS:[EDI+0x18],0x10
* 00A1A0B9 8A0418 MOV AL,BYTE PTR DS:[EAX+EBX]
* 00A1A0BC 8845 F8 MOV BYTE PTR SS:[EBP-0x8],AL
* 00A1A0BF 72 13 JB SHORT .00A1A0D4
* 00A1A0C1 8B47 04 MOV EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A0C4 C645 F7 02 MOV BYTE PTR SS:[EBP-0x9],0x2
* 00A1A0C8 8A4418 01 MOV AL,BYTE PTR DS:[EAX+EBX+0x1]
* 00A1A0CC 83C3 02 ADD EBX,0x2
* 00A1A0CF 8845 F9 MOV BYTE PTR SS:[EBP-0x7],AL
* 00A1A0D2 EB 30 JMP SHORT .00A1A104
* 00A1A0D4 8D47 04 LEA EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A0D7 C645 F7 02 MOV BYTE PTR SS:[EBP-0x9],0x2
* 00A1A0DB 8A4418 01 MOV AL,BYTE PTR DS:[EAX+EBX+0x1]
* 00A1A0DF 83C3 02 ADD EBX,0x2
* 00A1A0E2 8845 F9 MOV BYTE PTR SS:[EBP-0x7],AL
* 00A1A0E5 EB 1D JMP SHORT .00A1A104
* 00A1A0E7 837F 18 10 CMP DWORD PTR DS:[EDI+0x18],0x10
* 00A1A0EB 72 05 JB SHORT .00A1A0F2
* 00A1A0ED 8B47 04 MOV EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A0F0 EB 03 JMP SHORT .00A1A0F5
* 00A1A0F2 8D47 04 LEA EAX,DWORD PTR DS:[EDI+0x4]
* 00A1A0F5 8A0418 MOV AL,BYTE PTR DS:[EAX+EBX]
* 00A1A0F8 43 INC EBX
* 00A1A0F9 8845 F8 MOV BYTE PTR SS:[EBP-0x8],AL
* 00A1A0FC C645 F9 00 MOV BYTE PTR SS:[EBP-0x7],0x0
* 00A1A100 C645 F7 01 MOV BYTE PTR SS:[EBP-0x9],0x1
* 00A1A104 807F 48 01 CMP BYTE PTR DS:[EDI+0x48],0x1
* 00A1A108 75 21 JNZ SHORT .00A1A12B
* 00A1A10A 8B49 08 MOV ECX,DWORD PTR DS:[ECX+0x8]
* 00A1A10D 8D47 38 LEA EAX,DWORD PTR DS:[EDI+0x38]
* 00A1A110 50 PUSH EAX
* 00A1A111 FF77 28 PUSH DWORD PTR DS:[EDI+0x28]
* 00A1A114 8B47 24 MOV EAX,DWORD PTR DS:[EDI+0x24]
* 00A1A117 03C0 ADD EAX,EAX
* 00A1A119 50 PUSH EAX
* 00A1A11A 8D47 20 LEA EAX,DWORD PTR DS:[EDI+0x20]
* 00A1A11D 50 PUSH EAX
* 00A1A11E 8D47 1C LEA EAX,DWORD PTR DS:[EDI+0x1C]
* 00A1A121 50 PUSH EAX
* 00A1A122 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-0x8]
* 00A1A125 50 PUSH EAX
* 00A1A126 E8 85220000 CALL .00A1C3B0
* 00A1A12B FF77 34 PUSH DWORD PTR DS:[EDI+0x34]
* 00A1A12E 8B4D EC MOV ECX,DWORD PTR SS:[EBP-0x14]
* 00A1A131 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-0x8]
* 00A1A134 FF77 4C PUSH DWORD PTR DS:[EDI+0x4C]
* 00A1A137 FF77 30 PUSH DWORD PTR DS:[EDI+0x30]
* 00A1A13A FF77 2C PUSH DWORD PTR DS:[EDI+0x2C]
* 00A1A13D FF77 20 PUSH DWORD PTR DS:[EDI+0x20]
* 00A1A140 FF77 1C PUSH DWORD PTR DS:[EDI+0x1C]
* 00A1A143 50 PUSH EAX
* 00A1A144 E8 1733FFFF CALL .00A0D460
* 00A1A149 0FBE45 F7 MOVSX EAX,BYTE PTR SS:[EBP-0x9]
* 00A1A14D 0FAF47 24 IMUL EAX,DWORD PTR DS:[EDI+0x24]
* 00A1A151 0147 1C ADD DWORD PTR DS:[EDI+0x1C],EAX
* 00A1A154 807F 48 00 CMP BYTE PTR DS:[EDI+0x48],0x0
* 00A1A158 8B47 1C MOV EAX,DWORD PTR DS:[EDI+0x1C]
* 00A1A15B 75 1B JNZ SHORT .00A1A178
* 00A1A15D 3947 40 CMP DWORD PTR DS:[EDI+0x40],EAX
* 00A1A160 7F 16 JG SHORT .00A1A178
* 00A1A162 8B47 38 MOV EAX,DWORD PTR DS:[EDI+0x38]
* 00A1A165 8B4F 28 MOV ECX,DWORD PTR DS:[EDI+0x28]
* 00A1A168 014F 20 ADD DWORD PTR DS:[EDI+0x20],ECX
* 00A1A16B 8947 1C MOV DWORD PTR DS:[EDI+0x1C],EAX
* 00A1A16E 8B47 20 MOV EAX,DWORD PTR DS:[EDI+0x20]
* 00A1A171 03C1 ADD EAX,ECX
* 00A1A173 3B47 44 CMP EAX,DWORD PTR DS:[EDI+0x44]
* 00A1A176 7D 0C JGE SHORT .00A1A184
* 00A1A178 8B4D F0 MOV ECX,DWORD PTR SS:[EBP-0x10]
* 00A1A17B 3B5F 14 CMP EBX,DWORD PTR DS:[EDI+0x14]
* 00A1A17E ^0F82 ECFEFFFF JB .00A1A070
* 00A1A184 8B4D FC MOV ECX,DWORD PTR SS:[EBP-0x4]
* 00A1A187 5F POP EDI
* 00A1A188 5E POP ESI
* 00A1A189 33CD XOR ECX,EBP
* 00A1A18B 5B POP EBX
* 00A1A18C E8 87600200 CALL .00A40218
* 00A1A191 8BE5 MOV ESP,EBP
* 00A1A193 5D POP EBP
* 00A1A194 C2 0C00 RETN 0xC
* 00A1A197 CC INT3
* 00A1A198 CC INT3
*/
static void SpecialHookSilkys(hook_stack *stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t *len)
{
// DWORD arg1 = *(DWORD *)(esp_base + 0x4);
DWORD arg1 = stack->stack[1],
arg2 = stack->stack[2];
int size = *(DWORD *)(arg1 + 0x14);
if (size <= 0)
return;
enum
{
ShortTextCapacity = 0x10
};
DWORD text = 0;
// if (arg2 == 0) {
if (size >= ShortTextCapacity)
{
text = *(DWORD *)(arg1 + 4);
if (text && ::IsBadReadPtr((LPCVOID)text, size)) // this might not be needed though
text = 0;
}
if (!text)
{ // short text
text = arg1 + 4;
size = min(size, ShortTextCapacity);
}
*len = size;
*data = text;
*split = arg2 == 0 ? 1 : 2; // arg2 == 0 ? scenario : name
}
bool hookBefore(hook_stack *s, void *data1, size_t *len, uintptr_t *role)
{
auto arg = (TextUnionA *)(s->stack[0] + sizeof(DWORD)); // arg1
if (!arg || !arg->isValid())
return 0;
// FIXME: I am not able to distinguish choice out
*role =
s->stack[1] ? Engine::NameRole : // arg2 != 0 for name
// s->ebx > 0x0fffffff ? Engine::ChoiceRole : // edx is a pointer for choice
Engine::ScenarioRole;
std::string oldData(arg->getText(), arg->size);
return write_string_overwrite(data1, len, oldData);
}
TextUnionA *arg_,
argValue_;
void hookafter1(hook_stack *s, void *data1, size_t len)
{
auto newData = std::string((char *)data1, len);
auto arg = (TextUnionA *)(s->stack[0] + sizeof(DWORD)); // arg1
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;
}
bool InsertSilkysHook()
{
const BYTE bytes[] = {
0x66, 0x89, 0x45, 0xf9, // 00a1a062 66:8945 f9 mov word ptr ss:[ebp-0x7],ax
0x39, 0x47, 0x14 // 00a1a066 3947 14 cmp dword ptr ds:[edi+0x14],eax
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr)
{
ConsoleOutput("Silkys: pattern not found");
return false;
}
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
{
ConsoleOutput("Silkys: function not found");
return false;
}
HookParam hp;
hp.address = addr;
hp.text_fun = SpecialHookSilkys;
hp.type = USING_STRING | NO_CONTEXT; // = 9
ConsoleOutput("INSERT Silkys");
auto succ = NewHook(hp, "SilkysPlus");
auto fun = [](ULONG addr) -> bool
{
auto succ_ = false;
{
HookParam hp;
hp.address = addr;
hp.type = USING_STRING | NO_CONTEXT | EMBED_ABLE | EMBED_DYNA_SJIS;
hp.hook_before = hookBefore;
hp.hook_after = hookafter1;
hp.hook_font = F_GetGlyphOutlineA;
succ_ |= NewHook(hp, "EmbedSilkys");
}
{
HookParam hp;
hp.address = addr + 5;
hp.type = HOOK_EMPTY | EMBED_ABLE;
hp.hook_before = hookAfter;
succ_ |= NewHook(hp, "EmbedSilkys");
}
return succ_; // replace all functions
};
succ |= MemDbg::iterNearCallAddress(fun, addr, processStartAddress, processStopAddress);
return succ;
}
bool InsertSilkysHook2()
{
//[230825] [コンフィチュールソフト] ギャル×オタ ~織川きららはお世話したい~
auto addr = MemDbg::findCallerAddressAfterInt3((DWORD)GetCharacterPlacementW, processStartAddress, processStopAddress);
if (addr == 0)
return false;
BYTE sig[] = {
0x8b, 0x80, XX4,
0xff, 0xd0,
0x8b, 0xf0};
addr = MemDbg::findBytes(sig, sizeof(sig), addr, addr + 0x100);
if (addr == 0)
return false;
HookParam hp;
hp.address = addr + 8;
hp.type = CODEC_UTF16 | USING_STRING;
hp.offset = get_reg(regs::eax);
hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
{
static int idx = 0;
idx += 1;
return (bool)(idx % 2);
};
return NewHook(hp, "SilkysPlus2");
}
namespace
{
bool _s()
{
/// https://vndb.org/r68491
// 徒花異譚 / Adabana Odd Tales
BYTE sig[] = {
0xBA, 0x00, 0x01, 0x00, 0x00,
0xC7, 0x45, 0x08, 0x14, 0x20, 0x00, 0x00,
0x8D, 0x49, 0x00};
auto addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
if (addr == 0)
return false;
addr = findfuncstart(addr);
if (!addr)
return 0;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(1);
hp.newlineseperator = L"\\n";
hp.type = USING_STRING | CODEC_UTF16 | EMBED_ABLE | EMBED_BEFORE_SIMPLE | EMBED_AFTER_NEW;
return NewHook(hp, "EmbedSilkysX");
}
}
namespace
{
bool Silkys2Filter(LPVOID data, size_t *size, HookParam *)
{
auto text = reinterpret_cast<LPWSTR>(data);
auto len = reinterpret_cast<size_t *>(size);
StringCharReplacer(text, len, L"\\i", 2, L'\'');
return true;
}
bool InsertSilkys2Hook()
{
// https://vndb.org/r89173
// 同级生Remake
const BYTE bytes[] = {
// (unsigned __int16)v13 < 0x100u || (_WORD)v13 == 8212
0xC7, 0x45, XX, 0x00, 0x01, 0x00, 0x00,
0xC7, 0x45, XX, 0x14, 0x20, 0x00, 0x00};
const BYTE bytes2[] = {
// v6 = (_WORD *)(*v8 + *(_DWORD *)(v7 + 4 * v27));
// hook v6
0x8b, 0x4d, 0xf4,
0x8b, 0x3c, 0x8f,
0x03, 0x38};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr)
return false;
addr = reverseFindBytes(bytes2, sizeof(bytes2), addr - 0x100, addr);
if (!addr)
return false;
HookParam hp;
hp.address = addr + sizeof(bytes2);
hp.offset = get_reg(regs::edi);
hp.filter_fun = Silkys2Filter;
hp.type = CODEC_UTF16 | USING_STRING | NO_CONTEXT;
return NewHook(hp, "Silkys2");
}
}
namespace
{
bool saiminset()
{
//[230929][1237052][シルキーズSAKURA] 催眠奪女Set パッケージ版
auto addr1 = finddllfunctioncall((DWORD)GetGlyphOutlineA, processStartAddress, processStopAddress);
if (addr1 == 0)
return false;
auto func1 = MemDbg::findEnclosingAlignedFunction(addr1);
if (func1 == 0)
return false;
BYTE check[] = {
0x80, 0xf9, 0x81, XX2, // cmp cl, 81h
0x80, 0xf9, 0x9f, XX2, // cmp cl, 9Fh
};
if (MemDbg::findBytes(check, sizeof(check), func1, addr1) == 0)
return false;
auto xrefs = findxref_reverse_checkcallop(func1, processStartAddress, processStopAddress, 0xe8);
if (xrefs.size() == 0)
return false;
auto addr2 = xrefs[0];
auto addr = MemDbg::findEnclosingAlignedFunction(addr2);
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(1);
hp.index = 0;
hp.split = get_stack(6);
hp.type = USING_SPLIT | DATA_INDIRECT;
return NewHook(hp, "Silkys3");
}
}
namespace
{
// 言の葉舞い散る夏の風鈴
// https://vndb.org/v23466
bool silkys4()
{
BYTE check[] = {
0x80, 0xFA, 0x81,
0x72, XX,
0x80, 0xFA, 0x9F,
0x76, XX};
auto addr = MemDbg::findCallerAddress((ULONG)GetGlyphOutlineA, 0xec8b55, processStartAddress, processStopAddress);
if (addr == 0)
return false;
if (MemDbg::findBytes(check, sizeof(check), addr, addr + 0x100) == 0)
return false;
HookParam hp;
hp.address = addr;
hp.type = USING_CHAR | DATA_INDIRECT | USING_SPLIT;
hp.split = get_stack(1);
hp.offset = get_stack(1); // thiscall arg1
hp.filter_fun = [](LPVOID data, size_t *size, HookParam *)
{
static int idx = 0;
return (bool)((idx++) % 2);
};
return NewHook(hp, "Silkys4");
}
}
namespace
{
//[240531][1274293][シルキーズSAKURA] 淫魔淫姦 ~触手と合体して思い通りにやり返す~ DL版
bool silkys5()
{
// clang-format off
BYTE sig[]={
0xff,0xd0,//call eax
//<-- eax
0x8b,0x0f,
0x8b,0xf0,//mov esi,eax
0x68,0x80,0,0,0,
0x68,0x80,0,0,0,
0x6a,0,
0x8b,0x11,
0x6a,0,
};
// clang-format on
auto addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
if (!addr)
return false;
HookParam hp;
hp.address = addr + 2;
hp.type = USING_CHAR | DATA_INDIRECT | CODEC_UTF16;
hp.offset = get_reg(regs::eax);
hp.filter_fun = [](LPVOID data, size_t *size, HookParam *)
{
static int idx = 0;
return (bool)((idx++) % 2);
};
return NewHook(hp, "silkys5");
}
}
bool Silkys::attach_function()
{
auto b1 = InsertSilkys2Hook();
return InsertSilkysHook() || InsertSilkysHook2() || _s() || b1 || saiminset() || silkys4() || silkys5();
}
bool SilkysOld::attach_function()
{
// 愛姉妹・蕾…汚してください
auto addr = MemDbg::findCallerAddressAfterInt3((DWORD)TextOutA, processStartAddress, processStopAddress);
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(3);
hp.type = DATA_INDIRECT;
return NewHook(hp, "SilkysOld");
}
bool Siglusold::attach_function()
{
// 女系家族
// https://vndb.org/v5650
// int __cdecl sub_410C20(char *a1, _DWORD *a2)
// {
// unsigned __int16 v2; // dx
// int v3; // edi
// int result; // eax
// int v5; // eax
// HIBYTE(v2) = *a1;
// LOBYTE(v2) = a1[1];
// v3 = *a1;
// *a2 = 24 * (v2 & 0xF);
// if ( v2 < 0x8140u || v2 > 0x84FFu )
// {
// if ( v2 < 0x8740u || v2 > 0x879Fu )
// {
// if ( v2 < 0x8890u || v2 > 0x88FFu )
// {
// if ( v2 < 0x8940u || v2 > 0x9FFFu )
// {
// if ( v2 < 0xE040u || v2 > 0xEAA4u )
// {
// if ( v2 < 0xFA40u || v2 > 0xFAFCu )
// {
// if ( v2 < 0xFB40u || v2 > 0xFBFCu )
// {
// if ( v2 < 0xFC40u || v2 > 0xFC4Bu )
// {
BYTE bytes[] = {
0x66,
XX,
0x40,
0x87,
XX2,
0x66,
XX,
0x9f,
0x87,
};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (addr == 0)
return false;
addr = MemDbg::findEnclosingAlignedFunction_strict(addr);
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
hp.type = USING_CHAR | DATA_INDIRECT;
hp.offset = get_stack(1);
auto succ = NewHook(hp, "Siglusold_slow"); // 文本速度是慢速时这个有用,调成快速以后有无法过滤的重复
auto addrs = findxref_reverse_checkcallop(addr, addr - 0x1000, addr + 0x1000, 0xe8);
for (auto addr : addrs)
{
// 寻找调用者,速度为快速时调用者有正确的文本
addr = MemDbg::findEnclosingAlignedFunction_strict(addr);
if (addr == 0)
continue;
HookParam hpref;
hpref.address = addr;
hpref.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto a2 = (DWORD *)stack->stack[2];
auto len1 = stack->stack[3]; // 慢速时是1
auto len2 = a2[7] - a2[6];
if (len1 == 0 || len2 == 0)
return;
if (len1 == 1)
{ // 慢速
hp->type = USING_CHAR;
*data = a2[5] + a2[6];
*data = *(WORD *)*data;
auto check = (BYTE)*data; // 换行符
*len = 1 + IsDBCSLeadByteEx(932, check);
}
else
{ // 快速&&慢速下立即显示
*data = a2[5];
*len = len1;
}
};
hpref.type = USING_STRING;
succ |= NewHook(hpref, "Siglusold_fast");
}
return succ;
}
bool Silkyssakura::attach_function()
{
auto addr = MemDbg::findCallerAddressAfterInt3((DWORD)GetGlyphOutlineW, processStartAddress, processStopAddress);
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(3);
hp.split = get_stack(5);
hp.type = DATA_INDIRECT | USING_CHAR | USING_SPLIT | CODEC_UTF16;
auto xrefs = findxref_reverse_checkcallop(addr, processStartAddress, processStopAddress, 0xe8);
if (xrefs.size() == 1)
{
addr = MemDbg::findEnclosingAlignedFunction(xrefs[0]);
if (addr)
{
xrefs = findxref_reverse_checkcallop(addr, processStartAddress, processStopAddress, 0xe8);
if (xrefs.size() == 1)
{
addr = MemDbg::findEnclosingAlignedFunction(xrefs[0]);
if (addr)
{
HookParam hp_embed;
hp_embed.address = addr;
hp_embed.offset = get_stack(2);
hp_embed.type = USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW | EMBED_BEFORE_SIMPLE | CODEC_UTF16;
hp_embed.hook_font = F_GetGlyphOutlineW;
return NewHook(hp_embed, "embedSilkyssakura"); // 这个是分两层分别绘制文字和阴影,需要两个都内嵌。
}
}
}
}
return NewHook(hp, "Silkyssakura");
}
namespace
{
// flutter of birds II 天使たちの翼 DMM版
// EDSNHS932#-8@42650:Angel.exe √
// HS932#-8@44D90:Angel.exe
bool fob2()
{
// clang-format off
const BYTE bytes[] = {
0x53,
0x56,
0x8b,0xf1,
0x8b,0xde,
0x8d,0x4b,0x01,
0x8d,0xa4,0x24,0x00,0x00,0x00,0x00,
0x8a,0x03,
0x43,
0x84,0xc0,
0x75,XX,
0x2b,0xd9,
0xb8,0xa8,0x00,0x00,0x00,
0x3b,0xd8,
0x68,0xac,0x00,0x00,0x00,
};
// clang-format on
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr)
return false;
HookParam hp;
hp.address = addr;
hp.offset = get_reg(regs::ecx);
hp.newlineseperator = L"\\n";
hp.type = USING_STRING | EMBED_ABLE | EMBED_BEFORE_SIMPLE | EMBED_AFTER_NEW | EMBED_DYNA_SJIS;
return NewHook(hp, "SilkysX");
}
}
bool Silkysveryveryold_attach_function()
{
// flutter of birds II 天使たちの翼
// https://vndb.org/v2380
const BYTE bytes[] = {
0x8b, XX, XX,
0x03, XX, XX,
0x33, XX,
0x8a, 0x02,
0x83, XX, 0x5c,
0x0f, 0x85, XX4,
0x8b, XX, XX,
0x03, XX, XX,
0x33, XX,
0x8a, XX, 0x01,
0x83, XX, 0x6e};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
return false;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(1);
hp.newlineseperator = L"\\n";
hp.type = USING_STRING;
return NewHook(hp, "SilkysX");
}
bool Silkysveryveryold::attach_function()
{
return Silkysveryveryold_attach_function() || fob2();
}
bool Aisystem6::attach_function()
{
// 肢体を洗う
const BYTE bytes[] = {
// if ( *(_WORD *)lpString == 0x9381 && v9 == 2 )
0x66, 0x8B, 0x01, 0xF7, // mov ax, [ecx]
0xDD, 0x1B,
0xED, 0x83, 0xC5, 0x02,
0xD1, 0xEB,
0x0F, 0xAF, 0xDD,
0x66, 0x3D, 0x81, 0x93, // cmp ax, 9381h
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
return false;
// 有三个这个同型的函数分别显示不同的内容各自只调用一次在xref里面分发。
auto addrs = findxref_reverse_checkcallop(addr, addr - 0x1000, addr + 0x1000, 0xe8);
if (addrs.size() != 1)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addrs[0]);
if (!addr)
return false;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(1);
hp.type = USING_STRING | NO_CONTEXT; // 男主自定义人名会被分开
hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
{
StringCharReplacer((char *)data, len, "\x81\x93", 2, '\n');
return true;
};
return NewHook(hp, "Aisystem6");
}