Results 1 to 5 of 5
  1. #1
    Ch40zz-C0d3r's Avatar
    Join Date
    Apr 2011
    Gender
    male
    Posts
    831
    Reputation
    44
    Thanks
    401
    My Mood
    Twisted

    Getting Local Player Index Help

    Anyone know why i can't get my local player's index correctly, here is the function in ida.

    Code:
    int __cdecl GetLocalPlayerIndex()
    {
      int result; // eax@1
      int v1; // esi@1
      int v2; // ecx@1
    
      v1 = v2;
      result = sub_B4B9450(*(_BYTE *)(v2 + 30020));
      if ( (_BYTE)result )
        LOBYTE(result) = *(_BYTE *)(2032 * *(_BYTE *)(v1 + 30020) + v1 + 30028);
      else
        LOBYTE(result) = -1;
      return result;
    }
    Followed v1 and v2, v1 is set = to v2, then i followed ecx and ecx is our ClientShell address. Currently im using: (cshell is base address)
    Code:
    cshll + 0x7778C0
    To get ClientShell address.

    Then to get my local player index here is my code:


    This is sub_B4B9450, it normally returns a bool checking if this value is <= 0xF or 15. But i only care about getting the number of players in my game.

    Code:
    BYTE GetNumPlayers(DWORD dw_ClientShell)
    {
    	if(!dw_ClientShell)
    		return -1;
    
    	//*(_BYTE *)(v2 + 30020)
    	return *(BYTE*)(dw_ClientShell + dwPlayerStart);
    }
    Then this is how im calculating my local index:

    Yes it returns a char, look at function in IDA. It Generates it as an int, but it returns a char. 0-15 in decimal if u want to convert it.

    Code:
    char GetLocalIndex(DWORD dw_ClientShell)
    {
    	if(!dw_ClientShell)
    		return -1;
    
    	if(GetNumPlayers(dw_ClientShell) ==  -1)
    		return -1;
    
    	// *(_BYTE *)(2032 * *(_BYTE *)(v1 + 30020) + v1 + 30028)
    	if(GetNumPlayers(dw_ClientShell) <= 15)
    		return *(char*)(dwPlayerSize/*2032 0x7F0*/ * *(BYTE*)(dw_ClientShell/*v1*/ + dwPlayerStart/*30020 0x7544*/)/*same as bClient*/ + dw_ClientShell/*v1*/  + dwLocalPlayerOffset/*30028 0x754C*/);
    
    	return -1;
    }
    Keeps returning an invalid index such as random high numbers, and such. GetNumPlayers keeps returning 0..

    Not sure why, tried to find it a million times but couldnt
    Thanks in advance

    Progress with my game - "Disbanded"
    • Fixed FPS lag on spawning entities due to the ent_preload buffer!
    • Edit the AI code to get some better pathfinding
    • Fixed the view bug within the sniper scope view. The mirror entity is invisible now!
    • Added a new silencer for ALL weapons. Also fixed the rotation bugs
    • Added a ton of new weapons and the choice to choose a silencer for every weapon
    • Created a simple AntiCheat, noobs will cry like hell xD
    • The name will be Disbanded, the alpha starts on the 18th august 2014



    Some new physics fun (Serversided, works on every client)



    My new AI
    https://www.youtube.com/watch?v=EMSB1GbBVl8

    And for sure my 8 months old gameplay with 2 friends
    https://www.youtube.com/watch?v=Na2kUdu4d_k

  2. The Following User Says Thank You to Ch40zz-C0d3r For This Useful Post:

    NutJob69 (09-12-2014)

  3. #2
    luizimloko's Avatar
    Join Date
    Feb 2011
    Gender
    male
    Location
    fs:[0]
    Posts
    1,879
    Reputation
    136
    Thanks
    10,137
    My Mood
    Yeehaw
    @Ch40zz-C0d3r

    Code:
    #define GetPlayerByIndex( dwLTClientShell, dwID ) ( CPlayer * )( dwLTClientShell + ( dwID * PlayerSize ) + PlayerStart )
    
    CHAR GetLocalIndex( DWORD Index )
    {
    	if( Index )
    	{
    		BYTE Clients = *( BYTE * )( Index + PlayerStart );
    
    		if( Clients < 16 )
    			return *(CHAR *)( Index + Clients * PlayerSize + MeOffset );
    	}
    
    	return -1;
    }
    
    VOID CESP::UpdateCharacters(VOID)
    {
    	engine->pLocal = GetPlayerByIndex( engine->ClientBase, GetMyIndex( engine->ClientBase ) );
    
    	for( INT i = 0; i <= 16; i++ )
    		engine->Players[ i ].pPlayer = GetPlayerByIndex( engine->ClientBase, i );
    }
    
    //ESP...
    
    for( INT i = 0; i <= 16; i++ )
    	{
    		if( IsValidClient( engine->Players[ i ].pPlayer) && engine->Players[ i ].pPlayer->ClientID != engine->pLocal->ClientID )
    		{
    //...
    Last edited by luizimloko; 09-12-2014 at 06:12 PM.

  4. The Following 2 Users Say Thank You to luizimloko For This Useful Post:

    Ch40zz-C0d3r (09-13-2014),Rullez (09-15-2014)

  5. #3
    NutJob69's Avatar
    Join Date
    Sep 2014
    Gender
    male
    Posts
    4
    Reputation
    10
    Thanks
    0
    Quote Originally Posted by luizimloko View Post
    @Ch40zz-C0d3r

    Code:
    #define GetPlayerByIndex( dwLTClientShell, dwID ) ( CPlayer * )( dwLTClientShell + ( dwID * PlayerSize ) + PlayerStart )
    
    CHAR GetLocalIndex( DWORD Index )
    {
    	if( Index )
    	{
    		BYTE Clients = *( BYTE * )( Index + PlayerStart );
    
    		if( Clients < 16 )
    			return *(CHAR *)( Index + Clients * PlayerSize + MeOffset );
    	}
    
    	return -1;
    }
    
    VOID CESP::UpdateCharacters(VOID)
    {
    	engine->pLocal = GetPlayerByIndex( engine->ClientBase, GetMyIndex( engine->ClientBase ) );
    
    	for( INT i = 0; i <= 16; i++ )
    		engine->Players[ i ].pPlayer = GetPlayerByIndex( engine->ClientBase, i );
    }
    
    //ESP...
    
    for( INT i = 0; i <= 16; i++ )
    	{
    		if( IsValidClient( engine->Players[ i ].pPlayer) && engine->Players[ i ].pPlayer->ClientID != engine->pLocal->ClientID )
    		{
    //...
    Still same error, seems that ClientShell address is returning an invalid pointer and crashing the game. In Na the clientshell address is at cshell base + 0x7778C0, thats the pointer to it - and the pointer to that is to the vtable. Any ideas?

  6. #4
    luizimloko's Avatar
    Join Date
    Feb 2011
    Gender
    male
    Location
    fs:[0]
    Posts
    1,879
    Reputation
    136
    Thanks
    10,137
    My Mood
    Yeehaw
    Quote Originally Posted by NutJob69 View Post
    Still same error, seems that ClientShell address is returning an invalid pointer and crashing the game. In Na the clientshell address is at cshell base + 0x7778C0, thats the pointer to it - and the pointer to that is to the vtable. Any ideas?
    LTClientShell = LTClient + 0x0C , make sure that your address are right

  7. The Following 2 Users Say Thank You to luizimloko For This Useful Post:

    Ch40zz-C0d3r (09-13-2014),NutJob69 (09-12-2014)

  8. #5
    giniyat101's Avatar
    Join Date
    Sep 2011
    Gender
    male
    Location
    Not telling.
    Posts
    1,935
    Reputation
    130
    Thanks
    1,380
    My Mood
    Dead
    use ida features carefully to correctly reverse the function
    here is a step-by-step guide : (iam using a very old version of cshell.dll found here)

    lets check the same function in this old cshell.dll :

    Code:
    int __cdecl sub_1001EF50()
    {
      int v1; // ecx@0
      int v2; // esi@1
      int result; // eax@1
    
      v2 = v1;
      if ( sub_10148B80(*(_BYTE *)(v1 + 29636)) )
        LOBYTE(result) = *(_BYTE *)(1056 * *(_BYTE *)(v2 + 29636) + v2 + 29644);
      else
        LOBYTE(result) = -1;
      return result;
    }
    the first line is confusing because v1 is used without being initalized :
    Code:
    v2 = v1;
    but checking v1 declaration :
    Code:
    int v1; // ecx@0
    its passed to the function on ecx, which means the function is actually __thiscall (not __cdecl as stated)
    correct the mistake by right clicking on the function name and selecting "Set item type"
    also add a parameter "this"..
    now it should look like this:
    Code:
    int __thiscall sub_1001EF50(int this)
    for better code viewing, rename v2 to this2.

    now we have this line :
    Code:
    if ( sub_10148B80(*(_BYTE *)(this + 29636)) )
    lets split this one to several parts :

    Code:
    if ( sub_10148B80(...) )
    follow this function and check if it has something to offet:
    Code:
    char __cdecl sub_10148B80(unsigned int a1)
    {
      return a1 <= 15;
    }
    it seems to check if its parameter is less than or equal 15, lets keep this in mind for now.

    Code:
    (this + 29636)
    this one points to a member of the class at offset 29636.

    Code:
    *(_BYTE *)
    this one dereferences the pointer, and the member appears to have the type of _BYTE (which is equivalent to unsigned char).

    its time to tell ida about the new member..
    since ida doesn't have support to c++, we are going to create a c struct instead.
    press SHIFT+F1 to open "Local Types" subview,
    now right click somewhere and select "Insert..."
    and add this struct declaration :
    Code:
    struct mystruct
    {
        char _reserved0[29636];
        unsigned char m_byte1;
        char _align0[3];
        char _reservedn[1000000];
    };
    the member _reserved0 isn't real, its only there to force the compiler to put the next member (i.e m_byte1) in the correct offset,
    which is 29636 in this case..
    and _align0 isn't real either, but is put to maintain a struct alignment of 4.
    and member _reservedn is inserted to make sure our new struct has ATLEAST the size of original class.
    you might want to configure default align by selecting "Options->Compiler..."

    now return to pseudecode subview and change type of this and this2 from int to mystruct* and check the difference :
    Code:
    int __thiscall sub_1001EF50(mystruct *this)
    {
      mystruct *this2; // esi@1
      int result; // eax@1
    
      this2 = this;
      if ( sub_10148B80(this->m_byte1) )
        LOBYTE(result) = this2->_reservedn[1056 * this2->m_byte1 + 4];
      else
        LOBYTE(result) = -1;
      return result;
    }
    now we have this part :
    Code:
    LOBYTE(result)
    it stats that the right hand side has the type of char (or unsigned char)
    but there is a second one two lines after, and the right hand side is a negative value
    so its clear that this->_reservedn[n] has the type of signed char.

    the problem now is with this part :
    Code:
    this2->_reservedn[1056 * this2->m_byte1 + 4];
    notice the appearance of this pattern :
    Code:
    x * y + z
    this usually identify an array where :
    x is the size of each element, y is the index (or viseverse)
    z is the offset

    so we have an array of some type with size of 1056 starting at offset 4 from _reservedn.
    and this array has 16 elements, this explains why m_byte1 is checked first.
    we will have to create another struct with size of 1056 and its first member with type of char
    so create it now:
    Code:
    struct mysecondstruct
    {
        char m_char1;
        char _align0[3];
        char _reserved0[1052];
    };
    again, _align0 is there to keep struct alignment and _reserved0 to make proper struct size of 1056.

    modify mystruct (right click on it and select "Edit...") so it contain the array :
    Code:
    struct mystruct
    {
        char _reserved0[29636];
        unsigned char m_byte1;
        char _align0[3];
        char _reserved1[4];
        struct mysecondstruct m_second[16];
        char _reservedn[1000000];
    };
    notice how we pushed _reservedn down and placed a new placeholder in its location.

    now close the pseudecode subview and re-disassemble the same function :
    Code:
    int __thiscall sub_1001EF50(mystruct *this)
    {
      mystruct *this2; // esi@1
      int result; // eax@1
    
      this2 = this;
      if ( sub_10148B80(this->m_byte1) )
        LOBYTE(result) = this2->m_second[this2->m_byte1].m_char1;
      else
        LOBYTE(result) = -1;
      return result;
    }
    one last thing to do is to trace "this" pointer.. now you know it points to CLTClientShell.
    now the function is decompiled, but the names we used are not very friendly, so we will rename them after moving to c++ :
    Code:
    class CLTClientShell
    {
    public:
        char _reserved0[29636];
        unsigned char m_iLocalPlayerIndex;
        char _align0[3];
        char _reserved1[4];
        struct PLAYER m_Player[16];
    public:
        int GetLocalPlayerIndex();
    };
    Code:
    struct PLAYER
    {
        char m_iIndex;
        char _align0[3];
        char _reserved0[1052];
    };
    Code:
    bool IsValidPlayerIndex(int index)
    {
        return index <= 15;
    }
    
    int CLTClientShell::GetLocalPlayerIndex()
    {
        int result;
        if ( IsValidPlayerIndex(m_iLocalPlayerIndex) )
            result = m_Player[m_iLocalPlayerIndex].m_iIndex;
        else
            result = -1;
        return result;
    }
    note how _reservedn was stripped in the c++ version, as it is no longer needed.
    also, its safe to remove _align[] members as the compiler can handle this job.

    at last, iam sorry for using an old cshell, but i have uninstalled the game long time ago.
    if you still have any questions, feel free to contact me.
    regards.
    Last edited by giniyat101; 09-16-2014 at 06:44 AM.


     



    [img]https://i43.photobucke*****m/albums/e367/DeteSting/Steam-update.gif[/img]

  9. The Following User Says Thank You to giniyat101 For This Useful Post:

    jeroldcamacho (09-16-2014)

Similar Threads

  1. [Help Request] Get the Players in the lobby
    By Anonymous222 in forum Call of Duty Modern Warfare 3 Coding, Programming & Source Code
    Replies: 5
    Last Post: 07-24-2012, 08:49 AM
  2. [Help Request] Getting the players team
    By edub18 in forum Call of Duty Modern Warfare 3 Help
    Replies: 2
    Last Post: 02-14-2012, 03:53 AM
  3. [Help Request] How to get a chargeback. Please help.
    By smart_brian in forum CrossFire Help
    Replies: 8
    Last Post: 08-26-2011, 05:17 PM
  4. [HELP] How do i find Local Player Pointer?
    By klofee in forum Combat Arms Hack Coding / Programming / Source Code
    Replies: 6
    Last Post: 09-20-2010, 04:44 PM
  5. [AssaultCube]Get local player entity
    By Retoxified in forum C++/C Programming
    Replies: 1
    Last Post: 04-04-2010, 10:24 PM