2024-02-07 20:59:24 +08:00
# include"BGI.h"
# include"embed_util.h"
/********************************************************************************************
BGI hook :
Usually game folder contains BGI . * . After first run BGI . gdb appears .
BGI engine has font caching issue so the strategy is simple .
First find call to TextOutA or TextOutW then reverse to function entry point ,
until full text is caught .
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
namespace { // unnamed
#if 0 // jichi 12/28/2013: dynamic BGI is not used
static bool FindBGIHook ( DWORD fun , DWORD size , DWORD pt , WORD sig )
{
if ( ! fun ) {
ConsoleOutput ( " BGI: cannot find BGI hook " ) ;
//swprintf(str, L"Can't find BGI hook: %.8X.",fun);
//ConsoleOutput(str);
return false ;
}
//WCHAR str[0x40];
//i=FindCallBoth(fun,size,pt);
//swprintf(str, L"CALL addr: 0x%.8X",pt+i);
//ConsoleOutput(str);
for ( DWORD i = fun , j = fun ; j > i - 0x100 ; j - - )
if ( ( * ( WORD * ) ( pt + j ) ) = = sig ) { // Fun entry 1.
//swprintf(str, L"Entry 1: 0x%.8X",pt+j);
//ConsoleOutput(str);
for ( DWORD k = i + 0x100 ; k < i + 0x800 ; k + + )
if ( * ( BYTE * ) ( pt + k ) = = 0xe8 )
if ( k + 5 + * ( DWORD * ) ( pt + k + 1 ) = = j ) { // Find call to fun1.
//swprintf(str, L"CALL to entry 1: 0x%.8X",pt+k);
//ConsoleOutput(str);
for ( DWORD l = k ; l > k - 0x100 ; l - - )
if ( ( * ( WORD * ) ( pt + l ) ) = = 0xec83 ) { // Fun entry 2.
//swprintf(str, L"Entry 2(final): 0x%.8X",pt+l);
//ConsoleOutput(str);
HookParam hp ;
hp . address = ( DWORD ) pt + l ;
hp . offset = get_stack ( 2 ) ;
hp . split = get_reg ( regs : : esp ) ;
hp . type = CODEC_ANSI_BE | USING_SPLIT ;
ConsoleOutput ( " INSERT DynamicBGI " ) ;
return NewHook ( hp , " BGI " ) ;
}
}
}
ConsoleOutput ( " DynamicBGI: failed " ) ;
return false ;
}
bool InsertBGIDynamicHook ( LPVOID addr , DWORD frame , DWORD stack )
{
if ( addr ! = TextOutA & & addr ! = TextOutW ) {
//ConsoleOutput("DynamicBGI: failed");
return false ;
}
DWORD i = * ( DWORD * ) ( stack + 4 ) - processStartAddress ;
return FindBGIHook ( i , processStopAddress - processStartAddress , processStartAddress , 0xec83 ) ;
}
# endif // 0
/** jichi 5/12/2014
* Sample game : FORTUNE ARTERIAL , case 2 at 0x41ebd0
*
* sub_41EBD0 proc near , seems to take 5 parameters
*
* 0041 ebd0 / $ 83 ec 28 sub esp , 0x28 ; jichi : hook here , beginning of the function
* 0041 ebd3 | . 55 push ebp
* 0041 ebd4 | . 8 b6c24 38 mov ebp , dword ptr ss : [ esp + 0x38 ]
* 0041 ebd8 | . 81f d 00ff 0000 cmp ebp , 0xff00
* 0041 ebde | . 0f 82 e1000000 jb bgi .0041 ecc5
* 0041 ebe4 | . 81f d ffff0000 cmp ebp , 0xffff
* 0041 ebea | . 0f 87 d5000000 ja bgi .0041 ecc5
* 0041 ebf0 | . a1 54634900 mov eax , dword ptr ds : [ 0x496354 ]
* 0041 ebf5 | . 8 bd5 mov edx , ebp
* 0041 ebf7 | . 81e2 ff000000 and edx , 0xff
* 0041 ebfd | . 53 push ebx
* 0041 ebfe | . 4 a dec edx
* 0041 ebff | . 33 db xor ebx , ebx
* 0041 ec01 | . 3 bd0 cmp edx , eax
* 0041 ec03 | . 56 push esi
* 0041 ec04 | . 0f 8 d 8 a000000 jge bgi .0041 ec94
* 0041 ec0a | . 57 push edi
* 0041 ec0b | . b9 06000000 mov ecx , 0x6
* 0041 ec10 | . be 5 c634900 mov esi , bgi .0049635 c
* 0041 ec15 | . 8 d7c24 20 lea edi , dword ptr ss : [ esp + 0x20 ]
* 0041 ec19 | . f3 : a5 rep movs dword ptr es : [ edi ] , dword ptr ds >
* 0041 ec1b | . 8 b0d 58634900 mov ecx , dword ptr ds : [ 0x496358 ]
* 0041 ec21 | . 8 b7424 3 c mov esi , dword ptr ss : [ esp + 0x3c ]
* 0041 ec25 | . 8 bc1 mov eax , ecx
* 0041 ec27 | . 5f pop edi
* 0041 ec28 | . 0f afc2 imul eax , edx
* 0041 ec2b | . 8 b56 08 mov edx , dword ptr ds : [ esi + 0x8 ]
* 0041 ec2e | . 894424 0 c mov dword ptr ss : [ esp + 0xc ] , eax
* 0041 ec32 | . 3 bca cmp ecx , edx
* 0041 ec34 | . 7 e 02 jle short bgi .0041 ec38
* 0041 ec36 | . 8 bca mov ecx , edx
* 0041 ec38 | > 8 d4401 ff lea eax , dword ptr ds : [ ecx + eax - 0x1 ]
* 0041 ec3c | . 8 b4c24 28 mov ecx , dword ptr ss : [ esp + 0x28 ]
* 0041 ec40 | . 894424 14 mov dword ptr ss : [ esp + 0x14 ] , eax
* 0041 ec44 | . 8 b46 0 c mov eax , dword ptr ds : [ esi + 0xc ]
* 0041 ec47 | . 3 bc8 cmp ecx , eax
* 0041 ec49 | . 895 c24 10 mov dword ptr ss : [ esp + 0x10 ] , ebx
* 0041 ec4d | . 77 02 ja short bgi .0041 ec51
* 0041 ec4f | . 8 bc1 mov eax , ecx
* 0041 ec51 | > 8 d4c24 0 c lea ecx , dword ptr ss : [ esp + 0xc ]
* 0041 ec55 | . 8 d5424 1 c lea edx , dword ptr ss : [ esp + 0x1c ]
* 0041 ec59 | . 48 dec eax
* 0041 ec5a | . 51 push ecx
* 0041 ec5b | . 52 push edx
* 0041 ec5c | . 894424 20 mov dword ptr ss : [ esp + 0x20 ] , eax
* 0041 ec60 | . e8 7 b62feff call bgi .00404 ee0
* 0041 ec65 | . 8 b4424 34 mov eax , dword ptr ss : [ esp + 0x34 ]
* 0041 ec69 | . 83 c4 08 add esp , 0x8
* 0041 ec6c | . 83f 8 03 cmp eax , 0x3
* 0041 ec6f | . 75 15 jnz short bgi .0041 ec86
* 0041 ec71 | . 8 b4424 48 mov eax , dword ptr ss : [ esp + 0x48 ]
* 0041 ec75 | . 8 d4c24 1 c lea ecx , dword ptr ss : [ esp + 0x1c ]
* 0041 ec79 | . 50 push eax
* 0041 ec7a | . 51 push ecx
* 0041 ec7b | . 56 push esi
* 0041 ec7c | . e8 1f a0feff call bgi .00408 ca0
*/
bool InsertBGI1Hook ( )
{
union {
DWORD i ;
DWORD * id ;
BYTE * ib ;
} ;
HookParam hp ;
for ( i = processStartAddress + 0x1000 ; i < processStopAddress ; i + + ) {
if ( ib [ 0 ] = = 0x3d ) {
i + + ;
if ( id [ 0 ] = = 0xffff ) { //cmp eax,0xffff
hp . address = SafeFindEnclosingAlignedFunction ( i , 0x40 ) ;
if ( hp . address ) {
hp . offset = get_stack ( 3 ) ;
hp . split = get_reg ( regs : : esp ) ;
hp . type = CODEC_ANSI_BE | USING_SPLIT ;
ConsoleOutput ( " INSERT BGI#1 " ) ;
//RegisterEngineType(ENGINE_BGI);
return NewHook ( hp , " BGI " ) ;
}
}
}
if ( ib [ 0 ] = = 0x81 & & ( ( ib [ 1 ] & 0xf8 ) = = 0xf8 ) ) {
i + = 2 ;
if ( id [ 0 ] = = 0xffff ) { //cmp reg,0xffff
hp . address = SafeFindEnclosingAlignedFunction ( i , 0x40 ) ;
if ( hp . address ) {
hp . offset = get_stack ( 3 ) ;
hp . split = get_reg ( regs : : esp ) ;
hp . type = CODEC_ANSI_BE | USING_SPLIT ;
ConsoleOutput ( " INSERT BGI#2 " ) ;
//RegisterEngineType(ENGINE_BGI);
return NewHook ( hp , " BGI " ) ;
}
}
}
}
//ConsoleOutput("Unknown BGI engine.");
//ConsoleOutput("Probably BGI. Wait for text.");
//SwitchTrigger(true);
//trigger_fun=InsertBGIDynamicHook;
ConsoleOutput ( " BGI: failed " ) ;
return false ;
}
/**
* jichi 2 / 5 / 2014 : Add an alternative BGI hook
*
* Issue : This hook cannot extract character name for コ ト バ の 消 え た 日
*
* See : http : //tieba.baidu.com/p/2845113296
* 世 界 と 世 界 の 真 ん 中 で
* - / HSN4 @ 349E0 : sekachu . exe // Disabled BGI3, floating split char
* - / HS - 1 C : - 4 @ 68E56 // Not used, cannot detect character name
* - / HSC @ 34 C80 : sekachu . exe // BGI2, extract both scenario and character names
*
* [ Lump of Sugar ] 世 界 と 世 界 の 真 ん 中 で
* / HSC @ 34 C80 : sekachu . exe
* - addr : 216192 = 0x34c80
* - module : 3599131534
* - off : 12 = 0xc
* - type : 65 = 0x41
*
* base : 0x11a0000
* hook_addr = base + addr = 0x11d4c80
*
* 011 d4c7e cc int3
* 011 d4c7f cc int3
* 011 d4c80 / $ 55 push ebp ; jichi : hook here
* 011 d4c81 | . 8 bec mov ebp , esp
* 011 d4c83 | . 6 a ff push - 0x1
* 011 d4c85 | . 68 e6592601 push sekachu .012659e6
* 011 d4c8a | . 64 : a1 00000000 mov eax , dword ptr fs : [ 0 ]
* 011 d4c90 | . 50 push eax
* 011 d4c91 | . 81 ec 300 d0000 sub esp , 0xd30
* 011 d4c97 | . a1 d8c82801 mov eax , dword ptr ds : [ 0x128c8d8 ]
* 011 d4c9c | . 33 c5 xor eax , ebp
* 011 d4c9e | . 8945 f0 mov dword ptr ss : [ ebp - 0x10 ] , eax
* 011 d4ca1 | . 53 push ebx
* 011 d4ca2 | . 56 push esi
* 011 d4ca3 | . 57 push edi
* 011 d4ca4 | . 50 push eax
* 011 d4ca5 | . 8 d45 f4 lea eax , dword ptr ss : [ ebp - 0xc ]
* 011 d4ca8 | . 64 : a3 00000000 mov dword ptr fs : [ 0 ] , eax
* 011 d4cae | . 8 b4d 0 c mov ecx , dword ptr ss : [ ebp + 0xc ]
* 011 d4cb1 | . 8 b55 18 mov edx , dword ptr ss : [ ebp + 0x18 ]
* 011 d4cb4 | . 8 b45 08 mov eax , dword ptr ss : [ ebp + 0x8 ]
* 011 d4cb7 | . 8 b5d 10 mov ebx , dword ptr ss : [ ebp + 0x10 ]
* 011 d4cba | . 8 b7d 38 mov edi , dword ptr ss : [ ebp + 0x38 ]
* 011 d4cbd | . 898 d d8f3ffff mov dword ptr ss : [ ebp - 0xc28 ] , ecx
* 011 d4cc3 | . 8 b4d 28 mov ecx , dword ptr ss : [ ebp + 0x28 ]
* 011 d4cc6 | . 8995 9 cf3ffff mov dword ptr ss : [ ebp - 0xc64 ] , edx
* 011 d4ccc | . 51 push ecx
* 011 d4ccd | . 8 b0d 305 c2901 mov ecx , dword ptr ds : [ 0x1295c30 ]
* 011 d4cd3 | . 8985 e0f3ffff mov dword ptr ss : [ ebp - 0xc20 ] , eax
* 011 d4cd9 | . 8 b45 1 c mov eax , dword ptr ss : [ ebp + 0x1c ]
* 011 d4cdc | . 8 d95 4 cf4ffff lea edx , dword ptr ss : [ ebp - 0xbb4 ]
* 011 d4ce2 | . 52 push edx
* 011 d4ce3 | . 899 d 40f 4ff ff mov dword ptr ss : [ ebp - 0xbc0 ] , ebx
* 011 d4ce9 | . 8985 1 cf4ffff mov dword ptr ss : [ ebp - 0xbe4 ] , eax
* 011 d4cef | . 89 bd f0f3ffff mov dword ptr ss : [ ebp - 0xc10 ] , edi
* 011 d4cf5 | . e8 862 efdff call sekachu .011 a7b80
* 011 d4cfa | . 33 c9 xor ecx , ecx
* 011 d4cfc | . 8985 60f 3ff ff mov dword ptr ss : [ ebp - 0xca0 ] , eax
* 011 d4d02 | . 3 bc1 cmp eax , ecx
* 011 d4d04 | . 0f 84 0f 1 c0000 je sekachu .011 d6919
* 011 d4d0a | . e8 31f 6ff ff call sekachu .011 d4340
* 011 d4d0f | . e8 6 cf8ffff call sekachu .011 d4580
* 011 d4d14 | . 8985 64f 3ff ff mov dword ptr ss : [ ebp - 0xc9c ] , eax
* 011 d4d1a | . 8 a03 mov al , byte ptr ds : [ ebx ]
* 011 d4d1c | . 898 d 90f 3ff ff mov dword ptr ss : [ ebp - 0xc70 ] , ecx
* 011 d4d22 | . 898 d 14f 4ff ff mov dword ptr ss : [ ebp - 0xbec ] , ecx
* 011 d4d28 | . 898 d 38f 4ff ff mov dword ptr ss : [ ebp - 0xbc8 ] , ecx
* 011 d4d2e | . 8 d71 01 lea esi , dword ptr ds : [ ecx + 0x1 ]
* 011 d4d31 | . 3 c 20 cmp al , 0x20 ; jichi : pattern starts
* 011 d4d33 | . 7 d 75 jge short sekachu .011 d4daa
* 011 d4d35 | . 0f bec0 movsx eax , al
* 011 d4d38 | . 83 c0 fe add eax , - 0x2 ; switch ( cases 2. .8 )
* 011 d4d3b | . 83f 8 06 cmp eax , 0x6
* 011 d4d3e | . 77 6 a ja short sekachu .011 d4daa
* 011 d4d40 | . ff2485 38691 d0 > jmp dword ptr ds : [ eax * 4 + 0x11d6938 ]
*
* 蒼 の 彼 方 体 験 版 ( 8 / 6 / 2014 )
* 01312 cce cc int3 ; jichi : reladdr = 0x32cd0
* 01312 ccf cc int3
* 01312 cd0 $ 55 push ebp
* 01312 cd1 . 8 bec mov ebp , esp
* 01312 cd3 . 83e4 f8 and esp , 0xfffffff8
* 01312 cd6 . 6 a ff push - 0x1
* 01312 cd8 . 68 86583 a01 push 蒼 の 彼 方 .013 a5886
* 01312 cdd . 64 : a1 00000000 mov eax , dword ptr fs : [ 0 ]
* 01312 ce3 . 50 push eax
* 01312 ce4 . 81 ec 38090000 sub esp , 0x938
* 01312 cea . a1 24673 c01 mov eax , dword ptr ds : [ 0x13c6724 ]
* 01312 cef . 33 c4 xor eax , esp
* 01312 cf1 . 898424 3009000 > mov dword ptr ss : [ esp + 0x930 ] , eax
* 01312 cf8 . 53 push ebx
* 01312 cf9 . 56 push esi
* 01312 cfa . 57 push edi
* 01312 cfb . a1 24673 c01 mov eax , dword ptr ds : [ 0x13c6724 ]
* 01312 d00 . 33 c4 xor eax , esp
* 01312 d02 . 50 push eax
* 01312 d03 . 8 d8424 4809000 > lea eax , dword ptr ss : [ esp + 0x948 ]
* 01312 d0a . 64 : a3 00000000 mov dword ptr fs : [ 0 ] , eax
* 01312 d10 . 8 b45 08 mov eax , dword ptr ss : [ ebp + 0x8 ]
* 01312 d13 . 8 b7d 0 c mov edi , dword ptr ss : [ ebp + 0xc ]
* 01312 d16 . 8 b5d 30 mov ebx , dword ptr ss : [ ebp + 0x30 ]
* 01312 d19 . 898424 8800000 > mov dword ptr ss : [ esp + 0x88 ] , eax
* 01312 d20 . 8 b45 14 mov eax , dword ptr ss : [ ebp + 0x14 ]
* 01312 d23 . 898 c24 8 c00000 > mov dword ptr ss : [ esp + 0x8c ] , ecx
* 01312 d2a . 8 b0d a8734a01 mov ecx , dword ptr ds : [ 0x14a73a8 ]
* 01312 d30 . 894424 4 c mov dword ptr ss : [ esp + 0x4c ] , eax
* 01312 d34 . 899424 bc00000 > mov dword ptr ss : [ esp + 0xbc ] , edx
* 01312 d3b . 8 b55 20 mov edx , dword ptr ss : [ ebp + 0x20 ]
* 01312 d3e . 51 push ecx ; / arg1 = > 00000000
* 01312 d3f . 8 d8424 0 c02000 > lea eax , dword ptr ss : [ esp + 0x20c ] ; |
* 01312 d46 . 897 c24 34 mov dword ptr ss : [ esp + 0x34 ] , edi ; |
* 01312 d4a . 899 c24 8800000 > mov dword ptr ss : [ esp + 0x88 ] , ebx ; |
* 01312 d51 . e8 ca59fdff call 蒼 の 彼 方 .012e8720 ; \ 蒼 の 彼 方 .012e8720
* 01312 d56 . 33 c9 xor ecx , ecx
* 01312 d58 . 898424 f400000 > mov dword ptr ss : [ esp + 0xf4 ] , eax
* 01312 d5f . 3 bc1 cmp eax , ecx
* 01312 d61 . 0f 84 391 b0000 je 蒼 の 彼 方 .013148 a0
* 01312 d67 . e8 54280000 call 蒼 の 彼 方 .013155 c0
* 01312 d6c . e8 7f 2 a0000 call 蒼 の 彼 方 .013157f 0
* 01312 d71 . 898424 f800000 > mov dword ptr ss : [ esp + 0xf8 ] , eax
* 01312 d78 . 8 a07 mov al , byte ptr ds : [ edi ]
* 01312 d7a . 898 c24 c400000 > mov dword ptr ss : [ esp + 0xc4 ] , ecx
* 01312 d81 . 894 c24 2 c mov dword ptr ss : [ esp + 0x2c ] , ecx
* 01312 d85 . 894 c24 1 c mov dword ptr ss : [ esp + 0x1c ] , ecx
* 01312 d89 . b9 01000000 mov ecx , 0x1
* 01312 d8e . 3 c 20 cmp al , 0x20 ; jichi : pattern starts
* 01312 d90 . 7 d 58 jge short 蒼 の 彼 方 .01312 dea
* 01312 d92 . 0f bec0 movsx eax , al
* 01312 d95 . 83 c0 fe add eax , - 0x2 ; switch ( cases 2. .8 )
* 01312 d98 . 83f 8 06 cmp eax , 0x6
* 01312 d9b . 77 4 d ja short 蒼 の 彼 方 .01312 dea
* 01312 d9d . ff2485 c448310 > jmp dword ptr ds : [ eax * 4 + 0x13148c4 ]
* 01312 da4 > 898 c24 c400000 > mov dword ptr ss : [ esp + 0xc4 ] , ecx ; case 2 of switch 01312 d95
* 01312 dab . 03f 9 add edi , ecx
* 01312 dad . eb 37 jmp short 蒼 の 彼 方 .01312 de6
* 01312 daf > 894 c24 2 c mov dword ptr ss : [ esp + 0x2c ] , ecx ; case 3 of switch 01312 d95
* 01312 db3 . 03f 9 add edi , ecx
* 01312 db5 . eb 2f jmp short 蒼 の 彼 方 .01312 de6
* 01312 db7 > ba e0103b01 mov edx , 蒼 の 彼 方 .013 b10e0 ; case 4 of switch 01312 d95
* 01312 dbc . eb 1 a jmp short 蒼 の 彼 方 .01312 dd8
* 01312 dbe > ba e4103b01 mov edx , 蒼 の 彼 方 .013 b10e4 ; case 5 of switch 01312 d95
* 01312 dc3 . eb 13 jmp short 蒼 の 彼 方 .01312 dd8
* 01312 dc5 > ba e8103b01 mov edx , 蒼 の 彼 方 .013 b10e8 ; case 6 of switch 01312 d95
* 01312 dca . eb 0 c jmp short 蒼 の 彼 方 .01312 dd8
* 01312 dcc > ba ec103b01 mov edx , 蒼 の 彼 方 .013 b10ec ; case 7 of switch 01312 d95
* 01312 dd1 . eb 05 jmp short 蒼 の 彼 方 .01312 dd8
* 01312 dd3 > ba f0103b01 mov edx , 蒼 の 彼 方 .013 b10f0 ; case 8 of switch 01312 d95
* 01312 dd8 > 8 d7424 14 lea esi , dword ptr ss : [ esp + 0x14 ]
* 01312 ddc . 894 c24 1 c mov dword ptr ss : [ esp + 0x1c ] , ecx
* 01312 de0 . e8 1 b8dffff call 蒼 の 彼 方 .0130 bb00
* 01312 de5 . 47 inc edi
* 01312 de6 > 897 c24 30 mov dword ptr ss : [ esp + 0x30 ] , edi
* 01312 dea > 8 d8424 0802000 > lea eax , dword ptr ss : [ esp + 0x208 ] ; default case of switch 01312 d95
* 01312 df1 . e8 ba1b0000 call 蒼 の 彼 方 .013149 b0
* 01312 df6 . 837 d 10 00 cmp dword ptr ss : [ ebp + 0x10 ] , 0x0
* 01312 dfa . 8 bb424 2802000 > mov esi , dword ptr ss : [ esp + 0x228 ]
* 01312e01 . 894424 5 c mov dword ptr ss : [ esp + 0x5c ] , eax
* 01312e05 . 74 12 je short 蒼 の 彼 方 .01312e19
* 01312e07 . 56 push esi ; / arg1
* 01312e08 . e8 c31b0000 call 蒼 の 彼 方 .013149 d0 ; \ 蒼 の 彼 方 .013149 d0
* 01312e0 d . 83 c4 04 add esp , 0x4
* 01312e10 . 898424 c000000 > mov dword ptr ss : [ esp + 0xc0 ] , eax
* 01312e17 . eb 0 b jmp short 蒼 の 彼 方 .01312e24
* 01312e19 > c78424 c000000 > mov dword ptr ss : [ esp + 0xc0 ] , 0x0
* 01312e24 > 8 b4b 04 mov ecx , dword ptr ds : [ ebx + 0x4 ]
* 01312e27 . 0f afce imul ecx , esi
* 01312e2 a . b8 1f 85 eb51 mov eax , 0x51eb851f
* 01312e2 f . f7e9 imul ecx
* 01312e31 . c1fa 05 sar edx , 0x5
* 01312e34 . 8 bca mov ecx , edx
* 01312e36 . c1e9 1f shr ecx , 0x1f
* 01312e39 . 03 ca add ecx , edx
* 01312e3 b . 894 c24 70 mov dword ptr ss : [ esp + 0x70 ] , ecx
* 01312e3 f . 85 c9 test ecx , ecx
* 01312e41 . 7f 09 jg short 蒼 の 彼 方 .01312e4 c
* 01312e43 . b9 01000000 mov ecx , 0x1
* 01312e48 . 894 c24 70 mov dword ptr ss : [ esp + 0x70 ] , ecx
* 01312e4 c > 8 b53 08 mov edx , dword ptr ds : [ ebx + 0x8 ]
* 01312e4 f . 0f afd6 imul edx , esi
* 01312e52 . b8 1f 85 eb51 mov eax , 0x51eb851f
* 01312e57 . f7ea imul edx
* 01312e59 . c1fa 05 sar edx , 0x5
* 01312e5 c . 8 bc2 mov eax , edx
* 01312e5 e . c1e8 1f shr eax , 0x1f
* 01312e61 . 03 c2 add eax , edx
* 01312e63 . 894424 78 mov dword ptr ss : [ esp + 0x78 ] , eax
* 01312e67 . 85 c0 test eax , eax
* 01312e69 . 7f 09 jg short 蒼 の 彼 方 .01312e74
* 01312e6 b . b8 01000000 mov eax , 0x1
* 01312e70 . 894424 78 mov dword ptr ss : [ esp + 0x78 ] , eax
* 01312e74 > 33 d2 xor edx , edx
* 01312e76 . 895424 64 mov dword ptr ss : [ esp + 0x64 ] , edx
* 01312e7 a . 895424 6 c mov dword ptr ss : [ esp + 0x6c ] , edx
* 01312e7 e . 8 b13 mov edx , dword ptr ds : [ ebx ]
* 01312e80 . 4 a dec edx ; switch ( cases 1. .2 )
* 01312e81 . 74 0 e je short 蒼 の 彼 方 .01312e91
* 01312e83 . 4 a dec edx
* 01312e84 . 75 13 jnz short 蒼 の 彼 方 .01312e99
* 01312e86 . 8 d1409 lea edx , dword ptr ds : [ ecx + ecx ] ; case 2 of switch 01312e80
* 01312e89 . 895424 64 mov dword ptr ss : [ esp + 0x64 ] , edx
* 01312e8 d . 03 c0 add eax , eax
* 01312e8 f . eb 04 jmp short 蒼 の 彼 方 .01312e95
* 01312e91 > 894 c24 64 mov dword ptr ss : [ esp + 0x64 ] , ecx ; case 1 of switch 01312e80
* 01312e95 > 894424 6 c mov dword ptr ss : [ esp + 0x6c ] , eax
* 01312e99 > 8 b9c24 3802000 > mov ebx , dword ptr ss : [ esp + 0x238 ] ; default case of switch 01312e80
* 01312 ea0 . 8 bc3 mov eax , ebx
* 01312 ea2 . e8 d98bffff call 蒼 の 彼 方 .0130 ba80
* 01312 ea7 . 8 bc8 mov ecx , eax
* 01312 ea9 . 8 bc3 mov eax , ebx
* 01312 eab . e8 e08bffff call 蒼 の 彼 方 .0130 ba90
* 01312 eb0 . 6 a 01 push 0x1 ; / arg1 = 00000001
* 01312 eb2 . 8 bd0 mov edx , eax ; |
* 01312 eb4 . 8 db424 1 c01000 > lea esi , dword ptr ss : [ esp + 0x11c ] ; |
* 01312 ebb . e8 3056f dff call 蒼 の 彼 方 .012e84 f0 ; \ 蒼 の 彼 方 .012e84 f0
* 01312 ec0 . 8 bc7 mov eax , edi
* 01312 ec2 . 83 c4 04 add esp , 0x4
* 01312 ec5 . 8 d70 01 lea esi , dword ptr ds : [ eax + 0x1 ]
* 01312 ec8 > 8 a08 mov cl , byte ptr ds : [ eax ]
* 01312 eca . 40 inc eax
* 01312 ecb . 84 c9 test cl , cl
* 01312 ecd . ^ 75 f9 jnz short 蒼 の 彼 方 .01312 ec8
* 01312 ecf . 2 bc6 sub eax , esi
* 01312 ed1 . 40 inc eax
* 01312 ed2 . 50 push eax
* 01312 ed3 . e8 e74c0600 call 蒼 の 彼 方 .01377 bbf
* 01312 ed8 . 33f 6 xor esi , esi
* 01312 eda . 83 c4 04 add esp , 0x4
*
* 1 / 1 / 2016
* コ ド モ ノ ア ソ ビ trial
*
* 00 A64259 CC INT3
* 00 A6425A CC INT3
* 00 A6425B CC INT3
* 00 A6425C CC INT3
* 00 A6425D CC INT3
* 00 A6425E CC INT3
* 00 A6425F CC INT3
* 00 A64260 55 PUSH EBP
* 00 A64261 8 BEC MOV EBP , ESP
* 00 A64263 83E4 F8 AND ESP , 0xFFFFFFF8
* 00 A64266 6 A FF PUSH - 0x1
* 00 A64268 68 D610B000 PUSH .00 B010D6
* 00 A6426D 64 : A1 00000000 MOV EAX , DWORD PTR FS : [ 0 ]
* 00 A64273 50 PUSH EAX
* 00 A64274 81 EC 40090000 SUB ESP , 0x940
* 00 A6427A A1 2417 B200 MOV EAX , DWORD PTR DS : [ 0xB21724 ]
* 00 A6427F 33 C4 XOR EAX , ESP
* 00 A64281 898424 38090000 MOV DWORD PTR SS : [ ESP + 0x938 ] , EAX
* 00 A64288 53 PUSH EBX
* 00 A64289 56 PUSH ESI
* 00 A6428A 57 PUSH EDI
* 00 A6428B A1 2417 B200 MOV EAX , DWORD PTR DS : [ 0xB21724 ]
* 00 A64290 33 C4 XOR EAX , ESP
* 00 A64292 50 PUSH EAX
* 00 A64293 8 D8424 50090000 LEA EAX , DWORD PTR SS : [ ESP + 0x950 ]
* 00 A6429A 64 : A3 00000000 MOV DWORD PTR FS : [ 0 ] , EAX
* 00 A642A0 8 B45 08 MOV EAX , DWORD PTR SS : [ EBP + 0x8 ]
* 00 A642A3 8 B7D 0 C MOV EDI , DWORD PTR SS : [ EBP + 0xC ]
* 00 A642A6 8 B5D 30 MOV EBX , DWORD PTR SS : [ EBP + 0x30 ]
* 00 A642A9 894424 50 MOV DWORD PTR SS : [ ESP + 0x50 ] , EAX
* 00 A642AD 8 B45 14 MOV EAX , DWORD PTR SS : [ EBP + 0x14 ]
* 00 A642B0 894 C24 74 MOV DWORD PTR SS : [ ESP + 0x74 ] , ECX
* 00 A642B4 8 B0D A024B800 MOV ECX , DWORD PTR DS : [ 0xB824A0 ]
* 00 A642BA 894424 4 C MOV DWORD PTR SS : [ ESP + 0x4C ] , EAX
* 00 A642BE 899424 B8000000 MOV DWORD PTR SS : [ ESP + 0xB8 ] , EDX
* 00 A642C5 8 B55 20 MOV EDX , DWORD PTR SS : [ EBP + 0x20 ]
* 00 A642C8 51 PUSH ECX
* 00 A642C9 8 D8424 14020000 LEA EAX , DWORD PTR SS : [ ESP + 0x214 ]
* 00 A642D0 897 C24 2 C MOV DWORD PTR SS : [ ESP + 0x2C ] , EDI
* 00 A642D4 899 C24 88000000 MOV DWORD PTR SS : [ ESP + 0x88 ] , EBX
* 00 A642DB E8 504 CFDFF CALL .00 A38F30
* 00 A642E0 33 C9 XOR ECX , ECX
* 00 A642E2 898424 F8000000 MOV DWORD PTR SS : [ ESP + 0xF8 ] , EAX
* 00 A642E9 3 BC1 CMP EAX , ECX
* 00 A642EB 0F 84 391 C0000 JE .00 A65F2A
* 00 A642F1 E8 FA2A0000 CALL .00 A66DF0
* 00 A642F6 E8 252 D0000 CALL .00 A67020
* 00 A642FB 898424 FC000000 MOV DWORD PTR SS : [ ESP + 0xFC ] , EAX
* 00 A64302 8 A07 MOV AL , BYTE PTR DS : [ EDI ]
* 00 A64304 898 C24 CC000000 MOV DWORD PTR SS : [ ESP + 0xCC ] , ECX
* 00 A6430B 894 C24 30 MOV DWORD PTR SS : [ ESP + 0x30 ] , ECX
* 00 A6430F 894 C24 1 C MOV DWORD PTR SS : [ ESP + 0x1C ] , ECX
* 00 A64313 B9 01000000 MOV ECX , 0x1
* 00 A64318 3 C 20 CMP AL , 0x20 ; jichi : pattern found here
* 00 A6431A 7 D 58 JGE SHORT .00 A64374
* 00 A6431C 0F BEC0 MOVSX EAX , AL
* 00 A6431F 83 C0 FE ADD EAX , - 0x2
* 00 A64322 83F 8 06 CMP EAX , 0x6
* 00 A64325 77 4 D JA SHORT .00 A64374
* 00 A64327 FF2485 505F A600 JMP DWORD PTR DS : [ EAX * 4 + 0xA65F50 ]
* 00 A6432E 898 C24 CC000000 MOV DWORD PTR SS : [ ESP + 0xCC ] , ECX
* 00 A64335 03F 9 ADD EDI , ECX
* 00 A64337 EB 37 JMP SHORT .00 A64370
* 00 A64339 894 C24 30 MOV DWORD PTR SS : [ ESP + 0x30 ] , ECX
* 00 A6433D 03F 9 ADD EDI , ECX
* 00 A6433F EB 2F JMP SHORT .00 A64370
* 00 A64341 BA E0C1B000 MOV EDX , .00 B0C1E0
* 00 A64346 EB 1 A JMP SHORT .00 A64362
* 00 A64348 BA E4C1B000 MOV EDX , .00 B0C1E4
* 00 A6434D EB 13 JMP SHORT .00 A64362
* 00 A6434F BA E8C1B000 MOV EDX , .00 B0C1E8
* 00 A64354 EB 0 C JMP SHORT .00 A64362
* 00 A64356 BA ECC1B000 MOV EDX , .00 B0C1EC
* 00 A6435B EB 05 JMP SHORT .00 A64362
* 00 A6435D BA F0C1B000 MOV EDX , .00 B0C1F0
* 00 A64362 8 D7424 14 LEA ESI , DWORD PTR SS : [ ESP + 0x14 ]
* 00 A64366 894 C24 1 C MOV DWORD PTR SS : [ ESP + 0x1C ] , ECX
* 00 A6436A E8 A196FFFF CALL .00 A5DA10
* 00 A6436F 47 INC EDI
* 00 A64370 897 C24 28 MOV DWORD PTR SS : [ ESP + 0x28 ] , EDI
* 00 A64374 8 D8424 10020000 LEA EAX , DWORD PTR SS : [ ESP + 0x210 ]
* 00 A6437B E8 C01C0000 CALL .00 A66040
* 00 A64380 837 D 10 00 CMP DWORD PTR SS : [ EBP + 0x10 ] , 0x0
* 00 A64384 8 BB424 30020000 MOV ESI , DWORD PTR SS : [ ESP + 0x230 ]
* 00 A6438B 894424 60 MOV DWORD PTR SS : [ ESP + 0x60 ] , EAX
* 00 A6438F 74 12 JE SHORT .00 A643A3
* 00 A64391 56 PUSH ESI
* 00 A64392 E8 C91C0000 CALL .00 A66060
* 00 A64397 83 C4 04 ADD ESP , 0x4
* 00 A6439A 898424 C4000000 MOV DWORD PTR SS : [ ESP + 0xC4 ] , EAX
* 00 A643A1 EB 0 B JMP SHORT .00 A643AE
* 00 A643A3 C78424 C4000000 > MOV DWORD PTR SS : [ ESP + 0xC4 ] , 0x0
* 00 A643AE 8 B4B 04 MOV ECX , DWORD PTR DS : [ EBX + 0x4 ]
* 00 A643B1 0F AFCE IMUL ECX , ESI
* 00 A643B4 B8 1F 85 EB51 MOV EAX , 0x51EB851F
* 00 A643B9 F7E9 IMUL ECX
* 00 A643BB C1FA 05 SAR EDX , 0x5
* 00 A643BE 8 BCA MOV ECX , EDX
* 00 A643C0 C1E9 1F SHR ECX , 0x1F
* 00 A643C3 03 CA ADD ECX , EDX
* 00 A643C5 898 C24 94000000 MOV DWORD PTR SS : [ ESP + 0x94 ] , ECX
* 00 A643CC 85 C9 TEST ECX , ECX
* 00 A643D0 B9 01000000 MOV ECX , 0x1
* . . .
*/
//static inline size_t _bgistrlen(LPCSTR text)
//{
// size_t r = ::strlen(text);
// if (r >=2 && *(WORD *)(text + r - 2) == 0xa581) // remove trailing ▼ = \x81\xa5
// r -= 2;
// return r;
//}
//
//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);
// if (text) {
// *data = (DWORD)text;
// *len = _bgistrlen(text);
// }
//}
namespace Private {
enum { 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 ) {
DWORD retaddr = s - > stack [ 0 ] ; // retaddr
* role = Engine : : ScenarioRole ;
2024-03-21 17:57:04 +08:00
return write_string_overwrite ( data , len , ( LPCSTR ) s - > stack [ textIndex_ ] ) ;
2024-02-07 20:59:24 +08:00
}
static std : : string data_ ; // persistent storage, which makes this function not thread-safe
LPCSTR text = ( LPCSTR ) s - > stack [ textIndex_ ] ; // arg2 or arg3
if ( ! text | | ! * text )
return false ;
// 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
//DWORD split = stack->args[3]; // arg4
//DWORD split = s->stack[8]; // arg8
//auto sig = Engine::hashThreadSignature(s->stack[0], split);
//enum { role = Engine::UnknownRole };
//DWORD split = s->stack[8]; // this is a good split, but usually game-specific
DWORD retaddr = s - > stack [ 0 ] ; // retaddr
//* role = Engine::OtherRole;
switch ( type_ ) {
case Type3 :
switch ( s - > stack [ textIndex_ + 1 ] ) {
case 1 :
if ( * ( WORD * ) ( retaddr + 8 ) = = 0xcccc ) // two int3
* role = Engine : : ScenarioRole ;
break ;
case 0 :
if ( s - > stack [ 10 ] = = 0x00ffffff & & s - > stack [ 10 - 3 ] = = 1 | | // for old BGI2 games
s - > stack [ 10 ] = = 0 & & s - > stack [ 10 - 1 ] = = 0 & & s - > stack [ 10 - 2 ] = = 0 ) // for new BGI2 games
* role = Engine : : NameRole ;
break ;
} break ;
case Type2 :
switch ( s - > stack [ textIndex_ + 1 ] ) {
case 1 :
// Return address for history text
// 012B37BA 83C4 34 ADD ESP,0x34
// 012B37BD 837D 24 00 CMP DWORD PTR SS:[EBP+0x24],0x0
if ( * ( WORD * ) ( retaddr + 3 ) ! = 0x7d83 )
* role = Engine : : ScenarioRole ;
break ;
case 0 :
if ( s - > stack [ 12 ] = = 0x00ffffff & & s - > stack [ 12 - 3 ] = = 2 )
* role = Engine : : NameRole ;
break ;
} break ;
case Type1 :
switch ( s - > stack [ textIndex_ + 1 ] ) {
case 1 : * role = Engine : : ScenarioRole ; break ;
case 0 :
if ( s - > stack [ 12 ] = = 0x00ffffff & & s - > stack [ 12 - 3 ] = = 1 )
* role = Engine : : NameRole ;
break ;
} break ;
}
2024-03-21 17:57:04 +08:00
return write_string_overwrite ( data , len , ( LPCSTR ) s - > stack [ textIndex_ ] ) ;
2024-02-07 20:59:24 +08:00
}
}
/**
* 5 / 12 / 2014
* This is the caller of the ITH BGI hook , which extract text by characters
* and cannot be used for substition .
*
* Sample game : 世 界 征 服 彼 女
* ITH hooked function : BGI # 2 0x425550 , called by 0x427450
*
* 00427450 / $ 6 a ff push - 0x1 ; jichi : function starts
* 00427452 | . 68 78634900 push sekajyo_ .00496378 ; se handler installation
* 00427457 | . 64 : a1 00000000 mov eax , dword ptr fs : [ 0 ]
* 0042745 d | . 50 push eax
* 0042745 e | . 64 : 8925 000000 > mov dword ptr fs : [ 0 ] , esp
* 00427465 | . 81 ec d80c0000 sub esp , 0xcd8
* 0042746 b | . 8 b8424 080 d000 > mov eax , dword ptr ss : [ esp + 0xd08 ]
* 00427472 | . 56 push esi
* 00427473 | . 8 d8c24 3801000 > lea ecx , dword ptr ss : [ esp + 0x138 ]
* 0042747 a | . 50 push eax
* 0042747 b | . 51 push ecx
* 0042747 c | . 8 b0d e0464b00 mov ecx , dword ptr ds : [ 0x4b46e0 ]
* 004274 82 | . e8 f9fdfdff call sekajyo_ .00407280
* 004274 87 | . 33f 6 xor esi , esi
* 004274 89 | . 898424 b800000 > mov dword ptr ss : [ esp + 0xb8 ] , eax
* 004274 90 | . 3 bc6 cmp eax , esi
* 004274 92 | . 0f 84 95140000 je sekajyo_ .0042892 d
* 004274 98 | . 53 push ebx
* 004274 99 | . 55 push ebp
* 004274 9 a | . 8 bac24 fc0c000 > mov ebp , dword ptr ss : [ esp + 0xcfc ]
* 004274 a1 | . 57 push edi
* 004274 a2 | . 89 b424 b400000 > mov dword ptr ss : [ esp + 0xb4 ] , esi
* 004274 a9 | . 897424 10 mov dword ptr ss : [ esp + 0x10 ] , esi
* 004274 ad | . 8 a45 00 mov al , byte ptr ss : [ ebp ]
* 004274 b0 | . b9 01000000 mov ecx , 0x1
* 004274 b5 | . 3 c 20 cmp al , 0x20
* 004274 b7 | . 7 d 68 jge short sekajyo_ .00427521
* 004274 b9 | . 0f bec0 movsx eax , al
* 004274 bc | . 83 c0 fe add eax , - 0x2 ; switch ( cases 2. .8 )
*
* Sample game : FORTUNE ARTERIAL
* ITH hooked function : BGI # 2 sub_41EBD0 , called by 0x4207e0
*
* 0041 ebcd 90 nop
* 0041 ebce 90 nop
* 0041 ebcf 90 nop
* 004207e0 / $ 81 ec 30090000 sub esp , 0x930 ; jichi : function starts
* 004207e6 | . 8 b8424 5409000 > mov eax , dword ptr ss : [ esp + 0x954 ]
* 004207 ed | . 56 push esi
* 004207 ee | . 8 d8c24 0401000 > lea ecx , dword ptr ss : [ esp + 0x104 ]
* 004207f 5 | . 50 push eax
* 004207f 6 | . 51 push ecx
* 004207f 7 | . 8 b0d 48634900 mov ecx , dword ptr ds : [ 0x496348 ]
* 004207f d | . e8 ee47feff call bgi .00404f f0
* 00420 802 | . 33f 6 xor esi , esi
* 00420 804 | . 894424 54 mov dword ptr ss : [ esp + 0x54 ] , eax
* 00420 808 | . 3 bc6 cmp eax , esi
* 00420 80 a | . 0f 84 94080000 je bgi .004210 a4
* 00420 810 | . 53 push ebx
* 00420 811 | . 55 push ebp
* 00420 812 | . 8 bac24 4809000 > mov ebp , dword ptr ss : [ esp + 0x948 ]
* 00420 819 | . 57 push edi
* 00420 81 a | . 897424 54 mov dword ptr ss : [ esp + 0x54 ] , esi
* 00420 81 e | . 897424 10 mov dword ptr ss : [ esp + 0x10 ] , esi
* 00420 822 | . 8 a45 00 mov al , byte ptr ss : [ ebp ]
* 00420 825 | . 3 c 20 cmp al , 0x20
* 00420 827 | . 7 d 69 jge short bgi .00420892
* 00420 829 | . 0f bec0 movsx eax , al
* 00420 82 c | . 83 c0 fe add eax , - 0x2 ; switch ( cases 2. .8 )
* 0042082f | . 83f 8 06 cmp eax , 0x6
* 00420 832 | . 77 5 e ja short bgi .00420892
* 00420 834 | . ff2485 ac10420 > jmp dword ptr ds : [ eax * 4 + 0x4210ac ]
* 00420 83 b | > c74424 54 0100 > mov dword ptr ss : [ esp + 0x54 ] , 0x1 ; case 2 of switch 00420 82 c
* 00420 843 | . eb 45 jmp short bgi .0042088 a
* 00420 845 | > 8 d5424 1 c lea edx , dword ptr ss : [ esp + 0x1c ] ; case 4 of switch 00420 82 c
* 00420 849 | . 68 0 c424800 push bgi .0048420 c
* 00420 84 e | . 52 push edx
* 0042084f | . eb 29 jmp short bgi .0042087 a
* 00420 851 | > 68 08424800 push bgi .00484208 ; case 5 of switch 00420 82 c
* 00420 856 | . eb 1 d jmp short bgi .00420875
* 00420 858 | > 8 d4c24 1 c lea ecx , dword ptr ss : [ esp + 0x1c ] ; case 6 of switch 00420 82 c
* 00420 85 c | . 68 04424 800 push bgi .00484204
* 00420 861 | . 51 push ecx
* 00420 862 | . eb 16 jmp short bgi .0042087 a
* 00420 864 | > 8 d5424 1 c lea edx , dword ptr ss : [ esp + 0x1c ] ; case 7 of switch 00420 82 c
* 00420 868 | . 68 00424 800 push bgi .00484200
* 00420 86 d | . 52 push edx
* 00420 86 e | . eb 0 a jmp short bgi .0042087 a
* 00420 870 | > 68 fc414800 push bgi .004841f c ; case 8 of switch 00420 82 c
* 00420 875 | > 8 d4424 20 lea eax , dword ptr ss : [ esp + 0x20 ]
* 00420 879 | . 50 push eax
* 00420 87 a | > c74424 18 0100 > mov dword ptr ss : [ esp + 0x18 ] , 0x1
* 00420 882 | . e8 b9a7ffff call bgi .0041 b040
* 00420 887 | . 83 c4 08 add esp , 0x8
* 00420 88 a | > 45 inc ebp
* 00420 88 b | . 89 ac24 4 c09000 > mov dword ptr ss : [ esp + 0x94c ] , ebp
* 00420 892 | > 8 b9c24 3001000 > mov ebx , dword ptr ss : [ esp + 0x130 ] ; default case of switch 00420 82 c
* 00420 899 | . 8 d8c24 1001000 > lea ecx , dword ptr ss : [ esp + 0x110 ]
* 00420 8 a0 | . 51 push ecx
* 00420 8 a1 | . 895 c24 70 mov dword ptr ss : [ esp + 0x70 ] , ebx
* 00420 8 a5 | . e8 76080000 call bgi .00421120
* 00420 8 aa | . 894424 34 mov dword ptr ss : [ esp + 0x34 ] , eax
* 00420 8 ae | . 8 b8424 5409000 > mov eax , dword ptr ss : [ esp + 0x954 ]
* 00420 8 b5 | . 83 c4 04 add esp , 0x4
* 00420 8 b8 | . 3 bc6 cmp eax , esi
* 00420 8 ba | . 74 0f je short bgi .004208 cb
* 00420 8 bc | . 53 push ebx
* 00420 8 bd | . e8 7e080000 call bgi .00421140
*/
ULONG search1 ( ULONG startAddress , ULONG stopAddress )
{
//return 0x4207e0; // FORTUNE ARTERIAL
//const BYTE bytes[] = {
// 0x8a,0x45, 0x00, // 00420822 |. 8a45 00 mov al,byte ptr ss:[ebp]
// 0x3c, 0x20, // 00420825 |. 3c 20 cmp al,0x20
// 0x7d, 0x69, // 00420827 |. 7d 69 jge short bgi.00420892
// 0x0f,0xbe,0xc0, // 00420829 |. 0fbec0 movsx eax,al
// 0x83,0xc0, 0xfe, // 0042082c |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
// 0x83,0xf8, 0x06, // 0042082f |. 83f8 06 cmp eax,0x6
// 0x77, 0x5e // 00420832 |. 77 5e ja short bgi.00420892
//};
//enum { hook_offset = 0x4207e0 - 0x420822 }; // distance to the beginning of the function
const uint8_t bytes [ ] = { // 0fafcbf7e9c1fa058bc2c1e81f03d08bfa85ff
0x0f , 0xaf , 0xcb , // 004208de |. 0fafcb imul ecx,ebx
0xf7 , 0xe9 , // 004208e1 |. f7e9 imul ecx
0xc1 , 0xfa , 0x05 , // 004208e3 |. c1fa 05 sar edx,0x5
0x8b , 0xc2 , // 004208e6 |. 8bc2 mov eax,edx
0xc1 , 0xe8 , 0x1f , // 004208e8 |. c1e8 1f shr eax,0x1f
0x03 , 0xd0 , // 004208eb |. 03d0 add edx,eax
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
//ULONG range = qMin(stopAddress - startAddress, Engine::MaximumMemoryRange);
ULONG addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , startAddress , stopAddress ) ;
if ( ! addr )
//ConsoleOutput("BGI2: pattern not found");
return 0 ;
enum : WORD {
sub_esp = 0xec81 // 004207e0 /$ 81ec 30090000
, push_ff = 0xff6a // 00427450 /$ 6a ff push -0x1, seh handler
} ;
for ( int i = 0 ; i < 300 ; i + + , addr - - )
if ( * ( WORD * ) addr = = sub_esp ) { // beginning of the function without seh
// Sample game: 世界征服彼女 with SEH
// 00427450 /$ 6a ff push -0x1
// 00427452 |. 68 78634900 push sekajyo_.00496378 ; se handler installation
// 00427457 |. 64:a1 00000000 mov eax,dword ptr fs:[0]
// 0042745d |. 50 push eax
// 0042745e |. 64:8925 000000>mov dword ptr fs:[0],esp
// 00427465 |. 81ec d80c0000 sub esp,0xcd8
//
// 0x00427465 - 0x00427450 == 21
ULONG seh_addr = addr ;
for ( int j = 0 ; j < 40 ; j + + , seh_addr - - )
if ( * ( WORD * ) seh_addr = = push_ff ) // beginning of the function with seh
return seh_addr ;
return addr ;
}
return 0 ;
}
/**
* jichi 2 / 5 / 2014 : Add an alternative BGI hook
*
* Issue : This hook cannot extract character name for コ ト バ の 消 え た 日
*
* See : http : //tieba.baidu.com/p/2845113296
* 世 界 と 世 界 の 真 ん 中 で
* - / HSN4 @ 349E0 : sekachu . exe // Disabled BGI3, floating split char
* - / HS - 1 C : - 4 @ 68E56 // Not used, cannot detect character name
* - / HSC @ 34 C80 : sekachu . exe // BGI2, extract both scenario and character names
*
* [ Lump of Sugar ] 世 界 と 世 界 の 真 ん 中 で
* / HSC @ 34 C80 : sekachu . exe
* - addr : 216192 = 0x34c80
* - module : 3599131534
* - off : 12 = 0xc
* - type : 65 = 0x41
*
* base : 0x11a0000
* hook_addr = base + addr = 0x11d4c80
*
* 011 d4c7e cc int3
* 011 d4c7f cc int3
* 011 d4c80 / $ 55 push ebp ; jichi : hook here
* 011 d4c81 | . 8 bec mov ebp , esp
* 011 d4c83 | . 6 a ff push - 0x1
* 011 d4c85 | . 68 e6592601 push sekachu .012659e6
* 011 d4c8a | . 64 : a1 00000000 mov eax , dword ptr fs : [ 0 ]
* 011 d4c90 | . 50 push eax
* 011 d4c91 | . 81 ec 300 d0000 sub esp , 0xd30
* 011 d4c97 | . a1 d8c82801 mov eax , dword ptr ds : [ 0x128c8d8 ]
* 011 d4c9c | . 33 c5 xor eax , ebp
* 011 d4c9e | . 8945 f0 mov dword ptr ss : [ ebp - 0x10 ] , eax
* 011 d4ca1 | . 53 push ebx
* 011 d4ca2 | . 56 push esi
* 011 d4ca3 | . 57 push edi
* 011 d4ca4 | . 50 push eax
* 011 d4ca5 | . 8 d45 f4 lea eax , dword ptr ss : [ ebp - 0xc ]
* 011 d4ca8 | . 64 : a3 00000000 mov dword ptr fs : [ 0 ] , eax
* 011 d4cae | . 8 b4d 0 c mov ecx , dword ptr ss : [ ebp + 0xc ]
* 011 d4cb1 | . 8 b55 18 mov edx , dword ptr ss : [ ebp + 0x18 ]
* 011 d4cb4 | . 8 b45 08 mov eax , dword ptr ss : [ ebp + 0x8 ]
* 011 d4cb7 | . 8 b5d 10 mov ebx , dword ptr ss : [ ebp + 0x10 ]
* 011 d4cba | . 8 b7d 38 mov edi , dword ptr ss : [ ebp + 0x38 ]
* 011 d4cbd | . 898 d d8f3ffff mov dword ptr ss : [ ebp - 0xc28 ] , ecx
* 011 d4cc3 | . 8 b4d 28 mov ecx , dword ptr ss : [ ebp + 0x28 ]
* 011 d4cc6 | . 8995 9 cf3ffff mov dword ptr ss : [ ebp - 0xc64 ] , edx
* 011 d4ccc | . 51 push ecx
* 011 d4ccd | . 8 b0d 305 c2901 mov ecx , dword ptr ds : [ 0x1295c30 ]
* 011 d4cd3 | . 8985 e0f3ffff mov dword ptr ss : [ ebp - 0xc20 ] , eax
* 011 d4cd9 | . 8 b45 1 c mov eax , dword ptr ss : [ ebp + 0x1c ]
* 011 d4cdc | . 8 d95 4 cf4ffff lea edx , dword ptr ss : [ ebp - 0xbb4 ]
* 011 d4ce2 | . 52 push edx
* 011 d4ce3 | . 899 d 40f 4ff ff mov dword ptr ss : [ ebp - 0xbc0 ] , ebx
* 011 d4ce9 | . 8985 1 cf4ffff mov dword ptr ss : [ ebp - 0xbe4 ] , eax
* 011 d4cef | . 89 bd f0f3ffff mov dword ptr ss : [ ebp - 0xc10 ] , edi
* 011 d4cf5 | . e8 862 efdff call sekachu .011 a7b80
* 011 d4cfa | . 33 c9 xor ecx , ecx
* 011 d4cfc | . 8985 60f 3ff ff mov dword ptr ss : [ ebp - 0xca0 ] , eax
* 011 d4d02 | . 3 bc1 cmp eax , ecx
* 011 d4d04 | . 0f 84 0f 1 c0000 je sekachu .011 d6919
* 011 d4d0a | . e8 31f 6ff ff call sekachu .011 d4340
* 011 d4d0f | . e8 6 cf8ffff call sekachu .011 d4580
* 011 d4d14 | . 8985 64f 3ff ff mov dword ptr ss : [ ebp - 0xc9c ] , eax
* 011 d4d1a | . 8 a03 mov al , byte ptr ds : [ ebx ]
* 011 d4d1c | . 898 d 90f 3ff ff mov dword ptr ss : [ ebp - 0xc70 ] , ecx
* 011 d4d22 | . 898 d 14f 4ff ff mov dword ptr ss : [ ebp - 0xbec ] , ecx
* 011 d4d28 | . 898 d 38f 4ff ff mov dword ptr ss : [ ebp - 0xbc8 ] , ecx
* 011 d4d2e | . 8 d71 01 lea esi , dword ptr ds : [ ecx + 0x1 ]
* 011 d4d31 | . 3 c 20 cmp al , 0x20
* 011 d4d33 | . 7 d 75 jge short sekachu .011 d4daa
* 011 d4d35 | . 0f bec0 movsx eax , al
* 011 d4d38 | . 83 c0 fe add eax , - 0x2 ; switch ( cases 2. .8 )
* 011 d4d3b | . 83f 8 06 cmp eax , 0x6
* 011 d4d3e | . 77 6 a ja short sekachu .011 d4daa
* 011 d4d40 | . ff2485 38691 d0 > jmp dword ptr ds : [ eax * 4 + 0x11d6938 ]
*/
ULONG search2 ( ULONG startAddress , ULONG stopAddress )
{
//return startAddress + 0x31850; // 世界と世界の真ん中 体験版
const uint8_t bytes [ ] = { // 3c207d750fbec083c0fe83f806776a
0x3c , 0x20 , // 011d4d31 |. 3c 20 cmp al,0x20
0x7d , 0x75 , // 011d4d33 |. 7d 75 jge short sekachu.011d4daa
0x0f , 0xbe , 0xc0 , // 011d4d35 |. 0fbec0 movsx eax,al
0x83 , 0xc0 , 0xfe , // 011d4d38 |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
0x83 , 0xf8 , 0x06 , // 011d4d3b |. 83f8 06 cmp eax,0x6
0x77 , 0x6a // 011d4d3e |. 77 6a ja short sekachu.011d4daa
} ;
enum { 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 ) ;
if ( ! addr )
//ConsoleOutput("BGI2: pattern not found");
return 0 ;
addr + = hook_offset ;
enum : uint8_t { push_ebp = 0x55 } ; // 011d4c80 /$ 55 push ebp
if ( * ( uint8_t * ) addr ! = push_ebp )
//ConsoleOutput("BGI2: pattern found but the function offset is invalid");
return 0 ;
return addr ;
}
/**
* Sample Game : type 3 : 蒼 の 彼 方 体 験 版 ( 8 / 6 / 2014 )
* 01312 cce cc int3 ; jichi : reladdr = 0x32cd0
* 01312 ccf cc int3
* 01312 cd0 $ 55 push ebp
* 01312 cd1 . 8 bec mov ebp , esp
* 01312 cd3 . 83e4 f8 and esp , 0xfffffff8
* 01312 cd6 . 6 a ff push - 0x1
* 01312 cd8 . 68 86583 a01 push 蒼 の 彼 方 .013 a5886
* 01312 cdd . 64 : a1 00000000 mov eax , dword ptr fs : [ 0 ]
* 01312 ce3 . 50 push eax
* 01312 ce4 . 81 ec 38090000 sub esp , 0x938
* 01312 cea . a1 24673 c01 mov eax , dword ptr ds : [ 0x13c6724 ]
* 01312 cef . 33 c4 xor eax , esp
* 01312 cf1 . 898424 3009000 > mov dword ptr ss : [ esp + 0x930 ] , eax
* 01312 cf8 . 53 push ebx
* 01312 cf9 . 56 push esi
* 01312 cfa . 57 push edi
* 01312 cfb . a1 24673 c01 mov eax , dword ptr ds : [ 0x13c6724 ]
* 01312 d00 . 33 c4 xor eax , esp
* 01312 d02 . 50 push eax
* 01312 d03 . 8 d8424 4809000 > lea eax , dword ptr ss : [ esp + 0x948 ]
* 01312 d0a . 64 : a3 00000000 mov dword ptr fs : [ 0 ] , eax
* 01312 d10 . 8 b45 08 mov eax , dword ptr ss : [ ebp + 0x8 ]
* 01312 d13 . 8 b7d 0 c mov edi , dword ptr ss : [ ebp + 0xc ]
* 01312 d16 . 8 b5d 30 mov ebx , dword ptr ss : [ ebp + 0x30 ]
* 01312 d19 . 898424 8800000 > mov dword ptr ss : [ esp + 0x88 ] , eax
* 01312 d20 . 8 b45 14 mov eax , dword ptr ss : [ ebp + 0x14 ]
* 01312 d23 . 898 c24 8 c00000 > mov dword ptr ss : [ esp + 0x8c ] , ecx
* 01312 d2a . 8 b0d a8734a01 mov ecx , dword ptr ds : [ 0x14a73a8 ]
* 01312 d30 . 894424 4 c mov dword ptr ss : [ esp + 0x4c ] , eax
* 01312 d34 . 899424 bc00000 > mov dword ptr ss : [ esp + 0xbc ] , edx
* 01312 d3b . 8 b55 20 mov edx , dword ptr ss : [ ebp + 0x20 ]
* 01312 d3e . 51 push ecx ; / arg1 = > 00000000
* 01312 d3f . 8 d8424 0 c02000 > lea eax , dword ptr ss : [ esp + 0x20c ] ; |
* 01312 d46 . 897 c24 34 mov dword ptr ss : [ esp + 0x34 ] , edi ; |
* 01312 d4a . 899 c24 8800000 > mov dword ptr ss : [ esp + 0x88 ] , ebx ; |
* 01312 d51 . e8 ca59fdff call 蒼 の 彼 方 .012e8720 ; \ 蒼 の 彼 方 .012e8720
* 01312 d56 . 33 c9 xor ecx , ecx
* 01312 d58 . 898424 f400000 > mov dword ptr ss : [ esp + 0xf4 ] , eax
* 01312 d5f . 3 bc1 cmp eax , ecx
* 01312 d61 . 0f 84 391 b0000 je 蒼 の 彼 方 .013148 a0
* 01312 d67 . e8 54280000 call 蒼 の 彼 方 .013155 c0
* 01312 d6c . e8 7f 2 a0000 call 蒼 の 彼 方 .013157f 0
* 01312 d71 . 898424 f800000 > mov dword ptr ss : [ esp + 0xf8 ] , eax
* 01312 d78 . 8 a07 mov al , byte ptr ds : [ edi ]
* 01312 d7a . 898 c24 c400000 > mov dword ptr ss : [ esp + 0xc4 ] , ecx
* 01312 d81 . 894 c24 2 c mov dword ptr ss : [ esp + 0x2c ] , ecx
* 01312 d85 . 894 c24 1 c mov dword ptr ss : [ esp + 0x1c ] , ecx
* 01312 d89 . b9 01000000 mov ecx , 0x1
* 01312 d8e . 3 c 20 cmp al , 0x20 ; jichi : pattern starts
* 01312 d90 . 7 d 58 jge short 蒼 の 彼 方 .01312 dea
* 01312 d92 . 0f bec0 movsx eax , al
* 01312 d95 . 83 c0 fe add eax , - 0x2 ; switch ( cases 2. .8 )
* 01312 d98 . 83f 8 06 cmp eax , 0x6
* 01312 d9b . 77 4 d ja short 蒼 の 彼 方 .01312 dea
* 01312 d9d . ff2485 c448310 > jmp dword ptr ds : [ eax * 4 + 0x13148c4 ]
* 01312 da4 > 898 c24 c400000 > mov dword ptr ss : [ esp + 0xc4 ] , ecx ; case 2 of switch 01312 d95
* 01312 dab . 03f 9 add edi , ecx
* 01312 dad . eb 37 jmp short 蒼 の 彼 方 .01312 de6
* 01312 daf > 894 c24 2 c mov dword ptr ss : [ esp + 0x2c ] , ecx ; case 3 of switch 01312 d95
* 01312 db3 . 03f 9 add edi , ecx
* 01312 db5 . eb 2f jmp short 蒼 の 彼 方 .01312 de6
* 01312 db7 > ba e0103b01 mov edx , 蒼 の 彼 方 .013 b10e0 ; case 4 of switch 01312 d95
* 01312 dbc . eb 1 a jmp short 蒼 の 彼 方 .01312 dd8
* 01312 dbe > ba e4103b01 mov edx , 蒼 の 彼 方 .013 b10e4 ; case 5 of switch 01312 d95
* 01312 dc3 . eb 13 jmp short 蒼 の 彼 方 .01312 dd8
* 01312 dc5 > ba e8103b01 mov edx , 蒼 の 彼 方 .013 b10e8 ; case 6 of switch 01312 d95
* 01312 dca . eb 0 c jmp short 蒼 の 彼 方 .01312 dd8
* 01312 dcc > ba ec103b01 mov edx , 蒼 の 彼 方 .013 b10ec ; case 7 of switch 01312 d95
* 01312 dd1 . eb 05 jmp short 蒼 の 彼 方 .01312 dd8
* 01312 dd3 > ba f0103b01 mov edx , 蒼 の 彼 方 .013 b10f0 ; case 8 of switch 01312 d95
* 01312 dd8 > 8 d7424 14 lea esi , dword ptr ss : [ esp + 0x14 ]
* 01312 ddc . 894 c24 1 c mov dword ptr ss : [ esp + 0x1c ] , ecx
* 01312 de0 . e8 1 b8dffff call 蒼 の 彼 方 .0130 bb00
* 01312 de5 . 47 inc edi
* 01312 de6 > 897 c24 30 mov dword ptr ss : [ esp + 0x30 ] , edi
* 01312 dea > 8 d8424 0802000 > lea eax , dword ptr ss : [ esp + 0x208 ] ; default case of switch 01312 d95
* 01312 df1 . e8 ba1b0000 call 蒼 の 彼 方 .013149 b0
* 01312 df6 . 837 d 10 00 cmp dword ptr ss : [ ebp + 0x10 ] , 0x0
* 01312 dfa . 8 bb424 2802000 > mov esi , dword ptr ss : [ esp + 0x228 ]
* 01312e01 . 894424 5 c mov dword ptr ss : [ esp + 0x5c ] , eax
* 01312e05 . 74 12 je short 蒼 の 彼 方 .01312e19
* 01312e07 . 56 push esi ; / arg1
* 01312e08 . e8 c31b0000 call 蒼 の 彼 方 .013149 d0 ; \ 蒼 の 彼 方 .013149 d0
* 01312e0 d . 83 c4 04 add esp , 0x4
* 01312e10 . 898424 c000000 > mov dword ptr ss : [ esp + 0xc0 ] , eax
* 01312e17 . eb 0 b jmp short 蒼 の 彼 方 .01312e24
* 01312e19 > c78424 c000000 > mov dword ptr ss : [ esp + 0xc0 ] , 0x0
* 01312e24 > 8 b4b 04 mov ecx , dword ptr ds : [ ebx + 0x4 ]
* 01312e27 . 0f afce imul ecx , esi
* 01312e2 a . b8 1f 85 eb51 mov eax , 0x51eb851f
* 01312e2 f . f7e9 imul ecx
* 01312e31 . c1fa 05 sar edx , 0x5
* 01312e34 . 8 bca mov ecx , edx
* 01312e36 . c1e9 1f shr ecx , 0x1f
* 01312e39 . 03 ca add ecx , edx
* 01312e3 b . 894 c24 70 mov dword ptr ss : [ esp + 0x70 ] , ecx
* 01312e3 f . 85 c9 test ecx , ecx
* 01312e41 . 7f 09 jg short 蒼 の 彼 方 .01312e4 c
* 01312e43 . b9 01000000 mov ecx , 0x1
* 01312e48 . 894 c24 70 mov dword ptr ss : [ esp + 0x70 ] , ecx
* 01312e4 c > 8 b53 08 mov edx , dword ptr ds : [ ebx + 0x8 ]
* 01312e4 f . 0f afd6 imul edx , esi
* 01312e52 . b8 1f 85 eb51 mov eax , 0x51eb851f
* 01312e57 . f7ea imul edx
* 01312e59 . c1fa 05 sar edx , 0x5
* 01312e5 c . 8 bc2 mov eax , edx
* 01312e5 e . c1e8 1f shr eax , 0x1f
* 01312e61 . 03 c2 add eax , edx
* 01312e63 . 894424 78 mov dword ptr ss : [ esp + 0x78 ] , eax
* 01312e67 . 85 c0 test eax , eax
* 01312e69 . 7f 09 jg short 蒼 の 彼 方 .01312e74
* 01312e6 b . b8 01000000 mov eax , 0x1
* 01312e70 . 894424 78 mov dword ptr ss : [ esp + 0x78 ] , eax
* 01312e74 > 33 d2 xor edx , edx
* 01312e76 . 895424 64 mov dword ptr ss : [ esp + 0x64 ] , edx
* 01312e7 a . 895424 6 c mov dword ptr ss : [ esp + 0x6c ] , edx
* 01312e7 e . 8 b13 mov edx , dword ptr ds : [ ebx ]
* 01312e80 . 4 a dec edx ; switch ( cases 1. .2 )
* 01312e81 . 74 0 e je short 蒼 の 彼 方 .01312e91
* 01312e83 . 4 a dec edx
* 01312e84 . 75 13 jnz short 蒼 の 彼 方 .01312e99
* 01312e86 . 8 d1409 lea edx , dword ptr ds : [ ecx + ecx ] ; case 2 of switch 01312e80
* 01312e89 . 895424 64 mov dword ptr ss : [ esp + 0x64 ] , edx
* 01312e8 d . 03 c0 add eax , eax
* 01312e8 f . eb 04 jmp short 蒼 の 彼 方 .01312e95
* 01312e91 > 894 c24 64 mov dword ptr ss : [ esp + 0x64 ] , ecx ; case 1 of switch 01312e80
* 01312e95 > 894424 6 c mov dword ptr ss : [ esp + 0x6c ] , eax
* 01312e99 > 8 b9c24 3802000 > mov ebx , dword ptr ss : [ esp + 0x238 ] ; default case of switch 01312e80
* 01312 ea0 . 8 bc3 mov eax , ebx
* 01312 ea2 . e8 d98bffff call 蒼 の 彼 方 .0130 ba80
* 01312 ea7 . 8 bc8 mov ecx , eax
* 01312 ea9 . 8 bc3 mov eax , ebx
* 01312 eab . e8 e08bffff call 蒼 の 彼 方 .0130 ba90
* 01312 eb0 . 6 a 01 push 0x1 ; / arg1 = 00000001
* 01312 eb2 . 8 bd0 mov edx , eax ; |
* 01312 eb4 . 8 db424 1 c01000 > lea esi , dword ptr ss : [ esp + 0x11c ] ; |
* 01312 ebb . e8 3056f dff call 蒼 の 彼 方 .012e84 f0 ; \ 蒼 の 彼 方 .012e84 f0
* 01312 ec0 . 8 bc7 mov eax , edi
* 01312 ec2 . 83 c4 04 add esp , 0x4
* 01312 ec5 . 8 d70 01 lea esi , dword ptr ds : [ eax + 0x1 ]
* 01312 ec8 > 8 a08 mov cl , byte ptr ds : [ eax ]
* 01312 eca . 40 inc eax
* 01312 ecb . 84 c9 test cl , cl
* 01312 ecd . ^ 75 f9 jnz short 蒼 の 彼 方 .01312 ec8
* 01312 ecf . 2 bc6 sub eax , esi
* 01312 ed1 . 40 inc eax
* 01312 ed2 . 50 push eax
* 01312 ed3 . e8 e74c0600 call 蒼 の 彼 方 .01377 bbf
* 01312 ed8 . 33f 6 xor esi , esi
* 01312 eda . 83 c4 04 add esp , 0x4
*/
ULONG search3 ( ULONG startAddress , ULONG stopAddress )
{
//return startAddress + 0x31850; // 世界と世界の真ん中 体験版
const uint8_t bytes [ ] = { // 3c207d580fbec083c0fe83f806774d
0x3c , 0x20 , // 01312d8e 3c 20 cmp al,0x20 ; jichi: pattern starts
0x7d , 0x58 , // 01312d90 7d 58 jge short 蒼の彼方.01312dea
0x0f , 0xbe , 0xc0 , // 01312d92 0fbec0 movsx eax,al
0x83 , 0xc0 , 0xfe , // 01312d95 83c0 fe add eax,-0x2 ; switch (cases 2..8)
0x83 , 0xf8 , 0x06 , // 01312d98 83f8 06 cmp eax,0x6
0x77 , 0x4d // 01312d9b 77 4d ja short 蒼の彼方.01312dea
} ;
ULONG addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , startAddress , stopAddress ) ;
if ( ! addr )
return 0 ;
// distance to the beginning of the function
static const int hook_offsets [ ] = {
0x01312cd0 - 0x01312d8e // for new BGI2 game since 蒼の彼方 (2014/08), text is in arg2
, 0x00a64260 - 0x00a64318 // For newer BGI2 game since コドモノアソビ (2015/11)
} ;
enum { hook_offset_count = sizeof ( hook_offsets ) / sizeof ( * hook_offsets ) } ;
for ( size_t i = 0 ; i < hook_offset_count ; i + + ) {
int hook_offset = hook_offsets [ i ] ;
enum : uint8_t { push_ebp = 0x55 } ; // 011d4c80 /$ 55 push ebp
if ( * ( uint8_t * ) ( addr + hook_offset ) = = push_ebp )
return addr + hook_offset ;
}
return 0 ; // failed
}
ULONG search_bgi3 ( ULONG startAddress , ULONG stopAddress )
{
//黄昏のフォルクローレ
/* .text:00C3A700 push ebp
. text : 00 C3A701 mov ebp , esp
. text : 00 C3A703 push [ ebp + arg_30 ]
. text : 00 C3A706 mov edx , [ ebp + arg_4 ]
. text : 00 C3A709 push [ ebp + arg_2C ]
. text : 00 C3A70C mov ecx , [ ebp + arg_0 ]
. text : 00 C3A70F push [ ebp + arg_28 ]
. text : 00 C3A712 push [ ebp + arg_24 ]
. text : 00 C3A715 push [ ebp + arg_20 ]
. text : 00 C3A718 push [ ebp + arg_1C ]
. text : 00 C3A71B push [ ebp + arg_18 ]
. text : 00 C3A71E push [ ebp + arg_14 ]
. text : 00 C3A721 push [ ebp + arg_10 ]
. text : 00 C3A724 push [ ebp + arg_C ]
. text : 00 C3A727 push [ ebp + arg_8 ]
. text : 00 C3A72A call loc_C3A740
int __stdcall sub_C3A700 (
int a1 ,
int a2 ,
int a3 ,
int a4 ,
int a5 ,
int a6 ,
int a7 ,
int a8 ,
int a9 ,
int a10 ,
int a11 ,
int a12 ,
int a13 )
*/
const uint8_t bytes [ ] = {
0x55 ,
0x8b , 0xec ,
0xff , 0x75 , 0x38 ,
0x8b , 0x55 , 0x0c ,
0xff , 0x75 , 0x34 ,
0x8b , 0x4d , 0x08 ,
0xff , 0x75 , 0x30
} ;
ULONG range = min ( ULONG ( stopAddress - startAddress ) , ULONG ( 0x00300000 ) ) ;
ULONG addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , startAddress , startAddress + range ) ;
if ( addr = = 0 ) return 0 ;
return addr ;
}
bool search_tayutama ( DWORD * funaddr , DWORD * addr ) {
const BYTE bytes [ ] = {
// 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
//0x7d, XX, // 011d4d33 |. 7d 75 jge short sekachu.011d4daa ; jichi: 0x75 or 0x58
0x0f , 0xbe , 0xc0 , // 011d4d35 |. 0fbec0 movsx eax,al
0x83 , 0xc0 , 0xfe , // 011d4d38 |. 83c0 fe add eax,-0x2 ; switch (cases 2..8)
0x83 , 0xf8 //, 0x06 // 011d4d3b |. 83f8 06 cmp eax,0x6
// The following code does not exist in newer BGI games after 蒼の彼方
//0x77, 0x6a // 011d4d3e |. 77 6a ja short sekachu.011d4daa
} ;
ULONG range = min ( processStopAddress - processStartAddress , MAX_REL_ADDR ) ;
* addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , processStartAddress , processStartAddress + range ) ;
//GROWL_DWORD(reladdr);
if ( ! * addr ) {
return false ;
}
* funaddr = MemDbg : : findEnclosingAlignedFunction ( * addr , 0x300 ) ; // range is around 177 ~ 190
enum : BYTE { push_ebp = 0x55 } ; // 011d4c80 /$ 55 push ebp
if ( ! * funaddr | | * ( BYTE * ) * funaddr ! = push_ebp ) {
return false ;
}
return true ;
}
bool InsertBGI2Hook ( )
{
/* 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 ?
I don ' t have all these games so no way to confirm which ( if any ) are wrong .
But the first difference ( the important one since it ' s the one detecting offset = arg3 , all others give new ) seems to be four bytes off when hooking https : //vndb.org/v8158
. . . but maybe it ' s not ? Maybe I discovered a new difference ?
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 .
*/
ULONG addr , funaddr ; HookParam hp ;
hp . hook_font = F_TextOutA | F_TextOutW ;
if ( addr = search_bgi3 ( processStartAddress , processStopAddress ) ) {
//有乱码,无法处理。
Private : : textIndex_ = 3 ;
hp . offset = get_stack ( Private : : textIndex_ ) ;
Private : : type_ = Private : : Type_BGI3 ;
hp . hook_font | = F_GetTextExtentPoint32W ;
}
else if ( search_tayutama ( & funaddr , & addr ) ) {
switch ( funaddr - addr ) {
// for old BGI2 game, text is arg3
case 0x34c80 - 0x34d31 : // old offset
case 0x34c50 - 0x34d05 : // correction as mentioned above
Private : : textIndex_ = 3 ;
break ;
// for new BGI2 game since 蒼の彼方 (2014/08), text is in arg2
case 0x01312cd0 - 0x01312D92 :
// For newer BGI2 game since コドモノアソビ (2015/11)
case 0x00A64260 - 0x00A6431C :
// For latest BGI2 game since タユタマ2(2016/05) by @mireado
case 0x00E95290 - 0x00E95349 :
// For latest BGI2 game since 千の刃濤、桃花染の皇姫 体験版 by @mireado
case 0x00AF5640 - 0x00AF56FF :
// For latest BGI2 game since by BGI 1.633.0.0 @mireado
case 0x00D8A660 - 0x00D8A73A :
Private : : textIndex_ = 2 ;
break ;
// Artikash 8/1/2018: Looks like it's basically always 4*2. Remove error from default case: breaks SubaHibi HD. Will figure out how to do this properly if it becomes an issue.
default :
ConsoleOutput ( " BGI2 WARN: function-code distance unknown " ) ;
Private : : textIndex_ = 2 ;
break ;
}
Private : : type_ = Private : : Type3 ;
addr = funaddr ;
}
else if ( addr = search3 ( processStartAddress , processStopAddress ) ) {
Private : : type_ = Private : : Type3 ;
Private : : textIndex_ = 2 ; // use arg2, name = "BGI2";
} else if ( addr = search2 ( processStartAddress , processStopAddress ) ) {
Private : : type_ = Private : : Type2 ;
Private : : textIndex_ = 3 ; // use arg3, name = "BGI2";
} else if ( addr = search1 ( processStartAddress , processStopAddress ) ) {
Private : : type_ = Private : : Type1 ;
Private : : textIndex_ = 3 ; // use arg3, name = "BGI";
}
if ( addr = = 0 ) return false ;
hp . address = addr ;
hp . offset = get_stack ( Private : : textIndex_ ) ;
// 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 . hook_before = Private : : hookBefore ;
hp . filter_fun = [ ] ( void * data , size_t * len , HookParam * hp ) {
// It could be either <R..> or <r..>
static const std : : regex rx ( " <r.+?>(.+?)</r> " , std : : regex_constants : : icase ) ;
std : : string result = std : : string ( ( char * ) data , * len ) ;
result = std : : regex_replace ( result , rx , " $1 " ) ;
2024-03-21 17:57:04 +08:00
return write_string_overwrite ( data , len , result ) ;
2024-02-07 20:59:24 +08:00
} ;
hp . split = get_stack ( 8 ) ; // pseudo arg8
//GROWL_DWORD2(hp.address, processStartAddress);
return NewHook ( hp , " EmbedBGI " ) ;
}
bool InsertBGI3Hook ( )
{
/*
* Sample games :
* https : //vndb.org/v28283
* https : //vndb.org/v30456
* https : //vndb.org/v33996
* https : //vndb.org/v34532
* https : //vndb.org/v36131
*/
bool found = false ;
const BYTE pattern [ ] = {
0x55 , // 55 push ebp
0x8b , 0xec , // 8BEC mov ebp,esp
0x83 , 0xe4 , 0xf8 , // 83E4 F8 and esp,FFFFFFF8
0x81 , 0xec , 0x84 , 0x00 , 0x00 , 0x00 // 81EC 84000000 sub esp,0x84
} ;
for ( auto addr : Util : : SearchMemory ( pattern , sizeof ( pattern ) , PAGE_EXECUTE , processStartAddress , processStopAddress ) )
{
HookParam hp ;
hp . address = addr ;
hp . offset = get_stack ( 2 ) ;
hp . split = get_stack ( 1 ) ;
hp . type = CODEC_UTF16 | USING_SPLIT ;
ConsoleOutput ( " INSERT BGI3 " ) ;
found | = NewHook ( hp , " BGI3 " ) ;
}
if ( ! found ) ConsoleOutput ( " BGI3: pattern not found " ) ;
return found ;
}
#if 0
/**
* jichi 1 / 31 / 2014 : Add a new BGI hook
* See : http : //www.hongfire.com/forum/showthread.php/36807-AGTH-text-extraction-tool-for-games-translation/page702
* See : http : //www.hongfire.com/forum/showthread.php/36807-AGTH-text-extraction-tool-for-games-translation/page716
*
* Issue : This hook has floating split char
*
* [ ぷ ち け ろ ] コ ト バ の 消 え た 日 <EFBFBD> 忁 <EFBFBD> で 裸 に す る 純 <EFBFBD> 調 教 ~ 体 験 版
* / HS - 1 C : - 4 @ 68E56 : BGI . exe
* - addr : 429654 ( 0x68e56 )
* - module : 3927275266 ( 0xea157702 )
* - off : 4294967264 = 0xffffffe0 = - 0x20
* - split : 4294967288 = 0xfffffff8 = - 0x8
* - type : 81 = 0x51
*
* 00e88 e3d cc int3
* 00e88 e3e cc int3
* 00e88 e3f cc int3
* 00e88 e40 / . 55 push ebp
* 00e88 e41 | . 8 bec mov ebp , esp
* 00e88 e43 | . 56 push esi
* 00e88 e44 | . 57 push edi
* 00e88 e45 | . 8 b7d 08 mov edi , dword ptr ss : [ ebp + 0x8 ]
* 00e88 e48 | . 57 push edi
* 00e88 e49 | . e8 c28a0100 call bgi .00 ea1910
* 00e88 e4e | . 57 push edi ; | arg1
* 00e88 e4f | . 8 bf0 mov esi , eax ; |
* 00e88 e51 | . e8 ba8a0100 call bgi .00 ea1910 ; \ bgi .00 ea1910
* 00e88 e56 | . 83 c4 08 add esp , 0x8 ; jichi : hook here
* 00e88 e59 | . 2 bc6 sub eax , esi
* 00e88 e5b | . eb 03 jmp short bgi .00e88 e60
* 00e88 e5d | 8 d49 00 lea ecx , dword ptr ds : [ ecx ]
* 00e88 e60 | > 8 a0e / mov cl , byte ptr ds : [ esi ]
* 00e88 e62 | . 880 c30 | mov byte ptr ds : [ eax + esi ] , cl
* 00e88 e65 | . 46 | inc esi
* 00e88 e66 | . 84 c9 | test cl , cl
* 00e88 e68 | . ^ 75 f6 \ jnz short bgi .00e88 e60
* 00e88 e6a | . 5f pop edi
* 00e88 e6b | . 33 c0 xor eax , eax
* 00e88 e6d | . 5 e pop esi
* 00e88 e6e | . 5 d pop ebp
* 00e88 e6f \ . c3 retn
*/
bool InsertBGI3Hook ( )
{
const BYTE bytes [ ] = {
0x83 , 0xc4 , 0x08 , // 00e88e56 |. 83c4 08 add esp,0x8 ; hook here
0x2b , 0xc6 , // 00e88e59 |. 2bc6 sub eax,esi
0xeb , 0x03 , // 00e88e5b |. eb 03 jmp short bgi.00e88e60
0x8d , 0x49 , 0x00 , // 00e88e5d | 8d49 00 lea ecx,dword ptr ds:[ecx]
0x8a , 0x0e , // 00e88e60 |> 8a0e /mov cl,byte ptr ds:[esi]
0x88 , 0x0c , 0x30 , // 00e88e62 |. 880c30 |mov byte ptr ds:[eax+esi],cl
0x46 , // 00e88e65 |. 46 |inc esi
0x84 , 0xc9 , // 00e88e66 |. 84c9 |test cl,cl
0x75 , 0xf6 // 00e88e68 |.^75 f6 \jnz short bgi.00e88e60
//0x5f, // 00e88e6a |. 5f pop edi
//0x33,0xc0, // 00e88e6b |. 33c0 xor eax,eax
//0x5e, // 00e88e6d |. 5e pop esi
//0x5d, // 00e88e6e |. 5d pop ebp
//0xc3 // 00e88e6f \. c3 retn
} ;
//enum { addr_offset = 0 };
ULONG range = min ( processStopAddress - processStartAddress , MAX_REL_ADDR ) ;
ULONG addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , processStartAddress , processStartAddress + range ) ;
//reladdr = 0x68e56;
if ( ! addr ) {
ConsoleOutput ( " BGI3: pattern not found " ) ;
return false ;
}
HookParam hp ;
hp . type = USING_STRING | USING_SPLIT ;
hp . offset = get_reg ( regs : : esi ) ;
hp . split = get_reg ( regs : : eax ) ;
hp . address = addr ;
//GROWL_DWORD2(hp.address, processStartAddress);
ConsoleOutput ( " INSERT BGI3 " ) ;
return NewHook ( hp , " BGI3 " ) ;
}
# endif // 0
} // unnamed
// jichi 5/12/2014: BGI1 and BGI2 game can co-exist, such as 世界と世界の真ん中で
// BGI1 can exist in both old and new games
// BGI2 only exist in new games
// Insert BGI2 first.
// Artikash 6/12/2019: In newer games neither exists, but WideCharToMultiByte works, so insert that if BGI2 fails.
bool BGI7Filter ( LPVOID data , size_t * size , HookParam * )
{
auto text = reinterpret_cast < LPWSTR > ( data ) ;
auto len = reinterpret_cast < size_t * > ( size ) ;
CharFilter ( text , len , L ' \ x0001 ' ) ;
CharFilter ( text , len , L ' \ x0002 ' ) ;
CharFilter ( text , len , L ' \ x0003 ' ) ;
CharFilter ( text , len , L ' \ x0004 ' ) ;
CharFilter ( text , len , L ' \ x0005 ' ) ;
CharFilter ( text , len , L ' \ x000A ' ) ;
if ( text [ 0 ] = = L ' \ x3000 ' ) {
* len - = 2 ;
: : memmove ( text , text + 1 , * len ) ;
}
CharReplacer ( text , len , L ' \ x3000 ' , L ' ' ) ; //IDSP
if ( cpp_wcsnstr ( text , L " < " , * len / sizeof ( wchar_t ) ) ) {
StringFilterBetween ( text , len , L " < " , 1 , L " > " , 1 ) ;
}
return true ;
}
bool InsertBGI7Hook ( )
{
/*
* Sample games :
* https : //vndb.org/v26664
* https : //vndb.org/v44105
*/
bool found = false ;
const BYTE pattern [ ] = {
0x55 , // 55 push ebp << hook here
0x8b , 0xec , // 8BEC mov ebp,esp
0x53 , // 53 push ebx
0x56 , // 56 push esi
0x57 , // 57 push edi
0x33 , 0xFF , // 33 FF xor edi,edi
0xE8 , XX4 , // E8 23FDFFFF call saclet.exe+A0990
0x8B , 0xF0 // 8B F0 mov esi,eax
} ;
for ( auto addr : Util : : SearchMemory ( pattern , sizeof ( pattern ) , PAGE_EXECUTE , processStartAddress , processStopAddress ) )
{
HookParam hp ;
hp . address = addr ;
hp . offset = get_reg ( regs : : eax ) ;
hp . split = get_reg ( regs : : esp ) ;
hp . type = CODEC_UTF16 | USING_STRING | USING_SPLIT | KNOWN_UNSTABLE ;
hp . filter_fun = BGI7Filter ;
ConsoleOutput ( " INSERT BGI4 " ) ;
found | = NewHook ( hp , " BGI4 " ) ;
}
if ( ! found ) ConsoleOutput ( " BGI4: pattern not found " ) ;
return found ;
}
bool BGI56Filter ( LPVOID data , size_t * size , HookParam * )
{
auto text = reinterpret_cast < LPSTR > ( data ) ;
auto len = reinterpret_cast < size_t * > ( size ) ;
if ( text [ 0 ] = = ' @ ' ) {
* len - = 1 ;
: : memmove ( text , text + 1 , * len ) ;
}
return true ;
}
bool InsertBGI5Hook ( )
{
/*
* Sample games :
* https : //vndb.org/v473
*/
const BYTE bytes [ ] = {
0x90 , // nop
0x81 , 0xEC , XX4 , // sub esp,00000920 << hook here
0x8B , 0x84 , 0x24 , XX4 , // mov eax,[esp+00000944]
0x55 , // push ebp
0x8D , 0x8C , 0x24 , XX4 // lea ecx,[esp+000000F4]
} ;
ULONG range = min ( processStopAddress - processStartAddress , MAX_REL_ADDR ) ;
ULONG addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , processStartAddress , processStartAddress + range ) ;
if ( ! addr )
return false ;
HookParam hp ;
hp . address = addr + 1 ;
hp . offset = get_reg ( regs : : ecx ) ;
hp . padding = 1 ;
hp . type = USING_STRING ;
hp . filter_fun = BGI56Filter ;
ConsoleOutput ( " INSERT BGI5 " ) ;
return NewHook ( hp , " BGI5 " ) ;
}
bool InsertBGI6Hook ( )
{
/*
* Sample games :
* https : //vndb.org/r96578
*/
const BYTE bytes [ ] = {
0x90 , // nop
0x6A , 0xFF , // push -01 << hook here
0x68 , XX4 , // push BGI.exe+87AF8
0x64 , 0xA1 , 0x00 , 0x00 , 0x00 , 0x00 , // mov eax,fs:[00000000]
0x50 , // push eax
0x64 , 0x89 , 0x25 , 0x00 , 0x00 , 0x00 , 0x00 , // mov fs:[00000000],esp
0x81 , 0xEC , XX4 , // sub esp,000009B4
0x8B , 0x84 , 0x24 , 0xE4 , 0x09 , 0x00 , 0x00 // mov eax,[esp+000009E4]
} ;
ULONG range = min ( processStopAddress - processStartAddress , MAX_REL_ADDR ) ;
ULONG addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , processStartAddress , processStartAddress + range ) ;
if ( ! addr )
return false ;
HookParam hp ;
hp . address = addr + 1 ;
hp . offset = get_reg ( regs : : ecx ) ;
hp . padding = 1 ;
hp . type = USING_STRING ;
hp . filter_fun = BGI56Filter ;
ConsoleOutput ( " INSERT BGI6 " ) ;
return NewHook ( hp , " BGI6 " ) ;
}
bool InsertBGIHook ( )
{ return InsertBGI2Hook ( ) | | InsertBGI3Hook ( ) | | ( PcHooks : : hookOtherPcFunctions ( ) , InsertBGI1Hook ( ) ) ; }
bool InsertBGI4Hook ( )
{
const BYTE bytes [ ] = {
0xBE , 0xE9 , 0xFD , 0x00 , 0x00 , //cp=65001
XX2 ,
0xBE , 0xA4 , 0x03 , 0x00 , 0x00 //cp=932
} ;
auto addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , processStartAddress , processStopAddress ) ;
if ( addr = = 0 ) return false ;
addr = MemDbg : : findEnclosingAlignedFunction ( addr ) ;
if ( addr = = 0 ) return false ;
HookParam hp ;
hp . address = addr ;
hp . offset = get_reg ( regs : : eax ) ;
hp . split = get_reg ( regs : : esp ) ;
hp . type = CODEC_UTF16 | USING_STRING | USING_SPLIT ;
hp . filter_fun = BGI7Filter ;
ConsoleOutput ( " BGI4 " ) ;
return NewHook ( hp , " BGI4 " ) ;
}
namespace {
bool veryold ( ) {
//紅月-くれないつき-
//あの街の恋の詩
auto entry = Util : : FindImportEntry ( processStartAddress , ( DWORD ) GetGlyphOutlineA ) ;
if ( entry = = 0 ) return false ;
BYTE bytes [ ] = { 0xFF , 0x15 , XX4 } ;
memcpy ( bytes + 2 , & entry , 4 ) ;
BYTE bytes2 [ ] = { 0x8b , XX , XX4 } ; //mov ebp, ds:GetGlyphOutlineA
memcpy ( bytes2 + 2 , & entry , 4 ) ; //銀行淫~堕ちゆく女達~
auto addr = MemDbg : : findBytes ( bytes , sizeof ( bytes ) , processStartAddress , processStopAddress ) ;
if ( addr = = 0 )
addr = MemDbg : : findBytes ( bytes2 , sizeof ( bytes2 ) , processStartAddress , processStopAddress ) ;
if ( addr = = 0 ) return false ;
addr = MemDbg : : findEnclosingAlignedFunction ( addr ) ;
if ( addr = = 0 ) return false ;
auto xrefs = findxref_reverse_checkcallop ( addr , addr - 0x1000 , addr + 0x1000 , 0xe8 ) ;
if ( xrefs . size ( ) ! = 1 ) return false ;
auto xrefaddr = xrefs [ 0 ] ;
auto funcstart = MemDbg : : findEnclosingAlignedFunction ( xrefaddr ) ;
if ( funcstart = = 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 ;
hp . address = funcstart ;
hp . offset = get_stack ( 2 ) ;
hp . split = get_stack ( 1 ) ;
hp . type = CODEC_ANSI_BE | USING_SPLIT ;
return NewHook ( hp , " BGI5 " ) ;
}
}
bool BGI : : attach_function ( ) {
bool b1 = InsertBGIHook ( ) ;
bool b2 = InsertBGI4Hook ( ) ;
bool ok = b1 | | b2 | | veryold ( ) ;
ok = InsertBGI7Hook ( ) | | InsertBGI5Hook ( ) | | InsertBGI6Hook ( ) | | ok ;
return ok ;
}