So, to find the place where they actually use the functions/the weapon informations, I simply looked in the SDK provided by Valve(which is now outdated) for a place to start, and found a function called FX_FireBullets. This function calls different functions when it needs to access information about weapons:
v12 = sub_10242390(a4);//call to WeaponIDToAlias
if ( !v12 )
{
DevMsg("FX_FireBullets: weapon alias for ID %i not found\n", a4);
return;
}
sub_10322A70(&v37, 0x80u, "weapon_%s", v12);//call to a function similar to sprintf_s
v13 = sub_10173BE0((int)&v37);//call to LookupWeaponInfoSlot
if ( v13 == (unsigned __int16)sub_10110B90() )
{
DevMsg("FX_FireBullets: LookupWeaponInfoSlot failed for weapon %s\n", &v37);
return;
}
v14 = (int)sub_10173B00(v13);//call to GetFileWeaponInfoFromHandle These functions are essentially all we need(weapon ID's excluded) to get info about weapons, and as you can see, they are very easy to find in your favorite debugger, or IDA, since there are a nice pair of strings that we can find. So if we fire up a debugger and search for one of those strings, we will see the following disassembly(commented):MOV EBX,DWORD PTR SS:[ESP+140]; "weapon's ID" PUSH EBX CALL client.57153130; "call to WeaponIDToAlias" ADD ESP,4 TEST EAX,EAX JNZ SHORT client.57141D9B PUSH EBX PUSH client.574AB288; "ASCII 'FX_FireBullets: weapon alias for ID %i not found'" CALL DWORD PTR DS:[insert garbage here]; "call to DevMsg" ADD ESP,8 POP EDI POP ESI POP EBP POP EBX ADD ESP,120 RETN PUSH EAX; "the return value of WeaponIDToAlias(weapon's alias) is stored in EAX" PUSH client.574AADF0; "ASCII 'weapon_%s'" LEA ECX,DWORD PTR SS:[ESP+B8] PUSH 80 PUSH ECX CALL client.572351A0; "prints 'weapon_'+alias into a char array" LEA EDX,DWORD PTR SS:[ESP+C0]; "char array" PUSH EDX CALL client.57083BF0; "call to LookupWeaponInfoSlot(returnvalue is an unsigned short)" ADD ESP,14 MOVZX EDI,AX; "AX is used because of the short's small size" CALL client.56FBBCF0; "OR AX, 0x0FFFF" CMP DI,AX; "is the return value valid?" JNZ SHORT client.57141DF1 LEA EAX,DWORD PTR SS:[ESP+B0] PUSH EAX PUSH client.574AB24C; "ASCII 'FX_FireBullets: LookupWeaponInfoSlot failed for weapon %s'" CALL DWORD PTR DS:[insert garbage here]; "call to DevMsg" ADD ESP,8 POP EDI POP ESI POP EBP POP EBX ADD ESP,120 RETN PUSH EDI; "LookupWeaponInfoSlot return value" CALL client.57083B10; "GetFileWeaponInfoFromHandle" ADD ESP,4Essentially we want to call those functions. Easiest way to get a pointer to them would be to make a signature scan for each individual call. This can be done very easily with a plugin for OllyDBG such as SigMaker, or a similar plugin for IDA. Here are the signatures I made with OllyDBG+SigMaker v.4('?' is a wildcard obviously):
weaponIDToAlias: client.dll "\x8B\x4C\x24\x04\x33\xC0\x39\x0C\xC5????\x74\x0B" lookupWeaponInfoSlot: client.dll "\x8B\x44\x24\x04\x83\xEC\x08\x85\xC0\x74\x18" getFileWeaponInfoFromHandle: client.dll "\x66\x8b\x44\x24\x04\x66\x3b\x05????\x73"
Now we have valid pointers to these functions. How do we use them, you ask? I pasted some code below, to show how you can use these functions.
const char* GetWeaponAlias( int weaponID )
{
static void* weaponIDToAlias = 0;
if ( !weaponIDToAlias )
{
weaponIDToAlias = Global::Get()->Memory()->FindPattern( GetModuleHandle( "client.dll" ), "\x8B\x4C\x24\x04\x33\xC0\x39\x0C\xC5????\x74\x0B" );
}
char* weaponAlias = 0;
_asm
{
PUSH weaponID
CALL weaponIDToAlias
ADD ESP, 4
MOV weaponAlias, EAX
}
return weaponAlias;
}
void* GetSDKWeaponInfo( void* weapon )
{
static void* lookupWeaponInfoSlot = 0, getFileWeaponInfoFromHandle = 0;
if ( !lookupWeaponInfoSlot )
{
lookupWeaponInfoSlot = Global::Get()->Memory()->FindPattern( GetModuleHandle( "client.dll" ), "\x8B\x44\x24\x04\x83\xEC\x08\x85\xC0\x74\x18" );
}
if ( !getFileWeaponInfoFromHandle )
{
getFileWeaponInfoFromHandle = Global::Get()->Memory()->FindPattern( GetModuleHandle( "client.dll" ), "\x66\x8b\x44\x24\x04\x66\x3b\x05????\x73" );
}
char weaponName[128];
sprintf_s( weaponName, sizeof( weaponName ), "weapon_%s", GetWeaponAlias( GetWeaponID( weapon ) ) );
void* weaponInfo = 0;
_asm
{
LEA EDX, weaponName
PUSH EDX
CALL lookupWeaponInfoSlot
ADD ESP, 4
MOVZX EDI, AX
PUSH EDI
CALL getFileWeaponInfoFromHandle
ADD ESP, 4
MOV weaponInfo, EAX
}
return weaponInfo;
}
struct WeaponInfo_s
{
int weaponID;
int penetration;
int damage;
float maxRange;
float rangeModifier;
int bulletsPerShot;
int ammoType;
float penetrationRange;
float penetrationPower;
};
WeaponInfo_s GetWeaponInfo( void* localPlayer, void* weapon )
{
static void* getBulletTypeParameters = 0;
if ( !getBulletTypeParameters )
{
getBulletTypeParameters = 0/*find it yourself if you need it*/;
}
void* sdkWeaponInfo = GetSDKWeaponInfo( weapon );
WeaponInfo_s weaponInfo;
weaponInfo.penetration = *reinterpret_cast<int*>( (size_t)sdkWeaponInfo + 0x884 );
weaponInfo.damage = *reinterpret_cast<int*>( (size_t)sdkWeaponInfo + 0x888 );
weaponInfo.maxRange = *reinterpret_cast<float*>( (size_t)sdkWeaponInfo + 0x88C );
weaponInfo.rangeModifier = *reinterpret_cast<float*>( (size_t)sdkWeaponInfo + 0x890 );
weaponInfo.bulletsPerShot = *reinterpret_cast<int*>( (size_t)sdkWeaponInfo + 0x894 );
weaponInfo.ammoType = *reinterpret_cast<int*>( (size_t)sdkWeaponInfo + 0x6c0 );
weaponInfo.weaponID = GetWeaponID( weapon );
if ( weaponInfo.weaponID == WP_M4A1 )//The following was inside FX_Firebullets after these functions were called.
{
bool specialWeaponMode = *reinterpret_cast<bool*>( (size_t)weapon + 0x9d8 );
if ( specialWeaponMode == 1 )
{
weaponInfo.rangeModifier = .95f;
}
}
if ( weaponInfo.weaponID == WP_GLOCK18 )
{
bool specialWeaponMode = *reinterpret_cast<bool*>( (size_t)weapon + 0x9d0 );
if( specialWeaponMode )
{
int burstShotsRemaining = *reinterpret_cast<int*>( (size_t)weapon + 0x9dc );
if ( burstShotsRemaining > 0 )
{
weaponInfo.damage = 18;
weaponInfo.rangeModifier = .9f;
}
}
}
if ( weaponInfo.weaponID == WP_USP45 )
{
bool specialWeaponMode = *reinterpret_cast<bool*>( (size_t)weapon + 0x9d0 );
if ( specialWeaponMode )
{
weaponInfo.damage = 30;
}
}
_asm
{
LEA ECX, weaponInfo.penetrationRange
PUSH ECX
LEA EDX, weaponInfo.penetrationPower
PUSH EDX
PUSH weaponInfo.ammoType
MOV ECX, localPlayer
MOV ECX, DWORD PTR DS:[ECX]
CALL getBulletTypeParameters
}
return weaponInfo;
}
Ingen kommentarer:
Send en kommentar