The art of signature scanning
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 :nono:). 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:
PHP Code:
PHP Code:
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 |
Re: The art of signature scanning
Fellow, when you got a symbolic name like StartDeathCam__11CBasePlayer you don't want to find it in memory like you do for signature scanning. Signature scanning is to find bytes that represent processor instructions. The symbolic names are "mapped" to the addresses they represent with GetProcAddress in windows and dlsym in unix or linux or posix or whatever. Check the file library.cpp that you can find in the sources for the Rage module.
Edit: one thing you should get used to do is to play around with dlls and so's in IDA so you can see more of how a library is made on the inside. In this case, what you should have done to understand you were doing it wrong would be: In IDA checking the offset of CBasePlayer::StartDeathCam which is straightforward just a matter of browsing the code. In your code doing something like Code:
long offset = (long) gRS - (long) sigScanner.m_baseAddr; |
Re: The art of signature scanning
Aaa, yes! I noticed my mistake. I can't believe I was so stupid. But in that case,
I must ask, when do you want to use signature scanning? Is it only of interest when using windows? Since all executables/libraries have the symbols provided with them in Linux (which in turn means that dlsym will always find them)? I must say though, that this could not be a more interesting subject for me right now. I've just implemented a detour, and have caught InstallGameRules event (with pre-post hook), now I'm just trying to figure out how to use this class pointer it returns:) EDIT: call a function which takes a CBasePlayer pointer as an argument, should I provide an edict_t pointer or the pvPrivateData pointer? Haha, just hooked RoundRespawn and tried to call it with pvPrivateData. Couldn't have gone smoother! |
Re: The art of signature scanning
Quote:
InstallGameRules creates the global CHalfLifeMultiplay object. With it you can: call and hook its virtual functions with simple direct code just with their offsets in the virtual table call and hook its non virtual functions with signature scanning and more complicated hooking. Change its data. For example with this i'm modifing the object field named m_iUnBalancedRounds to make round balancing happen every round. About the last question you should provide the pointer pvPrivateData since that is a CBasePlayer* in the case of a player and is you are expected to pass it when you call a class member function. One thing you must be aware is that to call class member functions (classes that are non static and belong to a class) the convention call you must use is thiscall that is much different from windows to linux and therefore will force you to create different code to handle it with some ifdefs. |
Re: The art of signature scanning
Quote:
the CGameRules class by using 'fake' structure pointers which works perfect! Right now it looks something like this: PHP Code:
of the offets (and what they do)? I take it for granted that you haven't come up with these names by yourself? Currently I'm designing this structure from the file 'CGameOffsets' supplied in Arkshine's plugin "Round Terminator". This is because I have no idea myself, how to find these offets and _especially_ what they do (the name often describes that). About the _thiscall convention, it's a breeze for me. Since I'm only programming for linux, it's the GCC calling convention, which means no push to the ecx registry or anything, just use it as a first argument! Awesome :) Perhaps I should tell Arkshine this myself, but you also seem to have a lot of knowledge on the subject. In his CGameOffset file (supplied in the zip file here), a LOT of different offsets are specified, although I believe one of the offsets is incorrect (or around ~4 of them). According to the file, the variable (remember I'm talking linux offets here) m_flRequiredEscapeRatio is at offset 164 (and it's a long, or well a float, but it's still 4 bytes). This means that it takes up space for offsets 164-168 (4 bytes), but the adjacent offset specified, m_iNumEscapers, is at offset 166, which makes no sense, unless there is some low/upper bit computations behind the scene (which still makes no sense since its a float), it should be invalid. Which also (might) mean that all the offsets 'below' this one, is also invalid (i.e m_iHaveEscaped and m_pVIP). However I would appreciate it a lot if you could briefly explain how to find these member offsets (and their types, and names). EDIT: After further analyzing, it's pretty obvious m_iNumEscapers is at offset 168, not 166... EDIT 2: Another question I have is about CBasePlayer*. Let's take CGameRules as an example. It contains the member m_pVIP, which is a CBasePlayer pointer. If I want to, for example, find out the players name or fetch his entity (edict_t) how would I proceed? Normally one would just do STRING(m_pVIP->v.netname), but I have no insight/knowledge on how the CBasePlayer structure is? One way would be too loop all players entites, and check if their pvPrivateData matches the CBasePlayer address, but that isn't efficient... If I look here at the partial source code (player.cpp) it seems as if pev is a member structure (which obviously is an edict_t pointer). If that is true, I only need to find the offset of this structure (in CBasePlayer*), but how does one do that? |
Re: The art of signature scanning
Quote:
Quote:
Quote:
Quote:
|
Re: The art of signature scanning
Quote:
on a CBasePlayer entity, although I had no success. Since it is the 'first' variable, it should be at offset zero, right? Or perhaps some differentiation ~4 bytes. I had no success though. Trying to find out the offset, I used this code (it's rough I know, but its fast) PHP Code:
is stored in, is protected (which would require a call to mprotect), or the offset is completely wrong. Since you've written/found out about _tons_ of offsets, do you perhaps know the offset of the 'pev' member variable? NOTE: For the first 5 values, the fields were all empty (the netname returned an empty string). EDIT: Ops, the CBaseEntity is obviously not a pod structure, which means offset 0 is probably invalid. I'll try to find it using IDA I guess. EDIT2: I'd also like to ask, how exact do you estimate your CS-SDK is compared to the original? For example; it would be awesome if one could just cast the pvPrivateData to CBasePlayer (which you've both defined and declared in the CS-SDK). Obviously the implementations might be wrong, but the declarations in the header files (variables, function headers etc.)? |
Re: The art of signature scanning
PHP Code:
|
Re: The art of signature scanning
Quote:
requires more thorough explanation); is that really necessary? I didn't know about the edict_t pContainaingEntity member variable, but now that I do, I have no problems what so ever! I've just defined a simple CBasePlayer structure (which I convert pvPrivateData to) and access the entvars directly. For example: Code:
((CBasePlayer*)pEnt->pvPrivateData)->pev->pContainaingEntity more extensive, is there a reason behind it? Or why haven't you just called entvars directly to access pContainingEntity? Thanks so much for all help btw! NOTE: Judging by the code, is the pev offset dynamic? If that's the case, it doesn't make any sense? A structure can't be dynamic, entvars_t will always be at offset zero in the CBasePlayer structure, it's the nature of C(++)... EDIT: Perhaps it's mod specific? |
Re: The art of signature scanning
Quote:
Code:
@section cstrike linux |
All times are GMT -4. The time now is 14:38. |
Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.