📄 ucparse.c
字号:
/************************************************
* UC packet parser.
* Incompletely reversed by doublelee
* data: 2003.7
* edited: 2005.7
************************************************/
#include "ucparse.h"
#define PRINT_SECTION \
section_len = (u_short)*ptext;\
ptext += 2;\
sub_len -= 2;\
if(ptext+section_len>text+textlen)\
return 0;\
for(i=0; i<section_len; i++)\
{\
fprintf(pipe, "%c", *ptext++);\
sub_len--;\
}
// to print a section, length as header 2-byte indexed.
#define PRINT_UCID \
ucid = *(u_int*)ptext;\
fprintf(pipe, "%d\n", ucid);\
ptext += 8;\
// to print a 8-byte ucid.
#define PRINT_UCNICK \
section_len = *ptext++;\
if(ptext+section_len>text+textlen)\
return 0;\
fprintf(pipe, "UC nick is:\t");\
for(i=0; i<section_len; i++)\
{\
fprintf(pipe, "%c", *ptext++);\
}\
fprintf(pipe, "\n");\
// to print a uc nickname, one byte indexed.
void outputBinary ( const u_char * byteArray, const size_t byteArrayLen, FILE* pipe)
{
u_long offset;
int i, j, k;
fprintf( pipe, "binary data [ %lu bytes ] ----> \n", ( long unsigned int )byteArrayLen );
if ( byteArrayLen <= 0 )
{
return;
}
i = 0;
offset = 0;
for ( k = byteArrayLen / 16; k > 0; k--, offset += 16 )
{
fprintf( pipe, "%08X ", ( unsigned int )offset );
for ( j = 0; j < 16; j++, i++ )
{
if ( j == 8 )
{
fprintf( pipe, "-%02X", byteArray[i] );
}
else
{
fprintf( pipe, " %02X", byteArray[i] );
}
}
fprintf( pipe, " " );
i -= 16;
for ( j = 0; j < 16; j++, i++ )
{
/* if ( isprint( (int)byteArray[i] ) ) */
if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] <= 255 ) )
{
fprintf( pipe, "%c", byteArray[i] );
}
else
{
fprintf( pipe, "." );
}
}
fprintf( pipe, "\n" );
} /* end of for */
k = byteArrayLen - i;
if ( k <= 0 )
{
return;
}
fprintf( pipe, "%08X ", ( unsigned int )offset );
for ( j = 0 ; j < k; j++, i++ )
{
if ( j == 8 )
{
fprintf( pipe, "-%02X", byteArray[i] );
}
else
{
fprintf( pipe, " %02X", byteArray[i] );
}
}
i -= k;
for ( j = 16 - k; j > 0; j-- )
{
fprintf( pipe, " " );
}
fprintf( pipe, " " );
for ( j = 0; j < k; j++, i++ )
{
if ( ( byteArray[i] >= ' ' ) && ( byteArray[i] <= 255 ) )
{
fprintf( pipe, "%c", byteArray[i] );
}
else
{
fprintf( pipe, "." );
}
}
fprintf( pipe, "\n" );
return;
} /* end of outputBinary */
void printip(ip_info* pi, FILE* pipe)
{
// struct in_addr si;
// si.S_un.S_addr = pi->src_ip;
// fprintf(pipe, "Source: %s", inet_ntoa(si));
fprintf(pipe, "Source: %d.%d.%d.%d: %d\t Destination: %d.%d.%d.%d: %d\n\n",
(pi->src_ip)&0xFF, (pi->src_ip>>8)&0xff,
(pi->src_ip>>16)&0xff, (pi->src_ip>>24)&0xff,
((pi->src_port>>8)&0xff) + ((pi->src_port<<8)&0xff00),
(pi->dst_ip)&0xFF, (pi->dst_ip>>8)&0xff,
(pi->dst_ip>>16)&0xff, (pi->dst_ip>>24)&0xff,
((pi->dst_port>>8)&0xff) + ((pi->dst_port<<8)&0xff00) );
// a little ugly but maybe quicker than inet_ntoa();
}
int outputtext_tcp(u_char* text, u_short textlen, FILE* pipe)
{
u_short data_len, sub_len, section_len, count;
u_short room_id;
u_int i;
u_char* ptext;
#ifdef _DEBUG
outputBinary(text, textlen, pipe);
return 1;
#endif //_DEBUG
ptext = text;
sub_len = 0;
data_len = (u_short)(*ptext);
if( data_len+2 > textlen )
return 0;
ptext += 4;
room_id = *(u_short*)(ptext);
// fprintf(pipe, "\nRoom ID is %d\n", room_id);
ptext += 4;
data_len = *(u_short*)(ptext);
if(ptext+data_len>text+textlen)
{
return 0;
}
ptext += 2;
switch( *(u_short*)ptext )
{
case UC_WEB_CHAT:
ptext += 0x0E;
sub_len = *(u_short*)ptext;
ptext += 2;
PRINT_SECTION
fprintf(pipe, " (Font:");
section_len = *(u_short*)ptext;
ptext += 2;
sub_len -= 2;
for(i=0; i<section_len; i++)
{
if( '|' == *ptext )
{
fprintf(pipe, ")\n");
ptext++;
sub_len--;
continue;
}
fprintf(pipe, "%c", *ptext++);
sub_len--;
}
for(i=0; i+0x11 < sub_len; i++)
fprintf(pipe, "%c", *ptext++);
fprintf(pipe, "\n%%1=%d, %%2=%d\n",
*(u_int*)ptext, *(u_int*)(ptext+8) );
return 1;
case UC_WEB_USERIN:
// outputBinary(text, textlen, pipe);
ptext += 6;
fprintf(pipe, "用户(ucid=%d)(", *(u_int*)ptext);
ptext += 8;
PRINT_SECTION
fprintf(pipe, ")来了\tuser status: ");
for(i=0; i<8; i++)
{
fprintf(pipe, "%02x", *ptext++);
}
fprintf(pipe, "\n");
return 1;
case UC_WEB_USEROUT:
ptext += 6;
fprintf(pipe, "用户(ucid=%d)走了\n", *(u_int*)ptext);
return 1;
case UC_WEB_BROADCAST:
ptext += 2;
if( 0 == *(int*)ptext )
fprintf(pipe, "★系统广播★\n");
else
fprintf(pipe, "★房间广播★(ucid=%d)发布\n", *(u_int*)ptext);
ptext += 8;
PRINT_SECTION
fprintf(pipe, "\n");
return 1;
case UC_WEB_ROOMINFO:
ptext += 0x0B;
PRINT_SECTION
fprintf(pipe, "\nIP Address:");
PRINT_SECTION
fprintf(pipe, "\tPort:%d", *(u_short*)ptext);
ptext += 2;
fprintf(pipe, "\n★公告★本聊天室的主题是:");
PRINT_SECTION
fprintf(pipe, "\n★公告★\n");
PRINT_SECTION
fprintf(pipe, "\n");
return 1;
case UC_WEB_GETLIST:
ptext += 6;
count = *(u_short*)ptext;
ptext += 2;
fprintf(pipe, "聊天室中的%d人名单:\n",count);
for(; count--; )
{
fprintf(pipe, "ucid=%d", *(u_int*)ptext );
ptext += 8;
fprintf(pipe, "\tnick=");
PRINT_SECTION
fprintf(pipe, "\tuser status: ");
for(i=0; i<8; i++)
{
fprintf(pipe, "%02x", *ptext++);
}
fprintf(pipe, "\n");
}
return 1;
case UC_WEB_CHAT2:
case UC_WEB_UNK1:
case UC_WEB_UNK2:
case UC_WEB_UNK3:
case UC_WEB_UNK4:
case UC_WEB_UNK5:
default:
break;
}
return 0;
}
int outputtext_udp(u_char* text, u_short textlen, FILE* pipe)
{
u_short data_len, sub_len, section_len, cmd, i;
u_int ucid;
u_char* ptext, direction;
#ifdef _DEBUG
outputBinary(text, textlen, pipe);
return 1;
#endif //_DEBUG
ptext = text;
data_len = (u_short)(*ptext);
if(data_len+2>textlen)
return 0;
ptext += 2;
direction = *ptext++;
sub1:
sub_len = (u_short)(*ptext);
ptext += 2;
switch( cmd = *(u_short*)ptext )
{
case UC_CMD_LOGIN_54:
case UC_CMD_LOGIN_58:
case UC_CMD_LOGIN_5C:
case UC_CMD_LOGIN_5E:
case UC_CMD_LOGIN_62:
case UC_CMD_LOGIN_6B:
case UC_CMD_LOGIN_6A:
ptext += 2;
fprintf(pipe, "Login Client version:\t");
PRINT_SECTION
fprintf(pipe, "\n");
fprintf(pipe, "Login UC number:\t");
PRINT_UCID
if( UC_CMD_LOGIN_54 == cmd || UC_CMD_LOGIN_58 == cmd )
{
fprintf(pipe, "Login As:\t\t");
PRINT_SECTION
fprintf(pipe, "\n");
}
fprintf(pipe, "Login Password:\t\t");
PRINT_SECTION
fprintf(pipe, "\n");
if( UC_CMD_LOGIN_54 == cmd )
// 此时 *ptext == x (x=1代表通行证方式,x=2手机号,x=3邮件)
ptext += 2;
if( UC_CMD_LOGIN_58 == cmd )
ptext ++;
ptext += 0x0E;
fprintf(pipe, "Login IP is:\t\t");
PRINT_SECTION
fprintf(pipe, "\n");
ptext += 20;
fprintf(pipe, "User is:\t");
PRINT_UCID
PRINT_UCNICK
return 1;
case UC_CMD_CHG_STATUS:
case UC_CMD_CHG_STATUS_68:
ptext += 2;
ucid = *(u_int*)ptext;
ptext += 0x08;
if(UC_CMD_CHG_STATUS == cmd)
ptext++; //should be a byte of 0x01.
ptext++; //should be former status.
switch(*ptext++)
{
case UC_STATUS_OFFLINE:
//seems like some time counting data in this packet.
fprintf(pipe, "ucid %d is logging out!\n", ucid);
return 1;
case UC_STATUS_HIDDEN:
fprintf(pipe, "ucid %d is hidden.\n", ucid);
return 1;
case UC_STATUS_ONLINE:
fprintf(pipe, "ucid %d is online!\t", ucid);
PRINT_SECTION
fprintf(pipe, "\n");
return 1;
case UC_STATUS_GOAWAY:
fprintf(pipe, "ucid %d is away!\t", ucid);
PRINT_SECTION
fprintf(pipe, "\n");
return 1;
default:
return 0;
}
case UC_CMD_RREQ_FRI:
case UC_CMD_RREQ_FRI+1:
case UC_CMD_FRI_LIST:
case UC_CMD_FRI_LIST+1:
case UC_CMD_SEARCH:
case UC_CMD_SEARCH+1:
case UC_CMD_FRI_STATUS:
case UC_CMD_FRI_STATUS+1:
break;
case UC_CMD_TMP_STORE:
// send to server to store temporarily.
case UC_CMD_TMP_STORE+1:
// get from server the stored info.
ptext += 2;
fprintf(pipe, "Receiver ucid:\t");
PRINT_UCID
goto sub1;
case UC_CMD_BROADCAST:
ptext += 3;
fprintf(pipe, "Broadcast content:\n");
PRINT_SECTION
fprintf(pipe, "\n");
return 1;
break;
case UC_CMD_REDIR:
// redirected packet, need decipher again.
ptext += 2;
/* fprintf(pipe, "Receiver ucid:\t");
PRINT_UCID
fprintf(pipe, "Sender ucid:\t");
PRINT_UCID
*/ //don't print redirected packets' header, because I don't know if the
//data is meaningful for us.
ptext += 0x10;
ptext += 5;
section_len = (u_short)*ptext;
if(section_len%8) return 0;
ptext += 2;
for(i=0; i<section_len/8; i++)
{
UC_decipher( (u_long*)(ptext+8*i), (u_long*)(ptext+4+8*i) );
}
// outputBinary(text, textlen, pipe);
return outputtext_udp(ptext, section_len, pipe);
case 0x00E7:
case 0x00E8: //older version?
case 0x00EA:
case 0x00EB: // get friend info details.
break;
case 0x03E9: //4.01.920, 4.10.625
case 0x0487: //2.40 ~ 4.00.200
ptext += 2;
fprintf(pipe, "Sender ucid:\t");
PRINT_SECTION
fprintf(pipe, "\n");
fprintf(pipe, "Sender nick:\t");
PRINT_SECTION
fprintf(pipe, "\n");
// fprintf(pipe, "Receiver:\t(see Destination IP and port)\n");
// if you don't parse friend status packet and keep their status, you
// won't know who is the Receiver. While the real Receiver, the one
// listening on the correct ip and port knows that it is for him or her.
ptext += 6;
fprintf(pipe, "content:\t");
PRINT_SECTION
fprintf(pipe, "\n");
// following are other information such as font.
return 1;
case UC_CMD_ADD_FRI:
// add friend request.
/* ptext += 2;
fprintf(pipe, "Sender ucid:\t");
PRINT_UCID
fprintf(pipe, "Sender nick:\t");
PRINT_SECTION
ptext += 6;
fprintf(pipe, "info:\t\t");
PRINT_SECTION
return 1;
*/
break;
case UC_CMD_KEEP_ALIVE_C8:
case UC_CMD_KEEP_ALIVE_C8+1:
case UC_CMD_KEEP_ALIVE_CB:
case UC_CMD_KEEP_ALIVE_CB+1:
break;
case 0x6365: //ack of comman packet.
// infact "echo" here(65 63 68 6F)
/* fprintf(pipe, "echo: received!\n");
ptext += 0x18;
fprintf(pipe, "ucid is:\t");
PRINT_UCID
PRINT_UCNICK
return 1;
*/
break;
default:
// outputBinary(text, textlen, pipe);
// fprintf(pipe, "unknown cmd code is %02X\n", *(u_short*)ptext);
return 0;
}
return 0;
}
u_short parse_uc( const u_char * byteArray, const size_t byteArrayLen, FILE* pipe )
{
u_short i;
u_char* pdata;
u_int datalen;
uc_header *puh;
uc_webchat_header *puwch;
ip_info *pi;
pi = (ip_info*)&byteArray[0x1A];
if(byteArray[23] == 0x11) //UDP, should be port 3000~3003
{
pdata = (u_char*)(byteArray + LIBNET_ETH_H + LIBNET_IP_H + LIBNET_UDP_H);
puh = (uc_header*)pdata;
datalen = byteArrayLen - (LIBNET_ETH_H + LIBNET_IP_H + LIBNET_UDP_H);
if (puh->begin_tag != UC_BEGIN_TAG)
return 0;
if(datalen - puh->uc_cipher_len - UC_HEAD_LEN != 0 )
return 0;
if(puh->uc_unknown2 != UC_UNKNOWN2 )
return 0;
for(i=0; i < puh->uc_cipher_len/8; i++)
{
UC_decipher((u_long*)&puh->data[8*i],(u_long*)&puh->data[4+8*i]);
}
if(outputtext_udp(puh->data, puh->uc_cipher_len, pipe))
printip(pi, pipe);
return 1;
}
if(byteArray[23] == 0x06) //TCP, should be port 5000+
{
pdata = (u_char*)(byteArray + LIBNET_ETH_H + LIBNET_IP_H + LIBNET_TCP_H);
//maybe multi-message in one packet.
datalen = byteArrayLen - (LIBNET_ETH_H + LIBNET_IP_H + LIBNET_TCP_H);
do
{
puwch = (uc_webchat_header*)pdata;
if (puwch->begin_tag != UC_BEGIN_TAG)
return 0;
if (puwch->begin_tag2 != UC_BEGIN_TAG2)
return 0;
if(datalen - puwch->uc_cipher_len - UC_HEAD_LEN < 0 )
return 0;
if (*((u_short*)(&puwch->data[puwch->uc_cipher_len])) != UC_END_TAG2)
return 0;
if ((u_char*)(puwch->data[puwch->uc_cipher_len+2]) != UC_END_TAG)
return 0;
if (*((u_short*)(&puwch->data[puwch->uc_cipher_len+3])) != puwch->uc_cipher_len)
return 0;
for(i=0; i < puwch->uc_cipher_len/8; i++)
{
UC_decipher((u_long*)&puwch->data[8*i],(u_long*)&puwch->data[4+8*i]);
}
// outputBinary(puwch->data, puwch->uc_cipher_len, pipe);
if(outputtext_tcp(puwch->data, puwch->uc_cipher_len, pipe))
printip(pi, pipe);
//one subpacket parsed!
datalen -= (puwch->uc_cipher_len + UC_HEAD_LEN);
pdata += (puwch->uc_cipher_len + UC_HEAD_LEN);
}
while(datalen > 0);
if(datalen == 0)
return 1;
else
return 0;
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -