The login process in the GatewayServer is actually quite complex because it talks with both the GlobalManager and an AgentServer before handing out a successful Login acknowledge (0xA102).
I don't know how Chernobyl did it but from what I know the cleanest way is to replace the IBUV_GENERATE_REQ in the FIND_CONTENT_USER_ACK handler with code that sends a USER_VALIDATION_SUCCESS_REQ to the GlobalManager which would originally be sent only after the IBUV has been answered correctly.
The the function that calls IBUV_GENERATE_REQ is called from 0x00405CF5.
This is what the reverse engineered code from the actual place where the USER_VALIDATION_SUCCESS_REQ is sent looks like.
(at around 0x00406BB1)
Code:
pMsgUserValidationSuccessReq = g_NetEngine->vftbl_0->CNetEngine::NewMsg(g_NetEngine, 0);
*pMsgUserValidationSuccessReq->m_pID = 0x6112;// USER_VALIDATION_SUCCESS_REQ
if ( pCertParam->m_szUsername.capacity < 0x10u )
m_szUsername.c_str() = (const CHAR *)&pCertParam->m_szUsername.field1;
else
m_szUsername.c_str() = (const CHAR *)pCertParam->m_szUsername.field1;
CMsg::WriteString(dwNumberOfBytesWritten, m_szUsername.c_str(), pMsgUserValidationSuccessReq);
if ( !CServerProcessBase::SendRelayReq(
(CServerProcessBase *)this,
pMsgUserValidationSuccessReq,
g_pServerBodyOfMyself->pDivision->DivisionManagerBodyID,
0,
0,
pCertParam) )
{
pMsgLoginAck = g_NetEngine->vftbl_0->CNetEngine::NewMsg(g_NetEngine, 0);
*pMsgLoginAck->m_pID = 0xA102u; // LOGIN_ACK
HIWORD(a3a) = '\x06\x02';
CMsg::Write(1u, pMsgLoginAck, (char *)&a3a + 2);// 0x02
CMsg::Write(1u, pMsgLoginAck, (char *)&a3a + 3);// 0x06
g_NetEngine->vftbl_0->CNetEngine::SendMsg(g_NetEngine, pCertParam->m_SessionID, pMsgLoginAck);
g_NetEngine->vftbl_0->CNetEngine::FreeMsg(g_NetEngine, pMsgLoginAck);
g_NetEngine->vftbl_0->CNetEngine::DisconnectSessionById(g_NetEngine, pCertParam->m_SessionID, 1);
sub_414410(&a1, (int)pCertParam); // frees pCertParam
}
It's a lot of code to write in assembly so if you want to keep your sanity write a C++ detour hook dll thingy. If you have no idea what any of this means stick to your filter sending the default captcha code. This is by no means an easy task.