Project 1999

Go Back   Project 1999 > Blue Community > Blue Server Chat

Closed Thread
 
Thread Tools Display Modes
  #61  
Old 09-30-2019, 01:03 PM
Rogean Rogean is offline
¯\_(ツ)_/¯

Rogean's Avatar

Join Date: Oct 2009
Location: Massachusetts
Posts: 5,393
Default

Quote:
Originally Posted by Castamere [You must be logged in to view images. Log in or Register.]
Sure took long enough to implement. To me, that time passed was enough for me to believe staff wasn't as concerned about some of the smaller details. Time has proven me wrong.
Frankly this argument annoys me. You guys underestimate the difficulty of client side changes. We don't have access to Client source code. We have very limited dissassembly skillsets, and occasionally we rely on pseudocode. Haynar is better than I am at finding specific memory addresses and offsets, and I'm somewhat decent at finding/following code paths for functions to hook and modify their arguments and/or return values. Secrets is better than both of us at anything related to dissassembly, but often too busy to help us.

The Client psuedocode is 468,710 lines of code long, and most of it looks a lot like this:

Code:
//----- (0041ACE9) --------------------------------------------------------
signed int __thiscall sub_41ACE9(_DWORD *this, unsigned int a2)
{
  _DWORD *v2; // esi
  int v3; // edx
  int v4; // eax
  int v5; // edi
  signed int v6; // ebx
  int v7; // edi
  int v8; // eax
  int v9; // edi
  int v10; // eax
  int v11; // eax
  int v12; // eax
  int v13; // eax
  int v14; // edi
  char v15; // al
  int v16; // eax
  signed int v17; // ecx
  int v18; // eax
  int v19; // ebx
  signed int v20; // edi
  _DWORD *v21; // eax
  _DWORD *v22; // eax
  int v23; // eax
  int v24; // eax
  int v25; // edi
  int v26; // eax
  signed int v28; // [esp+Ch] [ebp-4h]
  _DWORD *v29; // [esp+Ch] [ebp-4h]

  v2 = this;
  v28 = sub_40E722((_DWORD *)((char *)this + *(_DWORD *)(this[1] + 4) + 4), a2);
  v4 = v2[2];
  if ( v4
    && !*(_BYTE *)(v4 + 580)
    && !*(_BYTE *)(v4 + 598)
    && !sub_4167E2((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4)) )
  {
    v29 = (_DWORD *)(*(int (**)(void))(*(_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4) + 64))();
    v5 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
    v6 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
    if ( v6 < (unsigned __int8)sub_5ED510(v29) )
    {
      v7 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
      if ( (unsigned __int8)sub_5ED510(v29) >= v7 + 2 )
        v5 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516) + 2;
      else
        v5 = (unsigned __int8)sub_5ED510(v29);
    }
    v8 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
    v9 = sub_44A448(v5, *(unsigned __int8 *)(v8 + 4508), a2, (int)v29);
    if ( sub_40E722((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), a2) < v9 )
      v9 = sub_40E722((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), a2);
    v10 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
    v11 = sub_4184F4(v2, a2, *(_DWORD *)(v10 + 4504));
    v28 = v9;
    if ( v9 <= v11 )
      v28 = v11;
  }
  v12 = v2[2];
  if ( v12 )
  {
    if ( !*(_BYTE *)(v12 + 580) )
    {
      v13 = sub_40E934((int)v2, v3, 122, 0);
      v14 = v13;
      if ( v13 )
      {
        sub_44D0D0(*(_DWORD *)(v13 + 4));
        if ( v15 )
        {
          sub_40CBD6(*(_DWORD *)(v14 + 4));
          if ( v16 )
          {
            if ( *(_DWORD *)(v16 + 48) == a2 )
            {
              v17 = *(_DWORD *)(v16 + 240);
              if ( v17 > 0 && v17 < 101 )
                v28 = v28 * (100 - v17) / 100;
            }
          }
        }
      }
    }
  }
  v18 = v2[2];
  v19 = 0;
  if ( v18 && !*(_BYTE *)(v18 + 580) )
  {
    v20 = 0;
    do
    {
      if ( sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20) )
      {
        v21 = (_DWORD *)sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20);
        if ( !sub_5ECCC0(v21) )
        {
          v22 = (_DWORD *)sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20);
          v23 = sub_5E3210(v22, a2, v28, 1);
          if ( v23 )
          {
            if ( v23 > v19 )
              v19 = v23;
          }
        }
      }
      ++v20;
    }
    while ( v20 < 22 );
    if ( v19 )
      v28 += v19;
    if ( a2 == 35 )
    {
      if ( *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 136) )
      {
        v24 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
        v25 = sub_5E3210(*(_DWORD **)(v24 + 136), 35, v28, 1);
        v26 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
        if ( sub_5ECC00(*(_DWORD **)(v26 + 136)) == 12 )
        {
          if ( v25 )
            v28 += v25;
        }
      }
    }
  }
  if ( v28 > 252 && sub_44A273(a2) )
    v28 = 252;
  return v28;
}
// 40CBD6: using guessed type double __stdcall sub_40CBD6(_DWORD);
// 44D0D0: using guessed type double __cdecl sub_44D0D0(_DWORD);
Now, the function I just listed above is a good example, because it handles the client's visual display of the values of skills in the skill window. In this function, it's handling a lot of processing on those values to check various caps based on class and skill ID, which it really should have no reason to do because we just want it to display what the server tells us it is.

