This commit is contained in:
恍兮惚兮 2024-10-22 00:49:26 +08:00
parent a5986fe7dd
commit 44ad71eb81

View File

@ -109,8 +109,8 @@
* 0012ed64 00951d88 ascii "2015/01/18"
*/
namespace { // unnamed
namespace
{ // unnamed
void SpecialHookWillPlus(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
@ -118,14 +118,16 @@ void SpecialHookWillPlus(hook_stack* stack, HookParam *hp, uintptr_t *data, uin
// if (detect_offset)
// return;
DWORD i, l;
union {
union
{
DWORD retn;
WORD *pw;
BYTE *pb;
};
retn = stack->retaddr; // jichi 1/18/2015: dynamically find function return address
i = 0;
while (*pw != 0xc483) { // add esp, $
while (*pw != 0xc483)
{ // add esp, $
l = ::disasm(pb);
if (++i == 5)
// ConsoleOutput("Fail to detect offset.");
@ -133,7 +135,8 @@ void SpecialHookWillPlus(hook_stack* stack, HookParam *hp, uintptr_t *data, uin
retn += l;
}
// jichi 2/11/2015: Check baddaddr which might crash the game on Windows XP.
if (*pw == 0xc483 && !::IsBadReadPtr((LPCVOID)(pb + 2), 1) && !::IsBadReadPtr((LPCVOID)(*(pb + 2) - 8), 1)) {
if (*pw == 0xc483 && !::IsBadReadPtr((LPCVOID)(pb + 2), 1) && !::IsBadReadPtr((LPCVOID)(*(pb + 2) - 8), 1))
{
ConsoleOutput("WillPlus1 pattern found");
// jichi 1/18/2015:
// By studying [honeybee] RE:BIRTHDAY SONG, it seems the scenario text is at fixed address
@ -147,8 +150,9 @@ void SpecialHookWillPlus(hook_stack* stack, HookParam *hp, uintptr_t *data, uin
*data = (DWORD)str;
*len = ::strlen(str);
*split = 0; // 8/3/2014 jichi: use return address as split
} else { // jichi 1/19/2015: Try willplus2
}
else
{ // jichi 1/19/2015: Try willplus2
ConsoleOutput("WillPlus1 pattern not found, try WillPlus2 instead");
hp->offset = 4 * 8; // arg8, address of text
hp->type = USING_STRING | NO_CONTEXT | USING_SPLIT; // merge different scenario threads
@ -166,9 +170,13 @@ void SpecialHookWillPlus(hook_stack* stack, HookParam *hp, uintptr_t *data, uin
bool InsertOldWillPlusHook()
{
//__debugbreak();
enum { sub_esp = 0xec81 }; // jichi: caller pattern: sub esp = 0x81,0xec byte
enum
{
sub_esp = 0xec81
}; // jichi: caller pattern: sub esp = 0x81,0xec byte
ULONG addr = MemDbg::findCallerAddress((ULONG)::GetGlyphOutlineA, sub_esp, processStartAddress, processStopAddress);
if (!addr) {
if (!addr)
{
ConsoleOutput("WillPlus: function call not found");
return false;
}
@ -185,8 +193,10 @@ const char *_willplus_trim_a(const char *text, size_t *size)
{
int textSize = ::strlen(text);
int prefix = 0;
if (text[0] == '%') {
while (prefix < textSize - 1 && text[prefix] == '%' && ::isupper(text[prefix+1])) {
if (text[0] == '%')
{
while (prefix < textSize - 1 && text[prefix] == '%' && ::isupper(text[prefix + 1]))
{
prefix += 2;
while (::isupper(text[prefix]))
prefix++;
@ -194,7 +204,8 @@ const char *_willplus_trim_a(const char *text, size_t *size)
}
{
int pos = textSize;
for (int i = textSize - 1; i >= prefix; i--) {
for (int i = textSize - 1; i >= prefix; i--)
{
char ch = text[i];
if (::isupper(ch))
;
@ -214,8 +225,10 @@ const wchar_t *_willplus_trim_w(const wchar_t *text, size_t *size)
{
int textSize = ::wcslen(text);
int prefix = 0;
if (text[0] == '%') {
while (prefix < textSize - 1 && text[prefix] == '%' && ::isupper(text[prefix+1])) {
if (text[0] == '%')
{
while (prefix < textSize - 1 && text[prefix] == '%' && ::isupper(text[prefix + 1]))
{
prefix += 2;
while (::isupper(text[prefix]))
prefix++;
@ -223,7 +236,8 @@ const wchar_t *_willplus_trim_w(const wchar_t *text, size_t *size)
}
{
int pos = textSize;
for (int i = textSize - 1; i >= prefix; i--) {
for (int i = textSize - 1; i >= prefix; i--)
{
wchar_t ch = text[i];
if (::isupper(ch))
;
@ -253,7 +267,8 @@ void SpecialHookWillPlusA(hook_stack* stack, HookParam *hp, uintptr_t *data, ui
*data = (DWORD)text;
*split = FIXED_SPLIT_VALUE << index;
}
bool WillPlus_extra_filter(void* data, size_t* size, HookParam*) {
bool WillPlus_extra_filter(void *data, size_t *size, HookParam *)
{
auto text = reinterpret_cast<LPWSTR>(data);
StringFilter(text, size, L"%XS", 5); // remove %XS followed by 2 chars
@ -278,7 +293,8 @@ bool InsertWillPlusAHook()
const BYTE bytes2[] = {0x8B, 0x00, 0xFF, 0x76, 0xFC, 0x8B, 0xCF, 0x50};
ULONG range2 = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr2 = MemDbg::findBytes(bytes2, sizeof(bytes2), processStartAddress, processStartAddress + range2);
if (addr2) {
if (addr2)
{
HookParam myhp;
myhp.address = addr2 + 2;
@ -296,7 +312,8 @@ bool InsertWillPlusAHook()
0x81, 0xec, 0x14, 0x08, 0x00, 0x00 // 0042B5E0 81EC 14080000 SUB ESP,0x814 ; jichi: text in eax, name in eax - 1024, able to copy
};
DWORD addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr) {
if (!addr)
{
ConsoleOutput("WillPlusA: pattern not found");
return false;
}
@ -322,14 +339,16 @@ void SpecialHookWillPlusW(hook_stack* stack, HookParam *hp, uintptr_t *data, ui
bool InsertWillPlusWHook()
{
const BYTE bytes1[] = { // scenario
const BYTE bytes1[] = {
// scenario
0x83, 0xc0, 0x20, // 00452b02 83c0 20 add eax,0x20 ; jichi: hook before here, text in ecx
0x33, 0xd2, // 00452b05 33d2 xor edx,edx
0x8b, 0xc1, // 00452b07 8bc1 mov eax,ecx
0xc7, 0x84, 0x24, 0xe0, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00 // 00452b09 c78424 e0010000 07000000 mov dword ptr ss:[esp+0x1e0],0x7
// 00452b14 c78424 dc010000 00000000 mov dword ptr ss:[esp+0x1dc],0x0
};
const BYTE bytes2[] = { // name
const BYTE bytes2[] = {
// name
0x33, 0xdb, // 00453521 33db xor ebx,ebx ; jichi: hook here, text in ecx
0x33, 0xd2, // 00453523 33d2 xor edx,edx
0x8b, 0xc1, // 00453525 8bc1 mov eax,ecx
@ -339,9 +358,11 @@ bool InsertWillPlusWHook()
const BYTE *bytes[] = {bytes1, bytes2};
const size_t sizes[] = {sizeof(bytes1), sizeof(bytes2)};
auto succ = false;
for (int i = 0; i < 2; i++) {
for (int i = 0; i < 2; i++)
{
DWORD addr = MemDbg::findBytes(bytes[i], sizes[i], processStartAddress, processStopAddress);
if (!addr) {
if (!addr)
{
ConsoleOutput("WillPlusW: pattern not found");
return false;
}
@ -450,7 +471,8 @@ static bool InsertNewWillPlusHook()
BYTE byte = *(BYTE *)(addr + 1);
regs offset = regs::invalid;
switch (byte) {
switch (byte)
{
case 0xf9:
offset = regs::ecx;
break;
@ -473,7 +495,8 @@ static bool InsertNewWillPlusHook()
offset = regs::edi;
break;
};
if (offset!=regs::invalid) {
if (offset != regs::invalid)
{
HookParam hp;
hp.address = addr + 8;
hp.type = CODEC_UTF16;
@ -481,7 +504,8 @@ static bool InsertNewWillPlusHook()
found |= NewHook(hp, "WillPlus3");
}
}
if (!found) ConsoleOutput("WillPlus: failed to find instructions");
if (!found)
ConsoleOutput("WillPlus: failed to find instructions");
return found;
}
@ -493,9 +517,12 @@ bool InsertWillPlusHook()
ok = InsertWillPlusWHook() || InsertNewWillPlusHook() || InsertWillPlusAHook() || ok;
return ok;
}
namespace will3{
namespace will3
{
int kp = 0;int lf=0;int lc=0;
int kp = 0;
int lf = 0;
int lc = 0;
bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role)
{
// DOUT(QString::fromUtf16((LPWSTR)s->stack[6]));//"MS UI Gothic"
@ -507,17 +534,21 @@ bool hookBefore(hook_stack*s,void* data, size_t* len,uintptr_t*role)
auto split = s->stack[0]; // retaddr
std::wstring str = ((LPWSTR)s->stack[7]);
kp=0;lf=0;
if (endWith(str,L"%K%P")){
kp = 0;
lf = 0;
if (endWith(str, L"%K%P"))
{
kp = 1;
str = str.substr(0, str.size() - 4);
}
if(startWith(str,L"%LF")){
if (startWith(str, L"%LF"))
{
lf = 1;
str = str.substr(3);
}
if(startWith(str,L"%LC")){
if (startWith(str, L"%LC"))
{
lc = 1;
str = str.substr(3);
}
@ -530,35 +561,41 @@ bool hookBefore(hook_stack*s,void* data, size_t* len,uintptr_t*role)
write_string_overwrite(data, len, str);
return true;
}
void hookafter(hook_stack*s,void* data, size_t len){
void hookafter(hook_stack *s, void *data, size_t len)
{
auto data_ = std::wstring((wchar_t *)data, len / 2); // EngineController::instance()->dispatchTextWSTD(innner, Engine::ScenarioRole, 0);
if (kp) {
if (kp)
{
data_.append(L"%K%P");
}
if(lf){
if (lf)
{
data_ = L"%LF" + data_;
}if(lc){
}
if (lc)
{
data_ = L"%LC" + data_;
}
s->stack[7] = (ULONG)(data_.c_str());
}
}
bool InsertWillPlus4Hook() {
bool InsertWillPlus4Hook()
{
// 星の乙女と六華の姉妹
const BYTE bytes[] = {
0xc7, 0x45, 0xfc, 0x00, 0x00, 0x00, 0x00,
0x33, 0xc9,
0xc7,0x47,0x78,0x00,0x00,0x00,0x00
};
0xc7, 0x47, 0x78, 0x00, 0x00, 0x00, 0x00};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (addr == 0)return false;
if (addr == 0)
return false;
addr = MemDbg::findEnclosingFunctionBeforeDword(0x83dc8b53, addr, MemDbg::MaximumFunctionSize, 1);
if (addr == 0)return false;
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(7);
@ -569,15 +606,15 @@ bool InsertWillPlus4Hook() {
hp.hook_after = will3::hookafter;
return NewHook(hp, "EmbedWillplus3");
}
bool InsertWillPlus5Hook() {
bool InsertWillPlus5Hook()
{
// ensemble 29th Project『乙女の剣と秘めごとコンチェルト』オフィシャルサイト 体验版
const BYTE bytes[] = {
0x3d, XX2, 0x00, 0x00,
0x72, XX,
0x3d, XX2, 0x00, 0x00,
0x77
};
0x77};
/*if (v26 >= 0xE63E)
{
if (v26 <= 0xE757)*/
@ -589,7 +626,8 @@ bool InsertWillPlus5Hook() {
bool ok = false;
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress);
for (auto addr : addrs) {
for (auto addr : addrs)
{
HookParam hp;
hp.address = addr;
hp.offset = get_reg(regs::eax);
@ -599,7 +637,8 @@ bool InsertWillPlus5Hook() {
}
return ok;
}
bool insertwillplus6(){
bool insertwillplus6()
{
/* 0x00492870
0: 50 push eax
@ -636,11 +675,11 @@ f: 6a 01 push 0x1
0x8b, 0xd6,
0xe8, XX4,
0x83, 0xf8,
0xff,0x75,0xdc
};
0xff, 0x75, 0xdc};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if(addr==0)return false;
if (addr == 0)
return false;
addr += sizeof(bytes);
ConsoleOutput("%p %p %p", addr, processStartAddress, processStopAddress);
HookParam hp;
@ -650,7 +689,8 @@ f: 6a 01 push 0x1
ConsoleOutput("INSERT WillPlus6");
return NewHook(hp, "WillPlus6");
}
bool willX(){
bool willX()
{
// 世界でいちばんNGな恋
// .text:0040EAE9 81 FE 94 81 00 00 cmp esi, 8194h
// .text:0040EAEF 74 2C jz short loc_40EB1D
@ -680,11 +720,11 @@ bool willX(){
0x74, XX,
0x81, 0xFE, 0x59, 0x81, 0x00, 0x00,
0x74, XX,
0x81,0xFE,0x96,0x81,0x00,0x00
};
0x81, 0xFE, 0x96, 0x81, 0x00, 0x00};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if(addr==0)return false;
if (addr == 0)
return false;
auto succ = false;
{
HookParam hp;
@ -707,12 +747,8 @@ bool willX(){
return succ;
}
namespace { // unnamed
namespace
{ // unnamed
// Sample prefix: %LF
// Sample suffix: %L%P%W
@ -720,21 +756,25 @@ template <typename strT>
strT trim(strT text, int *size)
{
int length = *size;
if (text[0] == '%') { // handle prefix
if (text[0] == '%')
{ // handle prefix
int pos = 0;
while (pos < length - 1 && text[pos] == '%' && ::isupper(text[pos+1])) {
while (pos < length - 1 && text[pos] == '%' && ::isupper(text[pos + 1]))
{
pos += 2;
while (::isupper(text[pos]))
pos++;
}
if (pos) {
if (pos)
{
length -= pos;
text += pos;
}
}
{ // handle suffix
int pos = length;
for (int i = length - 1; i >= 0; i--) {
for (int i = length - 1; i >= 0; i--)
{
if (::isupper(text[i]))
;
else if (text[i] == '%' && ::isupper(text[i + 1]))
@ -747,7 +787,8 @@ strT trim(strT text, int *size)
*size = length;
return text;
}
struct textinfo{
struct textinfo
{
std::wstring text_;
int stackIndex_;
int role_;
@ -762,7 +803,10 @@ namespace TextHookW
bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role)
{
auto info = savetyperef.at(idx);
enum { sig = 0 };
enum
{
sig = 0
};
auto text = (LPCWSTR)s->stack[info->stackIndex_];
if (!text || !*text)
return false;
@ -776,10 +820,14 @@ namespace TextHookW
return true;
}
template <int idx>
void hookafter(hook_stack*s,void* data, size_t len){
void hookafter(hook_stack *s, void *data, size_t len)
{
auto newText = std::wstring((LPWSTR)data, len / 2);
auto info = savetyperef.at(idx);
enum { sig = 0 };
enum
{
sig = 0
};
auto text = (LPCWSTR)s->stack[info->stackIndex_];
if (!text || !*text)
return;
@ -805,7 +853,8 @@ namespace TextHookW
bool attach(const uint8_t *pattern, size_t patternSize, ULONG startAddress, ULONG stopAddress, int hookStackIndex, int role = Engine::UnknownRole)
{
ULONG addr = MemDbg::findBytes(pattern, patternSize, startAddress, stopAddress);
if(addr==0)return false;
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
auto _tinfo = new textinfo{};
@ -958,7 +1007,6 @@ bool attachScenarioHookW2(ULONG startAddress, ULONG stopAddress)
};
int edi = get_reg(regs::edi) / 4;
return TextHookW::attach<2>(bytes, sizeof(bytes), startAddress, stopAddress, edi, Engine::ScenarioRole);
}
/**
* Sample game:
@ -1028,7 +1076,6 @@ bool attachNameHookW(ULONG startAddress, ULONG stopAddress)
int ecx = get_reg(regs::ecx) / 4;
return TextHookW::attach<3>(bytes, sizeof(bytes), startAddress, stopAddress, ecx, Engine::NameRole);
}
/**
@ -1096,12 +1143,13 @@ bool attachOtherHookW(ULONG startAddress, ULONG stopAddress)
int edx = get_reg(regs::edx) / 4;
return TextHookW::attach<4>(bytes, sizeof(bytes), startAddress, stopAddress, edx, Engine::OtherRole);
}
namespace PatchA {
namespace PatchA
{
namespace Private {
namespace Private
{
// The second argument is always 0 and not used
bool isLeadByteChar(int ch, int)
{
@ -1181,7 +1229,8 @@ bool csmemcpy(void *dst, const void *src, size_t size)
ulong replace_near_call(ulong addr, ulong val)
{
DWORD ret;
switch (::disasm((LPCVOID)addr)) {
switch (::disasm((LPCVOID)addr))
{
case 5: // near call / short jmp: relative address
ret = *(DWORD *)(addr + 1) + (addr + 5);
val -= addr + 5;
@ -1195,7 +1244,8 @@ ulong replace_near_call(ulong addr, ulong val)
*(DWORD *)(data + 1) = val - (addr + 5);
return csmemcpy((LPVOID)addr, data, sizeof(data)) ? ret : 0;
}
default: return 0;
default:
return 0;
}
}
ULONG patchEncoding(ULONG startAddress, ULONG stopAddress)
@ -1205,7 +1255,10 @@ ULONG patchEncoding(ULONG startAddress, ULONG stopAddress)
0xff, 0x75, 0x08, // 00487fe1 ff75 08 push dword ptr ss:[ebp+0x8]
0xe8, 0xaa, 0xff, 0xff, 0xff // 00487fe4 e8 aaffffff call .00487f93 ; jichi: called here
};
enum { addr_offset = 5 };
enum
{
addr_offset = 5
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
return addr; //&& replace_near_call(addr + addr_offset, (ULONG)Private::isLeadByteChar);
@ -1213,9 +1266,11 @@ ULONG patchEncoding(ULONG startAddress, ULONG stopAddress)
} // namespace PatchA
namespace ScenarioHookA {
namespace ScenarioHookA
{
namespace Private {
namespace Private
{
/*
void dispatch(LPSTR text, int role)
{
@ -1244,7 +1299,10 @@ namespace Private {
// dispatch(text - 1024, Engine::NameRole);
// dispatch(text, Engine::ScenarioRole);
enum { sig = 0 };
enum
{
sig = 0
};
if (!Engine::isAddressWritable(text) || !*text) // isAddressWritable is not needed for correct games
return false;
int size = ::strlen(text),
@ -1263,7 +1321,8 @@ namespace Private {
::strcpy(text, newData.c_str());
return true;*/
}
void hookafter(hook_stack*s,void* data, size_t len){
void hookafter(hook_stack *s, void *data, size_t len)
{
auto newData = std::string((char *)data, len);
auto text = (LPSTR)s->eax;
@ -1510,7 +1569,8 @@ bool attach(ULONG startAddress, ULONG stopAddress)
0x81, 0xec, 0x14, 0x08, 0x00, 0x00 // 0042B5E0 81EC 14080000 SUB ESP,0x814 ; jichi: text in eax, name in eax - 1024, able to copy
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
if(addr==0)return false;
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
@ -1521,12 +1581,13 @@ bool attach(ULONG startAddress, ULONG stopAddress)
hp.hook_font = F_GetGlyphOutlineA | F_TextOutA;
static ULONG paddr = (PatchA::patchEncoding(startAddress, stopAddress));
ConsoleOutput("%p", paddr);
if(paddr){
if (paddr)
{
hp.type |= EMBED_DYNA_SJIS;
hp.hook_font = F_GetGlyphOutlineA | F_TextOutA;
patch_fun=[](){
patch_fun = []()
{
PatchA::replace_near_call(paddr + 5, (ULONG)PatchA::Private::isLeadByteChar);
};
}
return NewHook(hp, "EmbedWillplusA");
@ -1534,9 +1595,11 @@ bool attach(ULONG startAddress, ULONG stopAddress)
} // namespace ScenarioHookA
namespace OtherHookA {
namespace OtherHookA
{
namespace Private {
namespace Private
{
bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role)
{
@ -1563,7 +1626,8 @@ namespace Private {
bool attach(ULONG startAddress, ULONG stopAddress)
{
ULONG addr = MemDbg::findCallerAddressAfterInt3((ULONG)::GetGlyphOutlineA, startAddress, stopAddress);
if(addr==0)return false;
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
hp.hook_before = Private::hookBefore;
@ -1577,21 +1641,23 @@ bool attach(ULONG startAddress, ULONG stopAddress)
} // unnamed namespace
/** Public class */
namespace WillPlusEngine{
namespace WillPlusEngine
{
bool attach()
{
ULONG startAddress = processStartAddress, stopAddress = processStopAddress;
if (::attachScenarioHookW1(startAddress, stopAddress) || ::attachScenarioHookW2(startAddress, stopAddress)) {
if (::attachScenarioHookW1(startAddress, stopAddress) || ::attachScenarioHookW2(startAddress, stopAddress))
{
(::attachNameHookW(startAddress, stopAddress));
(::attachOtherHookW(startAddress, stopAddress));
return true;
} else if (ScenarioHookA::attach(startAddress, stopAddress)) { // try widechar pattern first, which is more unique
}
else if (ScenarioHookA::attach(startAddress, stopAddress))
{ // try widechar pattern first, which is more unique
(OtherHookA::attach(startAddress, stopAddress));
// HijackManager::instance()->attachFunction((ULONG)::GetGlyphOutlineA);
@ -1603,7 +1669,8 @@ bool attach()
}
}
namespace{
namespace
{
static bool InsertWillPlus4()
{
@ -1620,7 +1687,8 @@ static bool InsertWillPlus4()
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr) {
if (!addr)
{
ConsoleOutput("WillPlus4: pattern not found");
return false;
}
@ -1651,7 +1719,8 @@ static bool InsertWillPlus5()
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr) {
if (!addr)
{
ConsoleOutput("WillPlus5: pattern not found");
return false;
}
@ -1669,7 +1738,8 @@ static bool InsertWillPlus5()
return true;
}
bool _xxx(){
bool _xxx()
{
bool ok = false;
ok = InsertWillPlus4() || ok;
ok = InsertWillPlus5() || ok;
@ -1677,7 +1747,8 @@ bool ok=false;
}
}
bool WillPlus::attach_function() {
bool WillPlus::attach_function()
{
bool succ = WillPlusEngine::attach();
succ |= InsertWillPlusHook();
succ |= InsertWillPlus4Hook();
@ -1689,17 +1760,19 @@ bool WillPlus::attach_function() {
return succ;
}
bool Willold::attach_function() {
bool Willold::attach_function()
{
// https://vndb.org/v17755
// 凌辱鬼
auto addr = MemDbg::findLongJumpAddress((ULONG)TextOutA, processStartAddress, processStopAddress);
if(addr==0)return false;
if (addr == 0)
return false;
addr = MemDbg::findNearCallAddress(addr, processStartAddress, processStopAddress);
if(addr==0)return false;
if (addr == 0)
return false;
addr = findfuncstart(addr, 0x200);
if(addr==0)return false;
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
hp.type = USING_CHAR | CODEC_ANSI_BE;