- Сообщения
- 896
- Реакции
- 2,411
Поскольку при использовании LTCG внутренние функции часто имеют собственное соглашение о вызовах, то просто так их вызвать через SDKCall нельзя, поэтому нужно сделать функцию "транслятор" которая будет соответствовать stdcall и вызывать нужную функцию.
Для примера возьмем CBaseAnimating::SequenceDuration она девает возврат через xmm0, функция "транслятор" получилась такая
Осталось самое главное реализовать это как-то на SP и тут на помощь приходит очень хорошая статья Блог Контика: Работа с памятью в SourcePawn основываясь на ней я сделал такой пример
Для примера возьмем CBaseAnimating::SequenceDuration она девает возврат через xmm0, функция "транслятор" получилась такая
C-подобный:
55 push ebp
89 e5 mov ebp,esp
8b 45 0c mov eax,DWORD PTR [ebp+0xc]
50 push eax
8b 45 08 mov eax,DWORD PTR [ebp+0x8]
50 push eax
b8 00 00 00 00 mov eax,0x0 ; в 0x0 запишем адрес "кривой" функции
ff d0 call eax
f3 0f 11 44 24 fc movss DWORD PTR [esp-0x4],xmm0 ; перемещаем значение из xmm0 в стек
d9 44 24 fc fld DWORD PTR [esp-0x4] ; перемещаем значение из стека в вершину FPU стека (куда и должно по нормальному перемещаться возвращаемое значение с плавающей точкой)
89 ec mov esp,ebp
5d pop ebp
c2 08 00 ret 0x8
Осталось самое главное реализовать это как-то на SP и тут на помощь приходит очень хорошая статья Блог Контика: Работа с памятью в SourcePawn основываясь на ней я сделал такой пример
PHP:
#include sdkhooks
#include sdktools
#pragma semicolon 1
Handle g_hConfig;
public void OnPluginStart()
{
g_hConfig = LoadGameConfigFile("windows_pizdez");
if(g_hConfig == null)
{
SetFailState("Геймдата не найдена");
return;
}
RegConsoleCmd("sm_test", sm_test);
}
public Action sm_test(int iClient, int args)
{
float fBuf = CBaseAnimating_SequenceDuration(iClient, 0, 0);
PrintToServer("CBaseAnimating_SequenceDuration %f", fBuf);
return Plugin_Handled;
}
float CBaseAnimating_SequenceDuration(int iClient, int pStudioHdr, int iSequence)
{
//Функция делат возврат через xmm0 поэтому исправляем
static Handle hSequenceDuration = null;
static Address pMemory = Address_Null;
static char ASMTRAMPOLINE[] = "\x55\x89\xE5\x8B\x45\x0C\x50\x8B\x45\x08\x50\xB8\x00\x00\x00\x00\xFF\xD0\xF3\x0F\x11\x44\x24\xFC\xD9\x44\x24\xFC\x89\xEC\x5D\xC2\x08\x00";
/*
https://defuse.ca/online-x86-assembler.htm
55 push ebp
89 e5 mov ebp,esp
8b 45 0c mov eax,DWORD PTR [ebp+0xc]
50 push eax
8b 45 08 mov eax,DWORD PTR [ebp+0x8]
50 push eax
b8 00 00 00 00 mov eax,0x0 ; pSequenceDuration
ff d0 call eax
f3 0f 11 44 24 fc movss DWORD PTR [esp-0x4],xmm0
d9 44 24 fc fld DWORD PTR [esp-0x4]
89 ec mov esp,ebp
5d pop ebp
c2 08 00 ret 0x8
*/
if(hSequenceDuration == null)
{
Address pSequenceDuration = GameConfGetAddress(g_hConfig, "CBaseAnimating::SequenceDuration");
if(pSequenceDuration == Address_Null)
{
SetFailState("Не удалось получить адрес CBaseAnimating::SequenceDuration");
return 0.0;
}
pMemory = CreateMemoryForSDKCall();
StartPrepSDKCall(SDKCall_Entity);
PrepSDKCall_SetAddress(pMemory);
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain);
hSequenceDuration = EndPrepSDKCall();
WriteDWORD(ASMTRAMPOLINE, pSequenceDuration, 12); //Запишем адрес функции
}
memcpy(pMemory, ASMTRAMPOLINE, sizeof ASMTRAMPOLINE);
return SDKCall(hSequenceDuration, iClient, pStudioHdr, iSequence);
}
Address CreateMemoryForSDKCall()
{
static Address pZeroMem = Address_Null;
if(pZeroMem != Address_Null)
{
return pZeroMem;
}
Address pServerBase = GameConfGetAddress(g_hConfig, "server");
int pAddr = view_as<int>(pServerBase) + GetModuleSize(pServerBase) - 1;
for(;;)
{
int b = LoadFromAddress(view_as<Address>(pAddr), NumberType_Int8);
if(b != 0x00)
{
break;
}
pAddr--;
}
/* Align for safe code injection */
pZeroMem = view_as<Address>(pAddr + 0x100 & 0xFFFFFF00); //255 bytes
return pZeroMem;
}
int GetModuleSize(Address pAddr)
{
int iOffset = LoadFromAddress(pAddr + view_as<Address>(0x3C), NumberType_Int32); // NT headers offset
return LoadFromAddress(pAddr + view_as<Address>(iOffset + 0x50), NumberType_Int32); // nt->OptionalHeader.SizeOfImage
}
void memcpy(Address pAddr, char[] data, int iSize)
{
//Чтобы ускорить копирование
int iSize2 = iSize / 4;
____memcpy4b(pAddr, view_as<any>(data), iSize2);
//Копирование остатка
for(iSize2 *= 4, pAddr += view_as<Address>(iSize2); iSize2 < iSize; iSize2++)
{
StoreToAddress(pAddr++, data[iSize2], NumberType_Int8);
}
}
void ____memcpy4b(Address pAddr, any[] data, int iSize)
{
//Сразу копирует по 4 байта
for(int i = 0; i < iSize; i++)
{
StoreToAddress(pAddr, data[i], NumberType_Int32);
pAddr+=view_as<Address>(4);
}
}
void WriteDWORD(char[] ASM, any pAddr, int iOffset = 0)
{
ASM[iOffset] = pAddr & 0xFF;
ASM[iOffset+1] = pAddr >> 8 & 0xFF;
ASM[iOffset+2] = pAddr >> 16 & 0xFF;
ASM[iOffset+3] = pAddr >> 24 & 0xFF;
}
C-подобный:
"Games"
{
"#default"
{
"Addresses"
{
"server"
{
"signature" "Find_Server"
}
"CBaseAnimating::SequenceDuration"
{
"signature" "CBaseAnimating::SequenceDuration"
}
}
"Signatures"
{
"Find_Server"
{
"library" "server"
"windows" "\x4D\x5A"
}
"CBaseAnimating::SequenceDuration"
{
"library" "server"
"windows" "\x55\x8B\xEC\x56\x8B\x75\x08\x57\x8B\xF9\x85\xF6\x75\x2A\x8B\x47\x60"
}
}
}
}