So, we hook it. Hooking is essentially rewriting the running code in memory at the location of this function to do a JMP (Jump/Detour) to our own custom function. At which point we access the Skill Value directly, using a global client pointer to the character's data, and return it:

Code:
signed int	CHooks::SkillCapCheck2_Detour(unsigned int a1) {
	return ((CharData2 *)((*(CharData **)0x905D00)->ExtendedData->pCharData2))->Skill[a1];
}
And this is actually one of the easier examples.
__________________
Sean "Rogean" Norton
Project 1999 Co-Manager

Project 1999 Setup Guide
  #62  
Old 09-30-2019, 01:07 PM
Chortles Snort|eS Chortles Snort|eS is offline
Banned


Join Date: Aug 2019
Location: GuK
Posts: 735
Default

u sure know how to stir up the geriatric playerS RoG doG
  #63  
Old 09-30-2019, 01:08 PM
Castamere Castamere is offline
Fire Giant


Join Date: Jul 2014
Posts: 522
Default

Quote:
Originally Posted by Rogean [You must be logged in to view images. Log in or Register.]
Frankly this argument annoys me. You guys underestimate the difficulty of client side changes. We don't have access to Client source code. We have very limited dissassembly skillsets, and occasionally we rely on pseudocode. Haynar is better than I am at finding specific memory addresses and offsets, and I'm somewhat decent at finding/following code paths for functions to hook and modify their arguments and/or return values. Secrets is better than both of us at anything related to dissassembly, but often too busy to help us.

The Client psuedocode is 468,710 lines of code long, and most of it looks a lot like this:

