638 lines
20 KiB
C++
Raw Normal View History

2024-07-29 01:12:19 +08:00
#include "Elf.h"
2024-02-07 20:59:24 +08:00
/**
* jichi 6/1/2014:
* Observations from 4
* - Scenario: arg1 + 4*5 is 0, arg1+0xc is address of the text
* - Character: arg1 + 4*10 is 0, arg1+0xc is text
*/
static inline size_t _elf_strlen(LPCSTR p) // limit search address which might be bad
{
2024-07-29 01:12:19 +08:00
// CC_ASSERT(p);
2024-02-07 20:59:24 +08:00
for (size_t i = 0; i < VNR_TEXT_CAPACITY; i++)
if (!*p++)
return i;
return 0; // when len >= VNR_TEXT_CAPACITY
}
2024-07-29 01:12:19 +08:00
static void SpecialHookElf(hook_stack *stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t *len)
2024-02-07 20:59:24 +08:00
{
2024-07-29 01:12:19 +08:00
// DWORD arg1 = *(DWORD *)(esp_base + 0x4);
2024-02-07 20:59:24 +08:00
DWORD arg1 = stack->stack[1];
2024-07-29 01:12:19 +08:00
DWORD arg2_scene = arg1 + 4 * 5,
arg2_chara = arg1 + 4 * 10;
2024-02-07 20:59:24 +08:00
DWORD text; //= 0; // This variable will be killed
2024-07-29 01:12:19 +08:00
if (*(DWORD *)arg2_scene == 0)
{
text = *(DWORD *)(arg2_scene + 4 * 3);
2024-02-07 20:59:24 +08:00
if (!text || ::IsBadReadPtr((LPCVOID)text, 1)) // Text from scenario could be bad when open backlog while the character is speaking
return;
*split = 1;
2024-07-29 01:12:19 +08:00
}
else if (*(DWORD *)arg2_chara == 0)
{
text = arg2_chara + 4 * 3;
2024-02-07 20:59:24 +08:00
*split = 2;
2024-07-29 01:12:19 +08:00
}
else
2024-02-07 20:59:24 +08:00
return;
2024-07-29 01:12:19 +08:00
// if (text && text < MemDbg::UserMemoryStopAddress) {
2024-02-07 20:59:24 +08:00
*len = _elf_strlen((LPCSTR)text); // in case the text is bad but still readable
//*len = ::strlen((LPCSTR)text);
*data = text;
}
/**
* jichi 5/31/2014: elf's
* Type1: SEXヂ<EFBFBD> trial, reladdr = 0x2f0f0, 2 parameters
* Type2: 4, reladdr = 0x2f9b0, 3 parameters
*
* IDA: sub_42F9B0 proc near ; bp-based frame
* var_8 = dword ptr -8
* var_4 = byte ptr -4
* var_3 = word ptr -3
* arg_0 = dword ptr 8
* arg_4 = dword ptr 0Ch
* arg_8 = dword ptr 10h
*
* Call graph (Type2):
* 0x2f9b0 ; hook here
* > 0x666a0 ; called multiple time
* > TextOutA ; there are two TextOutA, the second is the right one
*
* Function starts (Type1), pattern offset: 0xc
* - 012ef0f0 /$ 55 push ebp ; jichi: hook
* - 012ef0f1 |. 8bec mov ebp,esp
* - 012ef0f3 |. 83ec 10 sub esp,0x10
* - 012ef0f6 |. 837d 0c 00 cmp dword ptr ss:[ebp+0xc],0x0
* - 012ef0fa |. 53 push ebx
* - 012ef0fb |. 56 push esi
* - 012ef0fc |. 75 0f jnz short stt_tria.012ef10d ; jicchi: pattern starts
* - 012ef0fe |. 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
* - 012ef101 |. 8b48 04 mov ecx,dword ptr ds:[eax+0x4]
* - 012ef104 |. 8b91 90000000 mov edx,dword ptr ds:[ecx+0x90] ; jichi: pattern stops
* - 012ef10a |. 8955 0c mov dword ptr ss:[ebp+0xc],edx
* - 012ef10d |> 8b4d 08 mov ecx,dword ptr ss:[ebp+0x8]
* - 012ef110 |. 8b51 04 mov edx,dword ptr ds:[ecx+0x4]
* - 012ef113 |. 33c0 xor eax,eax
* - 012ef115 |. c645 f8 00 mov byte ptr ss:[ebp-0x8],0x0
* - 012ef119 |. 66:8945 f9 mov word ptr ss:[ebp-0x7],ax
* - 012ef11d |. 8b82 b0000000 mov eax,dword ptr ds:[edx+0xb0]
* - 012ef123 |. 8945 f4 mov dword ptr ss:[ebp-0xc],eax
* - 012ef126 |. 33db xor ebx,ebx
* - 012ef128 |> 8b4f 20 /mov ecx,dword ptr ds:[edi+0x20]
* - 012ef12b |. 83f9 10 |cmp ecx,0x10
*
* Function starts (Type2), pattern offset: 0x10
* - 0093f9b0 /$ 55 push ebp ; jichi: hook here
* - 0093f9b1 |. 8bec mov ebp,esp
* - 0093f9b3 |. 83ec 08 sub esp,0x8
* - 0093f9b6 |. 837d 10 00 cmp dword ptr ss:[ebp+0x10],0x0
* - 0093f9ba |. 53 push ebx
* - 0093f9bb |. 8b5d 0c mov ebx,dword ptr ss:[ebp+0xc]
* - 0093f9be |. 56 push esi
* - 0093f9bf |. 57 push edi
* - 0093f9c0 |. 75 0f jnz short silkys.0093f9d1 ; jichi: pattern starts
* - 0093f9c2 |. 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
* - 0093f9c5 |. 8b48 04 mov ecx,dword ptr ds:[eax+0x4]
* - 0093f9c8 |. 8b91 90000000 mov edx,dword ptr ds:[ecx+0x90] ; jichi: pattern stops
* - 0093f9ce |. 8955 10 mov dword ptr ss:[ebp+0x10],edx
* - 0093f9d1 |> 33c0 xor eax,eax
* - 0093f9d3 |. c645 fc 00 mov byte ptr ss:[ebp-0x4],0x0
* - 0093f9d7 |. 66:8945 fd mov word ptr ss:[ebp-0x3],ax
* - 0093f9db |. 33ff xor edi,edi
* - 0093f9dd |> 8b53 20 /mov edx,dword ptr ds:[ebx+0x20]
* - 0093f9e0 |. 8d4b 0c |lea ecx,dword ptr ds:[ebx+0xc]
* - 0093f9e3 |. 83fa 10 |cmp edx,0x10
*/
bool InsertElfHook()
{
const BYTE bytes[] = {
2024-07-29 01:12:19 +08:00
// 0x55, // 0093f9b0 /$ 55 push ebp ; jichi: hook here
// 0x8b,0xec, // 0093f9b1 |. 8bec mov ebp,esp
// 0x83,0xec, 0x08, // 0093f9b3 |. 83ec 08 sub esp,0x8
// 0x83,0x7d, 0x10, 0x00, // 0093f9b6 |. 837d 10 00 cmp dword ptr ss:[ebp+0x10],0x0
// 0x53, // 0093f9ba |. 53 push ebx
// 0x8b,0x5d, 0x0c, // 0093f9bb |. 8b5d 0c mov ebx,dword ptr ss:[ebp+0xc]
// 0x56, // 0093f9be |. 56 push esi
// 0x57, // 0093f9bf |. 57 push edi
0x75, 0x0f, // 0093f9c0 |. 75 0f jnz short silkys.0093f9d1
0x8b, 0x45, 0x08, // 0093f9c2 |. 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
0x8b, 0x48, 0x04, // 0093f9c5 |. 8b48 04 mov ecx,dword ptr ds:[eax+0x4]
0x8b, 0x91, 0x90, 0x00, 0x00, 0x00 // 0093f9c8 |. 8b91 90000000 mov edx,dword ptr ds:[ecx+0x90]
2024-02-07 20:59:24 +08:00
};
2024-07-29 01:12:19 +08:00
// enum { addr_offset = 0xc };
2024-02-07 20:59:24 +08:00
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
2024-07-29 01:12:19 +08:00
// GROWL_DWORD(addr);
// addr = 0x42f170; // 愛姉妹4 Trial
// reladdr = 0x2f9b0; // 愛姉妹4
// reladdr = 0x2f0f0; // SEXヂ<58>ーチャー剛史 trial
if (!addr)
{
2024-02-07 20:59:24 +08:00
ConsoleOutput("Elf: pattern not found");
return false;
}
2024-07-29 01:12:19 +08:00
enum : BYTE
{
push_ebp = 0x55
};
2024-02-07 20:59:24 +08:00
for (int i = 0; i < 0x20; i++, addr--) // value of i is supposed to be 0xc or 0x10
2024-07-29 01:12:19 +08:00
if (*(BYTE *)addr == push_ebp)
{ // beginning of the function
2024-02-07 20:59:24 +08:00
HookParam hp;
hp.address = addr;
hp.text_fun = SpecialHookElf;
2024-07-29 01:12:19 +08:00
hp.type = USING_STRING | NO_CONTEXT; // = 9
2024-02-07 20:59:24 +08:00
ConsoleOutput("INSERT Elf");
2024-07-29 01:12:19 +08:00
2024-02-07 20:59:24 +08:00
return NewHook(hp, "Elf");
}
ConsoleOutput("Elf: function not found");
return false;
}
2024-07-29 01:12:19 +08:00
namespace
{
bool __()
{
2024-02-07 20:59:24 +08:00
const BYTE bytes[] = {
2024-07-29 01:12:19 +08:00
// 姫騎士オリヴィア ~へ、変態、この変態男!少しは恥を知りなさい!
// 女系家族III秘密HIMITSU卑蜜
// ベロちゅー!~コスプレメイドをエロメロしちゃう魔法の舌戯~
0x0F, 0xB7, XX, XX4, // v11 == 30081 // movzx edx, ds:word_4C285C //word_4C285C dw 7581h
2024-02-07 20:59:24 +08:00
};
2024-07-29 01:12:19 +08:00
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress))
{
BYTE reg = *(BYTE *)(addr + 2);
if ((reg != 0x05) && (reg != 0x0d) && (reg != 0x1d) && (reg != 0x15))
continue;
int word_4C285C_addr = *(int *)(addr + 3);
if (word_4C285C_addr < processStartAddress || word_4C285C_addr > processStopAddress)
continue;
int word_4C285C = *(int *)word_4C285C_addr;
if ((word_4C285C) != 0x7581)
continue;
2024-02-07 20:59:24 +08:00
addr = findfuncstart(addr, 0x200);
2024-07-29 01:12:19 +08:00
if (addr == 0)
continue;
2024-02-07 20:59:24 +08:00
HookParam hp;
hp.address = addr;
2024-07-29 01:12:19 +08:00
hp.offset = get_stack(1);
2024-02-07 20:59:24 +08:00
hp.type = USING_STRING;
2024-07-29 01:12:19 +08:00
2024-02-07 20:59:24 +08:00
return NewHook(hp, "aiwin6");
}
2024-07-29 01:12:19 +08:00
return false;
2024-02-07 20:59:24 +08:00
}
}
2024-07-29 01:12:19 +08:00
namespace
{ // unnamed
namespace ScenarioHook
2024-02-07 20:59:24 +08:00
{
2024-07-29 01:12:19 +08:00
namespace Private
{
2024-02-07 20:59:24 +08:00
2024-07-29 01:12:19 +08:00
struct TextArgument
{
DWORD _unknown1[5];
2024-02-07 20:59:24 +08:00
2024-07-29 01:12:19 +08:00
DWORD scenarioFlag; // +4*5, 0 if it is scenario
DWORD _unknown2[2];
LPCSTR scenarioText; // +4*5+4*3, could be bad address though
DWORD _unknown3;
2024-02-07 20:59:24 +08:00
2024-07-29 01:12:19 +08:00
DWORD nameFlag; // +4*10, 0 if it is name
DWORD _unknown4[2];
char nameText[1]; // +4*10+4*3, could be bad address though
};
2024-02-07 20:59:24 +08:00
2024-07-29 01:12:19 +08:00
std::string data_;
TextArgument *scenarioArg_,
*nameArg_;
LPCSTR scenarioText_;
2024-02-07 20:59:24 +08:00
2024-07-29 01:12:19 +08:00
enum
{
MaxNameSize = 100
};
char nameText_[MaxNameSize + 1];
bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role)
{
auto arg = (TextArgument *)s->stack[0]; // arg1 on the top of the stack
// Scenario
if (arg->scenarioFlag == 0)
{
*role = Engine::ScenarioRole;
// Text from scenario could be bad when open backlog while the character is speaking
auto text = arg->scenarioText;
if (!Engine::isAddressReadable(text))
return 0;
return write_string_overwrite(data, len, text);
// data_ = q->dispatchTextASTD(text, role, sig);
// scenarioArg_ = arg;
// scenarioText_ = arg->scenarioText;
// arg->scenarioText = (LPCSTR)data_.c_str();
}
else if (arg->nameFlag == 0)
{
*role = Engine::NameRole;
auto text = arg->nameText;
return write_string_overwrite(data, len, text);
// ::memcpy(text, newData.constData(), qMin(oldData.size(), newData.size()));
// int left = oldData.size() - newData.size();
// if (left > 0)
// ::memset(text + oldData.size() - left, 0, left);
}
2024-02-07 20:59:24 +08:00
return 0;
2024-07-29 01:12:19 +08:00
}
void hookafter1(hook_stack *s, void *data1, size_t len)
{
auto newData = std::string((char *)data1, len);
auto arg = (TextArgument *)s->stack[0]; // arg1 on the top of the stack
2024-02-07 20:59:24 +08:00
2024-07-29 01:12:19 +08:00
// Scenario
if (arg->scenarioFlag == 0)
{
2024-02-07 20:59:24 +08:00
2024-07-29 01:12:19 +08:00
auto text = arg->scenarioText;
if (!Engine::isAddressReadable(text))
return;
data_ = newData;
scenarioArg_ = arg;
scenarioText_ = arg->scenarioText;
arg->scenarioText = (LPCSTR)data_.c_str();
}
else if (arg->nameFlag == 0)
{
2024-02-07 20:59:24 +08:00
2024-07-29 01:12:19 +08:00
auto text = arg->nameText;
std::string oldData = text;
::memcpy(text, newData.c_str(), min(oldData.size(), newData.size()));
int left = oldData.size() - newData.size();
if (left > 0)
::memset(text + oldData.size() - left, 0, left);
}
}
bool hookAfter(hook_stack *s, void *data, size_t *len, uintptr_t *role)
{
if (scenarioArg_)
{
scenarioArg_->scenarioText = scenarioText_;
scenarioArg_ = nullptr;
}
if (nameArg_)
{
::strcpy(nameArg_->nameText, nameText_);
nameArg_ = nullptr;
}
return 0;
}
} // namespace Private
/**
* jichi 5/31/2014: elf's
* Type1: SEXティーチャー剛史 trial, reladdr = 0x2f0f0, 2 parameters
* Type2: 4, reladdr = 0x2f9b0, 3 parameters
*
* The hooked function is the caller of the caller of TextOutA.
*/
bool attach(ULONG startAddress, ULONG stopAddress)
{
const uint8_t bytes[] = {
// 0x55, // 0093f9b0 /$ 55 push ebp ; jichi: hook here
// 0x8b,0xec, // 0093f9b1 |. 8bec mov ebp,esp
// 0x83,0xec, 0x08, // 0093f9b3 |. 83ec 08 sub esp,0x8
// 0x83,0x7d, 0x10, 0x00, // 0093f9b6 |. 837d 10 00 cmp dword ptr ss:[ebp+0x10],0x0
// 0x53, // 0093f9ba |. 53 push ebx
// 0x8b,0x5d, 0x0c, // 0093f9bb |. 8b5d 0c mov ebx,dword ptr ss:[ebp+0xc]
// 0x56, // 0093f9be |. 56 push esi
// 0x57, // 0093f9bf |. 57 push edi
0x75, 0x0f, // 0093f9c0 |. 75 0f jnz short silkys.0093f9d1
0x8b, 0x45, 0x08, // 0093f9c2 |. 8b45 08 mov eax,dword ptr ss:[ebp+0x8]
0x8b, 0x48, 0x04, // 0093f9c5 |. 8b48 04 mov ecx,dword ptr ds:[eax+0x4]
0x8b, 0x91, 0x90, 0x00, 0x00, 0x00 // 0093f9c8 |. 8b91 90000000 mov edx,dword ptr ds:[ecx+0x90]
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
if (!addr)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
return false;
int count = 0;
auto fun = [&count](ULONG addr) -> bool
{
bool succ = false;
HookParam hp;
hp.address = addr;
hp.hook_before = Private::hookBefore;
hp.hook_after = Private::hookafter1;
hp.type = USING_STRING | EMBED_ABLE | EMBED_DYNA_SJIS;
hp.hook_font = F_TextOutA;
succ |= NewHook(hp, "EmbedElf");
hp.address = addr + 5;
hp.hook_before = Private::hookAfter;
succ |= NewHook(hp, "EmbedElf");
count += 1;
return succ; // replace all functions
};
MemDbg::iterNearCallAddress(fun, addr, startAddress, stopAddress);
return count;
// lastCaller = MemDbg::findEnclosingAlignedFunction(lastCaller);
// Private::attached_ = false;
// return winhook::hook_before(lastCaller, [=](winhook::hook_stack *s) -> bool {
// if (Private::attached_)
// return true;
// Private::attached_ = true;
// if (ULONG addr = MemDbg::findEnclosingAlignedFunction(s->stack[0])) {
// DOUT("dynamic pattern found");
// Private::oldHookFun = (Private::hook_fun_t)winhook::replace_fun(addr, (ULONG)Private::newHookFun);
// }
// return true;
// });
}
} // namespace ScenarioHook
2024-02-07 20:59:24 +08:00
} // unnamed namespace
2024-07-29 01:12:19 +08:00
namespace
{
// flutter of birds鳥達の羽ばたき
// https://vndb.org/v2379
// 需要注意的是不能把文本跳到最快不然2~4行无法显示。
// 这个有一大堆候选
bool elf3()
{
bool succ = false;
BYTE sig[] = {
0x83, XX, 0x14, 0x10,
0x72, XX};
for (auto addr : Util::SearchMemory(sig, sizeof(sig), PAGE_EXECUTE, processStartAddress, processStopAddress))
{
auto check1 = *(BYTE *)(addr + 5);
if (check1 != 0x02 && check1 != 0x04)
continue;
auto check = *(BYTE *)(addr + 1);
2024-07-10 21:13:08 +08:00
HookParam hp;
2024-07-29 01:12:19 +08:00
hp.address = addr;
hp.user_value = check;
hp.type = USING_STRING | NO_CONTEXT;
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
2024-07-10 21:13:08 +08:00
DWORD ptr;
switch (hp->user_value)
{
case 0x7a:
2024-07-29 01:12:19 +08:00
ptr = stack->edx;
2024-07-10 21:13:08 +08:00
break;
case 0x7b:
2024-07-29 01:12:19 +08:00
ptr = stack->ebx;
2024-07-10 21:13:08 +08:00
break;
case 0x79:
2024-07-29 01:12:19 +08:00
ptr = stack->ecx;
2024-07-10 21:13:08 +08:00
break;
case 0x78:
2024-07-29 01:12:19 +08:00
ptr = stack->eax;
2024-07-10 21:13:08 +08:00
break;
case 0x7e:
2024-07-29 01:12:19 +08:00
ptr = stack->esi;
2024-07-10 21:13:08 +08:00
break;
case 0x7f:
2024-07-29 01:12:19 +08:00
ptr = stack->edi;
2024-07-10 21:13:08 +08:00
break;
case 0x7d:
2024-07-29 01:12:19 +08:00
ptr = stack->ebp;
2024-07-10 21:13:08 +08:00
break;
2024-07-29 01:12:19 +08:00
// esp:
// 83 7c 24 14 10
2024-07-10 21:13:08 +08:00
default:
2024-07-29 01:12:19 +08:00
hp->type = HOOK_EMPTY;
2024-07-10 21:13:08 +08:00
break;
}
2024-07-29 01:12:19 +08:00
auto text = (TextUnionA *)ptr;
*data = (DWORD)text->getText();
*len = text->size;
};
hp.filter_fun = all_ascii_Filter;
succ |= NewHook(hp, "elf3");
}
return succ;
2024-07-10 21:13:08 +08:00
}
}
2024-07-29 01:12:19 +08:00
bool Elf::attach_function()
{
auto _1 = InsertElfHook() || __() || elf3();
return ScenarioHook::attach(processStartAddress, processStopAddress) || _1;
2024-02-07 20:59:24 +08:00
}
2024-07-29 01:12:19 +08:00
bool isshiftjisX(WORD w)
{
return (((BYTE)(w)) <= 0xfc) && (((BYTE)(w)) >= 0x80);
}
void SpecialHookElf2(hook_stack *stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t *len)
2024-02-07 20:59:24 +08:00
{
static DWORD lasttext;
DWORD eax = stack->eax;
DWORD edx = stack->edx;
2024-07-29 01:12:19 +08:00
*data = *(WORD *)(eax + edx);
if (isshiftjisX(*data) == false)
{
*len = 0;
2024-02-07 20:59:24 +08:00
return;
}
*len = 2;
2024-07-29 01:12:19 +08:00
*split = stack->stack[1];
2024-02-07 20:59:24 +08:00
}
2024-07-29 01:12:19 +08:00
bool Elf2attach_function()
{
// 这个有好多乱码
2024-02-07 20:59:24 +08:00
//[エルフ]あしたの雪之丞 DVD Special Edition
const uint8_t bytes[] = {
2024-07-29 01:12:19 +08:00
0x53,
0x8a, 0x1c, 0x02,
0x8b, 0x54, 0x24, 0x08,
0x03, 0xc2};
2024-02-07 20:59:24 +08:00
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr)
2024-07-29 01:12:19 +08:00
return false;
2024-02-07 20:59:24 +08:00
HookParam hp;
2024-07-29 01:12:19 +08:00
hp.address = addr + 1;
2024-02-07 20:59:24 +08:00
hp.text_fun = SpecialHookElf2;
2024-07-29 01:12:19 +08:00
hp.type = NO_CONTEXT;
return NewHook(hp, "Elf");
}
bool elf2()
{
2024-02-07 20:59:24 +08:00
//[エルフ]あしたの雪之丞 DVD Special Edition
2024-07-29 01:12:19 +08:00
// 勝 あしたの雪之丞2
2024-02-07 20:59:24 +08:00
const uint8_t bytes[] = {
2024-07-29 01:12:19 +08:00
0x66, 0x8b, 0x8e, XX4,
0x66, 0x8b, 0x96, XX4,
0x66, 0x01, 0x8e, XX4,
0x66, 0x89, 0x96, XX4,
0x8b, 0x06,
0x6a, 0x00,
0x8b, 0xce,
0xff, 0x50, 0x08,
0x84, 0xc0};
2024-02-07 20:59:24 +08:00
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr)
2024-07-29 01:12:19 +08:00
return false;
2024-02-07 20:59:24 +08:00
HookParam hp;
2024-07-29 01:12:19 +08:00
hp.address = addr + sizeof(bytes);
hp.type = NO_CONTEXT | USING_STRING;
hp.offset = get_reg(regs::ebx);
return NewHook(hp, "Elf");
2024-02-07 20:59:24 +08:00
}
2024-07-29 01:12:19 +08:00
namespace
{
// リフレインブルー【Windows10対応】
bool _h1()
{
// HAN-18*-4@42E12:AI5WIN.exe
BYTE sig[] = {
0x33, 0xff,
0x8b, 0x06,
0x8b, 0xce,
0x6a, 0x01,
0x8b, 0x40, 0x08,
0xff, 0xd0,
0x0f, 0x0b6, 0xc0,
0x8b, 0xce,
0x66, 0xc1, 0xe0, 0x08,
0x0f, 0xb7, 0xc0,
0x89, 0x45, 0xfc,
0x8b, 0x06,
0x6a, 0x01,
0x8b, 0x40, 0x08,
0xff, 0xd0,
0x0f, 0xb6, 0xc0,
0x8b, 0xce,
0x66, 0x09, 0x45, 0xfc,
0xff, 0x75, 0xfc,
0xe8};
2024-05-14 07:56:51 +08:00
ULONG addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
2024-07-29 01:12:19 +08:00
if (!addr)
return false;
2024-05-14 07:56:51 +08:00
HookParam hp;
2024-07-29 01:12:19 +08:00
hp.address = addr + sizeof(sig) - 1;
hp.type = NO_CONTEXT | USING_CHAR | DATA_INDIRECT | CODEC_ANSI_BE;
hp.offset = get_reg(regs::ebp);
hp.index = -4;
return NewHook(hp, "Elf");
2024-05-14 07:56:51 +08:00
}
2024-07-29 01:12:19 +08:00
bool _h2()
{
// HAN4@49570:AI5WIN.exe
// clang-format off
2024-05-14 07:56:51 +08:00
BYTE sig[]={
0x33,0xc5,
0x89,0x45,0xfc,
0x8a,0x81,XX4,
0x84,0xc0,
0x75,0x0e,
0x8b,0x81,XX4,
0x03,0x81,XX4,
0xeb,XX,
0x3c,0x01,
0x75,0x0e,
0x8b,0x81,XX4,
0x03,0x81,XX4,
0xeb,XX,
0x3c,0x02,
0x75,0x0e,
0x8b,0x81,XX4,
0x03,0x81,XX4,
0xeb,XX,
};
2024-07-29 01:12:19 +08:00
// clang-format on
2024-05-14 07:56:51 +08:00
ULONG addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
2024-07-29 01:12:19 +08:00
if (!addr)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
return false;
2024-05-14 07:56:51 +08:00
HookParam hp;
2024-07-29 01:12:19 +08:00
hp.address = addr;
hp.type = NO_CONTEXT | USING_CHAR | CODEC_ANSI_BE;
hp.offset = get_stack(1);
return NewHook(hp, "Elf");
2024-05-14 07:56:51 +08:00
}
2024-07-29 01:12:19 +08:00
bool all()
{
return _h1() | _h2();
2024-05-14 07:56:51 +08:00
}
}
2024-07-29 01:12:19 +08:00
namespace
{
bool el()
{
// https://vndb.org/v2293
// 【el】【Windows10対応】
BYTE sig[] = {
// 0x66,0x8b,0x4d,0x0c
// 0x66,0x8b,0xc1
0x66, 0xc1, 0xe8, 0x08,
XX, // 0x57
0x3c, 0x81,
0x72, 0x04,
0x3c, 0x9f,
0x76, 0x08,
0x3c, 0xe0,
0x72, 0x10,
0x3c, 0xef,
0x77, 0x0c};
// clang-format on
ULONG addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
if (!addr)
return false;
HookParam hp;
hp.address = addr;
hp.type = NO_CONTEXT | USING_CHAR | CODEC_ANSI_BE;
hp.offset = get_reg(regs::eax);
return NewHook(hp, "Elf");
}
}
bool Elf2::attach_function()
{
return elf2() || Elf2attach_function() || all() || el();
2024-02-09 00:42:25 +08:00
}
2024-07-29 01:12:19 +08:00
bool ElfFunClubFinal::attach_function()
{
// mov reg,ds:TextOutA
bool succ = false;
for (auto addr : findiatcallormov_all((DWORD)TextOutA, processStartAddress, processStartAddress, processStopAddress, PAGE_EXECUTE, XX))
{
BYTE s[] = {XX, 0xCC, 0xCC, 0xCC};
addr = reverseFindBytes(s, 4, addr - 0x100, addr);
if (addr == 0)
continue;
2024-02-09 00:42:25 +08:00
HookParam hp;
2024-07-29 01:12:19 +08:00
hp.address = addr + 4;
hp.type = CODEC_ANSI_BE | USING_CHAR;
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
*data = (WORD)stack->stack[3];
*len = 2;
*split = stack->stack[2] > 8;
2024-02-09 00:42:25 +08:00
};
2024-07-29 01:12:19 +08:00
succ |= NewHook(hp, "ElfFunClubFinal");
2024-02-09 00:42:25 +08:00
}
return succ;
2024-02-07 20:59:24 +08:00
}