kiro-code-container

Sunday, June 17, 2012

CSGO: Chickens

 Shooting chickens is loads of fun in CSGO so I decided to code some stuff for it;
Chickens have 28 hitboxes:

enum EChickenHitboxes
{
 HITBOX_CHICKEN_PELVIS,
 HITBOX_CHICKEN_LEFTKNEE,
 HITBOX_CHICKEN_LEFTANKLE,
 HITBOX_CHICKEN_LEFTBACKTOE,
 HITBOX_CHICKEN_LEFTTOE,
 HITBOX_CHICKEN_RIGHTKNEE,
 HITBOX_CHICKEN_RIGHTANKLE,
 HITBOX_CHICKEN_RIGHTBACKTOE,
 HITBOX_CHICKEN_RIGHTTOE,
 HITBOX_CHICKEN_TAIL,
 HITBOX_CHICKEN_TAIL1,
 HITBOX_CHICKEN_TAIL2,
 HITBOX_CHICKEN_CLAVICAL, // gg misspell valve?
 HITBOX_CHICKEN_RIGHTBREAST,
 HITBOX_CHICKEN_RIGHTSHOULDER,
 HITBOX_CHICKEN_RIGHTELBOW,
 HITBOX_CHICKEN_RIGHTWRIST,
 HITBOX_CHICKEN_RIGHTTIP,
 HITBOX_CHICKEN_LEFTBREAST,
 HITBOX_CHICKEN_LEFTSHOULDER,
 HITBOX_CHICKEN_LEFTELBOW,
 HITBOX_CHICKEN_LEFTWRIST,
 HITBOX_CHICKEN_LEFTTIP,
 HITBOX_CHICKEN_NECK1,
 HITBOX_CHICKEN_NECK2,
 HITBOX_CHICKEN_NECK3,
 HITBOX_CHICKEN_HEAD,
 HITBOX_CHICKEN_WOBBLER
};

The chickens all have the clientclass CDynamicProp, and you can check wether it's a chicken or not by checking model name; Ex:
 bool CEntity::IsChicken( void )
{
 const model_t *model = GetModel();

 if ( !model )
 {
  LOG_ERROR( "model_t was 0" );
  return false;
 }


 studiohdr_t *studioHeader = g_InterfaceManager->ModelInfo()->GetVTable<IVModelInfo>()->GetStudiomodel( model );

 if ( !studioHeader )
 {
  LOG_ERROR( "studiohdr_t was 0" );
  return false;
 }


 return strstr( studioHeader->name, "chicken" );
}
  The pelvis hitbox is very big, almost like a bounding box tbh. and the height of the chickens hull is ~23;

A video of the result:

Thursday, June 14, 2012

Networked Variables in the Source engine

I needed a way to hook networked props/get offsets simply in the source engine, so I implemented ghetto's/altimor's recursive solution in my netvars class.

 netvars.h:
#pragma once


#include "main.h"


class CNetworkedVariableManager
{
public:

    // stores all tables, and all props inside those
    CNetworkedVariableManager( void );


    // calls GetProp wrapper to get the absolute offset of the prop
    int GetOffset( const char *tableName, const char *propName );


    // calls GetProp wrapper to get prop and sets the proxy of the prop
    bool HookProp( const char *tableName, const char *propName, RecvVarProxyFn function );


private:

    // wrapper so we can use recursion without too much performance loss
    int GetProp( const char *tableName, const char *propName, RecvProp **prop = 0 );


    // uses recursion to return a the relative offset to the given prop and sets the prop param
    int GetProp( RecvTable *recvTable, const char *propName, RecvProp **prop = 0 );


    RecvTable *GetTable( const char *tableName );


    std::vector<RecvTable*>    m_tables;
};


extern CNetworkedVariableManager *g_NetworkedVariableManager; 


netvars.cpp:
#include "main.h"


CNetworkedVariableManager *g_NetworkedVariableManager = 0;


