First of all, you should open any MU Online Protocol on server side, then you need a protocol on client side ( you can use xteam, reedlan addons ) to see what an witch packet does.
Packet Headers example ( connect server protocol ):
Code:
#pragma once
#define SET_NUMBERHB(x) ((BYTE)((DWORD)(x)>>(DWORD)8))
#define SET_NUMBERLB(x) ((BYTE)((DWORD)(x)&0xFF))
#define SET_NUMBERHW(x) ((WORD)((DWORD)(x)>>(DWORD)16))
#define SET_NUMBERLW(x) ((WORD)((DWORD)(x)&0xFFFF))
#define SET_NUMBERHDW(x) ((DWORD)((QWORD)(x)>>(QWORD)32))
#define SET_NUMBERLDW(x) ((DWORD)((QWORD)(x)&0xFFFFFFFF))
#define MAKE_NUMBERW(x,y) ((WORD)(((BYTE)((y)&0xFF))|((BYTE)((x)&0xFF)<<8)))
#define MAKE_NUMBERDW(x,y) ((DWORD)(((WORD)((y)&0xFFFF))|((WORD)((x)&0xFFFF)<<16)))
#define MAKE_NUMBERQW(x,y) ((QWORD)(((DWORD)((y)&0xFFFFFFFF))|((DWORD)((x)&0xFFFFFFFF)<<32)))
//**********************************************//
//************ Packet Base *********************//
//**********************************************//
struct PBMSG_HEAD
{
void set(BYTE head,BYTE size) // OK
{
this->type = 0xC1;
this->size = size;
this->head = head;
}
void setE(BYTE head,BYTE size) // OK
{
this->type = 0xC3;
this->size = size;
this->head = head;
}
BYTE type;
BYTE size;
BYTE head;
};
struct PSBMSG_HEAD
{
void set(BYTE head,BYTE subh,BYTE size) // OK
{
this->type = 0xC1;
this->size = size;
this->head = head;
this->subh = subh;
}
void setE(BYTE head,BYTE subh,BYTE size) // OK
{
this->type = 0xC3;
this->size = size;
this->head = head;
this->subh = subh;
}
BYTE type;
BYTE size;
BYTE head;
BYTE subh;
};
struct PWMSG_HEAD
{
void set(BYTE head,WORD size) // OK
{
this->type = 0xC2;
this->size[0] = SET_NUMBERHB(size);
this->size[1] = SET_NUMBERLB(size);
this->head = head;
}
void setE(BYTE head,WORD size) // OK
{
this->type = 0xC4;
this->size[0] = SET_NUMBERHB(size);
this->size[1] = SET_NUMBERLB(size);
this->head = head;
}
BYTE type;
BYTE size[2];
BYTE head;
};
struct PSWMSG_HEAD
{
void set(BYTE head,BYTE subh,WORD size) // OK
{
this->type = 0xC2;
this->size[0] = SET_NUMBERHB(size);
this->size[1] = SET_NUMBERLB(size);
this->head = head;
this->subh = subh;
}
void setE(BYTE head,BYTE subh,WORD size) // OK
{
this->type = 0xC4;
this->size[0] = SET_NUMBERHB(size);
this->size[1] = SET_NUMBERLB(size);
this->head = head;
this->subh = subh;
}
BYTE type;
BYTE size[2];
BYTE head;
BYTE subh;
};
//**********************************************//
//********** Client -> ConnectServer ***********//
//**********************************************//
struct PMSG_SERVER_INFO_RECV
{
PSBMSG_HEAD header; // C1:F4:03
BYTE ServerCode;
};
struct PMSG_SERVER_LIST_RECV
{
PSBMSG_HEAD header; // C1:F4:06
};
//**********************************************//
//********** ConnectServer -> Client ***********//
//**********************************************//
struct PMSG_SERVER_INIT_SEND
{
PBMSG_HEAD header; // C1:00
BYTE result;
};
struct PMSG_SERVER_INFO_SEND
{
PSBMSG_HEAD header; // C1:F4:03
char ServerAddress[16];
WORD ServerPort;
};
struct PMSG_SERVER_LIST_SEND
{
PSWMSG_HEAD header; // C1:F4:06
BYTE count[2];
};
struct PMSG_SERVER_LIST
{
WORD ServerCode;
BYTE UserTotal;
BYTE type;
};
//**********************************************//
//**********************************************//
//**********************************************//
void ConnectServerProtocolCore(int index,BYTE head,BYTE* lpMsg,int size);
void CCServerInfoRecv(PMSG_SERVER_INFO_RECV* lpMsg,int index);
void CCServerListRecv(PMSG_SERVER_LIST_RECV* lpMsg,int index);
void CCServerInitSend(int index,int result);
And then the actuall Protocol ( connect server ):
Code:
void ConnectServerProtocolCore(int index,BYTE head,BYTE* lpMsg,int size) // OK
{
PROTECT_START
gClientManager[index].m_PacketTime = GetTickCount();
switch(head)
{
case 0xF4:
switch(lpMsg[3])
{
case 0x03:
CCServerInfoRecv((PMSG_SERVER_INFO_RECV*)lpMsg,index);
break;
case 0x06:
CCServerListRecv((PMSG_SERVER_LIST_RECV*)lpMsg,index);
break;
}
break;
}
PROTECT_FINAL
}
void CCServerInfoRecv(PMSG_SERVER_INFO_RECV* lpMsg,int index) // OK
{
if(gServerList.CheckJoinServerState() == 0)
{
return;
}
SERVER_LIST_INFO* lpServerListInfo = gServerList.GetServerListInfo(lpMsg->ServerCode);
if(lpServerListInfo == 0)
{
return;
}
if(lpServerListInfo->ServerShow == 0 || lpServerListInfo->ServerState == 0)
{
return;
}
PMSG_SERVER_INFO_SEND pMsg;
pMsg.header.set(0xF4,0x03,sizeof(pMsg));
memcpy(pMsg.ServerAddress,lpServerListInfo->ServerAddress,sizeof(pMsg.ServerAddress));
pMsg.ServerPort = lpServerListInfo->ServerPort;
gSocketManager.DataSend(index,(BYTE*)&pMsg,pMsg.header.size);
}
void CCServerListRecv(PMSG_SERVER_LIST_RECV* lpMsg,int index) // OK
{
BYTE send[2048];
PMSG_SERVER_LIST_SEND pMsg;
pMsg.header.set(0xF4,0x06,0);
int size = sizeof(pMsg);
int count = gServerList.GenerateServerList(send,&size);
pMsg.count[0] = SET_NUMBERHB(count);
pMsg.count[1] = SET_NUMBERLB(count);
pMsg.header.size[0] = SET_NUMBERHB(size);
pMsg.header.size[1] = SET_NUMBERLB(size);
memcpy(send,&pMsg,sizeof(pMsg));
gSocketManager.DataSend(index,send,size);
}
void CCServerInitSend(int index,int result) // OK
{
PMSG_SERVER_INIT_SEND pMsg;
pMsg.header.set(0x00,sizeof(pMsg));
pMsg.result = result;
gSocketManager.DataSend(index,(BYTE*)&pMsg,pMsg.header.size);
}
Manipulating packets it`s not actually easy because you need to know the size of the packet and other stuff...
Please remmeber that the packets will be all the same in the gameserver usually, but there will be more "cases" and "C1" you will see a lot when your are moving around in game (movement)
For the decryption, there is not much to say, because webzen uses the "XOR" encrypt wich looks like this:
Code:
static unsigned char bBuxCode[3]={0xF1, 0xDC, 0xEF}; // Xox Key
void BuxConvert(char* buf, int size)
{
int n;
for (n=0;n<size;n++)
{
buf[n]^=bBuxCode[n%3] ;
}
}
It's old and it's shit and any hacker can break a XOR encryption. Best of luck!