/* EQ2Emulator: Everquest II Server Emulator Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) This file is part of EQ2Emulator. EQ2Emulator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. EQ2Emulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with EQ2Emulator. If not, see . */ #include "debug.h" #include #include #include #include #include "EQPacket.h" #include "misc.h" #include "op_codes.h" #include "CRC16.h" #include "opcodemgr.h" #include "packet_dump.h" #include #include "Log.h" #include using namespace std; extern mapEQOpcodeManager; uint8 EQApplicationPacket::default_opcode_size=2; EQPacket::EQPacket(const uint16 op, const unsigned char *buf, uint32 len) { this->opcode=op; this->pBuffer=NULL; this->size=0; version = 0; setTimeInfo(0,0); if (len>0) { this->size=len; pBuffer= new unsigned char[this->size]; if (buf) { memcpy(this->pBuffer,buf,this->size); } else { memset(this->pBuffer,0,this->size); } } } int8 EQ2Packet::PreparePacket(int16 MaxLen){ int16 OpcodeVersion = GetOpcodeVersion(version); // stops a crash for incorrect version if(EQOpcodeManager.count(OpcodeVersion) == 0) { LogWrite(PACKET__ERROR, 0, "Packet", "Version %i is not listed in the opcodes table.",version); return -1; } packet_prepared = true; int16 login_opcode = EQOpcodeManager[OpcodeVersion]->EmuToEQ(login_op); int8 offset = 0; //one of the int16s is for the seq, other is for the EQ2 opcode and compressed flag (OP_Packet is the header, not the opcode) int32 new_size = size + sizeof(int16) + sizeof(int8); bool oversized = false; if(login_opcode != 2){ new_size+=sizeof(int8); //for opcode if(login_opcode >= 255){ new_size += sizeof(int16); oversized = true; } else login_opcode = ntohs(login_opcode); } uchar* new_buffer = new uchar[new_size]; memset(new_buffer,0,new_size); uchar* ptr = new_buffer + sizeof(int16); // sequence is first if(login_opcode != 2){ if(oversized){ ptr += sizeof(int8); //compressed flag int8 addon = 0xff; memcpy(ptr, &addon, sizeof(int8)); ptr += sizeof(int8); } memcpy(ptr, &login_opcode, sizeof(int16)); ptr += sizeof(int16); } else{ memcpy(ptr, &login_opcode, sizeof(int8)); ptr += sizeof(int8); } memcpy(ptr, pBuffer, size); safe_delete_array(pBuffer); pBuffer = new_buffer; offset = new_size - size - 1; size = new_size; return offset; } uint32 EQProtocolPacket::serialize(unsigned char *dest, int8 offset) const { if (opcode>0xff) { *(uint16 *)dest=opcode; } else { *(dest)=0; *(dest+1)=opcode; } memcpy(dest+2,pBuffer+offset,size-offset); return size+2; } uint32 EQApplicationPacket::serialize(unsigned char *dest) const { if (app_opcode_size==1) *(unsigned char *)dest=opcode; else *(uint16 *)dest=opcode; memcpy(dest+app_opcode_size,pBuffer,size); return size+app_opcode_size; } EQPacket::~EQPacket() { safe_delete_array(pBuffer); pBuffer=NULL; } void EQPacket::DumpRawHeader(uint16 seq, FILE* to) const { /*if (timestamp.tv_sec) { char temp[20]; tm t; const time_t sec = timestamp.tv_sec; localtime_s(&t, &sec); strftime(temp, 20, "%F %T", &t); fprintf(to, "%s.%06lu ", temp, timestamp.tv_usec); }*/ DumpRawHeaderNoTime(seq, to); } const char* EQPacket::GetOpcodeName(){ int16 OpcodeVersion = GetOpcodeVersion(version); if(EQOpcodeManager.count(OpcodeVersion) > 0) return EQOpcodeManager[OpcodeVersion]->EQToName(opcode); else return NULL; } void EQPacket::DumpRawHeaderNoTime(uint16 seq, FILE *to) const { if (src_ip) { string sIP,dIP;; sIP=long2ip(src_ip); dIP=long2ip(dst_ip); fprintf(to, "[%s:%d->%s:%d] ",sIP.c_str(),src_port,dIP.c_str(),dst_port); } if (seq != 0xffff) fprintf(to, "[Seq=%u] ",seq); string name; int16 OpcodeVersion = GetOpcodeVersion(version); if(EQOpcodeManager.count(OpcodeVersion) > 0) name = EQOpcodeManager[OpcodeVersion]->EQToName(opcode); fprintf(to, "[OpCode 0x%04x (%s) Size=%u]\n",opcode,name.c_str(),size); } void EQPacket::DumpRaw(FILE *to) const { DumpRawHeader(); if (pBuffer && size) dump_message_column(pBuffer, size, " ", to); fprintf(to, "\n"); } EQProtocolPacket::EQProtocolPacket(const unsigned char *buf, uint32 len, int in_opcode) { uint32 offset = 0; if(in_opcode>=0) opcode = in_opcode; else{ offset=2; opcode=ntohs(*(const uint16 *)buf); } if (len-offset) { pBuffer= new unsigned char[len-offset]; size=len-offset; if(buf) memcpy(pBuffer,buf+offset,len-offset); else memset(pBuffer,0,size); } else { pBuffer=NULL; size=0; } version = 0; eq2_compressed = false; packet_prepared = false; packet_encrypted = false; sent_time = 0; attempt_count = 0; sequence = 0; } bool EQ2Packet::AppCombine(EQ2Packet* rhs){ bool result = false; uchar* tmpbuffer = 0; bool over_sized_packet = false; int32 new_size = 0; //bool whee = false; // DumpPacket(this); // DumpPacket(rhs); /*if(rhs->size >= 255){ DumpPacket(this); DumpPacket(rhs); whee = true; }*/ if (opcode==OP_AppCombined && ((size + rhs->size + 3) < 512)){ int16 tmp_size = rhs->size - 2; if(tmp_size >= 255){ new_size = size+tmp_size+3; over_sized_packet = true; } else new_size = size+tmp_size+1; tmpbuffer = new uchar[new_size]; uchar* ptr = tmpbuffer; memcpy(ptr, pBuffer, size); ptr += size; if(over_sized_packet){ memset(ptr, 255, sizeof(int8)); ptr += sizeof(int8); tmp_size = htons(tmp_size); memcpy(ptr, &tmp_size, sizeof(int16)); ptr += sizeof(int16); } else{ memcpy(ptr, &tmp_size, sizeof(int8)); ptr += sizeof(int8); } memcpy(ptr, rhs->pBuffer+2, rhs->size-2); delete[] pBuffer; size = new_size; pBuffer=tmpbuffer; safe_delete(rhs); result=true; } else if((size + rhs->size + 6) < 512){ int32 tmp_size = size - 2; int32 tmp_size2 = rhs->size - 2; opcode=OP_AppCombined; bool over_sized_packet2 = false; new_size = size; if(tmp_size >= 255){ new_size += 5; over_sized_packet = true; } else new_size += 3; if(tmp_size2 >= 255){ new_size += tmp_size2+3; over_sized_packet2 = true; } else new_size += tmp_size2+1; tmpbuffer = new uchar[new_size]; tmpbuffer[2]=0; tmpbuffer[3]=0x19; uchar* ptr = tmpbuffer+4; if(over_sized_packet){ memset(ptr, 255, sizeof(int8)); ptr += sizeof(int8); tmp_size = htons(tmp_size); memcpy(ptr, &tmp_size, sizeof(int16)); ptr += sizeof(int16); } else{ memcpy(ptr, &tmp_size, sizeof(int8)); ptr += sizeof(int8); } memcpy(ptr, pBuffer+2, size-2); ptr += (size-2); if(over_sized_packet2){ memset(ptr, 255, sizeof(int8)); ptr += sizeof(int8); tmp_size2 = htons(tmp_size2); memcpy(ptr, &tmp_size2, sizeof(int16)); ptr += sizeof(int16); } else{ memcpy(ptr, &tmp_size2, sizeof(int8)); ptr += sizeof(int8); } memcpy(ptr, rhs->pBuffer+2, rhs->size-2); size = new_size; delete[] pBuffer; pBuffer=tmpbuffer; safe_delete(rhs); result=true; } /*if(whee){ DumpPacket(this); cout << "fsdfsdf"; }*/ //DumpPacket(this); return result; } bool EQProtocolPacket::combine(const EQProtocolPacket *rhs) { bool result=false; //if(dont_combine) // return false; //if (opcode==OP_Combined && size+rhs->size+5<256) { if (opcode == OP_Combined && size + rhs->size + 5 < 256) { auto tmpbuffer = new unsigned char[size + rhs->size + 3]; memcpy(tmpbuffer, pBuffer, size); uint32 offset = size; tmpbuffer[offset++] = rhs->Size(); offset += rhs->serialize(tmpbuffer + offset); size = offset; delete[] pBuffer; pBuffer = tmpbuffer; result = true; } else if (size + rhs->size + 7 < 256) { auto tmpbuffer = new unsigned char[size + rhs->size + 6]; uint32 offset = 0; tmpbuffer[offset++] = Size(); offset += serialize(tmpbuffer + offset); tmpbuffer[offset++] = rhs->Size(); offset += rhs->serialize(tmpbuffer + offset); size = offset; delete[] pBuffer; pBuffer = tmpbuffer; opcode = OP_Combined; result = true; } return result; } EQApplicationPacket::EQApplicationPacket(const unsigned char *buf, uint32 len, uint8 opcode_size) { uint32 offset=0; app_opcode_size=(opcode_size==0) ? EQApplicationPacket::default_opcode_size : opcode_size; if (app_opcode_size==1) { opcode=*(const unsigned char *)buf; offset++; } else { opcode=*(const uint16 *)buf; offset+=2; } if ((len-offset)>0) { pBuffer=new unsigned char[len-offset]; memcpy(pBuffer,buf+offset,len-offset); size=len-offset; } else { pBuffer=NULL; size=0; } emu_opcode = OP_Unknown; } bool EQApplicationPacket::combine(const EQApplicationPacket *rhs) { cout << "CALLED AP COMBINE!!!!\n"; return false; } void EQApplicationPacket::SetOpcode(EmuOpcode emu_op) { if(emu_op == OP_Unknown) { opcode = 0; emu_opcode = OP_Unknown; return; } opcode = EQOpcodeManager[GetOpcodeVersion(version)]->EmuToEQ(emu_op); if(opcode == OP_Unknown) { LogWrite(PACKET__DEBUG, 0, "Packet", "Unable to convert Emu opcode %s (%d) into an EQ opcode.", OpcodeNames[emu_op], emu_op); } //save the emu opcode we just set. emu_opcode = emu_op; } const EmuOpcode EQApplicationPacket::GetOpcodeConst() const { if(emu_opcode != OP_Unknown) { return(emu_opcode); } if(opcode == 10000) { return(OP_Unknown); } EmuOpcode emu_op; emu_op = EQOpcodeManager[GetOpcodeVersion(version)]->EQToEmu(opcode); if(emu_op == OP_Unknown) { LogWrite(PACKET__DEBUG, 1, "Packet", "Unable to convert EQ opcode 0x%.4X (%i) to an emu opcode (%s)", opcode, opcode, __FUNCTION__); } return(emu_op); } EQApplicationPacket *EQProtocolPacket::MakeApplicationPacket(uint8 opcode_size) const { EQApplicationPacket *res = new EQApplicationPacket; res->app_opcode_size=(opcode_size==0) ? EQApplicationPacket::default_opcode_size : opcode_size; if (res->app_opcode_size==1) { res->pBuffer= new unsigned char[size+1]; memcpy(res->pBuffer+1,pBuffer,size); *(res->pBuffer)=htons(opcode)&0xff; res->opcode=opcode&0xff; res->size=size+1; } else { res->pBuffer= new unsigned char[size]; memcpy(res->pBuffer,pBuffer,size); res->opcode=opcode; res->size=size; } res->copyInfo(this); return(res); } bool EQProtocolPacket::ValidateCRC(const unsigned char *buffer, int length, uint32 Key) { bool valid=false; // OP_SessionRequest, OP_SessionResponse, OP_OutOfSession are not CRC'd if (buffer[0]==0x00 && (buffer[1]==OP_SessionRequest || buffer[1]==OP_SessionResponse || buffer[1]==OP_OutOfSession)) { valid=true; } else if(buffer[2] == 0x00 && buffer[3] == 0x19){ valid = true; } else { uint16 comp_crc=CRC16(buffer,length-2,Key); uint16 packet_crc=ntohs(*(const uint16 *)(buffer+length-2)); #ifdef EQN_DEBUG if (packet_crc && comp_crc != packet_crc) { cout << "CRC mismatch: comp=" << hex << comp_crc << ", packet=" << packet_crc << dec << endl; } #endif valid = (!packet_crc || comp_crc == packet_crc); } return valid; } uint32 EQProtocolPacket::Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize) { uint32 newlen=0; uint32 flag_offset=0; newbuf[0]=buffer[0]; if (buffer[0]==0x00) { flag_offset=2; newbuf[1]=buffer[1]; } else flag_offset=1; if (length>2 && buffer[flag_offset]==0x5a) { LogWrite(PACKET__DEBUG, 0, "Packet", "In Decompress 1"); newlen=Inflate(const_cast(buffer+flag_offset+1),length-(flag_offset+1)-2,newbuf+flag_offset,newbufsize-flag_offset)+2; newbuf[newlen++]=buffer[length-2]; newbuf[newlen++]=buffer[length-1]; } else if (length>2 && buffer[flag_offset]==0xa5) { LogWrite(PACKET__DEBUG, 0, "Packet", "In Decompress 2"); memcpy(newbuf+flag_offset,buffer+flag_offset+1,length-(flag_offset+1)); newlen=length-1; } else { memcpy(newbuf,buffer,length); newlen=length; } return newlen; } uint32 EQProtocolPacket::Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize) { uint32 flag_offset=1,newlength; //dump_message_column(buffer,length,"Before: "); newbuf[0]=buffer[0]; if (buffer[0]==0) { flag_offset=2; newbuf[1]=buffer[1]; } if (length>30) { newlength=Deflate(const_cast(buffer+flag_offset),length-flag_offset,newbuf+flag_offset+1,newbufsize); *(newbuf+flag_offset)=0x5a; newlength+=flag_offset+1; } else { memmove(newbuf+flag_offset+1,buffer+flag_offset,length-flag_offset); *(newbuf+flag_offset)=0xa5; newlength=length+1; } //dump_message_column(newbuf,length,"After: "); return newlength; } void EQProtocolPacket::ChatDecode(unsigned char *buffer, int size, int DecodeKey) { if (buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) { int Key=DecodeKey; unsigned char *test=(unsigned char *)malloc(size); buffer+=2; size-=2; int i; for (i = 0 ; i+4 <= size ; i+=4) { int pt = (*(int*)&buffer[i])^(Key); Key = (*(int*)&buffer[i]); *(int*)&test[i]=pt; } unsigned char KC=Key&0xFF; for ( ; i < size ; i++) { test[i]=buffer[i]^KC; } memcpy(buffer,test,size); free(test); } } void EQProtocolPacket::ChatEncode(unsigned char *buffer, int size, int EncodeKey) { if (buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) { int Key=EncodeKey; char *test=(char*)malloc(size); int i; buffer+=2; size-=2; for ( i = 0 ; i+4 <= size ; i+=4) { int pt = (*(int*)&buffer[i])^(Key); Key = pt; *(int*)&test[i]=pt; } unsigned char KC=Key&0xFF; for ( ; i < size ; i++) { test[i]=buffer[i]^KC; } memcpy(buffer,test,size); free(test); } } bool EQProtocolPacket::IsProtocolPacket(const unsigned char* in_buff, uint32_t len, bool bTrimCRC) { bool ret = false; uint16_t opcode = ntohs(*(uint16_t*)in_buff); uint32_t offset = 2; switch (opcode) { case OP_SessionRequest: case OP_SessionDisconnect: case OP_KeepAlive: case OP_SessionStatResponse: case OP_Packet: case OP_Combined: case OP_Fragment: case OP_Ack: case OP_OutOfOrderAck: case OP_OutOfSession: { ret = true; break; } } return ret; } void DumpPacketHex(const EQApplicationPacket* app) { DumpPacketHex(app->pBuffer, app->size); } void DumpPacketAscii(const EQApplicationPacket* app) { DumpPacketAscii(app->pBuffer, app->size); } void DumpPacket(const EQProtocolPacket* app) { DumpPacketHex(app->pBuffer, app->size); } void DumpPacket(const EQApplicationPacket* app, bool iShowInfo) { if (iShowInfo) { cout << "Dumping Applayer: 0x" << hex << setfill('0') << setw(4) << app->GetOpcode() << dec; cout << " size:" << app->size << endl; } DumpPacketHex(app->pBuffer, app->size); // DumpPacketAscii(app->pBuffer, app->size); } void DumpPacketBin(const EQApplicationPacket* app) { DumpPacketBin(app->pBuffer, app->size); }