wireshark抓到的包可以导出:file->export->file
在packet format下可以选择导出的格式,但如果需要的数据是多个包的组合那就麻烦了,因为导出的数据无论如何都会加上链路层、IP层和传输层的头信息,手动删除基本可能。
比如,我捕获了很多RTP包,但我只想取出RTP的payload来分析数据是否正确,我可以这样做:
首先导出packet byte格式的数据,我把该数据保存在RAW.dat中,数据的格式是这样的(一个wireshark中的包):
然后把其中的16进制数据提取出来,上代码:
#include "stdlib.h"
#include "stdio.h"
typedef enum state //状态机实现
{
IGNORE,
WAITCR,
WAITLF,
READY,
READ_L,
READ_H
}STATE;
int AToI(unsigned char *pData)
{
unsigned char tmp[2];
int ret;
tmp[0] = *pData;
tmp[1] = *(pData+1);
for (int i=0; i<2; i++)
{
if (tmp[i] <= 0x39 && tmp[i] >= 0x30)
{
tmp[i] &= 0x0f;
}
else if(tmp[i] <= 0x66 && tmp[i] >= 0x61)
{
tmp[i] = 9 + tmp[i]&0x0f;
}
else
{
printf("Err\n");
return -1;
}
}
ret = tmp[0]*16 + tmp[1];
return ret;
}
int main()
{
FILE *FI, *FO;
FI = fopen("RAW.dat", "rb");
FO = fopen("RTP.dat", "wb");
STATE stat=IGNORE;
unsigned char tmp;
int hex;
unsigned char ch[2] = {0};
int count = 0, line = 0;
int blankCount = 0;
bool bFalse = false;
unsigned long PacketCount = 0;
while(!feof(FI) && !bFalse)
{
tmp = fgetc(FI);
switch(stat)
{
case IGNORE:
if (tmp == 0x20)
{
stat = READY;
}
break;
case WAITCR:
if (tmp == 0x0d)
{
stat = WAITLF;
}
break;
case WAITLF:
if (tmp == 0x0a)
{
stat = IGNORE;
}
break;
case READY:
if(tmp != 0x20)
{
ch[0] = tmp;
stat = READ_L;
blankCount = 0;
}
else
{
if (++blankCount >= 2)
{
PacketCount++;
blankCount = 0;
count = 0;
stat = WAITCR;
}
}
break;
case READ_L:
ch[1] = tmp;
stat = READ_H;
break;
case READ_H:
hex = AToI(ch);
if (hex < 0)
{
bFalse = true;
break;
}
fputc(hex, FO);
if (++count == 16)
{
count = 0;
line++;
stat = WAITCR;
}
else
{
stat = READY;
}
break;
}
}
fclose(FI);
fclose(FO);
return 0;
}
因为我抓取的是RTP数据,因此我又写了个小工具,从上面提取的裸数据中在一起提取出RTP数据:
#include "stdlib.h"
#include "stdio.h"
#include <assert.h>
int main()
{
FILE *FI, *FO;
FI = fopen("raw.dat", "rb");
FO = fopen("rtp.dat", "wb");
if (!FI || !FO)
{
return -1;
}
int ret=0;
unsigned long ToTalLen=0, PacketLen = 0;
unsigned long count = 0;
unsigned char *pBuf = new unsigned char[10 * 1024 *1024];
unsigned char *pPos = pBuf;
int paddingLen = 0;
bool bHasPadding = false;
do
{
ret = fread(pPos, 1, 1024*1024, FI);
ToTalLen += ret;
pPos += ret;
}while(ret > 0);
pPos = pBuf;
do
{
while(ToTalLen > 0)
{
if(*pPos != 0x50 || *(pPos+1)!= 0xe5)
{
printf("Has decode %d\n", count);
break;
}
PacketLen = (*(pPos+38)<<8) + *(pPos+39);
PacketLen -= (8 + 12);
if (PacketLen > 1460)
{
break;
}
pPos += (14 + 20 + 8 + 12);
if (PacketLen != fwrite(pPos, 1, PacketLen, FO))
{
break;
}
count++;
pPos += PacketLen;
//如果RTP的payload是4, 那么以太网的包长度肯定为4 + 12 + 8 + 20 + 14 == 58 小于 60
//因此会有2个字节是需要丢弃的
if (PacketLen == 4)
{
pPos += 2;
}
}
} while(0);
delete []pBuf;
fclose(FI);
fclose(FO);
return 0;
}
其他的传输层数据可以类似地提取,不用去掉RTP头长度(12)。