Code:
//----- (0041ACE9) --------------------------------------------------------
signed int __thiscall sub_41ACE9(_DWORD *this, unsigned int a2)
{
  _DWORD *v2; // esi
  int v3; // edx
  int v4; // eax
  int v5; // edi
  signed int v6; // ebx
  int v7; // edi
  int v8; // eax
  int v9; // edi
  int v10; // eax
  int v11; // eax
  int v12; // eax
  int v13; // eax
  int v14; // edi
  char v15; // al
  int v16; // eax
  signed int v17; // ecx
  int v18; // eax
  int v19; // ebx
  signed int v20; // edi
  _DWORD *v21; // eax
  _DWORD *v22; // eax
  int v23; // eax
  int v24; // eax
  int v25; // edi
  int v26; // eax
  signed int v28; // [esp+Ch] [ebp-4h]
  _DWORD *v29; // [esp+Ch] [ebp-4h]

  v2 = this;
  v28 = sub_40E722((_DWORD *)((char *)this + *(_DWORD *)(this[1] + 4) + 4), a2);
  v4 = v2[2];
  if ( v4
    && !*(_BYTE *)(v4 + 580)
    && !*(_BYTE *)(v4 + 598)
    && !sub_4167E2((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4)) )
  {
    v29 = (_DWORD *)(*(int (**)(void))(*(_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4) + 64))();
    v5 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
    v6 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
    if ( v6 < (unsigned __int8)sub_5ED510(v29) )
    {
      v7 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516);
      if ( (unsigned __int8)sub_5ED510(v29) >= v7 + 2 )
        v5 = *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 4516) + 2;
      else
        v5 = (unsigned __int8)sub_5ED510(v29);
    }
    v8 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
    v9 = sub_44A448(v5, *(unsigned __int8 *)(v8 + 4508), a2, (int)v29);
    if ( sub_40E722((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), a2) < v9 )
      v9 = sub_40E722((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), a2);
    v10 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
    v11 = sub_4184F4(v2, a2, *(_DWORD *)(v10 + 4504));
    v28 = v9;
    if ( v9 <= v11 )
      v28 = v11;
  }
  v12 = v2[2];
  if ( v12 )
  {
    if ( !*(_BYTE *)(v12 + 580) )
    {
      v13 = sub_40E934((int)v2, v3, 122, 0);
      v14 = v13;
      if ( v13 )
      {
        sub_44D0D0(*(_DWORD *)(v13 + 4));
        if ( v15 )
        {
          sub_40CBD6(*(_DWORD *)(v14 + 4));
          if ( v16 )
          {
            if ( *(_DWORD *)(v16 + 48) == a2 )
            {
              v17 = *(_DWORD *)(v16 + 240);
              if ( v17 > 0 && v17 < 101 )
                v28 = v28 * (100 - v17) / 100;
            }
          }
        }
      }
    }
  }
  v18 = v2[2];
  v19 = 0;
  if ( v18 && !*(_BYTE *)(v18 + 580) )
  {
    v20 = 0;
    do
    {
      if ( sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20) )
      {
        v21 = (_DWORD *)sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20);
        if ( !sub_5ECCC0(v21) )
        {
          v22 = (_DWORD *)sub_40CC50((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 4), v20);
          v23 = sub_5E3210(v22, a2, v28, 1);
          if ( v23 )
          {
            if ( v23 > v19 )
              v19 = v23;
          }
        }
      }
      ++v20;
    }
    while ( v20 < 22 );
    if ( v19 )
      v28 += v19;
    if ( a2 == 35 )
    {
      if ( *(_DWORD *)(sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8)) + 136) )
      {
        v24 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
        v25 = sub_5E3210(*(_DWORD **)(v24 + 136), 35, v28, 1);
        v26 = sub_5EC220((_DWORD *)((char *)v2 + *(_DWORD *)(v2[1] + 4) + 8));
        if ( sub_5ECC00(*(_DWORD **)(v26 + 136)) == 12 )
        {
          if ( v25 )
            v28 += v25;
        }
      }
    }
  }
  if ( v28 > 252 && sub_44A273(a2) )
    v28 = 252;
  return v28;
}
// 40CBD6: using guessed type double __stdcall sub_40CBD6(_DWORD);
// 44D0D0: using guessed type double __cdecl sub_44D0D0(_DWORD);
Now, the function I just listed above is a good example, because it handles the client's visual display of the values of skills in the skill window. In this function, it's handling a lot of processing on those values to check various caps based on class and skill ID, which it really should have no reason to do because we just want it to display what the server tells us it is.

So, we hook it. Hooking is essentially rewriting the running code in memory at the location of this function to do a JMP (Jump/Detour) to our own custom function. At which point we access the Skill Value directly, using a global client pointer to the character's data, and return it:

Code:
signed int	CHooks::SkillCapCheck2_Detour(unsigned int a1) {
	return ((CharData2 *)((*(CharData **)0x905D00)->ExtendedData->pCharData2))->Skill[a1];
}
And this is actually one of the easier examples.
It wasn't intended to be a jab at you or your staff. I realize how it may have come across that way. I'll retract that statement, based on all the smart stuff you just posted.
  #64  
Old 09-30-2019, 01:20 PM
kaev kaev is offline
Planar Protector


Join Date: Sep 2011
Posts: 1,909
Default

Quote:
Originally Posted by Rogean [You must be logged in to view images. Log in or Register.]
...
Now, the function I just listed above is a good example, because it handles the client's visual display of the values of skills in the skill window. ...
Numeric skill display in the client was added some time after release, might have been post-Kunark release, all you got were the "Awful/Below Average/.../Master" strings at first. I hand-parsed logs to work out what my characters' skills were at and what the level caps were from the numeric skill-up messages. My inner Nilbog wants to see this true on green.
  #65  
Old 09-30-2019, 01:26 PM
Mblake81 Mblake81 is offline
Banned


Join Date: Jan 2011
Location: Bristlebane <Reckless Fury>
Posts: 1,811
Default It's a Unix System

