Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 133 additions & 45 deletions Source/GameSource/WORLDSERVER/DPSrvr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9699,55 +9699,146 @@ void CDPSrvr::OnCreateAngel( CAr & ar, DPID dpidCache, DPID dpidUser, LPBYTE /*l
char str1[1024];
ar.ReadString( str1, _countof( str1 ) );

char * str2 = strstr(str1,"DD"); if (str2==NULL) return;
*str2 = 0; str2=str2+2;
char * split1 = strchr(str1,'D'); if (split1==NULL) return;
*split1 = 0; split1++;
int id1 = atoi(str1);
int cnt1 = atoi(split1);
FLItemElem* pItemElem1 = (FLItemElem*)pUser->GetItemId( id1 );
if( pItemElem1==NULL || !IsUsableItem( pItemElem1 ) ) return;
int dwid1 = pItemElem1->GetProp()->dwID;
if (dwid1 == ITEM_INDEX(2035,II_GEN_MAT_ORICHALCUM01) || (dwid1 == ITEM_INDEX(2082,II_GEN_MAT_ORICHALCUM01_1) ) ) nOrichalcum+= cnt1;
if (dwid1 == ITEM_INDEX(2036,II_GEN_MAT_MOONSTONE) || (dwid1 == ITEM_INDEX(2083,II_GEN_MAT_MOONSTONE_1) ) ) nMoonstone += cnt1;


FLItemElem* pItemElem2 =NULL;
int id2 = 0;
// Exploit fix: never trust client-provided counts / item ids
struct AngelCreatePacket
{
static bool ParseDwordStrict( const char* psz, DWORD& out )
{
if( psz == NULL || *psz == '\0' )
return false;
unsigned __int64 v = 0;
for( const unsigned char* p = (const unsigned char*)psz; *p; ++p )
{
if( *p < '0' || *p > '9' )
return false;
v = ( v * 10 ) + ( *p - '0' );
if( v > 0xFFFFFFFFULL )
return false;
}
out = (DWORD)v;
return true;
}

static bool ParsePositiveIntStrict( const char* psz, int& out )
{
if( psz == NULL || *psz == '\0' )
return false;
unsigned __int64 v = 0;
for( const unsigned char* p = (const unsigned char*)psz; *p; ++p )
{
if( *p < '0' || *p > '9' )
return false;
v = ( v * 10 ) + ( *p - '0' );
if( v > 2147483647ULL )
return false;
}
if( v == 0 )
return false;
out = (int)v;
return true;
}

static bool IsMaterialOrichalcum( const DWORD dwid )
{
return ( dwid == ITEM_INDEX(2035,II_GEN_MAT_ORICHALCUM01) || dwid == ITEM_INDEX(2082,II_GEN_MAT_ORICHALCUM01_1) );
}
static bool IsMaterialMoonstone( const DWORD dwid )
{
return ( dwid == ITEM_INDEX(2036,II_GEN_MAT_MOONSTONE) || dwid == ITEM_INDEX(2083,II_GEN_MAT_MOONSTONE_1) );
}
};

char* str2 = strstr( str1, "DD" );
if( str2 == NULL )
return;
*str2 = '\0';
str2 += 2;
char* split1 = strchr( str1, 'D' );
if( split1 == NULL )
return;
*split1 = '\0';
++split1;

DWORD dwObjId1 = 0;
int cnt1 = 0;
if( !AngelCreatePacket::ParseDwordStrict( str1, dwObjId1 ) || !AngelCreatePacket::ParsePositiveIntStrict( split1, cnt1 ) )
return;
FLItemElem* pItemElem1 = (FLItemElem*)pUser->GetItemId( dwObjId1 );
if( pItemElem1 == NULL || !IsUsableItem( pItemElem1 ) )
return;
if( cnt1 > pItemElem1->m_nItemNum )
return;
const DWORD dwid1 = pItemElem1->GetProp()->dwID;
if( AngelCreatePacket::IsMaterialOrichalcum( dwid1 ) )
nOrichalcum += cnt1;
else if( AngelCreatePacket::IsMaterialMoonstone( dwid1 ) )
nMoonstone += cnt1;
else
return;

FLItemElem* pItemElem2 = NULL;
DWORD dwObjId2 = 0;
int cnt2 = 0;
char * str3 = strstr(str2,"DD");
if (str3)
{
char * split2 = strchr(str2,'D'); if (split2==NULL) return;
*split2 = 0; split2++;
id2 =atoi(str2);
cnt2 = atoi(split2);
pItemElem2 = (FLItemElem*)pUser->GetItemId( id2 );
if(pItemElem2==NULL || !IsUsableItem( pItemElem2 ) ) return;
int dwid2 = pItemElem2->GetProp()->dwID;
if (dwid2 == ITEM_INDEX(2035,II_GEN_MAT_ORICHALCUM01) || (dwid2 == ITEM_INDEX(2082,II_GEN_MAT_ORICHALCUM01_1) ) ) nOrichalcum+= cnt2;
if (dwid2 == ITEM_INDEX(2036,II_GEN_MAT_MOONSTONE) || (dwid2 == ITEM_INDEX(2083,II_GEN_MAT_MOONSTONE_1) ) ) nMoonstone += cnt2;
}


///////////////////////////////////////////////////////

// R/B/G/W
float greenAngelRate = (float) (nOrichalcum + nMoonstone);
float blueAngelRate = greenAngelRate * 2.0f;
float whiteAngelRate = greenAngelRate * 0.1f;
float redAngelRate = 100.0f - ( whiteAngelRate + greenAngelRate + blueAngelRate );
char* str3 = strstr( str2, "DD" );
if( str3 )
{
*str3 = '\0';
char* split2 = strchr( str2, 'D' );
if( split2 == NULL )
return;
*split2 = '\0';
++split2;
if( !AngelCreatePacket::ParseDwordStrict( str2, dwObjId2 ) || !AngelCreatePacket::ParsePositiveIntStrict( split2, cnt2 ) )
return;
pItemElem2 = (FLItemElem*)pUser->GetItemId( dwObjId2 );
if( pItemElem2 == NULL || !IsUsableItem( pItemElem2 ) )
return;
if( cnt2 > pItemElem2->m_nItemNum )
return;
const DWORD dwid2 = pItemElem2->GetProp()->dwID;
if( AngelCreatePacket::IsMaterialOrichalcum( dwid2 ) )
nOrichalcum += cnt2;
else if( AngelCreatePacket::IsMaterialMoonstone( dwid2 ) )
nMoonstone += cnt2;
else
return;
// avoid double-removing/logging the same stack if a malicious client sends the same item twice
if( dwObjId2 == dwObjId1 )
{
if( cnt1 + cnt2 > pItemElem1->m_nItemNum )
return;
cnt1 += cnt2;
cnt2 = 0;
pItemElem2 = NULL;
}
}

const int nMaterial = ( nOrichalcum + nMoonstone );
if( nMaterial <= 0 )
return;

// R/B/G/W (normalize to prevent negative/overflow rates)
float greenAngelRate = (float)nMaterial;
float blueAngelRate = greenAngelRate * 2.0f;
float whiteAngelRate = greenAngelRate * 0.1f;
float redAngelRate = 100.0f - ( whiteAngelRate + greenAngelRate + blueAngelRate );
if( redAngelRate < 0.0f )
redAngelRate = 0.0f;
const float totalRate = redAngelRate + blueAngelRate + greenAngelRate + whiteAngelRate;
if( totalRate <= 0.0f )
return;
// 30035, II_SYS_SYS_QUE_ANGEL_RED
// 30036, II_SYS_SYS_QUE_ANGEL_BLUE
// 30037, II_SYS_SYS_QUE_ANGEL_GREEN
// 30038, II_SYS_SYS_QUE_ANGEL_WHITE
static DWORD adwItemId[4] = { 30035, 30036, 30037, 30038};
FLOAT fRate[4];
fRate[0] = redAngelRate;
fRate[1] = fRate[0] + blueAngelRate;
fRate[2] = fRate[1] + greenAngelRate;
fRate[3] = fRate[2] + whiteAngelRate;
float rand = xRandom(1000) / 10.0f;
const float fScale = 100.0f / totalRate;
fRate[0] = redAngelRate * fScale;
fRate[1] = fRate[0] + ( blueAngelRate * fScale );
fRate[2] = fRate[1] + ( greenAngelRate * fScale );
fRate[3] = 100.0f;
float rand = xRandom(1000) / 10.0f;
DWORD dwItemId = 0;
for( int i = 0; i < 4; i++ )
{ if( rand <= fRate[i] )
Expand All @@ -9759,9 +9850,6 @@ void CDPSrvr::OnCreateAngel( CAr & ar, DPID dpidCache, DPID dpidUser, LPBYTE /*l
if( dwItemId <= 0 )
return;




if( pUser->m_Inventory.GetEmptyCountByItemId( dwItemId ) < 1 )
{ pUser->AddDiagText( prj.GetText( TID_GAME_LACKSPACE ) );
return;
Expand Down