IPB

Welcome Guest ( Log In | Register )

 
Reply to this topicStart new topic
> rcbot_const_mstr_offset needs updating?
JRob
post Aug 26 2015, 12:52 AM
Post #1


Advanced Member
***

Group: Members
Posts: 52
Joined: 30-April 11
Member No.: 1,970



I tried playing around with rcbot again and it keeps crashing at

CTeamControlPointRound *CTeamControlPointMaster:: getCurrentRound ()

CBaseEntity *pent = m_ControlPointRounds[m_iCurrentRoundIndex];

So I took a look at what that was and apparently, CTeamControlPointRound is found through dark hackery and the magic number at rcbot_const_mstr_offset.

Can you update this? Or also tell people how to find these offsets?
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Nightc0re
post Aug 26 2015, 11:31 PM
Post #2


Advanced Member
***

Group: Moderator
Posts: 58
Joined: 10-July 15
From: Austria
Member No.: 2,397



QUOTE(JRob @ Aug 26 2015, 02:52 AM) *

I tried playing around with rcbot again and it keeps crashing at

CTeamControlPointRound *CTeamControlPointMaster:: getCurrentRound ()

CBaseEntity *pent = m_ControlPointRounds[m_iCurrentRoundIndex];

So I took a look at what that was and apparently, CTeamControlPointRound is found through dark hackery and the magic number at rcbot_const_mstr_offset.

Can you update this? Or also tell people how to find these offsets?

I've searched and updated all offsets for Linux and Windows smile.gif
You can find the offsets in my post here.

But you also have to use my updated plugin, because the current plugin has a bug.
The "old" version is loading the offsets from the file after they where used.

So even if you are using the correct offsets, they won't get loaded in time.
In this case, the plugin is always using the hard-coded default values.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Cheeseh
post Aug 26 2015, 11:39 PM
Post #3


Admin
*****

Group: Admin
Posts: 3,018
Joined: 11-September 03
From: uk
Member No.: 1



QUOTE(JRob @ Aug 26 2015, 01:52 AM) *

I tried playing around with rcbot again and it keeps crashing at

CTeamControlPointRound *CTeamControlPointMaster:: getCurrentRound ()

CBaseEntity *pent = m_ControlPointRounds[m_iCurrentRoundIndex];

So I took a look at what that was and apparently, CTeamControlPointRound is found through dark hackery and the magic number at rcbot_const_mstr_offset.

Can you update this? Or also tell people how to find these offsets?


as far as I know there should be no problem with the offset right now

however

This is a way of finding the guts of CTeamControlPoint.

The problem is that "CBaseEntity" is difficult to use in plugins - so I avoided it completely and instead just coded in the parts of CTeamControlPoint that are useful, and instead of having several offsets I just need one for the class below: It is expanded from CBaseEntity (its subclass) so it has all that CBaseEntity crap beforehand.

Maybe a better way of doing this would be to declare a basic CBaseEntity through the engine code then do a sizeof() and just use that as the offset. OR create a CTeamControlPoint entity -- find the size doing sizeof then delete the size of only the CTeamControlPoint class without CBaseEntity from it.

CTeamControlPoint : public CBaseEntity
{
...
// USEFUL STUFF HERE
CUtlMap<int, CTeamControlPoint *> m_ControlPoints;
bool m_bFoundPoints;

CUtlVector<CTeamControlPointRound *> m_ControlPointRounds;
int m_iCurrentRoundIndex;

}

The problem is trying to find this stuff from a CBaseEntity pointer of CTeamControlPoint (unless you know of a better way)

So basically I get the start point of the CBaseEntity

CBaseEntity *pMaster

then add the offset between the start point and CUtlMap<int, CTeamControlPoint *> m_ControlPoints . which last time was 844

It's probably only moved by 4 bytes or in increments of 4

I usually debug this by running through a debugger -- changing the offset and vieweing the resulting CTeamControlPoint that I made to see if it makes sense, then just keep the offset like that

Don't have much time to explain more -- hope it's enough for now
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Nightc0re
post Aug 27 2015, 12:14 PM
Post #4


