[Plugin] Hooking Public Callbacks correctly
#1

Hey.

I am trying to find a way how to hook into callbacks in my plugin.
I do not want to depend on any pawn code here:

Код:
public OnPlayerConnect(playerid) {
    return hook_OnPlayerConnect(playerid);
}
I want to hook a callback directly by swapping their address with the address of my callback (and calling the original callback then...)
I already worked out how to do this with natives (functions):

Hooking Natives (functions)

Код:
AMX_NATIVE original_SetPlayerHealth;
cell AMX_NATIVE_CALL hook_SetPlayerHealth(AMX *amx, cell *params)  {
  logprintf("  SetPlayerPos called! Player did not use health cheat...");
  return original_SetPlayerHealth(amx, params);
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad( AMX *amx )
{	
  int index=0;
  if(amx_FindNative(amx, "SetPlayerHealth", &index) == AMX_ERR_NONE) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base); 
    AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);     

    //SWAP the addresses of the original function with my hook
    //store the original address to call it in the hook afterwards
    ::original_SetPlayerHealth = reinterpret_cast<AMX_NATIVE>(natives[index].address);
    natives[index].address = reinterpret_cast<ucell>( hook_SetPlayerHealth );

    logprintf(" SetPlayerPos found and hooked successfully!");
  } 
  else {
    logprintf(" SetPlayerHealth is not used in this script...");
  }
  return amx_Register(amx, PluginNatives, -1);
}
This works for natives... but now lets try callbacks (which are publics)
I am not an expert in the field of embedded scripting but I guess if I copy the original address of any callback and then call it in my hooked address this should work... shouldn't it?

Unfortunately the server just crashes because of an exception...
This is my code:

Hooking Callbacks (publics?)

Код:
AMX_NATIVE original_OnPlayerConnect;
cell AMX_NATIVE_CALL hooked_OnPlayerConnect(AMX *amx, cell *params) 
{
    logprintf("  ON PLAYER CONNECT called!");
    return original_OnPlayerConnect(amx, params);
}


PLUGIN_EXPORT int PLUGIN_CALL AmxLoad( AMX *amx )
{	
  int basis = 0;
  if(amx_FindPublic(amx, "OnPlayerConnect", &basis) == AMX_ERR_NONE) 
  {		
    AMX_HEADER *header = reinterpret_cast<AMX_HEADER*>( amx->base );
    AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + header->publics);
    ::original_OnPlayerConnect = reinterpret_cast< ucell >(publics[basis].address);
    publics[basis].address = reinterpret_cast<ucell>( hooked_OnPlayerConnect );
    logprintf(" Hooking event OnPlayerConnect");
  }
  else {
    logprintf(" OnPlayerConnect NOT found?!");  
  }
}
My suggestions:
  • Callbacks are much more difficult to hook than I thought
  • The type of original_OnPlayerConnect is wrong
I am totally stuck here.
Thank you for any help!
Reply
#2

Why the hell doesn't you want to use PAWN ?

As written in the "Plugin development guide", "plugins are an extension to PAWN, not a replacement".
Reply
#3

Quote:
Originally Posted by webcode421F
Посмотреть сообщение
Hey.

I am trying to find a way how to hook into callbacks in my plugin.
I do not want to depend on any pawn code here:

Код:
public OnPlayerConnect(playerid) {
    return hook_OnPlayerConnect(playerid);
}
I want to hook a callback directly by swapping their address with the address of my callback (and calling the original callback then...)
I already worked out how to do this with natives (functions):

Hooking Natives (functions)

Код:
AMX_NATIVE original_SetPlayerHealth;
cell AMX_NATIVE_CALL hook_SetPlayerHealth(AMX *amx, cell *params)  {
  logprintf("  SetPlayerPos called! Player did not use health cheat...");
  return original_SetPlayerHealth(amx, params);
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad( AMX *amx )
{	
  int index=0;
  if(amx_FindNative(amx, "SetPlayerHealth", &index) == AMX_ERR_NONE) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base); 
    AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);     

    //SWAP the addresses of the original function with my hook
    //store the original address to call it in the hook afterwards
    ::original_SetPlayerHealth = reinterpret_cast<AMX_NATIVE>(natives[index].address);
    natives[index].address = reinterpret_cast<ucell>( hook_SetPlayerHealth );

    logprintf(" SetPlayerPos found and hooked successfully!");
  } 
  else {
    logprintf(" SetPlayerHealth is not used in this script...");
  }
  return amx_Register(amx, PluginNatives, -1);
}
This works for natives... but now lets try callbacks (which are publics)
I am not an expert in the field of embedded scripting but I guess if I copy the original address of any callback and then call it in my hooked address this should work... shouldn't it?

Unfortunately the server just crashes because of an exception...
This is my code:

Hooking Callbacks (publics?)

Код:
AMX_NATIVE original_OnPlayerConnect;
cell AMX_NATIVE_CALL hooked_OnPlayerConnect(AMX *amx, cell *params) 
{
    logprintf("  ON PLAYER CONNECT called!");
    return original_OnPlayerConnect(amx, params);
}


PLUGIN_EXPORT int PLUGIN_CALL AmxLoad( AMX *amx )
{	
  int basis = 0;
  if(amx_FindPublic(amx, "OnPlayerConnect", &basis) == AMX_ERR_NONE) 
  {		
    AMX_HEADER *header = reinterpret_cast<AMX_HEADER*>( amx->base );
    AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + header->publics);
    ::original_OnPlayerConnect = reinterpret_cast< ucell >(publics[basis].address);
    publics[basis].address = reinterpret_cast<ucell>( hooked_OnPlayerConnect );
    logprintf(" Hooking event OnPlayerConnect");
  }
  else {
    logprintf(" OnPlayerConnect NOT found?!");  
  }
}
My suggestions:
  • Callbacks are much more difficult to hook than I thought
  • The type of original_OnPlayerConnect is wrong
I am totally stuck here.
Thank you for any help!
https://sampforum.blast.hk/showthread.php?tid=421090

Good luck!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)