这是一篇流水账,记录前两天在解决http中解压gzip数据流程。(写完这篇就可以做其他工作了~~)
目的:c语言解压http的中gzip文件
一、 tcpdump抓包,这条数据包是我试用某app时收到的包,咱们先是用wireshark解析。
图上的标号解释下:
1.Content-Encoding: gzip\r\n 指明数据包是gzip;
2.Okhttp走的并不是原生的http请求,因此他在header里面并没有真正的User-Agent,而是“okhttp/版本号”这样的字符串,因为后台需要统计信息,要求传入正确的User-Agent;(这段网上复制的)
3.gzip数据包有1376字节;
4.gzip压缩的数据,可以看到数据包的前6字节1f8b08,1F0B代表gzip格式,08代码deflate算法;
5.因为有gzip标识,所以wireshark自动解压出来了gzip数据,如果用printf打印,是乱码,必须解压;
6.同5;
7.这里的字段是我们最终要找的字段,我给打码了,是这个app的账号;
8.gzip有1376字节,解压后的大小为4093字节。
二、c语言找到gzip数据包起始位置
1.从http字段找到“Content-Encoding: gzip”,可以在这里判断http数据是否用gzip压缩过,以 \r\n\r\n结尾的表示http报文结束(gzip是压缩过的数据,紧跟在http结束标志后面)
2.紧跟着的一组ascll码是gzip数据包的大小,xxxxxx\r\n ,这里的\r\n为gzip长度结束;
3.接下来的位置是gzip数据包的起始位置;
好了,到现在gzip起始位置与gzip数据包长度都找到了,一切都好说咯~
//贴一段功能函数,ascll码转十进制
int chrtodec(char chr)
{
int value=0;
//先全部将小写转换为大写
if((chr>='a')&&(chr<='z'))
chr=chr-32;
//将字符转化成相应的数字
if((chr>='0')&&(chr<='9'))
value=chr-48;
else if((chr>='A')&&(chr<='Z'))
value=chr-65+10;
return value;
}
三、gzip解压
1.方式一,gzip数据写在文件里,在命令行解压这个文件,虽说可以成功,但比较笨拙的赶脚,不推荐。
2.方式二,调用zlib库,在内存里解压,这段代码不是我写的,从某一位网友那里copy过来的,很好用。(详见本文最后几个链接)
/* Gzip uncompress*/
/* 注意:gzip和zip解压大致相同,但是他们的头数据大小不一样,这个得注意,用inflateInit2(&d_stream,47)*/
int
vidpeek_uncompressGzip(unsigned char* pSrc, unsigned int srcSize,char**pOutDest, unsigned int* pOutBufSize)
{
#define OK 0
#define ERR -1
int ret = OK;
char* pBuf = pSrc+ (srcSize - 1);
unsigned int len =*pBuf;
int uncompressResult;
z_stream d_stream;
int i = 0;
printf("#############pSrc 0x%x 0x%x 0x%x 0x%x", pSrc[0], pSrc[1], pSrc[2], pSrc[3]);
//check gz file,rfc1952 P6
if((*pSrc !=0x1f)||(*(pSrc+1) != 0x8b))
{
printf("\nuncompressGzip non Gzip\n");
return ERR;
}
for(i = 0; i < 3; i++)
{
pBuf--;
len <<= 8;
len += *pBuf;
}
//fortest
if((len== 0) || (len > 1000000))
{
printf("\nuncompressGzip,error gzip!\n");
return ERR;
}
//gzipdecompression start!!!
d_stream.zalloc =Z_NULL;
d_stream.zfree =Z_NULL;
d_stream.opaque = Z_NULL;
d_stream.next_in =Z_NULL;
d_stream.avail_in= 0;
uncompressResult =inflateInit2(&d_stream,47);
if(uncompressResult!=Z_OK)
{
printf("\ninflateInit2 error:%d\n",uncompressResult);
return uncompressResult;
}
d_stream.next_in=pSrc;
d_stream.avail_in=srcSize;
d_stream.next_out=(char *)*pOutDest;
d_stream.avail_out=len;
uncompressResult =inflate(&d_stream,Z_NO_FLUSH);
switch(uncompressResult)
{
case Z_NEED_DICT:
uncompressResult = Z_DATA_ERROR;
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&d_stream);
return uncompressResult;
}
//printf("outlen= %d, total_in= %d, total_out= %d, avail_out= %d@@@@@@@@@@@\n",len, d_stream.total_in, d_stream.total_out, d_stream.avail_out);
inflateEnd(&d_stream);
*pOutBufSize = len-2;
return ret;
}
四、解析解压成功的数据
根据解压成功数据,找到目标字段,比如 "p":" ,注意c语言的双引号前面要加"\"。
结果:成功找到gzip中的app账户字段!
参考链接
https://blog.csdn.net/fcryuuhou/article/details/12951279
https://blog.csdn.net/qinggebuyao/article/details/7728520
http://www.openedv.com/forum.php?mod=viewthread&tid=231109
好了,溜了~~~
有缘看到的盆友,欢迎提意见啊!
感谢!大家一起技术进步哟~~