Advanced Member
***

Group: Moderator
Posts: 58
Joined: 10-July 15
From: Austria
Member No.: 2,397



QUOTE(Cheeseh @ Aug 27 2015, 01:39 AM) *
as far as I know there should be no problem with the offset right now

Regarding the offset bug, I was referring to the version 0.98.
I don't have tested the offset behaviour with 0.96 or a newer version than 0.98 smile.gif

QUOTE(Cheeseh @ Aug 27 2015, 01:39 AM) *
then add the offset between the start point and CUtlMap<int, CTeamControlPoint *> m_ControlPoints . which last time was 844
It's probably only moved by 4 bytes or in increments of 4

I usually debug this by running through a debugger -- changing the offset and vieweing the resulting CTeamControlPoint that I made to see if it makes sense, then just keep the offset like that
Don't have much time to explain more -- hope it's enough for now

I was using this little algorithm on the map "cp_dustbowl" to find the offset.

CODE

void CTeamFortress2Mod::updatePointMaster()
{
    if ( m_PointMasterResource.get() == NULL )
    {
        edict_t *pMaster = CClassInterface::FindEntityByClassnameNearest(Vector(0,0,0),"team_control_point_master",65535);

        if ( pMaster )
        {
            extern ConVar rcbot_const_point_master_offset;
            CBaseEntity *pent = pMaster->GetUnknown()->GetBaseEntity();
            unsigned long mempoint = ((unsigned long)pent)+rcbot_const_point_master_offset.GetInt();

            //m_PointMaster = (CTeamControlPointMaster*)mempoint;
            //m_PointMasterResource = pMaster;

            for (int i = 800; i < 900; ++i) {
                unsigned long mempoint = ((unsigned long)pent) + i;

                m_PointMaster = (CTeamControlPointMaster*)mempoint;
                m_PointMasterResource = pMaster;

                int idx = m_PointMaster->m_iCurrentRoundIndex;
                int size = m_PointMaster->m_ControlPointRounds.Size();

                // for cp_dustbowl
                if (idx >= 0 && size == 3) {
                    CBotGlobals::botMessage(NULL, 0, "rcbot_const_point_master_offset: %d", i);
                    break;
                }
            }
        }
    }

    if ( m_PointMaster != NULL )
    {
        m_pCurrentRound =  m_PointMaster->getCurrentRound();
    }
}


Using this method I got an offset of 864 for Linux, and 844 for Windows.
I retrieved this on 15th of July, 2015.

Have a nice day smile.gif
Best regards
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Cheeseh
post Aug 27 2015, 01:27 PM
Post #5


Admin
*****

Group: Admin
Posts: 3,018
Joined: 11-September 03
From: uk
Member No.: 1



yep I'm guessing Linux one needs updating. Cheers
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
JRob
post Aug 27 2015, 07:02 PM
Post #6


Advanced Member
***

Group: Members
Posts: 52
Joined: 30-April 11
Member No.: 1,970



QUOTE(Cheeseh @ Aug 27 2015, 01:27 PM) *

yep I'm guessing Linux one needs updating. Cheers


Surely there's an automatic way to find these offsets? Or an easier way to get the data you need from this entity?

It seems horrible that after each update, we have to load up dustbowl and HOPE that nothing else happens early in the structure happens to be 3.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Nightc0re
post Aug 29 2015, 12:52 PM
Post #7


Advanced Member
***

Group: Moderator
Posts: 58
Joined: 10-July 15
From: Austria
Member No.: 2,397



QUOTE(JRob @ Aug 27 2015, 09:02 PM) *

Surely there's an automatic way to find these offsets? Or an easier way to get the data you need from this entity?

It seems horrible that after each update, we have to load up dustbowl and HOPE that nothing else happens early in the structure happens to be 3.

This was my approach some weeks ago, but Cheeseh is using a different approach.
Look here.

Side note to Cheeseh:
You are not using this variable, was this intended?
CODE
unsigned long full_size = sizeof(pMasterEntity);

