Raised This Month: $51 Target: $400
 12% 

Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
meTaLiCroSS
Gaze Upon My Hat
Join Date: Feb 2009
Location: Viņa del Mar, Chile
Old 02-08-2017 , 03:48   Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #1

Time ago I've had troubles with hooking this function with Orpheu.

Now I tried to make a module to deal with this, by knowing it was some kind of weird optimization. It has the same behavior that SetAnimation function has. Reference: https://forums.alliedmods.net/showpo...postcount=1462

First, what I tried to do is to read Arkshine's way to deal with SetAnimation module: https://forums.alliedmods.net/showpo...51&postcount=7

Then I looked through the gamedll with IDA Pro and discover what does register store.

Inside CBasePlayer:ackDeadPlayerItems:



and..:



What I guessed first was "ECX contains packAmmo parameter", which makes sense reading a decompiled version of PackDeadPlayerItems (it's always 1)

Then, reading this code, I tried to understand decompiled version of it.

PHP Code:
void packPlayerItem(CBasePlayer *pPlayerCBasePlayerItem *pItembool packAmmo)
{
    if (
pItem// ITEM CHECK FIRST
    
{
        const 
char *modelName GetCSModelName(pItem->m_iId);

        if (
modelName)
        {
            
CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create("weaponbox"pPlayer->pev->originpPlayer->pev->anglesENT(pPlayer->pev));
            
pWeaponBox->pev->angles.0;
            
pWeaponBox->pev->angles.0;
            
pWeaponBox->pev->velocity pPlayer->pev->velocity 0.75;
            
pWeaponBox->SetThink(&CWeaponBox::Kill);
            
pWeaponBox->pev->nextthink gpGlobals->time 300;
            
pWeaponBox->PackWeapon(pItem);

            if (
packAmmo// 3RD PARAM CONDITION
                
pWeaponBox->PackAmmo(MAKE_STRING(CBasePlayerItem::ItemInfoArray[pItem->m_iId].pszAmmo1), pPlayer->m_rgAmmo[pItem->PrimaryAmmoIndex()]);

            
SET_MODEL(ENT(pWeaponBox->pev), modelName);
        }
    }

Then, just with the decompiled version:

Code:
int __cdecl packPlayerItem(CBasePlayer *a1, CBasePlayerItem *a2, bool a3) {
  int result; // eax@0
  int v4; // edx@0
  char v5; // cl@0
  int v6; // ebx@1   int v7; // esi@1   int v8; // ebp@2   int v9; // edi@3   int v10; // edx@3   int v11; // eax@3
  long double v12; // fst6@3
  long double v13; // fst7@3   long double v14; // fst5@3   globalvars_t *v15; // edx@3   int v16; // eax@3   int v17; // eax@6   int this; // [sp+0h] [bp-3Ch]@0   edict_s *v19; // [sp+10h] [bp-2Ch]@0   char v20; // [sp+1Fh] [bp-1Dh]@1   v6 = result;   v7 = v4;   v20 = v5;
  if ( v4 ) // if(pItem) ???
  {     result = GetCSModelName(this);     v8 = result;     if ( result )     {       v9 = CBaseEntity::Create(              "weaponbox",              (char *)(*(_DWORD *)(v6 + 4) + 8),              (const Vector *)(*(_DWORD *)(v6 + 4) + 80),              *(const Vector **)(*(_DWORD *)(v6 + 4) + 520),              v19);       *(_DWORD *)(*(_DWORD *)(v9 + 4) + 80) = 0;       *(_DWORD *)(*(_DWORD *)(v9 + 4) + 88) = 0;       v10 = *(_DWORD *)(v6 + 4);       v11 = *(_DWORD *)(v9 + 4);       v12 = *(float *)(v10 + 40) * 0.75;       v13 = *(float *)(v10 + 36) * 0.75;       v14 = 0.75 * *(float *)(v10 + 32);       v15 = gpGlobals;       *(float *)(v11 + 32) = v14;       *(float *)(v11 + 36) = v13;       *(float *)(v11 + 40) = v12;       *(_DWORD *)(v9 + 16) = CWeaponBox::Kill;       v16 = *(_DWORD *)(v9 + 4);       *(_DWORD *)(v9 + 20) = 0;       *(float *)(v16 + 260) = v15->time + 300.0;       CWeaponBox::PackWeapon((CWeaponBox *)v9, (CBasePlayerItem *)v7);
      if ( v20 ) // 3RD PARAM CONDITION
      {         v17 = (*(int (__cdecl **)(int))(*(_DWORD *)v7 + 296))(v7);         CWeaponBox::PackAmmo(           (CWeaponBox *)v9,           *(_DWORD *)&CBasePlayerItem::ItemInfoArray[44 * *(_DWORD *)(v7 + 188) + 8]         - (unsigned int)gpGlobals->pStringBase,           *(_DWORD *)(v6 + 4 * v17 + 1524));       }       result = ((int (__cdecl *)(_DWORD, int))g_engfuncs.pfnSetModel)(*(_DWORD *)(*(_DWORD *)(v9 + 4) + 520), v8);     }   }   return result; }

Just read it and you'll understand.

v20 is packAmmo, v20 equals to v5 and v5 contains the value of CL register, lower part of ECX register, set as 1 in the pictures below. (also see this one)

v4 is pItem, and it points to EDX register.

Inside CBaseEntity::Create you can see references with v6 to the player pev->origin entvar. then you guess that v6 = result, and results references to the EAX register.

Now it makes sense this picture



I managed to create this code, by reading a few guides of Inline Assembly in cpp and also Arkshine's SetAnimation hooker:

PHP Code:
//native Call_packPlayerItem(iId, iAnim)
static cell AMX_NATIVE_CALL Native_Call_packPlayerItem(AMX *amxcell *params)
{
    
voidpPlayer TypeConversion.id_to_cbase(params[1]);
    
    if(!
pPlayer)
    {
        
MF_LogError(amxAMX_ERR_NATIVE"Invalid player %d"params[1]);
        return 
0;
    }    
    
    
voidpItem TypeConversion.id_to_cbase(params[2]);
    
    if(!
pItem)
    {
        
MF_LogError(amxAMX_ERR_NATIVE"Invalid item %d"params[2]);
        return 
0;
    }
    
    
int packAmmo params[3];
    
    
SERVER_PRINT(UTIL_VarArgs("Calling packPlayerItem(%p, %p, %s)\n"pPlayerpItempackAmmo "TRUE" "FALSE"));    

    
asm volatile
    
(
        
"movl %0, %%eax;"
        "movl %1, %%edx;"
        "movl %2, %%ecx;"
        
/* no output */
        
"m" (pPlayer), "m" (pItem), "m" (packAmmo
        : 
"%eax""%edx""%ecx"
    
);
    
OrigFunc_packPlayerItem(pPlayerpItem, (bool)packAmmo);
    return 
1;

Retrieving it's address correctly also:

PHP Code:
void Patch_packPlayerItem()
{
    
OrigFunc_packPlayerItem Hooker->MemorySearchFunc_packPlayerItem >( "0x83,*,*,0x85,*,0x89,*,*,*,0x89,*,0x89,*,*,*,0x89,*,0x89,*,*,*,0x89", ( void* )MDLL_SpawnFALSE );

    if(
OrigFunc_packPlayerItem)
    {
        
// hooking was a hell also, so what I did was just to get function address
        /*Hook_packPlayerItem = Hooker->CreateHook( ( void* )OrigFunc_packPlayerItem, ( void* )OnpackPlayerItem, TRUE );

        if( Hook_packPlayerItem )
            SERVER_PRINT( "Hook created successfully\n" );
        else 
            SERVER_PRINT( "Hook creation failed\n" );*/
    
}
    else
        
SERVER_PRINT"Signature/symbol could not be found\n" );

Output throws correct values, function executed normally, weapon thrown and tested with players.

PHP Code:
L 02/08/2017 05:27:16"PM32<1><STEAM_0:0:nothankslol><>" joined team "CT"
Calling packPlayerItem(0xac022100xabfec30TRUE)
Calling packPlayerItem(0xac022100xac061e0TRUE)
Calling packPlayerItem(0xac022100xac06a10TRUE
The most FUNNY about about this is the next.

If I comment SERVER_PRINT call, server crashes with a seg fault. Why? I dont know.

So, my first guess is the inline assembler code that I wrote has a mistake, and I believe it's that. Am I doing right with it? Or am I forgetting something?

Thanks for reading.
__________________
Quote:
Originally Posted by joropito View Post
You're right Metalicross
meTaLiCroSS is offline
Arkshine
AMX Mod X Plugin Approver
Join Date: Oct 2005
Old 02-08-2017 , 11:18   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #2

I don't know much the assembly language, but is it really needed the following: " : "%eax", "%edx", "%ecx" "?
__________________

Last edited by Arkshine; 02-08-2017 at 11:48.
Arkshine is offline
PRoSToTeM@
Veteran Member
Join Date: Jan 2010
Location: Russia, Ivanovo
Old 02-08-2017 , 12:08   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #3

Try to declare OrigFunc_packPlayerItem with __attribute__((regparm(3))) before *.
__________________
PRoSToTeM@ is offline
Send a message via ICQ to PRoSToTeM@ Send a message via Skype™ to PRoSToTeM@
Asmodai
New Member
Join Date: May 2011
Old 02-08-2017 , 13:22   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #4

Quote:
Originally Posted by Arkshine View Post
I don't know much the assembly language, but is it really needed the following: " : "%eax", "%edx", "%ecx" "?
Yes, we must list all used registers because gcc didn't parsing asm insertions.

And your code from link
Code:
DETOUR_DECL_MEMBER1(SetAnimation, void, int, playerAnim)
{
	const void *pvPlayer = reinterpret_cast<const void*>(this);

#if defined(LINUX)

	asm volatile
	(
		"movl %%edx, %0;"
		"movl %%eax, %1;"
		: "=d" (playerAnim), "=a" (pvPlayer) : :
	);

#endif

	if (MF_ExecuteForward(OnSetAnimationForward, Utils::PrivateToIndex(pvPlayer), playerAnim) > 0)
	{
		return;
	}

#if defined(WIN32) || defined(APPLE)

	DETOUR_MEMBER_CALL(SetAnimation)(playerAnim);

#elif defined(LINUX)

	SetAnimationDetour->DisableDetour();
	SetAnimationOrig(pvPlayer, playerAnim);
	SetAnimationDetour->EnableDetour();

#endif
}
will not work, because eax and edx is a scratch registers that can be changed by any function call. You should change this registers only immediately before jmp to SetAnimation.

Last edited by Asmodai; 02-08-2017 at 13:35.
Asmodai is offline
Arkshine
AMX Mod X Plugin Approver
Join Date: Oct 2005
Old 02-08-2017 , 16:41   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #5

The code above works, I don't post module which has not been tested. But it's possible I did not test in a way he would not work, I don't know. Also, I'm confused, I don't change the registers, I get the values from them and set them in variables.
__________________
Arkshine is offline
Asmodai
New Member
Join Date: May 2011
Old 02-08-2017 , 17:38   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #6

Ah, right. I'm forgot about reverse operands order. Yes, in this way it's correct. I thought that you are calling original SetAnimation.

Last edited by Asmodai; 02-08-2017 at 17:40.
Asmodai is offline
meTaLiCroSS
Gaze Upon My Hat
Join Date: Feb 2009
Location: Viņa del Mar, Chile
Old 02-08-2017 , 17:45   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #7

Quote:
Originally Posted by PRoSToTeM@ View Post
Try to declare OrigFunc_packPlayerItem with __attribute__((regparm(3))) before *.
So it should be something like..

PHP Code:
typedef void __attribute__((regparm(3))) *Func_packPlayerItem )( void*, void*, bool );
Func_packPlayerItem OrigFunc_packPlayerItem NULL
?

Quote:
Originally Posted by Asmodai View Post
Yes, we must list all used registers because gcc didn't parsing asm insertions.

And your code from link
Code:
DETOUR_DECL_MEMBER1(SetAnimation, void, int, playerAnim)
{
	const void *pvPlayer = reinterpret_cast<const void*>(this);

#if defined(LINUX)

	asm volatile
	(
		"movl %%edx, %0;"
		"movl %%eax, %1;"
		: "=d" (playerAnim), "=a" (pvPlayer) : :
	);

#endif

	if (MF_ExecuteForward(OnSetAnimationForward, Utils::PrivateToIndex(pvPlayer), playerAnim) > 0)
	{
		return;
	}

#if defined(WIN32) || defined(APPLE)

	DETOUR_MEMBER_CALL(SetAnimation)(playerAnim);

#elif defined(LINUX)

	SetAnimationDetour->DisableDetour();
	SetAnimationOrig(pvPlayer, playerAnim);
	SetAnimationDetour->EnableDetour();

#endif
}
will not work, because eax and edx is a scratch registers that can be changed by any function call. You should change this registers only immediately before jmp to SetAnimation.
He's doing right, because SetAnimation was split in 2. What Arkshine did was to retrieve inside's function address (the one which has optimization) and then inside the hook, it calls the original function, the one who calls the hooked inside, so he just need to retrieve values from register and he can call a normal function with it.

Also thanks for answering. The way I wrote the clubbed list is right then?

Quote:
Originally Posted by Arkshine View Post
The code above works, I don't post module which has not been tested. But it's possible I did not test in a way he would not work, I don't know. Also, I'm confused, I don't change the registers, I get the values from them and set them in variables.
What I tested from your code was that if you retrieve these values from those register, they will be set to -1. If you retrieve eax and edx register 2 times and print his values, second call will throw -1, so I guess it has sense, but it's not wrong
__________________
Quote:
Originally Posted by joropito View Post
You're right Metalicross
meTaLiCroSS is offline
PRoSToTeM@
Veteran Member
Join Date: Jan 2010
Location: Russia, Ivanovo
Old 02-08-2017 , 18:00   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #8

Quote:
Originally Posted by meTaLiCroSS View Post
So it should be something like..

PHP Code:
typedef void __attribute__((regparm(3))) *Func_packPlayerItem )( void*, void*, bool );
Func_packPlayerItem OrigFunc_packPlayerItem NULL
?
Yep.
__________________
PRoSToTeM@ is offline
Send a message via ICQ to PRoSToTeM@ Send a message via Skype™ to PRoSToTeM@
joropito
AlliedModders Donor
Join Date: Mar 2009
Location: pfnAddToFullPack
Old 02-08-2017 , 19:20   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #9

Didn't read all but the original function is cdecl so your function must be of cdecl type, remember that
__________________

Divide et vinces
approved plugins | steam account

I don't accept PM for support. Just ask on forums.
If you're looking for private work, PM me.
joropito is offline
Send a message via MSN to joropito
meTaLiCroSS
Gaze Upon My Hat
Join Date: Feb 2009
Location: Viņa del Mar, Chile
Old 02-08-2017 , 19:30   Re: Issue with packPlayerItem hooking (dealing with registers EAX-EDX-ECX)
Reply With Quote #10

Quote:
Originally Posted by PRoSToTeM@ View Post
Yep.
I did it and it worked. I commented SERVER_PRINT, added this and worked without crash.

My final doubt is, does the "m" constraints are ok?
__________________
Quote:
Originally Posted by joropito View Post
You're right Metalicross
meTaLiCroSS is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 04:02.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode