Hi!
I just joined this community, and even though it might not seem as the most
appropriate one (I'm only doing metamod extensions, which aren't related to amxx),
but I won't deny that it is flourishing (considering GoldSrc's age of 14 years)
and this seemed as the best place to find help.
I've noticed that signature scanning is highly appreciated since it is the most efficient
and dynamic way to get full access of the modifications that GoldSrc has to offer.
In my specific case, I'm trying to learn signature scanning to be used in my
Counter-Strike extension. Right now I do not have any specific goal nor does
my extension have a purpose, but I do want to master (or at least learn) the
art of signature scanning (I hate explicit offsets
).
Right now I'm testing signature scanning with the "StartDeathCam__11CBasePlayer" call,
which obviously is: void CBasePlayer::StartDeathCam(void) from player.h@Ln:1349.
I'm using the well spread method that is documented on the alliedmodders
wiki.
The problem I am experiencing is simple, yet I have not been able to solve it. I do
my signature call (Note: I'm on linux so there's no interest for Windows atm) to find
the address of the "StartDeathCam" method.
After I've found out the position I create a pointer to the address (void (*StartDeathCam) (void*),
where as void* is a CBasePlayer pointer) which I then call in-game by user command (i.e 'say .test').
As mentioned
here, I am calling this method by simple specifying a pvPrivateData
pointer as the void* (CBasePlayer*) since the 'this' pointer is the first one to be
pushed onto the stack under GCC.
This casues an instant crash (note: I've tried to use the command under several circumstances,
such as: dead, alive, round end, freezetime etc...) with no recovery, and this is where I am stuck.
This is the code that I am using (sigscanner.h):
PHP Code:
#ifndef SIGSCANNER_H
#define SIGSCANNER_H
// Include files
#include <extdll.h>
#include "global.h" // Just contains type defines such-as unsigned char = byte etc...
class SigScanner
{
public:
// Constructor
SigScanner(void);
// Public functions
bool Init(void * pAddr); // Initialize signature scanner
void * FindSignature(byte * pSignature, size_t sigLength); // Finds a specified signature
private:
// Private variables
byte * m_baseAddr; // Base address to memory
size_t m_baseLength; // Our base address length
};
#endif
And this is the sigscanner implementation:
PHP Code:
// Header files
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
// Our class header
#include "sigscanner.h"
SigScanner::SigScanner(void)
{
// Just reset variables
m_baseAddr = null;
m_baseLength = 0;
}
bool SigScanner::Init(void * pAddr)
{
// Setup variables
Dl_info info;
struct stat buffer;
// Load our address
if(!dladdr(pAddr, &info))
return false;
if(!info.dli_fbase || !info.dli_fname)
return false;
if(stat(info.dli_fname, &buffer) != 0)
return false;
// Success, setup variables
m_baseAddr = (byte*) info.dli_fbase;
m_baseLength = buffer.st_size;
// Return...
return true;
}
void * SigScanner::FindSignature(byte * pSignature, size_t sigLength)
{
// Setup our memory pointers
byte * pBasePtr = m_baseAddr;
byte * pEndPtr = m_baseAddr + m_baseLength /* 0x100000 <-- Should this be used instead? */;
size_t i;
// Start searching memory
while(pBasePtr < pEndPtr)
{
for(i = 0; i < sigLength; i++)
{
if(pSignature[i] != 0x2A && pSignature[i] != pBasePtr[i])
break;
}
// Check for a match
if(i == sigLength/* + 1 */)
{
// Return our match
return (void*) pBasePtr;
}
// Search memory in an aligned manner
pBasePtr += sizeof(byte*);
}
// No success...
return (void*) null;
}
And this is how I use the sig-scanner implementation (read comments):
PHP Code:
// Global function pointer and type define
typedef void (*StartDeathCam)(void *);
StartDeathCam gRS = null;
void Game::EventServerActivatePost(edict_t * pEntList, int /*edictCount*/, int clientMax)
{
// Initializing some stuff first
// ...
// Here, I initialize my signature scanner (and specifies AddToFullPack as start address)
if(m_sigScanner.Init((void*) MDLL_AddToFullPack))
{
// This is the Linux signature for StartDeathCam method
char signature[] = "StartDeathCam__11CBasePlayer";
// And this is where I am fetching the function pointer (note: it is valid, i.e the logs outputs success)
StartDeathCam gRS = (StartDeathCam) m_sigScanner.FindSignature((byte*) signature, strlen(signature));
if(gRS != null)
{
m_debug->Log("We have found our signature!");
}
else m_debug->Log("Failed to find signature.");
} else m_debug->Log("Failed to initialize SigScanner.");
}
void Game::EventClientCommand(edict_t * pEnt)
{
// Sorting out all invalid objects and verifying commands
// ....
if(strcmp(command, ".test") != 0)
Meta::Return(Meta::Ignored);
// This is where I am calling the function,
// but it results in a server crash...
(gRS)(pEnt->pvPrivateData);
// Return as ignored...
Meta::Return(Meta::Ignored);
}
I'm sorry for the wall of code, but C++ code easily gets extensive.
I am also aware of the popular Orpheu module which uses signature
scanning, but it consists of _so_ much code that it is hardly extinguishable
from the rest (of the incurious code).
I do not know if I am to be expecting a reply since I presented everything
kinda sloppy, but I would appreciate any help/assistance that is offered!
EDIT: In case of interest I'm using g++ 4.6.3 @ Ubuntu 12.04 i386