User is offlineProfile CardPM
Go to the top of the page
+Quote Post
JRob
post Aug 29 2015, 09:17 PM
Post #8


Advanced Member
***

Group: Members
Posts: 52
Joined: 30-April 11
Member No.: 1,970



QUOTE(Nightc0re @ Aug 29 2015, 12:52 PM) *

This was my approach some weeks ago, but Cheeseh is using a different approach.
Look here.

Side note to Cheeseh:
You are not using this variable, was this intended?
CODE
unsigned long full_size = sizeof(pMasterEntity);



He's not doing anything new here, he is adding a magic number to the CBaseEntity pointer.

He isn't even using sizeof(CBaseEntity). Is this even guaranteed to be the right number? The hl2sdk has some definitions for it, but the TF2 code can obviously diverge from the SDK because it was never made for people to mod TF2. If the TF2 team wants to add some extra stuff to CBaseEntity, it won't show up on the hl2sdk unless the people at AlliedMods reverse engineers it. And from what I see, they don't depend on CBaseEntity.

That's why the linux magic number increased. They might have added stuff or maybe changed compiler flags so the offset was increased.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Cheeseh
post Aug 30 2015, 05:53 AM
Post #9


Admin
*****

Group: Admin
Posts: 3,018
Joined: 11-September 03
From: uk
Member No.: 1



QUOTE(JRob @ Aug 29 2015, 10:17 PM) *

He's not doing anything new here, he is adding a magic number to the CBaseEntity pointer.

He isn't even using sizeof(CBaseEntity). Is this even guaranteed to be the right number? The hl2sdk has some definitions for it, but the TF2 code can obviously diverge from the SDK because it was never made for people to mod TF2. If the TF2 team wants to add some extra stuff to CBaseEntity, it won't show up on the hl2sdk unless the people at AlliedMods reverse engineers it. And from what I see, they don't depend on CBaseEntity.

That's why the linux magic number increased. They might have added stuff or maybe changed compiler flags so the offset was increased.


it was used as a test so it's not being used . sizeof(CBaseEntity) would be the correct way but the CBAseEntity class isn't declared in plugins - that's the problem and this is the way around it
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
JRob
post Aug 30 2015, 07:38 PM
Post #10


Advanced Member
***

Group: Members
Posts: 52
Joined: 30-April 11
Member No.: 1,970



QUOTE(Cheeseh @ Aug 30 2015, 05:53 AM) *

it was used as a test so it's not being used . sizeof(CBaseEntity) would be the correct way but the CBAseEntity class isn't declared in plugins - that's the problem and this is the way around it


How about this? You locate CTeamControlPointMaster::Spawn() which seems to have never changed, and is unlikely to change.

https://github.com/ValveSoftware/source-sdk..._master.cpp#L85

Then you scan the function for this

m_bFoundPoints = false;

Which looks like this in a dissembler.
CTeamControlPointMaster::Spawn() + 0x1A
mov byte ptr [ebx+37Ch], 0

So you know that m_bFoundPoints is located at 892. If you subtract sizeof(bool) and sizeof(CUtlMap<int, CTeamControlPoint *>), I believe you will get the size of CBaseEntity.

This method should work for other classes based on CBaseEntity and maybe there is an easier one to use. It could be automated and more robust than the current method.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Cheeseh
post Aug 31 2015, 03:42 AM
Post #11


Admin
*****

Group: Admin
Posts: 3,018
Joined: 11-September 03
From: uk
Member No.: 1



this is one way but will need the signature for CTeamControlPointMaster::Spawn() (which might actually include mov byte ptr [ebx+37Ch], 0) in which case it would be redundant to find it this way. you'd need to find a signature at the end of the previous function. Unless it can be found via the virtual pointer - i'll check this at home
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
JRob
post Aug 31 2015, 06:39 PM
Post #12


Advanced Member
***

Group: Members
Posts: 52
Joined: 30-April 11
Member No.: 1,970



QUOTE(Cheeseh @ Aug 31 2015, 03:42 AM) *