Quote:
Originally Posted by Rogean [You must be logged in to view images. Log in or Register.]
Frankly this argument annoys me. You guys underestimate the difficulty of client side changes. We don't have access to Client source code. We have very limited dissassembly skillsets, and occasionally we rely on pseudocode. Haynar is better than I am at finding specific memory addresses and offsets, and I'm somewhat decent at finding/following code paths for functions to hook and modify their arguments and/or return values. Secrets is better than both of us at anything related to dissassembly, but often too busy to help us.

The Client psuedocode is 468,710 lines of code long, and most of it looks a lot like this:

Now, the function I just listed above is a good example, because it handles the client's visual display of the values of skills in the skill window. In this function, it's handling a lot of processing on those values to check various caps based on class and skill ID, which it really should have no reason to do because we just want it to display what the server tells us it is.

So, we hook it. Hooking is essentially rewriting the running code in memory at the location of this function to do a JMP (Jump/Detour) to our own custom function. At which point we access the Skill Value directly, using a global client pointer to the character's data, and return it:

And this is actually one of the easier examples.
-Programmed from Rogeans SGI Crimson & Machintosh Quadra

Now we wait for the storm to steal the dino dna. [You must be logged in to view images. Log in or Register.]
Last edited by Mblake81; 09-30-2019 at 01:29 PM..
  #66  
Old 09-30-2019, 01:32 PM
Bardp1999 Bardp1999 is offline
Planar Protector

Bardp1999's Avatar

Join Date: Feb 2015
Location: Maceland
Posts: 1,443
Default

Quote:
Originally Posted by Mblake81 [You must be logged in to view images. Log in or Register.]
Now we wait for the storm to steal the dino dna. [You must be logged in to view images. Log in or Register.]
[You must be logged in to view images. Log in or Register.]
__________________
Forum Quest
Spyder73 (BANNED)
NecroP1999 (BANNED)

#LobsterClan
#FreeWuTang
  #67  
Old 09-30-2019, 01:38 PM
Gustoo Gustoo is offline
Planar Protector

Gustoo's Avatar

Join Date: Mar 2012
Location: The side of Bristlebane
Posts: 6,002
Default

Yeah I remember going to the guild trainer to see what my actual skills were.
__________________
Discord PVP Server:
Quote:
Originally Posted by Rogean View Post
Lost but not forgotten.
  #68  
Old 09-30-2019, 04:33 PM
Baler Baler is offline
Planar Protector

Baler's Avatar

Join Date: Mar 2014
Posts: 9,523
Default

[You must be logged in to view images. Log in or Register.]
__________________
  #69  
Old 09-30-2019, 05:13 PM
Secrets Secrets is offline
VIP / Contributor

Secrets's Avatar

Join Date: Oct 2009
Posts: 1,354
Default

Quote:
Originally Posted by Rogean [You must be logged in to view images. Log in or Register.]
Secrets is better than both of us at anything related to dissassembly, but often too busy to help us.
On that note...

The code for cycling through targets did not exist in any client prior to 2004. Please stop using "I read it in a Usenet group" or "it was bound to tab". It's fake news. The only thing bound to tab was cycle between self and target.
__________________
Engineer of Things and Stuff, Wearer of Many Hats

“Knowing yourself is the beginning of all wisdom.” — Aristotle
  #70  
Old 09-30-2019, 05:18 PM
Secrets Secrets is offline
VIP / Contributor

Secrets's Avatar

Join Date: Oct 2009
Posts: 1,354
Default

Quote:
Originally Posted by kaev [You must be logged in to view images. Log in or Register.]
Numeric skill display in the client was added some time after release, might have been post-Kunark release, all you got were the "Awful/Below Average/.../Master" strings at first. I hand-parsed logs to work out what my characters' skills were at and what the level caps were from the numeric skill-up messages. My inner Nilbog wants to see this true on green.
The strings were generated from actual numerical values. Evidence of this exists as early as the client shipped in 1999 on the disks.
__________________
Engineer of Things and Stuff, Wearer of Many Hats

“Knowing yourself is the beginning of all wisdom.” — Aristotle
Closed Thread


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 03:02 PM.


Everquest is a registered trademark of Daybreak Game Company LLC.
Project 1999 is not associated or affiliated in any way with Daybreak Game Company LLC.
Powered by vBulletin®
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.