CNetworkedVariableManager::CNetworkedVariableManager( void )
{
    m_tables.clear();


    ClientClass *clientClass = g_InterfaceManager->Client()->GetOriginalMethod<GetAllClasses_t>( INDEX_GETALLCLASSES )( g_InterfaceManager->Client()->thisptr() );

    if ( !clientClass )
    {
        LOG_ERROR( "ClientClass was not found" );
        return;
    }


    while ( clientClass )
    {
        RecvTable *recvTable = clientClass->m_pRecvTable;


        m_tables.push_back( recvTable );


        clientClass = clientClass->m_pNext;
    }
}


// calls GetProp wrapper to get the absolute offset of the prop
int CNetworkedVariableManager::GetOffset( const char *tableName, const char *propName )
{
    int offset = GetProp( tableName, propName );

    if ( !offset )
    {
        LOG_ERROR( "Failed to find offset for prop: %s from table: %s", propName, tableName );
        return 0;
    }


    return offset;
}


// calls GetProp wrapper to get prop and sets the proxy of the prop
bool CNetworkedVariableManager::HookProp( const char *tableName, const char *propName, RecvVarProxyFn function )
{
    RecvProp *recvProp = 0;
    GetProp( tableName, propName, &recvProp );


    if ( !recvProp )
    {
        LOG_ERROR( "Failed to hook prop: %s from table: %s", propName, tableName );
        return false;
    }


    recvProp->m_ProxyFn = function;

    return true;
}


// wrapper so we can use recursion without too much performance loss
int CNetworkedVariableManager::GetProp( const char *tableName, const char *propName, RecvProp **prop )
{
    RecvTable *recvTable = GetTable( tableName );

    if ( !recvTable )
    {
        LOG_ERROR( "Failed to find table: %s", tableName );
        return 0;
    }


    int offset = GetProp( recvTable, propName, prop );

    if ( !offset )
    {
        LOG_ERROR( "Failed to find prop: %s from table: %s", propName, tableName );
        return 0;
    }


    return offset;
}


// uses recursion to return a the relative offset to the given prop and sets the prop param
int CNetworkedVariableManager::GetProp( RecvTable *recvTable, const char *propName, RecvProp **prop )
{
    int extraOffset = 0;

    for ( int i = 0; i < recvTable->m_nProps; ++i )
    {
        RecvProp *recvProp = &recvTable->m_pProps[i];


        RecvTable *child = recvProp->m_pDataTable;

        if ( child
            && ( child->m_nProps > 0 ) )
        {
            int tmp = GetProp( child, propName, prop );

            if ( tmp )
            {
                extraOffset += ( recvProp->m_Offset + tmp );
            }
        }


        if ( stricmp( recvProp->m_pVarName, propName ) )
        {
            continue;
        }


        if ( prop )
        {
            *prop = recvProp;
        }

        return ( recvProp->m_Offset + extraOffset );
    }

    return extraOffset;
}


RecvTable *CNetworkedVariableManager::GetTable( const char *tableName )
{
    if ( m_tables.empty() )
    {
        LOG_ERROR( "Failed to find table: %s (m_tables is empty)", tableName );
        return 0;
    }


    for each ( RecvTable *table in m_tables )
    {
        if ( !table )
        {
            continue;
        }


        if ( stricmp( table->m_pNetTableName, tableName ) == 0 )
        {
            return table;
        }
    }

    return 0;
}

example usages:
// we need to construct this manually
g_NetworkedVariableManager = new CNetworkedVariableManager();

// hook netvar proxy
g_NetworkedVariableManager->HookProp( "DT_CSPlayer", "m_angEyeAngles[0]", CSPlayer_EyeAnglesX );
Vector CPlayer::GetViewOffset( void )
{
 static int offset = g_NetworkedVariableManager->GetOffset( "DT_BasePlayer", "m_vecViewOffset[0]" );
 return *Member<Vector*>( this, offset );
}

Saturday, June 9, 2012

CTraceFilterSkipTwoEntities