this is one way but will need the signature for CTeamControlPointMaster::Spawn() (which might actually include mov byte ptr [ebx+37Ch], 0) in which case it would be redundant to find it this way. you'd need to find a signature at the end of the previous function. Unless it can be found via the virtual pointer - i'll check this at home


I don't know what signature finding code you use, but it should allow you to have wildcard bytes.

So it shouldn't matter if the front of the function has dynamic addresses.

Also, this probably isn't of much concern to you since you develop on Windows, but on Linux, symbols are not stripped and you can locate functions by their symbol names which is why I like hosting TF2 on Linux so much.

Here is my attempt at a signature. It happens to have no wildcard parts and succeeds in locating only that function.

55 89 E5 53 83 EC 24 8B 5D 08 8B 03 89 1C 24 FF 50

.text:00BAAE30 push ebp
.text:00BAAE31 mov ebp, esp
.text:00BAAE33 push ebx
.text:00BAAE34 sub esp, 24h
.text:00BAAE37 mov ebx, [ebp+this]
.text:00BAAE3A mov eax, [ebx]
.text:00BAAE3C mov [esp], ebx
.text:00BAAE3F call dword ptr [eax+60h]

The signature ends before the +60h at the end which could possibly change. However it assumes that the number of local variables doesn't change which I think is a fairly safe assumption, but you could probably make that part a wildcard too.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
JRob
post Sep 11 2015, 10:55 PM
Post #13


Advanced Member
***

Group: Members
Posts: 52
Joined: 30-April 11
Member No.: 1,970



Any update on this? I am starting to add it myself.

I noticed that you ripped out the sig scanning code from sourcemod, but you removed the symbol resolving code. It looks like you have some parts of it, but it doesn't work.

You can easily get this functionality with just 3 files.

https://github.com/alliedmodders/sourcemod/...MemoryUtils.cpp
https://github.com/alliedmodders/sourcemod/...k/MemoryUtils.h
https://github.com/alliedmodders/sourcemod/...k/sm_symtable.h

You need to edit MemoryUtils.h and remove "using namespace SourceMod" and add

#if defined __linux__
#define PLATFORM_LINUX
#endif

And done...

CODE


    MemoryUtils* sigscan = new MemoryUtils;
    void* server = dlopen("tf/bin/server_srv.so", RTLD_LAZY);
    dlclose(server);
    
#ifdef __linux__
    char* CTeamControlPointMaster_Spawn = (char*)sigscan->ResolveSymbol(server, "_ZN23CTeamControlPointMaster5SpawnEv");
#endif

    if(CTeamControlPointMaster_Spawn)
    {
        int CBaseEntityLength = *(int*)(CTeamControlPointMaster_Spawn + 0x1A) - sizeof(CUtlMap<int, CBaseEntity *>);
        rcbot_const_point_master_offset.SetValue(CBaseEntityLength);
    }
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Cheeseh
post Oct 3 2015, 01:42 PM
Post #14


Admin
*****

Group: Admin
Posts: 3,018
Joined: 11-September 03
From: uk
Member No.: 1



I made a sigscan class which is included and works

bot_sigscan.h
CODE

class CSignatureFunction
{
public:
    CSignatureFunction() { m_func = 0x0; }
private:
    size_t decodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr);

    bool getLibraryInfo(const void *libPtr, DynLibInfo &lib);

    void *findPattern(const void *libPtr, const char *pattern, size_t len);

    void *findSignature ( void *addrInBase, const char *signature );
protected:
    void findFunc ( CRCBotKeyValueList *kv, const char *pKey, void *pAddrBase, const char *defaultsig );

    void *m_func;
};

// Examples
class CGameRulesObject : public CSignatureFunction
{
public:
    CGameRulesObject(CRCBotKeyValueList *list, void *pAddrBase);

    bool found() { return m_func != NULL; }

    void **getGameRules() { return reinterpret_cast<void **>(m_func); }
};

CGameRulesObject::CGameRulesObject(CRCBotKeyValueList *list, void *pAddrBase)
{
#ifdef _WIN32
    m_func = NULL;
#else
    findFunc(list, "g_pGameRules", pAddrBase, "@g_pGameRules");
#endif
}

