mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-10-22 23:18:16 +08:00
Update BGI.cpp
This commit is contained in:
parent
7b61703dcb
commit
ed299f7b20
@ -1,4 +1,4 @@
|
|||||||
#include"BGI.h"
|
#include "BGI.h"
|
||||||
/********************************************************************************************
|
/********************************************************************************************
|
||||||
BGI hook:
|
BGI hook:
|
||||||
Usually game folder contains BGI.*. After first run BGI.gdb appears.
|
Usually game folder contains BGI.*. After first run BGI.gdb appears.
|
||||||
@ -9,7 +9,8 @@ BGI hook:
|
|||||||
After 2 tries we will get to the right place. Use ESP value to split text since
|
After 2 tries we will get to the right place. Use ESP value to split text since
|
||||||
it's likely to be different for different calls.
|
it's likely to be different for different calls.
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
namespace { // unnamed
|
namespace
|
||||||
|
{ // unnamed
|
||||||
#if 0 // jichi 12/28/2013: dynamic BGI is not used
|
#if 0 // jichi 12/28/2013: dynamic BGI is not used
|
||||||
static bool FindBGIHook(DWORD fun, DWORD size, DWORD pt, WORD sig)
|
static bool FindBGIHook(DWORD fun, DWORD size, DWORD pt, WORD sig)
|
||||||
{
|
{
|
||||||
@ -63,7 +64,7 @@ bool InsertBGIDynamicHook(LPVOID addr, DWORD frame, DWORD stack)
|
|||||||
}
|
}
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
/** jichi 5/12/2014
|
/** jichi 5/12/2014
|
||||||
* Sample game: FORTUNE ARTERIAL, case 2 at 0x41ebd0
|
* Sample game: FORTUNE ARTERIAL, case 2 at 0x41ebd0
|
||||||
*
|
*
|
||||||
* sub_41EBD0 proc near, seems to take 5 parameters
|
* sub_41EBD0 proc near, seems to take 5 parameters
|
||||||
@ -125,56 +126,64 @@ bool InsertBGIDynamicHook(LPVOID addr, DWORD frame, DWORD stack)
|
|||||||
* 0041ec7b |. 56 push esi
|
* 0041ec7b |. 56 push esi
|
||||||
* 0041ec7c |. e8 1fa0feff call bgi.00408ca0
|
* 0041ec7c |. e8 1fa0feff call bgi.00408ca0
|
||||||
*/
|
*/
|
||||||
bool InsertBGI1Hook()
|
bool InsertBGI1Hook()
|
||||||
{
|
{
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
DWORD i;
|
DWORD i;
|
||||||
DWORD *id;
|
DWORD *id;
|
||||||
BYTE *ib;
|
BYTE *ib;
|
||||||
};
|
};
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
for (i = processStartAddress + 0x1000; i < processStopAddress; i++) {
|
for (i = processStartAddress + 0x1000; i < processStopAddress; i++)
|
||||||
if (ib[0] == 0x3d) {
|
{
|
||||||
|
if (ib[0] == 0x3d)
|
||||||
|
{
|
||||||
i++;
|
i++;
|
||||||
if (id[0] == 0xffff) { //cmp eax,0xffff
|
if (id[0] == 0xffff)
|
||||||
|
{ // cmp eax,0xffff
|
||||||
hp.address = SafeFindEnclosingAlignedFunction(i, 0x40);
|
hp.address = SafeFindEnclosingAlignedFunction(i, 0x40);
|
||||||
if (hp.address) {
|
if (hp.address)
|
||||||
hp.offset=get_stack(3);
|
{
|
||||||
|
hp.offset = get_stack(3);
|
||||||
hp.split = get_reg(regs::esp);
|
hp.split = get_reg(regs::esp);
|
||||||
hp.type = CODEC_ANSI_BE|USING_SPLIT;
|
hp.type = CODEC_ANSI_BE | USING_SPLIT;
|
||||||
ConsoleOutput("INSERT BGI#1");
|
ConsoleOutput("INSERT BGI#1");
|
||||||
|
|
||||||
//RegisterEngineType(ENGINE_BGI);
|
// RegisterEngineType(ENGINE_BGI);
|
||||||
return NewHook(hp, "BGI");
|
return NewHook(hp, "BGI");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ib[0] == 0x81 && ((ib[1] & 0xf8) == 0xf8)) {
|
if (ib[0] == 0x81 && ((ib[1] & 0xf8) == 0xf8))
|
||||||
|
{
|
||||||
i += 2;
|
i += 2;
|
||||||
if (id[0] == 0xffff) { //cmp reg,0xffff
|
if (id[0] == 0xffff)
|
||||||
|
{ // cmp reg,0xffff
|
||||||
hp.address = SafeFindEnclosingAlignedFunction(i, 0x40);
|
hp.address = SafeFindEnclosingAlignedFunction(i, 0x40);
|
||||||
if (hp.address) {
|
if (hp.address)
|
||||||
hp.offset=get_stack(3);
|
{
|
||||||
|
hp.offset = get_stack(3);
|
||||||
hp.split = get_reg(regs::esp);
|
hp.split = get_reg(regs::esp);
|
||||||
hp.type = CODEC_ANSI_BE|USING_SPLIT;
|
hp.type = CODEC_ANSI_BE | USING_SPLIT;
|
||||||
ConsoleOutput("INSERT BGI#2");
|
ConsoleOutput("INSERT BGI#2");
|
||||||
|
|
||||||
//RegisterEngineType(ENGINE_BGI);
|
// RegisterEngineType(ENGINE_BGI);
|
||||||
return NewHook(hp, "BGI");
|
return NewHook(hp, "BGI");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//ConsoleOutput("Unknown BGI engine.");
|
// ConsoleOutput("Unknown BGI engine.");
|
||||||
|
|
||||||
//ConsoleOutput("Probably BGI. Wait for text.");
|
// ConsoleOutput("Probably BGI. Wait for text.");
|
||||||
//SwitchTrigger(true);
|
// SwitchTrigger(true);
|
||||||
//trigger_fun=InsertBGIDynamicHook;
|
// trigger_fun=InsertBGIDynamicHook;
|
||||||
ConsoleOutput("BGI: failed");
|
ConsoleOutput("BGI: failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* jichi 2/5/2014: Add an alternative BGI hook
|
* jichi 2/5/2014: Add an alternative BGI hook
|
||||||
*
|
*
|
||||||
* Issue: This hook cannot extract character name for コトバの消えた日
|
* Issue: This hook cannot extract character name for コトバの消えた日
|
||||||
@ -511,32 +520,40 @@ bool InsertBGI1Hook()
|
|||||||
* 00A643D0 B9 01000000 MOV ECX,0x1
|
* 00A643D0 B9 01000000 MOV ECX,0x1
|
||||||
* ...
|
* ...
|
||||||
*/
|
*/
|
||||||
//static inline size_t _bgistrlen(LPCSTR text)
|
// static inline size_t _bgistrlen(LPCSTR text)
|
||||||
//{
|
//{
|
||||||
// size_t r = ::strlen(text);
|
// size_t r = ::strlen(text);
|
||||||
// if (r >=2 && *(WORD *)(text + r - 2) == 0xa581) // remove trailing ▼ = \x81\xa5
|
// if (r >=2 && *(WORD *)(text + r - 2) == 0xa581) // remove trailing ▼ = \x81\xa5
|
||||||
// r -= 2;
|
// r -= 2;
|
||||||
// return r;
|
// return r;
|
||||||
//}
|
// }
|
||||||
//
|
//
|
||||||
//static void SpecialHookBGI2(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
|
// static void SpecialHookBGI2(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
|
||||||
//{
|
//{
|
||||||
// LPCSTR text = (LPCSTR)*(DWORD *)(esp_base + hp->offset);
|
// LPCSTR text = (LPCSTR)*(DWORD *)(esp_base + hp->offset);
|
||||||
// if (text) {
|
// if (text) {
|
||||||
// *data = (DWORD)text;
|
// *data = (DWORD)text;
|
||||||
// *len = _bgistrlen(text);
|
// *len = _bgistrlen(text);
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
namespace Private {
|
namespace Private
|
||||||
enum { Type1 = 1, Type2, Type3,Type_BGI3 } type_;
|
{
|
||||||
int textIndex_; // the i-th of argument on the stack holding the text
|
enum
|
||||||
bool hookBefore(hook_stack*s,void* data, size_t* len,uintptr_t*role)
|
{
|
||||||
|
Type1 = 1,
|
||||||
|
Type2,
|
||||||
|
Type3,
|
||||||
|
Type_BGI3
|
||||||
|
} type_;
|
||||||
|
int textIndex_; // the i-th of argument on the stack holding the text
|
||||||
|
bool hookBefore(hook_stack *s, void *data, size_t *len, uintptr_t *role)
|
||||||
|
{
|
||||||
|
if (type_ == Type_BGI3)
|
||||||
{
|
{
|
||||||
if (type_ == Type_BGI3) {
|
|
||||||
|
|
||||||
DWORD retaddr = s->stack[0]; // retaddr
|
DWORD retaddr = s->stack[0]; // retaddr
|
||||||
* role = Engine::ScenarioRole;
|
*role = Engine::ScenarioRole;
|
||||||
return write_string_overwrite(data,len,(LPCSTR)s->stack[textIndex_]);
|
return write_string_overwrite(data, len, (LPCSTR)s->stack[textIndex_]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string data_; // persistent storage, which makes this function not thread-safe
|
static std::string data_; // persistent storage, which makes this function not thread-safe
|
||||||
@ -546,18 +563,20 @@ namespace Private {
|
|||||||
return false;
|
return false;
|
||||||
// In Type 1, split = arg8
|
// In Type 1, split = arg8
|
||||||
// In Type 2, there is no arg8. However, arg8 seems to be a good split that can differenciate choice and character name
|
// In Type 2, there is no arg8. However, arg8 seems to be a good split that can differenciate choice and character name
|
||||||
//DWORD split = stack->args[3]; // arg4
|
// DWORD split = stack->args[3]; // arg4
|
||||||
//DWORD split = s->stack[8]; // arg8
|
// DWORD split = s->stack[8]; // arg8
|
||||||
//auto sig = Engine::hashThreadSignature(s->stack[0], split);
|
// auto sig = Engine::hashThreadSignature(s->stack[0], split);
|
||||||
//enum { role = Engine::UnknownRole };
|
// enum { role = Engine::UnknownRole };
|
||||||
|
|
||||||
//DWORD split = s->stack[8]; // this is a good split, but usually game-specific
|
// DWORD split = s->stack[8]; // this is a good split, but usually game-specific
|
||||||
DWORD retaddr = s->stack[0]; // retaddr
|
DWORD retaddr = s->stack[0]; // retaddr
|
||||||
//* role = Engine::OtherRole;
|
//* role = Engine::OtherRole;
|
||||||
switch (type_) {
|
switch (type_)
|
||||||
|
{
|
||||||
|
|
||||||
case Type3:
|
case Type3:
|
||||||
switch (s->stack[textIndex_+1]) {
|
switch (s->stack[textIndex_ + 1])
|
||||||
|
{
|
||||||
case 1:
|
case 1:
|
||||||
if (*(WORD *)(retaddr + 8) == 0xcccc) // two int3
|
if (*(WORD *)(retaddr + 8) == 0xcccc) // two int3
|
||||||
*role = Engine::ScenarioRole;
|
*role = Engine::ScenarioRole;
|
||||||
@ -567,9 +586,11 @@ namespace Private {
|
|||||||
s->stack[10] == 0 && s->stack[10 - 1] == 0 && s->stack[10 - 2] == 0) // for new BGI2 games
|
s->stack[10] == 0 && s->stack[10 - 1] == 0 && s->stack[10 - 2] == 0) // for new BGI2 games
|
||||||
*role = Engine::NameRole;
|
*role = Engine::NameRole;
|
||||||
break;
|
break;
|
||||||
} break;
|
}
|
||||||
|
break;
|
||||||
case Type2:
|
case Type2:
|
||||||
switch (s->stack[textIndex_+1]) {
|
switch (s->stack[textIndex_ + 1])
|
||||||
|
{
|
||||||
case 1:
|
case 1:
|
||||||
// Return address for history text
|
// Return address for history text
|
||||||
// 012B37BA 83C4 34 ADD ESP,0x34
|
// 012B37BA 83C4 34 ADD ESP,0x34
|
||||||
@ -581,20 +602,25 @@ namespace Private {
|
|||||||
if (s->stack[12] == 0x00ffffff && s->stack[12 - 3] == 2)
|
if (s->stack[12] == 0x00ffffff && s->stack[12 - 3] == 2)
|
||||||
*role = Engine::NameRole;
|
*role = Engine::NameRole;
|
||||||
break;
|
break;
|
||||||
} break;
|
}
|
||||||
|
break;
|
||||||
case Type1:
|
case Type1:
|
||||||
switch (s->stack[textIndex_+1]) {
|
switch (s->stack[textIndex_ + 1])
|
||||||
case 1: *role = Engine::ScenarioRole; break;
|
{
|
||||||
|
case 1:
|
||||||
|
*role = Engine::ScenarioRole;
|
||||||
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
if (s->stack[12] == 0x00ffffff && s->stack[12 - 3] == 1)
|
if (s->stack[12] == 0x00ffffff && s->stack[12 - 3] == 1)
|
||||||
*role = Engine::NameRole;
|
*role = Engine::NameRole;
|
||||||
break;
|
break;
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
return write_string_overwrite(data,len,(LPCSTR)s->stack[textIndex_]);
|
break;
|
||||||
|
}
|
||||||
|
return write_string_overwrite(data, len, (LPCSTR)s->stack[textIndex_]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 5/12/2014
|
* 5/12/2014
|
||||||
@ -705,8 +731,8 @@ namespace Private {
|
|||||||
*/
|
*/
|
||||||
ULONG search1(ULONG startAddress, ULONG stopAddress)
|
ULONG search1(ULONG startAddress, ULONG stopAddress)
|
||||||
{
|
{
|
||||||
//return 0x4207e0; // FORTUNE ARTERIAL
|
// return 0x4207e0; // FORTUNE ARTERIAL
|
||||||
//const BYTE bytes[] = {
|
// const BYTE bytes[] = {
|
||||||
// 0x8a,0x45, 0x00, // 00420822 |. 8a45 00 mov al,byte ptr ss:[ebp]
|
// 0x8a,0x45, 0x00, // 00420822 |. 8a45 00 mov al,byte ptr ss:[ebp]
|
||||||
// 0x3c, 0x20, // 00420825 |. 3c 20 cmp al,0x20
|
// 0x3c, 0x20, // 00420825 |. 3c 20 cmp al,0x20
|
||||||
// 0x7d, 0x69, // 00420827 |. 7d 69 jge short bgi.00420892
|
// 0x7d, 0x69, // 00420827 |. 7d 69 jge short bgi.00420892
|
||||||
@ -714,31 +740,35 @@ namespace Private {
|
|||||||
// 0x83,0xc0, 0xfe, // 0042082c |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
|
// 0x83,0xc0, 0xfe, // 0042082c |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
|
||||||
// 0x83,0xf8, 0x06, // 0042082f |. 83f8 06 cmp eax,0x6
|
// 0x83,0xf8, 0x06, // 0042082f |. 83f8 06 cmp eax,0x6
|
||||||
// 0x77, 0x5e // 00420832 |. 77 5e ja short bgi.00420892
|
// 0x77, 0x5e // 00420832 |. 77 5e ja short bgi.00420892
|
||||||
//};
|
// };
|
||||||
//enum { hook_offset = 0x4207e0 - 0x420822 }; // distance to the beginning of the function
|
// enum { hook_offset = 0x4207e0 - 0x420822 }; // distance to the beginning of the function
|
||||||
|
|
||||||
const uint8_t bytes[] = { // 0fafcbf7e9c1fa058bc2c1e81f03d08bfa85ff
|
const uint8_t bytes[] = {
|
||||||
0x0f,0xaf,0xcb, // 004208de |. 0fafcb imul ecx,ebx
|
// 0fafcbf7e9c1fa058bc2c1e81f03d08bfa85ff
|
||||||
0xf7,0xe9, // 004208e1 |. f7e9 imul ecx
|
0x0f, 0xaf, 0xcb, // 004208de |. 0fafcb imul ecx,ebx
|
||||||
0xc1,0xfa, 0x05, // 004208e3 |. c1fa 05 sar edx,0x5
|
0xf7, 0xe9, // 004208e1 |. f7e9 imul ecx
|
||||||
0x8b,0xc2, // 004208e6 |. 8bc2 mov eax,edx
|
0xc1, 0xfa, 0x05, // 004208e3 |. c1fa 05 sar edx,0x5
|
||||||
0xc1,0xe8, 0x1f, // 004208e8 |. c1e8 1f shr eax,0x1f
|
0x8b, 0xc2, // 004208e6 |. 8bc2 mov eax,edx
|
||||||
0x03,0xd0, // 004208eb |. 03d0 add edx,eax
|
0xc1, 0xe8, 0x1f, // 004208e8 |. c1e8 1f shr eax,0x1f
|
||||||
0x8b,0xfa, // 004208ed |. 8bfa mov edi,edx
|
0x03, 0xd0, // 004208eb |. 03d0 add edx,eax
|
||||||
0x85,0xff, // 004208ef |. 85ff test edi,edi
|
0x8b, 0xfa, // 004208ed |. 8bfa mov edi,edx
|
||||||
|
0x85, 0xff, // 004208ef |. 85ff test edi,edi
|
||||||
};
|
};
|
||||||
//enum { hook_offset = 0x4207e0 - 0x4208de }; // distance to the beginning of the function
|
// enum { hook_offset = 0x4207e0 - 0x4208de }; // distance to the beginning of the function
|
||||||
//ULONG range = qMin(stopAddress - startAddress, Engine::MaximumMemoryRange);
|
// ULONG range = qMin(stopAddress - startAddress, Engine::MaximumMemoryRange);
|
||||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
//ConsoleOutput("BGI2: pattern not found");
|
// ConsoleOutput("BGI2: pattern not found");
|
||||||
return 0;
|
return 0;
|
||||||
enum : WORD {
|
enum : WORD
|
||||||
|
{
|
||||||
sub_esp = 0xec81 // 004207e0 /$ 81ec 30090000
|
sub_esp = 0xec81 // 004207e0 /$ 81ec 30090000
|
||||||
, push_ff = 0xff6a // 00427450 /$ 6a ff push -0x1, seh handler
|
,
|
||||||
|
push_ff = 0xff6a // 00427450 /$ 6a ff push -0x1, seh handler
|
||||||
};
|
};
|
||||||
for (int i = 0; i < 300; i++, addr--)
|
for (int i = 0; i < 300; i++, addr--)
|
||||||
if (*(WORD *)addr == sub_esp) { // beginning of the function without seh
|
if (*(WORD *)addr == sub_esp)
|
||||||
|
{ // beginning of the function without seh
|
||||||
|
|
||||||
// Sample game: 世界征服彼女 with SEH
|
// Sample game: 世界征服彼女 with SEH
|
||||||
// 00427450 /$ 6a ff push -0x1
|
// 00427450 /$ 6a ff push -0x1
|
||||||
@ -838,26 +868,33 @@ namespace Private {
|
|||||||
*/
|
*/
|
||||||
ULONG search2(ULONG startAddress, ULONG stopAddress)
|
ULONG search2(ULONG startAddress, ULONG stopAddress)
|
||||||
{
|
{
|
||||||
//return startAddress + 0x31850; // 世界と世界の真ん中 体験版
|
// return startAddress + 0x31850; // 世界と世界の真ん中 体験版
|
||||||
const uint8_t bytes[] = { // 3c207d750fbec083c0fe83f806776a
|
const uint8_t bytes[] = {
|
||||||
|
// 3c207d750fbec083c0fe83f806776a
|
||||||
0x3c, 0x20, // 011d4d31 |. 3c 20 cmp al,0x20
|
0x3c, 0x20, // 011d4d31 |. 3c 20 cmp al,0x20
|
||||||
0x7d, 0x75, // 011d4d33 |. 7d 75 jge short sekachu.011d4daa
|
0x7d, 0x75, // 011d4d33 |. 7d 75 jge short sekachu.011d4daa
|
||||||
0x0f,0xbe,0xc0, // 011d4d35 |. 0fbec0 movsx eax,al
|
0x0f, 0xbe, 0xc0, // 011d4d35 |. 0fbec0 movsx eax,al
|
||||||
0x83,0xc0, 0xfe, // 011d4d38 |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
|
0x83, 0xc0, 0xfe, // 011d4d38 |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
|
||||||
0x83,0xf8, 0x06, // 011d4d3b |. 83f8 06 cmp eax,0x6
|
0x83, 0xf8, 0x06, // 011d4d3b |. 83f8 06 cmp eax,0x6
|
||||||
0x77, 0x6a // 011d4d3e |. 77 6a ja short sekachu.011d4daa
|
0x77, 0x6a // 011d4d3e |. 77 6a ja short sekachu.011d4daa
|
||||||
};
|
};
|
||||||
enum { hook_offset = 0x34c80 - 0x34d31 }; // distance to the beginning of the function
|
enum
|
||||||
//ULONG range = qMin(stopAddress - startAddress, Engine::MaximumMemoryRange);
|
{
|
||||||
|
hook_offset = 0x34c80 - 0x34d31
|
||||||
|
}; // distance to the beginning of the function
|
||||||
|
// ULONG range = qMin(stopAddress - startAddress, Engine::MaximumMemoryRange);
|
||||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
//ConsoleOutput("BGI2: pattern not found");
|
// ConsoleOutput("BGI2: pattern not found");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
addr += hook_offset;
|
addr += hook_offset;
|
||||||
enum : uint8_t { push_ebp = 0x55 }; // 011d4c80 /$ 55 push ebp
|
enum : uint8_t
|
||||||
|
{
|
||||||
|
push_ebp = 0x55
|
||||||
|
}; // 011d4c80 /$ 55 push ebp
|
||||||
if (*(uint8_t *)addr != push_ebp)
|
if (*(uint8_t *)addr != push_ebp)
|
||||||
//ConsoleOutput("BGI2: pattern found but the function offset is invalid");
|
// ConsoleOutput("BGI2: pattern found but the function offset is invalid");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
@ -1016,15 +1053,16 @@ namespace Private {
|
|||||||
* 01312ed8 . 33f6 xor esi,esi
|
* 01312ed8 . 33f6 xor esi,esi
|
||||||
* 01312eda . 83c4 04 add esp,0x4
|
* 01312eda . 83c4 04 add esp,0x4
|
||||||
*/
|
*/
|
||||||
ULONG search3(ULONG startAddress, ULONG stopAddress)
|
ULONG search3(ULONG startAddress, ULONG stopAddress)
|
||||||
{
|
{
|
||||||
//return startAddress + 0x31850; // 世界と世界の真ん中 体験版
|
// return startAddress + 0x31850; // 世界と世界の真ん中 体験版
|
||||||
const uint8_t bytes[] = { // 3c207d580fbec083c0fe83f806774d
|
const uint8_t bytes[] = {
|
||||||
|
// 3c207d580fbec083c0fe83f806774d
|
||||||
0x3c, 0x20, // 01312d8e 3c 20 cmp al,0x20 ; jichi: pattern starts
|
0x3c, 0x20, // 01312d8e 3c 20 cmp al,0x20 ; jichi: pattern starts
|
||||||
0x7d, 0x58, // 01312d90 7d 58 jge short 蒼の彼方.01312dea
|
0x7d, 0x58, // 01312d90 7d 58 jge short 蒼の彼方.01312dea
|
||||||
0x0f,0xbe,0xc0, // 01312d92 0fbec0 movsx eax,al
|
0x0f, 0xbe, 0xc0, // 01312d92 0fbec0 movsx eax,al
|
||||||
0x83,0xc0, 0xfe, // 01312d95 83c0 fe add eax,-0x2 ; switch (cases 2..8)
|
0x83, 0xc0, 0xfe, // 01312d95 83c0 fe add eax,-0x2 ; switch (cases 2..8)
|
||||||
0x83,0xf8, 0x06, // 01312d98 83f8 06 cmp eax,0x6
|
0x83, 0xf8, 0x06, // 01312d98 83f8 06 cmp eax,0x6
|
||||||
0x77, 0x4d // 01312d9b 77 4d ja short 蒼の彼方.01312dea
|
0x77, 0x4d // 01312d9b 77 4d ja short 蒼の彼方.01312dea
|
||||||
};
|
};
|
||||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
|
||||||
@ -1034,22 +1072,30 @@ ULONG search3(ULONG startAddress, ULONG stopAddress)
|
|||||||
// distance to the beginning of the function
|
// distance to the beginning of the function
|
||||||
static const int hook_offsets[] = {
|
static const int hook_offsets[] = {
|
||||||
0x01312cd0 - 0x01312d8e // for new BGI2 game since 蒼の彼方 (2014/08), text is in arg2
|
0x01312cd0 - 0x01312d8e // for new BGI2 game since 蒼の彼方 (2014/08), text is in arg2
|
||||||
, 0x00a64260 - 0x00a64318 // For newer BGI2 game since コドモノアソビ (2015/11)
|
,
|
||||||
|
0x00a64260 - 0x00a64318 // For newer BGI2 game since コドモノアソビ (2015/11)
|
||||||
|
};
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
hook_offset_count = sizeof(hook_offsets) / sizeof(*hook_offsets)
|
||||||
};
|
};
|
||||||
enum { hook_offset_count = sizeof(hook_offsets) / sizeof(*hook_offsets) };
|
|
||||||
|
|
||||||
for (size_t i = 0; i < hook_offset_count; i++) {
|
for (size_t i = 0; i < hook_offset_count; i++)
|
||||||
|
{
|
||||||
int hook_offset = hook_offsets[i];
|
int hook_offset = hook_offsets[i];
|
||||||
|
|
||||||
enum : uint8_t { push_ebp = 0x55 }; // 011d4c80 /$ 55 push ebp
|
enum : uint8_t
|
||||||
|
{
|
||||||
|
push_ebp = 0x55
|
||||||
|
}; // 011d4c80 /$ 55 push ebp
|
||||||
if (*(uint8_t *)(addr + hook_offset) == push_ebp)
|
if (*(uint8_t *)(addr + hook_offset) == push_ebp)
|
||||||
return addr + hook_offset;
|
return addr + hook_offset;
|
||||||
}
|
}
|
||||||
return 0; // failed
|
return 0; // failed
|
||||||
}
|
}
|
||||||
ULONG search_bgi3(ULONG startAddress, ULONG stopAddress )
|
ULONG search_bgi3(ULONG startAddress, ULONG stopAddress)
|
||||||
{
|
{
|
||||||
//黄昏のフォルクローレ
|
// 黄昏のフォルクローレ
|
||||||
/* .text:00C3A700 push ebp
|
/* .text:00C3A700 push ebp
|
||||||
.text : 00C3A701 mov ebp, esp
|
.text : 00C3A701 mov ebp, esp
|
||||||
.text : 00C3A703 push[ebp + arg_30]
|
.text : 00C3A703 push[ebp + arg_30]
|
||||||
@ -1084,47 +1130,53 @@ ULONG search_bgi3(ULONG startAddress, ULONG stopAddress )
|
|||||||
*/
|
*/
|
||||||
const uint8_t bytes[] = {
|
const uint8_t bytes[] = {
|
||||||
0x55,
|
0x55,
|
||||||
0x8b,0xec,
|
0x8b, 0xec,
|
||||||
0xff,0x75,0x38,
|
0xff, 0x75, 0x38,
|
||||||
0x8b,0x55,0x0c,
|
0x8b, 0x55, 0x0c,
|
||||||
0xff,0x75,0x34,
|
0xff, 0x75, 0x34,
|
||||||
0x8b,0x4d,0x08,
|
0x8b, 0x4d, 0x08,
|
||||||
0xff,0x75,0x30
|
0xff, 0x75, 0x30};
|
||||||
};
|
|
||||||
ULONG range = min(ULONG(stopAddress - startAddress), ULONG(0x00300000));
|
ULONG range = min(ULONG(stopAddress - startAddress), ULONG(0x00300000));
|
||||||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, startAddress + range);
|
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, startAddress + range);
|
||||||
if (addr == 0)return 0;
|
if (addr == 0)
|
||||||
|
return 0;
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
bool search_tayutama(DWORD *funaddr,DWORD *addr){
|
bool search_tayutama(DWORD *funaddr, DWORD *addr)
|
||||||
|
{
|
||||||
const BYTE bytes[] = {
|
const BYTE bytes[] = {
|
||||||
// The following code does not exist in newer BGI games after BGI 1.633.0.0 (tayutama2_trial_EX)
|
// The following code does not exist in newer BGI games after BGI 1.633.0.0 (tayutama2_trial_EX)
|
||||||
//0x3c, 0x20, // 011d4d31 |. 3c 20 cmp al,0x20
|
// 0x3c, 0x20, // 011d4d31 |. 3c 20 cmp al,0x20
|
||||||
//0x7d, XX, // 011d4d33 |. 7d 75 jge short sekachu.011d4daa ; jichi: 0x75 or 0x58
|
// 0x7d, XX, // 011d4d33 |. 7d 75 jge short sekachu.011d4daa ; jichi: 0x75 or 0x58
|
||||||
0x0f,0xbe,0xc0, // 011d4d35 |. 0fbec0 movsx eax,al
|
0x0f, 0xbe, 0xc0, // 011d4d35 |. 0fbec0 movsx eax,al
|
||||||
0x83,0xc0, 0xfe, // 011d4d38 |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
|
0x83, 0xc0, 0xfe, // 011d4d38 |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
|
||||||
0x83,0xf8//, 0x06 // 011d4d3b |. 83f8 06 cmp eax,0x6
|
0x83, 0xf8 //, 0x06 // 011d4d3b |. 83f8 06 cmp eax,0x6
|
||||||
// The following code does not exist in newer BGI games after 蒼の彼方
|
// The following code does not exist in newer BGI games after 蒼の彼方
|
||||||
//0x77, 0x6a // 011d4d3e |. 77 6a ja short sekachu.011d4daa
|
// 0x77, 0x6a // 011d4d3e |. 77 6a ja short sekachu.011d4daa
|
||||||
};
|
};
|
||||||
|
|
||||||
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||||
* addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
*addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
||||||
//GROWL_DWORD(reladdr);
|
// GROWL_DWORD(reladdr);
|
||||||
if (!*addr) {
|
if (!*addr)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
* funaddr = MemDbg::findEnclosingAlignedFunction(*addr, 0x300); // range is around 177 ~ 190
|
*funaddr = MemDbg::findEnclosingAlignedFunction(*addr, 0x300); // range is around 177 ~ 190
|
||||||
|
|
||||||
enum : BYTE { push_ebp = 0x55 }; // 011d4c80 /$ 55 push ebp
|
enum : BYTE
|
||||||
if (!*funaddr || *(BYTE *)*funaddr != push_ebp) {
|
{
|
||||||
|
push_ebp = 0x55
|
||||||
|
}; // 011d4c80 /$ 55 push ebp
|
||||||
|
if (!*funaddr || *(BYTE *)*funaddr != push_ebp)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool InsertBGI2Hook()
|
bool InsertBGI2Hook()
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Artikash 6/14/2019: Ugh, what a mess I've dug up...
|
/* Artikash 6/14/2019: Ugh, what a mess I've dug up...
|
||||||
At some point the beginning four bytes to search for were removed, but the difference below were not corrected? Or maybe they were?
|
At some point the beginning four bytes to search for were removed, but the difference below were not corrected? Or maybe they were?
|
||||||
@ -1134,20 +1186,24 @@ bool InsertBGI2Hook()
|
|||||||
I think the safest option is to just add the new? difference as a case that detects offset=arg3 since either way one case will detect offset=arg3 correctly.
|
I think the safest option is to just add the new? difference as a case that detects offset=arg3 since either way one case will detect offset=arg3 correctly.
|
||||||
And all the other cases fall through to offset=arg2.
|
And all the other cases fall through to offset=arg2.
|
||||||
*/
|
*/
|
||||||
ULONG addr , funaddr;HookParam hp;
|
ULONG addr, funaddr;
|
||||||
hp.hook_font=F_TextOutA|F_TextOutW;
|
HookParam hp;
|
||||||
if (addr=search_bgi3(processStartAddress, processStopAddress)){
|
hp.hook_font = F_TextOutA | F_TextOutW;
|
||||||
//有乱码,无法处理。
|
if (addr = search_bgi3(processStartAddress, processStopAddress))
|
||||||
|
{
|
||||||
|
// 有乱码,无法处理。
|
||||||
Private::textIndex_ = 3;
|
Private::textIndex_ = 3;
|
||||||
hp.offset=get_stack(Private::textIndex_);
|
hp.offset = get_stack(Private::textIndex_);
|
||||||
Private::type_ = Private::Type_BGI3;
|
Private::type_ = Private::Type_BGI3;
|
||||||
hp.hook_font|=F_GetTextExtentPoint32W;
|
hp.hook_font |= F_GetTextExtentPoint32W;
|
||||||
if(addr-processStartAddress==0x3B860)//[220729][1171051][きゃべつそふと] ジュエリー・ハーツ・アカデミア -We will wing wonder world-,无法处理的乱码,不知道怎么回事。
|
if (addr - processStartAddress == 0x3B860) //[220729][1171051][きゃべつそふと] ジュエリー・ハーツ・アカデミア -We will wing wonder world-,无法处理的乱码,不知道怎么回事。
|
||||||
addr=0;
|
addr = 0;
|
||||||
}
|
}
|
||||||
else if ( search_tayutama(&funaddr,&addr)) {
|
else if (search_tayutama(&funaddr, &addr))
|
||||||
|
{
|
||||||
|
|
||||||
switch (funaddr - addr) {
|
switch (funaddr - addr)
|
||||||
|
{
|
||||||
// for old BGI2 game, text is arg3
|
// for old BGI2 game, text is arg3
|
||||||
case 0x34c80 - 0x34d31: // old offset
|
case 0x34c80 - 0x34d31: // old offset
|
||||||
case 0x34c50 - 0x34d05: // correction as mentioned above
|
case 0x34c50 - 0x34d05: // correction as mentioned above
|
||||||
@ -1174,44 +1230,48 @@ bool InsertBGI2Hook()
|
|||||||
Private::type_ = Private::Type3;
|
Private::type_ = Private::Type3;
|
||||||
addr = funaddr;
|
addr = funaddr;
|
||||||
}
|
}
|
||||||
else if (addr =search3(processStartAddress, processStopAddress)) {
|
else if (addr = search3(processStartAddress, processStopAddress))
|
||||||
|
{
|
||||||
Private::type_ = Private::Type3;
|
Private::type_ = Private::Type3;
|
||||||
Private::textIndex_ = 2; // use arg2, name = "BGI2";
|
Private::textIndex_ = 2; // use arg2, name = "BGI2";
|
||||||
}else if (addr = search2(processStartAddress, processStopAddress)) {
|
}
|
||||||
|
else if (addr = search2(processStartAddress, processStopAddress))
|
||||||
|
{
|
||||||
Private::type_ = Private::Type2;
|
Private::type_ = Private::Type2;
|
||||||
Private::textIndex_ = 3; // use arg3, name = "BGI2";
|
Private::textIndex_ = 3; // use arg3, name = "BGI2";
|
||||||
} else if (addr =search1(processStartAddress, processStopAddress)) {
|
}
|
||||||
|
else if (addr = search1(processStartAddress, processStopAddress))
|
||||||
|
{
|
||||||
Private::type_ = Private::Type1;
|
Private::type_ = Private::Type1;
|
||||||
Private::textIndex_ = 3; // use arg3, name = "BGI";
|
Private::textIndex_ = 3; // use arg3, name = "BGI";
|
||||||
}
|
}
|
||||||
if(addr==0)return false;
|
if (addr == 0)
|
||||||
|
return false;
|
||||||
hp.address = addr;
|
hp.address = addr;
|
||||||
hp.offset=get_stack(Private::textIndex_);
|
hp.offset = get_stack(Private::textIndex_);
|
||||||
// jichi 5/12/2014: Using split could distinguish name and choices. But the signature might become unstable
|
// jichi 5/12/2014: Using split could distinguish name and choices. But the signature might become unstable
|
||||||
hp.type = USING_STRING|USING_SPLIT|EMBED_ABLE|EMBED_DYNA_SJIS|EMBED_AFTER_NEW;
|
hp.type = USING_STRING | USING_SPLIT | EMBED_ABLE | EMBED_DYNA_SJIS | EMBED_AFTER_NEW;
|
||||||
|
|
||||||
hp.hook_before=Private::hookBefore;
|
hp.hook_before = Private::hookBefore;
|
||||||
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){
|
hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
|
||||||
|
{
|
||||||
// It could be either <R..> or <r..>
|
// It could be either <R..> or <r..>
|
||||||
static const std::regex rx("<r.+?>(.+?)</r>", std::regex_constants::icase);
|
static const std::regex rx("<r.+?>(.+?)</r>", std::regex_constants::icase);
|
||||||
std::string result = std::string((char*)data,*len);
|
std::string result = std::string((char *)data, *len);
|
||||||
result = std::regex_replace(result, rx, "$1");
|
result = std::regex_replace(result, rx, "$1");
|
||||||
|
|
||||||
return write_string_overwrite(data,len,result);
|
return write_string_overwrite(data, len, result);
|
||||||
} ;
|
};
|
||||||
|
|
||||||
hp.split = get_stack(8); // pseudo arg8
|
hp.split = get_stack(8); // pseudo arg8
|
||||||
|
|
||||||
//GROWL_DWORD2(hp.address, processStartAddress);
|
// GROWL_DWORD2(hp.address, processStartAddress);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return NewHook(hp, "EmbedBGI");
|
return NewHook(hp, "EmbedBGI");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InsertBGI3Hook()
|
bool InsertBGI3Hook()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Sample games:
|
* Sample games:
|
||||||
* https://vndb.org/v28283
|
* https://vndb.org/v28283
|
||||||
@ -1223,24 +1283,25 @@ bool InsertBGI3Hook()
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
const BYTE pattern[] = {
|
const BYTE pattern[] = {
|
||||||
0x55, // 55 push ebp
|
0x55, // 55 push ebp
|
||||||
0x8b,0xec, // 8BEC mov ebp,esp
|
0x8b, 0xec, // 8BEC mov ebp,esp
|
||||||
0x83,0xe4, 0xf8, // 83E4 F8 and esp,FFFFFFF8
|
0x83, 0xe4, 0xf8, // 83E4 F8 and esp,FFFFFFF8
|
||||||
0x81,0xec, 0x84,0x00,0x00,0x00 // 81EC 84000000 sub esp,0x84
|
0x81, 0xec, 0x84, 0x00, 0x00, 0x00 // 81EC 84000000 sub esp,0x84
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto addr : Util::SearchMemory(pattern, sizeof(pattern), PAGE_EXECUTE, processStartAddress, processStopAddress))
|
for (auto addr : Util::SearchMemory(pattern, sizeof(pattern), PAGE_EXECUTE, processStartAddress, processStopAddress))
|
||||||
{
|
{
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.address = addr;
|
hp.address = addr;
|
||||||
hp.offset=get_stack(2);
|
hp.offset = get_stack(2);
|
||||||
hp.split =get_stack(1);
|
hp.split = get_stack(1);
|
||||||
hp.type = CODEC_UTF16 | USING_SPLIT;
|
hp.type = CODEC_UTF16 | USING_SPLIT;
|
||||||
ConsoleOutput("INSERT BGI3");
|
ConsoleOutput("INSERT BGI3");
|
||||||
found|=NewHook(hp, "BGI3");
|
found |= NewHook(hp, "BGI3");
|
||||||
}
|
}
|
||||||
if (!found) ConsoleOutput("BGI3: pattern not found");
|
if (!found)
|
||||||
|
ConsoleOutput("BGI3: pattern not found");
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/**
|
/**
|
||||||
@ -1338,20 +1399,32 @@ bool BGI7Filter(LPVOID data, size_t *size, HookParam *)
|
|||||||
{
|
{
|
||||||
auto text = reinterpret_cast<LPWSTR>(data);
|
auto text = reinterpret_cast<LPWSTR>(data);
|
||||||
auto len = reinterpret_cast<size_t *>(size);
|
auto len = reinterpret_cast<size_t *>(size);
|
||||||
|
// BGI4 split不管用,所以只好手动过滤掉了
|
||||||
|
auto ws = std::wstring(text, *len / 2);
|
||||||
|
if (endWith(ws, L".bs5"))
|
||||||
|
return false;
|
||||||
|
if (endWith(ws, L".arc"))
|
||||||
|
return false;
|
||||||
|
if (all_ascii(ws.c_str()) && (ws.find(L"-") != ws.npos) && (ws.find(L"_") != ws.npos))
|
||||||
|
return false;
|
||||||
|
if (ws.find(L"[ 0 ]") != ws.npos)
|
||||||
|
return false; // 個別アニメーション [ 0 ] の透明度
|
||||||
|
//
|
||||||
CharFilter(text, len, L'\x0001');
|
CharFilter(text, len, L'\x0001');
|
||||||
CharFilter(text, len, L'\x0002');
|
CharFilter(text, len, L'\x0002');
|
||||||
CharFilter(text, len, L'\x0003');
|
CharFilter(text, len, L'\x0003');
|
||||||
CharFilter(text, len, L'\x0004');
|
CharFilter(text, len, L'\x0004');
|
||||||
CharFilter(text, len, L'\x0005');
|
CharFilter(text, len, L'\x0005');
|
||||||
CharFilter(text, len, L'\x000A');
|
CharFilter(text, len, L'\x000A');
|
||||||
if (text[0] == L'\x3000') {
|
if (text[0] == L'\x3000')
|
||||||
|
{
|
||||||
*len -= 2;
|
*len -= 2;
|
||||||
::memmove(text, text+1, *len);
|
::memmove(text, text + 1, *len);
|
||||||
}
|
}
|
||||||
CharReplacer(text, len, L'\x3000', L' '); //IDSP
|
CharReplacer(text, len, L'\x3000', L' '); // IDSP
|
||||||
|
|
||||||
if (cpp_wcsnstr(text, L"<", *len/sizeof(wchar_t))) {
|
if (cpp_wcsnstr(text, L"<", *len / sizeof(wchar_t)))
|
||||||
|
{
|
||||||
StringFilterBetween(text, len, L"<", 1, L">", 1);
|
StringFilterBetween(text, len, L"<", 1, L">", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1369,7 +1442,7 @@ bool InsertBGI7Hook()
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
const BYTE pattern[] = {
|
const BYTE pattern[] = {
|
||||||
0x55, // 55 push ebp << hook here
|
0x55, // 55 push ebp << hook here
|
||||||
0x8b,0xec, // 8BEC mov ebp,esp
|
0x8b, 0xec, // 8BEC mov ebp,esp
|
||||||
0x53, // 53 push ebx
|
0x53, // 53 push ebx
|
||||||
0x56, // 56 push esi
|
0x56, // 56 push esi
|
||||||
0x57, // 57 push edi
|
0x57, // 57 push edi
|
||||||
@ -1382,14 +1455,15 @@ bool InsertBGI7Hook()
|
|||||||
{
|
{
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.address = addr;
|
hp.address = addr;
|
||||||
hp.offset=get_reg(regs::eax);
|
hp.offset = get_reg(regs::eax);
|
||||||
hp.split =get_reg(regs::esp);
|
hp.split = get_reg(regs::esp);
|
||||||
hp.type = CODEC_UTF16 | USING_STRING | USING_SPLIT | KNOWN_UNSTABLE;
|
hp.type = CODEC_UTF16 | USING_STRING | USING_SPLIT | KNOWN_UNSTABLE;
|
||||||
hp.filter_fun = BGI7Filter;
|
hp.filter_fun = BGI7Filter;
|
||||||
ConsoleOutput("INSERT BGI4");
|
ConsoleOutput("INSERT BGI4");
|
||||||
found|=NewHook(hp, "BGI4");
|
found |= NewHook(hp, "BGI4");
|
||||||
}
|
}
|
||||||
if (!found) ConsoleOutput("BGI4: pattern not found");
|
if (!found)
|
||||||
|
ConsoleOutput("BGI4: pattern not found");
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1398,7 +1472,8 @@ bool BGI56Filter(LPVOID data, size_t *size, HookParam *)
|
|||||||
auto text = reinterpret_cast<LPSTR>(data);
|
auto text = reinterpret_cast<LPSTR>(data);
|
||||||
auto len = reinterpret_cast<size_t *>(size);
|
auto len = reinterpret_cast<size_t *>(size);
|
||||||
|
|
||||||
if (text[0] == '@') {
|
if (text[0] == '@')
|
||||||
|
{
|
||||||
*len -= 1;
|
*len -= 1;
|
||||||
::memmove(text, text + 1, *len);
|
::memmove(text, text + 1, *len);
|
||||||
}
|
}
|
||||||
@ -1428,7 +1503,7 @@ bool InsertBGI5Hook()
|
|||||||
|
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.address = addr + 1;
|
hp.address = addr + 1;
|
||||||
hp.offset=get_reg(regs::ecx);
|
hp.offset = get_reg(regs::ecx);
|
||||||
hp.padding = 1;
|
hp.padding = 1;
|
||||||
hp.type = USING_STRING;
|
hp.type = USING_STRING;
|
||||||
hp.filter_fun = BGI56Filter;
|
hp.filter_fun = BGI56Filter;
|
||||||
@ -1462,7 +1537,7 @@ bool InsertBGI6Hook()
|
|||||||
|
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.address = addr + 1;
|
hp.address = addr + 1;
|
||||||
hp.offset=get_reg(regs::ecx);
|
hp.offset = get_reg(regs::ecx);
|
||||||
hp.padding = 1;
|
hp.padding = 1;
|
||||||
hp.type = USING_STRING;
|
hp.type = USING_STRING;
|
||||||
hp.filter_fun = BGI56Filter;
|
hp.filter_fun = BGI56Filter;
|
||||||
@ -1471,8 +1546,9 @@ bool InsertBGI6Hook()
|
|||||||
return NewHook(hp, "BGI6");
|
return NewHook(hp, "BGI6");
|
||||||
}
|
}
|
||||||
bool InsertBGIHook()
|
bool InsertBGIHook()
|
||||||
{ return InsertBGI2Hook() || InsertBGI3Hook() || (PcHooks::hookOtherPcFunctions(), InsertBGI1Hook()); }
|
{
|
||||||
|
return InsertBGI2Hook() || InsertBGI3Hook() || (PcHooks::hookOtherPcFunctions(), InsertBGI1Hook());
|
||||||
|
}
|
||||||
|
|
||||||
bool InsertBGI4Hook()
|
bool InsertBGI4Hook()
|
||||||
{
|
{
|
||||||
@ -1509,119 +1585,135 @@ bool InsertBGI4Hook()
|
|||||||
return v3;
|
return v3;
|
||||||
}*/
|
}*/
|
||||||
const BYTE bytes[] = {
|
const BYTE bytes[] = {
|
||||||
0xBE,0xE9,0xFD,0x00,0x00, //cp=65001
|
0xBE, 0xE9, 0xFD, 0x00, 0x00, // cp=65001
|
||||||
XX2,
|
XX2,
|
||||||
0xBE,0xA4,0x03,0x00,0x00 //cp=932
|
0xBE, 0xA4, 0x03, 0x00, 0x00 // cp=932
|
||||||
};
|
};
|
||||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||||
if (addr == 0)return false;
|
if (addr == 0)
|
||||||
|
return false;
|
||||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||||
if (addr == 0)return false;
|
if (addr == 0)
|
||||||
|
return false;
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.address = addr;
|
hp.address = addr;
|
||||||
// hp.offset=get_reg(regs::eax);
|
// hp.offset=get_reg(regs::eax);
|
||||||
// hp.split = get_reg(regs::esp);
|
// hp.split = get_reg(regs::esp);
|
||||||
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||||
*data=stack->stack[2];
|
{
|
||||||
*split=stack->stack[6];//不一定对
|
*data = stack->stack[2];
|
||||||
switch(*split){
|
*split = stack->stack[6]; // 不一定对
|
||||||
case 0://name
|
*len = 2 * wcslen((wchar_t *)*data);
|
||||||
case 1:
|
// switch(*split){
|
||||||
*len=2*wcslen((wchar_t*)*data);
|
// case 0://name
|
||||||
break;
|
// case 1:
|
||||||
}
|
// *len=2*wcslen((wchar_t*)*data);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
hp.type = CODEC_UTF16 | USING_STRING|NO_CONTEXT |EMBED_ABLE|EMBED_BEFORE_SIMPLE|EMBED_AFTER_OVERWRITE;
|
hp.type = CODEC_UTF16 | USING_STRING | NO_CONTEXT | EMBED_ABLE | EMBED_BEFORE_SIMPLE | EMBED_AFTER_OVERWRITE;
|
||||||
hp.hook_font=F_TextOutW|F_GetTextExtentPoint32W;
|
hp.hook_font = F_TextOutW | F_GetTextExtentPoint32W;
|
||||||
hp.filter_fun = BGI7Filter;
|
hp.filter_fun = BGI7Filter;
|
||||||
ConsoleOutput("BGI4");
|
ConsoleOutput("BGI4");
|
||||||
|
|
||||||
return NewHook(hp, "BGI4");
|
return NewHook(hp, "BGI4");
|
||||||
}
|
}
|
||||||
namespace{
|
namespace
|
||||||
bool veryold(){
|
{
|
||||||
//紅月-くれないつき-
|
bool veryold()
|
||||||
//あの街の恋の詩
|
{
|
||||||
auto addr = findiatcallormov((DWORD)GetGlyphOutlineA,processStartAddress,processStartAddress,processStopAddress);
|
// 紅月-くれないつき-
|
||||||
if (addr == 0)//銀行淫~堕ちゆく女達~ //mov ebp, ds:GetGlyphOutlineA
|
// あの街の恋の詩
|
||||||
addr = findiatcallormov((DWORD)GetGlyphOutlineA,processStartAddress,processStartAddress,processStopAddress,false,XX);
|
auto addr = findiatcallormov((DWORD)GetGlyphOutlineA, processStartAddress, processStartAddress, processStopAddress);
|
||||||
if (addr == 0)return false;
|
if (addr == 0) // 銀行淫~堕ちゆく女達~ //mov ebp, ds:GetGlyphOutlineA
|
||||||
|
addr = findiatcallormov((DWORD)GetGlyphOutlineA, processStartAddress, processStartAddress, processStopAddress, false, XX);
|
||||||
|
if (addr == 0)
|
||||||
|
return false;
|
||||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||||
if (addr == 0)return false;
|
if (addr == 0)
|
||||||
auto xrefs=findxref_reverse_checkcallop(addr,addr-0x1000,addr+0x1000,0xe8);
|
return false;
|
||||||
if(xrefs.size()!=1)return false;
|
auto xrefs = findxref_reverse_checkcallop(addr, addr - 0x1000, addr + 0x1000, 0xe8);
|
||||||
auto xrefaddr=xrefs[0];
|
if (xrefs.size() != 1)
|
||||||
|
return false;
|
||||||
|
auto xrefaddr = xrefs[0];
|
||||||
auto funcstart = MemDbg::findEnclosingAlignedFunction(xrefaddr);
|
auto funcstart = MemDbg::findEnclosingAlignedFunction(xrefaddr);
|
||||||
if (funcstart == 0)return false;
|
if (funcstart == 0)
|
||||||
BYTE sig[]={0x81,XX,0x00,0x01,0x00,0x00};//cmp ebx, 100h
|
return false;
|
||||||
if(MemDbg::findBytes(sig, sizeof(sig), xrefaddr-0x40, xrefaddr)==0)return false;
|
BYTE sig[] = {0x81, XX, 0x00, 0x01, 0x00, 0x00}; // cmp ebx, 100h
|
||||||
|
if (MemDbg::findBytes(sig, sizeof(sig), xrefaddr - 0x40, xrefaddr) == 0)
|
||||||
|
return false;
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.address = funcstart;
|
hp.address = funcstart;
|
||||||
hp.offset=get_stack(2);
|
hp.offset = get_stack(2);
|
||||||
hp.split =get_stack(1);
|
hp.split = get_stack(1);
|
||||||
hp.type = CODEC_ANSI_BE |USING_SPLIT;
|
hp.type = CODEC_ANSI_BE | USING_SPLIT;
|
||||||
|
|
||||||
return NewHook(hp, "BGI5");
|
return NewHook(hp, "BGI5");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace{
|
namespace
|
||||||
|
{
|
||||||
//[220729][1171051][きゃべつそふと] ジュエリー・ハーツ・アカデミア -We will wing wonder world-
|
//[220729][1171051][きゃべつそふと] ジュエリー・ハーツ・アカデミア -We will wing wonder world-
|
||||||
//int __fastcall sub_438E90(int a1, int *a2, int a3, _DWORD *a4, int a5)
|
// int __fastcall sub_438E90(int a1, int *a2, int a3, _DWORD *a4, int a5)
|
||||||
bool hook7(){
|
bool hook7()
|
||||||
BYTE sig[]={
|
{
|
||||||
0x55,0x8b,0xec,
|
BYTE sig[] = {
|
||||||
0x83,0xe4,0xf0,
|
0x55, 0x8b, 0xec,
|
||||||
0x83,0xec,XX,
|
0x83, 0xe4, 0xf0,
|
||||||
|
0x83, 0xec, XX,
|
||||||
0x56,
|
0x56,
|
||||||
0x57,
|
0x57,
|
||||||
0x8b,XX,0x08,
|
0x8b, XX, 0x08,
|
||||||
0x8b,0xf2,
|
0x8b, 0xf2,
|
||||||
0x8b,0xd1,
|
0x8b, 0xd1,
|
||||||
0x81,0xcf,0x00,0x00,0x00,0x80,
|
0x81, 0xcf, 0x00, 0x00, 0x00, 0x80,
|
||||||
0x8b,0xcf,
|
0x8b, 0xcf,
|
||||||
0x89,0x54,0x24,0x0c,
|
0x89, 0x54, 0x24, 0x0c,
|
||||||
0xe8,XX4,
|
0xe8, XX4,
|
||||||
0x85,0xc0,
|
0x85, 0xc0,
|
||||||
0x0f,0x84,XX4,
|
0x0f, 0x84, XX4,
|
||||||
0x8b,0x45,0x08
|
0x8b, 0x45, 0x08
|
||||||
|
|
||||||
};
|
};
|
||||||
auto addr=MemDbg::findBytes(sig,sizeof(sig),processStartAddress,processStopAddress);
|
auto addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
|
||||||
if(!addr)return false;
|
if (!addr)
|
||||||
|
return false;
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.address=addr;
|
hp.address = addr;
|
||||||
//hp.offset=get_stack(1);
|
// hp.offset=get_stack(1);
|
||||||
//hp.split=get_stack(3);
|
// hp.split=get_stack(3);
|
||||||
hp.type=USING_CHAR|CODEC_UTF16|NO_CONTEXT;//|USING_SPLIT;
|
hp.type = USING_CHAR | CODEC_UTF16 | NO_CONTEXT; //|USING_SPLIT;
|
||||||
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||||
*data=(wchar_t)stack->stack[1];
|
{
|
||||||
switch(stack->stack[3]){
|
*data = (wchar_t)stack->stack[1];
|
||||||
|
switch (stack->stack[3])
|
||||||
|
{
|
||||||
case 0xfefefe:
|
case 0xfefefe:
|
||||||
hp->user_value=stack->retaddr;
|
hp->user_value = stack->retaddr;
|
||||||
*len=2;
|
*len = 2;
|
||||||
*split=1;
|
*split = 1;
|
||||||
break;
|
break;
|
||||||
case 0xffffff://名字&历史+零散的文字,由于no_context他们被合并,但是和名字和文本是同一个调用地址
|
case 0xffffff: // 名字&历史+零散的文字,由于no_context他们被合并,但是和名字和文本是同一个调用地址
|
||||||
|
|
||||||
if(hp->user_value==stack->retaddr){
|
if (hp->user_value == stack->retaddr)
|
||||||
*len=2;
|
{
|
||||||
*split=2;
|
*len = 2;
|
||||||
|
*split = 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xfcfcc0://历史
|
case 0xfcfcc0: // 历史
|
||||||
default:
|
default:;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return NewHook(hp,"bgi7");
|
return NewHook(hp, "bgi7");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool BGI::attach_function() {
|
bool BGI::attach_function()
|
||||||
bool b1= InsertBGIHook();
|
{
|
||||||
bool b2=InsertBGI4Hook();
|
bool b1 = InsertBGIHook();
|
||||||
bool ok= b1||b2||veryold();
|
bool b2 = InsertBGI4Hook();
|
||||||
ok|=hook7();
|
bool ok = b1 || b2 || veryold();
|
||||||
ok=InsertBGI7Hook()|| InsertBGI5Hook() || InsertBGI6Hook()||ok;
|
ok |= hook7();
|
||||||
|
ok = InsertBGI7Hook() || InsertBGI5Hook() || InsertBGI6Hook() || ok;
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user