mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-11-23 22:05:36 +08:00
75 lines
2.8 KiB
C++
75 lines
2.8 KiB
C++
#include "AB2Try.h"
|
||
|
||
/********************************************************************************************
|
||
AkabeiSoft2Try hook:
|
||
Game folder contains YaneSDK.dll. Maybe we should call the engine Yane(屋<> = 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.
|
||
|
||
********************************************************************************************/
|
||
namespace
|
||
{ // unnamed
|
||
|
||
typedef struct _NSTRING
|
||
{
|
||
PVOID vfTable;
|
||
DWORD lenWithNull;
|
||
DWORD lenWithoutNull;
|
||
WCHAR str[1];
|
||
} NSTRING;
|
||
|
||
// qsort correctly identifies overflow.
|
||
int cmp(const void *a, const void *b)
|
||
{
|
||
return *(int *)a - *(int *)b;
|
||
}
|
||
|
||
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;
|
||
|
||
// 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
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
} // unnamed namespace
|
||
bool AB2Try::attach_function()
|
||
{
|
||
return FindCharacteristInstruction();
|
||
} |