void CSignatureFunction :: findFunc ( CRCBotKeyValueList *kv, const char*pKey, void *pAddrBase, const char *defaultsig )
{
    char *sig = NULL;

    if ( kv->getString(pKey,&sig) && sig )
        m_func = findSignature(pAddrBase,sig);
    else
        m_func = findSignature(pAddrBase,defaultsig);
}

// Sourcemod - Metamod - Allied Modders.net
void *CSignatureFunction::findSignature ( void *addrInBase, const char *signature )
{
    // First, preprocess the signature
    unsigned char real_sig[511];

    size_t real_bytes;

    real_bytes = decodeHexString(real_sig, sizeof(real_sig), signature);

    if (real_bytes >= 1)
    {
        return findPattern(addrInBase, (char*) real_sig, real_bytes);
    }

    return NULL;
}


CODE

CGameRulesObject *g_pGameRules_Obj;
...
g_pGameRules_Obj = new CGameRulesObject(pKVL, gameServerFactory);


I'll translate it into using this class for next version, cheers

PS , got a signature for windows?
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
JRob
post Oct 20 2015, 01:08 AM
Post #15


Advanced Member
***

Group: Members
Posts: 52
Joined: 30-April 11
Member No.: 1,970



Unless you changed it recently, the sigscan class you have doesn't resolve linux symbols which never change and is much better than a sigscan.

The Windows signature I presume would be the same one as the Linux sig scan I proposed earlier.

QUOTE(Cheeseh @ Oct 3 2015, 01:42 PM) *

I made a sigscan class which is included and works

bot_sigscan.h
CODE

class CSignatureFunction
{
public:
    CSignatureFunction() { m_func = 0x0; }
private:
    size_t decodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr);

    bool getLibraryInfo(const void *libPtr, DynLibInfo &lib);

    void *findPattern(const void *libPtr, const char *pattern, size_t len);

    void *findSignature ( void *addrInBase, const char *signature );
protected:
    void findFunc ( CRCBotKeyValueList *kv, const char *pKey, void *pAddrBase, const char *defaultsig );

    void *m_func;
};

// Examples
class CGameRulesObject : public CSignatureFunction
{
public:
    CGameRulesObject(CRCBotKeyValueList *list, void *pAddrBase);

    bool found() { return m_func != NULL; }

    void **getGameRules() { return reinterpret_cast<void **>(m_func); }
};

CGameRulesObject::CGameRulesObject(CRCBotKeyValueList *list, void *pAddrBase)
{
#ifdef _WIN32
    m_func = NULL;
#else
    findFunc(list, "g_pGameRules", pAddrBase, "@g_pGameRules");
#endif
}

void CSignatureFunction :: findFunc ( CRCBotKeyValueList *kv, const char*pKey, void *pAddrBase, const char *defaultsig )
{
    char *sig = NULL;

    if ( kv->getString(pKey,&sig) && sig )
        m_func = findSignature(pAddrBase,sig);
    else
        m_func = findSignature(pAddrBase,defaultsig);
}

// Sourcemod - Metamod - Allied Modders.net
void *CSignatureFunction::findSignature ( void *addrInBase, const char *signature )
{
    // First, preprocess the signature
    unsigned char real_sig[511];

    size_t real_bytes;

    real_bytes = decodeHexString(real_sig, sizeof(real_sig), signature);

    if (real_bytes >= 1)
    {
        return findPattern(addrInBase, (char*) real_sig, real_bytes);
    }

    return NULL;
}


CODE

CGameRulesObject *g_pGameRules_Obj;
...
g_pGameRules_Obj = new CGameRulesObject(pKVL, gameServerFactory);


I'll translate it into using this class for next version, cheers

PS , got a signature for windows?

User is offlineProfile CardPM
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 User(s) are reading this topic (2 Guests and 0 Anonymous Users)
0 Members:

 



- Lo-Fi Version Time is now: 16th December 2019 - 02:06 PM