[I WON'T GO INTO DETAILS WITH THIS]
This isn't anything special, but since there always seems to be alot of drama going on when there has been an update, I figured I'll post some code here and simple instructions on how to find it. If you will be using Olly, you need the SigMaker plugin, by p47r!ck: Sig Maker 0.4


This tracefilter(CTraceFilterSkipTwoEntities) which is used in peoples tracing code, can be found alot of places, but my preferred location is inside the CSPlayer::FireBullet function, which contains a neat little string which we can follow: "gunshotsplash".
The call to CTraceFilterSkipTwoEntities's constructor is almost at the top of the function and should look something like this(raw copy paste from Olly):

54227F7C   6A 00            PUSH 0
54227F7E   57               PUSH EDI
54227F7F   56               PUSH ESI
54227F80   8D8D 9CFDFFFF    LEA ECX,DWORD PTR SS:[EBP-264]
54227F86   E8 E54BFCFF      CALL client.541ECB70
Just follow that call and make a signature/get the relative offset for it. Please note that this is achievable in IDA aswell, but Olly is my preferred tool.
 
void Aimbot::GetTraceFilterSkipTwoEntities( CSPlayer *first, CSPlayer *second, DWORD* thisptr )
{
 typedef void ( __thiscall *TraceFilterSkipTwoEntities_t )( void *thisptr, const CSPlayer *first, const CSPlayer *second, int group );
 static TraceFilterSkipTwoEntities_t traceFilterskiptwoentities = (TraceFilterSkipTwoEntities_t)memory::FindPattern( GetModuleHandle( "client.dll" ), "\x55\x8B\xEC\x8B\x55\x10\x8B\xC1\x8B\x4D\x08\x89\x48\x04\x8B\x4D\x0C\x89\x50\x08\xC7\x40" );

 if ( !traceFilterskiptwoentities )
 {
  LOG_ERROR( "TraceFilterSkipTwoEntities not found" );
 }


 traceFilterskiptwoentities( thisptr, first, second, 0 );
}
ex. usage: 
DWORD traceFilter[5]; // 20 or 0x14 bytes
GetTraceFilterSkipTwoEntities( m_localPlayer, skipPlayer, traceFilter );
TraceRay( ray, 0x4600400B, (ITraceFilter*)&traceFilter, &traceData );

Monday, February 6, 2012

Creating materials at runtime in Source engine

An example on a common material used in the source engine can be:

"VertexLitGeneric"
{
    "$baseTexture" "models\props_equipment/Cargo_container03"
    "$Envmap" "env_cubemap"
    "$EnvmapMask" "models\props_equipment\Cargo_container03_ref"
    "$BlendTintByBaseAlpha" "1"
    "$envmapfresnel" "1"
    "$envmapFresnelMinMaxExp" "[0.03 0.03 2]"
}

...a .vmt file(Valve Material Type). So we need a way to create these materials at runtime, dynamically.

After looking through the old SDK, and reading about it on valve wiki it was pretty obvious what needed to be done. Please see below code sample.

#define MAT( _TYPE_ ) "\"" + _TYPE_ + "\"\n{\n\t\"$basetexture\" \"VGUI/white_additive\"\n\t\"$ignorez\" \"1\"\n\t\"$nofog\" \"1\"\n\t\"$halflambert\" \"1\"\n}"
#define MAT_IGNOREZ( _TYPE_ ) "\"" + _TYPE_ + "\"\n{\n\t\"$basetexture\" \"VGUI/white_additive\"\n\t\"$ignorez\" \"0\"\n\t\"$nofog\" \"1\"\n\t\"$halflambert\" \"1\"\n}"

IMaterial* CreateMaterial( bool shouldIgnoreZ )
{
 static int created = 0;

 //this is a pointer to the cvar I use for controlling lighting on the materials,
 //I registered it in the source engines linked list of ConVars,
 //and it's changable through the games console
 static ConVar* shadows = Singleton::Get()->Interfaces()->m_Cvar->FindVar( "cheat_chams_shadows" );

 std::string type = ( shadows->GetFloat() == 0.f ) ? "UnlitGeneric" : "VertexLitGeneric";

 //materialBuffer holds the vmt "script" or what to call it
 char materialBuffer[2048];
 if ( shouldIgnoreZ )
 {
  std::string tmp( MAT( type ) );
  sprintf( materialBuffer, tmp.c_str() );
 }
    else
 {
  std::string tmp( MAT_IGNOREZ( type ) );
  sprintf( materialBuffer, tmp.c_str() );
 }

 //make a unique name for our material
 char materialName[512];
 sprintf( materialName, "custom_material_%i.vmt", created );
    ++created;

 //construct keyvalues based on the material type
 KeyValues* keyValues = new KeyValues( type.c_str() );

 //load vmt "script" into our instance of keyvalues
    keyValues->LoadFromBuffer( materialName, materialBuffer );

 //create the actual material
 IMaterial* createdMaterial = Singleton::Get()->Interfaces()->m_MaterialSystem->CreateMaterial( materialName, keyValues );
    createdMaterial->IncrementReferenceCount();
 
    return createdMaterial;
}

Friday, January 27, 2012

Adjusting aiming height for players with anti-aim

When playing HvH(Hacks vs. Hacks) in CSS, a feature, known as anti-aim, is often used.
I attached a screenshot of a bot, using anti-aim via the bot_mimic 1 convar:

As you can see on the screenshot, aiming at the center of the head hitbox, is not very effective for getting headshots.

I have attached my solution below with comments explaining the code:

struct Hitbox
{
 Hitbox( void )
 {
  hitbox = -1;
 }


 Hitbox( int newHitBox )
 {
  hitbox = newHitBox;
 }


 int  hitbox;
 Vector points[9];
};


enum
{
 FL_HIGH =  (1<<0),
 FL_LOW =  (1<<1),
 FL_SPECIAL = (1<<2)
};


struct BestPoint
{
 BestPoint( void )
 {
  hitbox = -1;
  point = 0;
  index = -1;
  dmg = -1;
  flags = 0;
 }


 BestPoint( int newHitBox )
 {
  hitbox = newHitBox;
  point = 0;
  index = -1;
  dmg = -1;
  flags = 0;
 }


 Vector point;
 int  index;
 int  dmg;
 int  flags;
 int  hitbox;
};
  
bool Aimbot::GetHitbox( CSPlayer *targetPlayer, Hitbox *box )
{
 matrix3x4_t matrix[MAXSTUDIOBONES];
 if ( !targetPlayer->SetupBones( matrix, MAXSTUDIOBONES, BONE_USED_BY_HITBOX, 0 ) )
 {
  return false;
 }


 studiohdr_t *studioHeader = g_InterfaceManager->ModelInfo()->GetVTable<IVModelInfo>()->GetStudiomodel( targetPlayer->GetModel() );
 if ( !studioHeader )
 {
  return false;
 }


 mstudiohitboxset_t *hitboxSet = studioHeader->pHitboxSet( targetPlayer->GetHitboxSet() );
 mstudiobbox_t *untransformedBox = hitboxSet->pHitbox( box->hitbox );

 
 // center and all the corners of the hitbox hehe
 Vector points[] = { ( ( untransformedBox->bbmin + untransformedBox->bbmax ) * .5f ),
  Vector( untransformedBox->bbmin.x, untransformedBox->bbmin.y, untransformedBox->bbmin.z ),
  Vector( untransformedBox->bbmin.x, untransformedBox->bbmax.y, untransformedBox->bbmin.z ),
  Vector( untransformedBox->bbmax.x, untransformedBox->bbmax.y, untransformedBox->bbmin.z ),
  Vector( untransformedBox->bbmax.x, untransformedBox->bbmin.y, untransformedBox->bbmin.z ),
  Vector( untransformedBox->bbmax.x, untransformedBox->bbmax.y, untransformedBox->bbmax.z ),
  Vector( untransformedBox->bbmin.x, untransformedBox->bbmax.y, untransformedBox->bbmax.z ),
  Vector( untransformedBox->bbmin.x, untransformedBox->bbmin.y, untransformedBox->bbmax.z ),
  Vector( untransformedBox->bbmax.x, untransformedBox->bbmin.y, untransformedBox->bbmax.z ) };


 for ( int index = 0; index <= 8; ++index )
 {
  if ( index != 0 )
  {
   // scale down the hitbox size
   points[index] =  ( ( ( ( points[index] + points[0] ) * .5f ) + points[index] ) * .5f );
  }
  
  // transform the vector
  VectorTransform( points[index], matrix[untransformedBox->bone], box->points[index] );

  //box.points[index] = this->GetExtrapolatedPosition( box.points[index], targetPlayer );
 }

 return true;
}


bool Aimbot::GetBestPoint( CSPlayer *targetPlayer, Hitbox *box, BestPoint *best )
{
 Vector center = box->points[0];

 // if we're checking the head hitbox
 if ( box->hitbox == 12 )
 {
  // aimpoints is already 3/4 of hitbox size
  Vector high = ( ( box->points[3] + box->points[5] ) * .5f );

  // is target looking down?
  float pitch = targetPlayer->GetEyeAngles().x;
  if ( ( pitch > 0.f )
   && ( pitch <= 89.f ) )
  {
   Vector height = ( ( ( high - box->points[0] ) / 3 ) * 4 );
   Vector newhigh = ( box->points[0] + ( height * ( pitch / 89.f ) ) );

   box->points[0] = newhigh;
   best->flags |= FL_HIGH;
  }
  // is target looking up?
  else if ( ( pitch < 292.5f )
   && ( pitch >= 271.f ) )
  {
   // lower the aimpoint
   box->points[0] -= Vector( 0.f, 0.f, 1.f );
   best->flags |= FL_LOW;
  }
 }


 for ( int index = 0; index <= 8; ++index )
 {
  int tmpdmg = GetDamage( box->points[index], targetPlayer );

  if ( ( tmpdmg != -1 )
   && ( best->dmg < tmpdmg )
   && ( ( tmpdmg - best->dmg ) > 1 ) )
  {
   best->dmg = tmpdmg;
   best->point = box->points[index];
   best->index = index;
  }
 }

 return ( best->dmg > 0 );
}
Usage should be quite obvious;
Result:
Happy hacking!

Tuesday, January 10, 2012

Creating a simple string reversing user defined function(UDF) in C, for MySQL and running on CentOS

For an upcomming project, I need to use user defined functions in MySQL. Therefore I decided to figure out how it works, and what the optimal method of compiling an extention with the desired function, on CentOS would be.

To acquire the includes etc, download and install the MySQL source.

You need to customize the header called mysql_version.h according to your version of MySQL:
#ifndef _mysql_version_h
#define _mysql_version_h
#ifdef _CUSTOMCONFIG_
#include 
#else
#define PROTOCOL_VERSION 5
#define MYSQL_SERVER_VERSION "5.0.77"
#define MYSQL_BASE_VERSION "mysqld-5.0"
#define MYSQL_SERVER_SUFFIX_DEF  ""
#define FRM_VER 0
#define MYSQL_VERSION_ID 0
#define MYSQL_PORT 3306
#define MYSQL_PORT_DEFAULT 3306
#define MYSQL_UNIX_ADDR "/tmp/mysql.sock"
#define MYSQL_CONFIG_NAME "my"
#define MYSQL_COMPILATION_COMMENT ""

#endif /* _CUSTOMCONFIG_ */

#ifndef LICENSE
#define LICENSE GPL
#endif /* LICENSE */

#endif /* _mysql_version_h */

Now you can include mysql.h to your C-file, and start coding your UDF, I've coded a simple function for reversing a string, code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef unsigned long long ulonglong;
typedef long long longlong;
#include <mysql.h>
#include <ctype.h>


my_bool Inverse_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
void Inverse_deinit( UDF_INIT* initid );
char* Inverse( UDF_INIT* initid, UDF_ARGS* args, char* result, unsigned long* length, char* is_null, char* error );


my_bool Inverse_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
{
 if ( ( args->arg_count != 1 ) || ( args->arg_type[0] != STRING_RESULT ) )
 {
  strcpy( message, "Wrong argument type" );
  return 1;
 }

 return 0;
}


void Inverse_deinit( UDF_INIT* initid )
{
}


char* Inverse( UDF_INIT* initid, UDF_ARGS* args, char* result, unsigned long* length, char* is_null, char* error )
{
 const char* arg = args->args[0];

 (*length) = strlen( arg );

 int i;
 for ( i = (*length); i >= 0; i-- )
 {
  result[(*length) - i - 1] = arg[i];
 }

 return result;
}

 I have not made this code to be compatible with Unicode, but I intend to make a post in the near future, explaining Unicode.

We need to compile this, so let's fire up our CentOS and go the the directory where we saved the C-File(save it in your MySQL source directory somewhere), and compile using the following command:
gcc -shared -o filenamehere.so filenamehere.c -I ../include/

Obviously you want to customize the include directory parameter to lead to the include directory, from the directory where your file is, the include directories is: */mysqlsource/include/

So now that we have the shared object(.so) file, we can go ahead and put it in the following directory: */usr/lib/ 
then restart our mysqld service:
service mysqld restart

You can now load up your SQLyog, and define your newly created function using:
CREATE FUNCTION Inverse RETURNS STRING SONAME 'filenamehere.so'


And now your UDF is ready for use!

Wednesday, December 14, 2011

Game hacking: VTable hooking explanation and example

When hacking a game, you will sometimes need to hook some of the engine's functions. In case of the function that you want to hook is in a so called virtual method table(class with virtual functions), hooking the functions is very easy.
A virtual function is essentially a function in a class, that allows inherited classes to overwrite that function. On assembly level, this means that the compiler generates a table of pointers to functions, which are then called instead of calling the function directly. This allows inherited classes to easily overwrite the virtual function in the class instance. ex:

2521a783
2521a825
25220052
25228252
As you can see, it consists merely pointers, that point to the functions themselves.
(I am working on my paint skills):







With this information, we can actually easily replace the address that exists within the vmt with a pointer to our own function, while preserving the original function pointer for later use.
I've coded a little example code here just for the sake of consistency;

 
class VirtualTable
{
public:

virtual void VirtualFunction01( void );
};


void VirtualTable::VirtualFunction01( void )
{
cout << "VirtualFunction01 called" << endl;
}

//we use this to store and call the original function inside our custom one
typedef void ( __thiscall* VirtualFunction01_t )( void* thisptr );
VirtualFunction01_t g_org_VirtualFunction01;

//our custom function
void __fastcall hk_VirtualFunction01( void* thisptr, int edx )
{
cout << "Custom function called" << endl;

//call the original function
g_org_VirtualFunction01(thisptr);
}


int _tmain(int argc, _TCHAR* argv[])
{
VirtualTable* myTable = new VirtualTable();

//get the pointer to the actual virtual method table from our pointer to our class instance
void** base = *(void***)myTable;

DWORD oldProtection;
//one way to remove page protection(not the best but this is an example only)
VirtualProtect( &base[0], 4, PAGE_EXECUTE_READWRITE, &oldProtection );
//save the original function
g_org_VirtualFunction01 = (VirtualFunction01_t)base[0];
//overwrite
base[0] = &hk_VirtualFunction01;
//restore page protection
VirtualProtect( &base[0], 4, oldProtection, 0 );

//call the virtual function (now hooked) from our class instance
myTable->VirtualFunction01();

system("pause");

return 0;
}
Output:
Custom function called
VirtualFunction01 called

Friday, November 25, 2011

Reversing Valve's Source Engine functions: Getting Weapon Information without using Valve Source SDK

I have lately found myself in the need of being able to get the exact data about weapons that Valve uses in their own functions. Due to Valve's SDK being outdated, I decided to reverse the functions that the Source Engine uses to to get information from a file. In this post I will be using OllyDBG, aswell as IDA.
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,4
Essentially 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;
}