LunaHook-mirror/LunaHook/engine32/AOS.cpp

279 lines
10 KiB
C++
Raw Normal View History

2024-02-07 20:59:24 +08:00
#include"AOS.h"
/**
* jichi 4/1/2014: Insert AOS hook
* About <EFBFBD>: http://erogetrailers.com/brand/165
* About AOS: http://asmodean.reverse.net/pages/exaos.html
*
* Sample games:
*
* [140228] [Sugar Pot] <EFBFBD> V1.00 H-CODE by <EFBFBD>쿿
* - /HB8*0@3C2F0:<EFBFBD>.exe
* - /HBC*0@3C190:<EFBFBD>.exe
*
* [120224] [Sugar Pot] <EFBFBD>
*
* LiLiM games
*
* /HB8*0@3C2F0:<EFBFBD>
* - addr: 246512 = 0x3c2f0
* - length_offset: 1
* - module: 1814017450
* - off: 8
* - type: 72 = 0x48
*
* 00e3c2ed cc int3
* 00e3c2ee cc int3
* 00e3c2ef cc int3
* 00e3c2f0 /$ 51 push ecx ; jichi: hook here, function starts
* 00e3c2f1 |. a1 0c64eb00 mov eax,dword ptr ds:[0xeb640c]
* 00e3c2f6 |. 8b0d 7846eb00 mov ecx,dword ptr ds:[0xeb4678]
* 00e3c2fc |. 53 push ebx
* 00e3c2fd |. 55 push ebp
* 00e3c2fe |. 8b6c24 10 mov ebp,dword ptr ss:[esp+0x10]
* 00e3c302 |. 56 push esi
* 00e3c303 |. 8b35 c446eb00 mov esi,dword ptr ds:[0xeb46c4]
* 00e3c309 |. 57 push edi
* 00e3c30a |. 0fb63d c746eb00 movzx edi,byte ptr ds:[0xeb46c7]
* 00e3c311 |. 81e6 ffffff00 and esi,0xffffff
* 00e3c317 |. 894424 18 mov dword ptr ss:[esp+0x18],eax
* 00e3c31b |. 85ff test edi,edi
* 00e3c31d |. 74 6b je short <EFBFBD>00e3c38a
* 00e3c31f |. 8bd9 mov ebx,ecx
* 00e3c321 |. 85db test ebx,ebx
* 00e3c323 |. 74 17 je short <EFBFBD>00e3c33c
* 00e3c325 |. 8b4b 28 mov ecx,dword ptr ds:[ebx+0x28]
* 00e3c328 |. 56 push esi ; /color
* 00e3c329 |. 51 push ecx ; |hdc
* 00e3c32a |. ff15 3c40e800 call dword ptr ds:[<&gdi32.SetTextColor>>; \settextcolor
* 00e3c330 |. 89b3 c8000000 mov dword ptr ds:[ebx+0xc8],esi
* 00e3c336 |. 8b0d 7846eb00 mov ecx,dword ptr ds:[0xeb4678]
* 00e3c33c |> 0fbf55 1c movsx edx,word ptr ss:[ebp+0x1c]
* 00e3c340 |. 0fbf45 0a movsx eax,word ptr ss:[ebp+0xa]
* 00e3c344 |. 0fbf75 1a movsx esi,word ptr ss:[ebp+0x1a]
* 00e3c348 |. 03d7 add edx,edi
* 00e3c34a |. 03c2 add eax,edx
* 00e3c34c |. 0fbf55 08 movsx edx,word ptr ss:[ebp+0x8]
* 00e3c350 |. 03f7 add esi,edi
* 00e3c352 |. 03d6 add edx,esi
* 00e3c354 |. 85c9 test ecx,ecx
* 00e3c356 |. 74 32 je short <EFBFBD>00e3c38a
*/
bool InsertAOS1Hook()
{
// jichi 4/2/2014: The starting of this function is different from ヂ<>ツキ
// So, use a pattern in the middle of the function instead.
//
//const BYTE bytes[] = {
// 0x51, // 00e3c2f0 /$ 51 push ecx ; jichi: hook here, function begins
// 0xa1, 0x0c,0x64,0xeb,0x00, // 00e3c2f1 |. a1 0c64eb00 mov eax,dword ptr ds:[0xeb640c]
// 0x8b,0x0d, 0x78,0x46,0xeb,0x00, // 00e3c2f6 |. 8b0d 7846eb00 mov ecx,dword ptr ds:[0xeb4678]
// 0x53, // 00e3c2fc |. 53 push ebx
// 0x55, // 00e3c2fd |. 55 push ebp
// 0x8b,0x6c,0x24, 0x10, // 00e3c2fe |. 8b6c24 10 mov ebp,dword ptr ss:[esp+0x10]
// 0x56, // 00e3c302 |. 56 push esi
// 0x8b,0x35, 0xc4,0x46,0xeb,0x00, // 00e3c303 |. 8b35 c446eb00 mov esi,dword ptr ds:[0xeb46c4]
// 0x57, // 00e3c309 |. 57 push edi
// 0x0f,0xb6,0x3d, 0xc7,0x46,0xeb,0x00, // 00e3c30a |. 0fb63d c746eb00 movzx edi,byte ptr ds:[0xeb46c7]
// 0x81,0xe6, 0xff,0xff,0xff,0x00 // 00e3c311 |. 81e6 ffffff00 and esi,0xffffff
//};
//enum { addr_offset = 0 };
const BYTE bytes[] = {
0x0f,0xbf,0x55, 0x1c, // 00e3c33c |> 0fbf55 1c movsx edx,word ptr ss:[ebp+0x1c]
0x0f,0xbf,0x45, 0x0a, // 00e3c340 |. 0fbf45 0a movsx eax,word ptr ss:[ebp+0xa]
0x0f,0xbf,0x75, 0x1a, // 00e3c344 |. 0fbf75 1a movsx esi,word ptr ss:[ebp+0x1a]
0x03,0xd7, // 00e3c348 |. 03d7 add edx,edi
0x03,0xc2, // 00e3c34a |. 03c2 add eax,edx
0x0f,0xbf,0x55, 0x08, // 00e3c34c |. 0fbf55 08 movsx edx,word ptr ss:[ebp+0x8]
0x03,0xf7, // 00e3c350 |. 03f7 add esi,edi
0x03,0xd6, // 00e3c352 |. 03d6 add edx,esi
0x85,0xc9 // 00e3c354 |. 85c9 test ecx,ecx
};
enum { addr_offset = 0x00e3c2f0 - 0x00e3c33c }; // distance to the beginning of the function, which is 0x51 (push ecx)
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
//GROWL(reladdr);
if (!addr) {
ConsoleOutput("AOS1: pattern not found");
return false;
}
addr += addr_offset;
//GROWL(addr);
enum { push_ecx = 0x51 }; // beginning of the function
if (*(BYTE *)addr != push_ecx) {
ConsoleOutput("AOS1: beginning of the function not found");
return false;
}
HookParam hp;
hp.address = addr;
hp.offset=get_stack(2);
hp.type = DATA_INDIRECT;
ConsoleOutput("INSERT AOS1");
return NewHook(hp, "AOS1");
}
bool InsertAOS2Hook()
{
const BYTE bytes[] = {
0x51, // 00C4E7E0 /$ 51 PUSH ECX ; mireado: hook here, function begins
0x33,0xc0, // 00C4E7E1 |. 33C0 XOR EAX,EAX
0x53, // 00C4E7E3 |. 53 PUSH EBX
0x55, // 00C4E7E4 |. 55 PUSH EBP
0x8b,0x2d//, XX4, // 00C4E7E5 |. 8B2D 40A3CF00 MOV EBP,DWORD PTR DS:[0CFA340] ; mireado: some time changing 40A3CF00 => 40A3C000
//0x89,0x07, // 00C4E7EB |. 8907 MOV DWORD PTR DS:[EDI],EAX
//0x89,0x47, 0x04 // 00C4E7ED |. 8947 04 MOV DWORD PTR DS:[EDI+4],EAX
//0x56, // 00C4E7F0 |. 56 PUSH ESI
//0x8b,0x75, 0x44 // 00C4E7F1 |. 8B75 44 MOV ESI,DWORD PTR SS:[EBP+44]
};
enum { addr_offset = 0 }; // distance to the beginning of the function, which is 0x51 (push ecx)
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
//GROWL(reladdr);
if (!addr) {
ConsoleOutput("AOS2: pattern not found");
return false;
}
addr += addr_offset;
//GROWL(addr);
enum { push_ecx = 0x51 }; // beginning of the function
if (*(BYTE *)addr != push_ecx) {
ConsoleOutput("AOS2: beginning of the function not found");
return false;
}
HookParam hp;
hp.address = addr;
hp.offset=get_stack(2);
hp.type = DATA_INDIRECT;
ConsoleOutput("INSERT AOS2");
return NewHook(hp, "AOS2");
}
bool InsertAOSHook()
{ return InsertAOS1Hook() || InsertAOS2Hook();}
namespace{
DWORD calladdr(DWORD addr){
if(addr==0)return 0;
BYTE callop[] = { 0xe8 };
addr = reverseFindBytes(callop, sizeof(callop), addr - 0x20, addr);
if (addr == 0)return 0;
auto calladdr = *(int*)((char*)addr + 1);
ConsoleOutput("calladdr %p", calladdr);
addr = calladdr + addr + 5;
ConsoleOutput("funcaddr %p", addr);
if (*(BYTE*)((BYTE*)addr - 1) != 0xcc)return 0;
return addr;
}
DWORD lastcall(){
auto entry=Util::FindImportEntry(processStartAddress,(DWORD)TextOutA);
if(entry==0)return 0;
BYTE bytes[]={0xFF,0x15,XX4};
memcpy(bytes+2,&entry,4);
auto addr = reverseFindBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if(addr==0)return 0;
addr = MemDbg::findEnclosingAlignedFunction(addr);
return addr;
}
}
regs mov_reg_ebpoffset(int reg) {
switch (reg) {
case 0x4B:
return regs::ebx;
case 0x48:
return regs::eax;
case 0x49:
return regs::ecx;
case 0x4a:
return regs::edx;
case 0x4c:
return regs::ebp;
case 0x4d:
return regs::esp;
case 0x4e:
return regs::esi;
case 0x4f:
return regs::edi;
default:
return regs::invalid;
}
}
bool AOS_EX() {
BYTE aos_shared_bytes1[] = {
0x3c,XX,
0x74,XX,
0x3c,XX,
0x74,XX,
0x3c,XX,
0x74,XX,
0x3c,XX,
0x74,XX,
0x3c,XX,
0x74,XX,
};
BYTE aos_shared_bytes2[] = {
0x80,0xfb,XX,
0x74,XX,
0x80,0xfb,XX,
0x74,XX,
0x80,0xfb,XX,
0x74,XX,
0x80,0xfb,XX,
0x74,XX
};
std::vector<DWORD>addrs;
addrs.push_back(calladdr(MemDbg::findBytes(aos_shared_bytes1, sizeof(aos_shared_bytes1), processStartAddress, processStopAddress)));
addrs.push_back(calladdr(MemDbg::findBytes(aos_shared_bytes2, sizeof(aos_shared_bytes2), processStartAddress, processStopAddress)));
addrs.push_back(lastcall());
for(auto addr: addrs){
if (addr == 0)continue;
auto reg = mov_reg_ebpoffset(*(BYTE*)((BYTE*)addr + 5));
int off;
if (reg!=regs::invalid){
//usercall
off=get_reg(reg);
}
else if(((*(WORD*)addr))==0xec83) {
//姫様LOVEライフ
//也是usercall但是第二个参数是栈上。
off=get_stack(1);
}
else{
//螺旋遡行のディストピア -The infinite set of alternative version- 官方中文
BYTE sig[]={0x89,0x55,0xFC};
if(MemDbg::findBytes(sig, sizeof(sig), addr, addr+0x20)){
off=get_reg(regs::edx);
}
else{
//cdecl;
off=get_stack(2);
}
}
HookParam hp;
hp.address = addr;
hp.offset = off;
hp.type = NO_CONTEXT | DATA_INDIRECT;
hp.index = 0;
return NewHook(hp, "AOS_EX");
}
return false;
}
bool AOS::attach_function() {
bool b1=InsertAOSHook();
bool b3=AOS_EX();
return b1||b3;
}