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 GetFileWeaponInfoFromHandleThese 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