2024-11-02 15:49:09 +08:00
|
|
|
|
#include "AB2Try.h"
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
|
|
|
|
/********************************************************************************************
|
|
|
|
|
AkabeiSoft2Try hook:
|
|
|
|
|
Game folder contains YaneSDK.dll. Maybe we should call the engine Yane(屋<EFBFBD> = roof)?
|
|
|
|
|
This engine is based on .NET framework. This really makes it troublesome to locate a
|
|
|
|
|
valid hook address. The problem is that the engine file merely contains bytecode for
|
|
|
|
|
the CLR. Real meaningful object code is generated dynamically and the address is randomized.
|
|
|
|
|
Therefore the easiest method is to brute force search whole address space. While it's not necessary
|
|
|
|
|
to completely search the whole address space, since non-executable pages can be excluded first.
|
|
|
|
|
The generated code sections do not belong to any module(exe/dll), hence they do not have
|
|
|
|
|
a section name. So we can also exclude executable pages from all modules. At last, the code
|
|
|
|
|
section should be long(>0x2000). The remain address space should be several MBs in size and
|
|
|
|
|
can be examined in reasonable time(less than 0.1s for P8400 Win7x64).
|
|
|
|
|
Characteristic sequence is 0F B7 44 50 0C, stands for movzx eax, word ptr [edx*2 + eax + C].
|
|
|
|
|
Obviously this instruction extracts one unicode character from a string.
|
|
|
|
|
A main shortcoming is that the code is not generated if it hasn't been used yet.
|
|
|
|
|
So if you are in title screen this approach will fail.
|
|
|
|
|
|
|
|
|
|
********************************************************************************************/
|
2024-11-02 15:49:09 +08:00
|
|
|
|
namespace
|
|
|
|
|
{ // unnamed
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
2024-11-02 15:49:09 +08:00
|
|
|
|
typedef struct _NSTRING
|
|
|
|
|
{
|
|
|
|
|
PVOID vfTable;
|
|
|
|
|
DWORD lenWithNull;
|
|
|
|
|
DWORD lenWithoutNull;
|
|
|
|
|
WCHAR str[1];
|
|
|
|
|
} NSTRING;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
2024-11-02 15:49:09 +08:00
|
|
|
|
// qsort correctly identifies overflow.
|
|
|
|
|
int cmp(const void *a, const void *b)
|
|
|
|
|
{
|
|
|
|
|
return *(int *)a - *(int *)b;
|
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
2024-11-02 15:49:09 +08:00
|
|
|
|
void SpecialHookAB2Try(hook_stack *stack, HookParam *, uintptr_t *data, uintptr_t *split, size_t *len)
|
|
|
|
|
{
|
|
|
|
|
// DWORD test = *(DWORD*)(esp_base - 0x10);
|
|
|
|
|
DWORD edx = stack->edx;
|
|
|
|
|
if (edx != 0)
|
|
|
|
|
return;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
2024-11-02 15:49:09 +08:00
|
|
|
|
// NSTRING *s = *(NSTRING **)(esp_base - 8);
|
|
|
|
|
if (const NSTRING *s = (NSTRING *)stack->eax)
|
|
|
|
|
{
|
|
|
|
|
*len = s->lenWithoutNull << 1;
|
|
|
|
|
*data = (DWORD)s->str;
|
|
|
|
|
//*split = 0;
|
|
|
|
|
*split = FIXED_SPLIT_VALUE; // 8/3/2014 jichi: change to single threads
|
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 15:49:09 +08:00
|
|
|
|
bool FindCharacteristInstruction()
|
|
|
|
|
{
|
|
|
|
|
const BYTE bytes[] = {0x0F, 0xB7, 0x44, 0x50, 0x0C, 0x89};
|
|
|
|
|
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE_READWRITE))
|
|
|
|
|
{
|
|
|
|
|
// GROWL_DWORD(addr);
|
|
|
|
|
HookParam hp;
|
|
|
|
|
hp.address = addr;
|
|
|
|
|
hp.text_fun = SpecialHookAB2Try;
|
|
|
|
|
hp.type = USING_STRING | NO_CONTEXT | CODEC_UTF16;
|
|
|
|
|
// ConsoleOutput("Please adjust text speed to fastest/immediate.");
|
|
|
|
|
// RegisterEngineType(ENGINE_AB2T);
|
|
|
|
|
return NewHook(hp, "AB2Try");
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
} // unnamed namespace
|
2024-11-02 15:49:09 +08:00
|
|
|
|
bool AB2Try::attach_function()
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
2024-11-02 15:49:09 +08:00
|
|
|
|
return FindCharacteristInstruction();
|
|
|
|
|
}
|