【*高分求助*】hook socket系列API 遇到分包不知道怎么处理 c++socket源码gzip组包 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 谢谢回答 是的 我的确是有知道文件的大小 也就是16k 但每次只能收4k 因为是用的hook 我必须还得往上层传 但是包没收完不能解压 那我是传呢还是不传呢? 赵老师 你好 共享内存可以很好的实现我需要的逻辑么? 我把我hook recv的代码贴一下 麻烦再帮我看看int WINAPI HookRecv( IN SOCKET s, __out_bcount_part(len, return) __out_data_source(NETWORK) char FAR * buf, IN int len, IN int flags){ //int nRecvBufLen = 2 * 1024 * 10; //设置为2m //setsockopt(s, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBufLen, sizeof(int)); int nRet = 0; nRet = SysRecv(s, buf, len, flags); if (nRet <= 0) return nRet; CString str = buf; CString str1 = ""; if (str.Mid(0, 4) == "HTTP") { //分析包头(这里分析包头发现Content-Length有16k, 但是本次实际收到的数据只有4k,意味着服务器自动分包了) OperateRecvPackageEx(buf, nRet); } return nRet;} 谢谢回答 是的 我的确是有知道文件的大小 也就是16k 但每次只能收4k 因为是用的hook 我必须还得往上层传 但是包没收完不能解压 那我是传呢还是不传呢?肯定要往上传了,但你在共享的内存空间里把数据先保存下来,这样接收完后就能解压了 这个东西我做过,是直接修改网页数据的。你说的情况,可以直接在返回数据后判断是否HTTP/1.1 200 OK如果是,那就解析文件头,里面包含有长度,编码类型,传输类型,是否GZIP压缩,是否是chunked编码等,如果没有Content-Length,那就判断是否是chunked,都没有,那直接就检测Connection是否是close。如果是,那数据就到头了,然后就合并所有接收到的数据,返回给调用方即可。我的框架是,建立socket句柄的数据映射,可以是list,map,随意,因为是多线程的,这点是必须的。结构大致如下myrevc_{申请新映射或者,如果有,就根据调用方提供的缓存大小依次返回数据,offset控制好即可,数据返回完毕就删除映射,。调用原始recv,判断网页类型,超文本协议,获取文件长度,编码类型等等。这里不考虑大文件,所以循环调用原始recv,读取出所有数据,直到结束,然后合并,解码,dosameting。返回调用方剩余的缓存区大小。}WSARecv大同小异,OVERLAPPED也不影响,因为是很早以前的东西,不是用vc写的,所以源码就不贴出来了。 谢谢两位 如果我把数据先保存下来 然后等数据齐了再解压 这样是不是就没办法实现修改返回数据包的功能了?因为前面的数据都已经传上去了你不用管调用方如何,直接在hook内循环调用原始recv获取到所有数据,然后调用在下一次调用的时候,直接判断s句柄,依次copymem就行了, 还有一点需要注意的就是,在返回给调用方数据的时候,一定要把协议头改成正确的,比如gbk你转换成了UNICODE操作,GZIP解压了,chunked解码了,等等,这些都需要修改http的协议头,如果不修改则可能出现乱码等情况。一般去掉chunked属性,即删除Transfer-Encoding。填对Content-Length即可。这个如果不改正确,则可能出现内存错误(数据长度不对,越界),网页显示不完整等情况。 谢谢两位 如果我把数据先保存下来 然后等数据齐了再解压 这样是不是就没办法实现修改返回数据包的功能了?因为前面的数据都已经传上去了你不用管调用方如何,直接在hook内循环调用原始recv获取到所有数据,然后调用在下一次调用的时候,直接判断s句柄,依次copymem就行了,谢谢回答 我昨天晚上也在尝试直接在hook里面循环调用原始recv来获取数据 经测试这种方法是可行的 不过测试中发现会导致浏览器不稳定 特别是浏览数据比较多的页面更容易奔溃 正在找问题所在 怀疑是内存管理有问题 因为我每次都动态new了200k的内存用来存储一个完整的数据包 不知道您在实现中有碰到这样的情况么? 是否注意到上面的问题?暂存数据的时候,要调用方再次recv接收完毕才能释放内存,还要注意多线程问题,做好临界区或读写锁。 是否注意到上面的问题?暂存数据的时候,要调用方再次recv接收完毕才能释放内存,还要注意多线程问题,做好临界区或读写锁。我现在还没做gzip以及chunked等参数的处理,纯粹是把多个数据包全部收取再合并成一个返回调用方,我把代码贴一下,麻烦帮我看一下哪里有问题 因为总会导致浏览器奔溃 不会是这种强行去多次循环读取数据的方式 会破坏结构吧?另外,您提到的多线程问题,我目前只hook处理recv 也需要处理多线程么?用什么样的方式来处理呢?int WINAPI HookRecv( IN SOCKET s, __out_bcount_part(len, return) __out_data_source(NETWORK) char FAR * buf, IN int len, IN int flags){ int nRealLen=0, nLen=0, nTotalLen=0; CString strBuffer="", strHeader=""; BOOL bRet = FALSE; char *pBuffer = NULL; char *pPoint = NULL; try { do { //循环调用系统的recv方法 nRealLen = SysRecv(s, buf, len, flags); if (nRealLen <= 0) break; strBuffer = buf; if (strBuffer.Mid(0, 4) == "HTTP") {//新的包头 //分离包头和包体 nLen = strBuffer.Find("\r\n\r\n"); if (nLen == -1) break; strHeader = str.Left(nLen + 4); //解析包头 RESPONSEHEADER resHttpHead; bRet = ParseResHttpHead(strHeader, &resHttpHead); if (!bRet) break; //只处理html类型页面 if (resHttpHead.strContentType.Find("text/html") == -1) break; //申请临时存储内存(200kb) pBuffer = new char[nMaxBufLen]; memset(pBuffer, 0, nMaxBufLen); //将首地址赋给临时指针 pPoint = pBuffer; if (pPoint == NULL) break; } if (nRealLen > (nMaxBufLen-nTotalLen)) {//当前内容超过临时内存剩余大小 break; } //将缓冲区内容拷贝到临时内存 memcpy(pPoint, buf, nRealLen); //指针偏移 pPoint += nRealLen; nTotalLen += nRealLen; } while (nRealLen>0); } catch (CException* e) { e->Delete(); } if (nTotalLen > 0 && pBuffer) { //将临时内存中的数据拷贝到系统缓冲区,并设置数据大小 memcpy(buf, pBuffer, nTotalLen); nRealLen = nTotalLen; delete[] pBuffer; pBuffer = NULL; } return nRealLen;} cstring不是线程安全的,而recv基本上都是多线程应用,所以不建议使用,推荐你用我的思路框架来设计,因为recv第一次调用,你获取完所有数据之后,需要做一个socket句柄的数据映射,如果第一次缓冲区不够存放,调用方会接二连三的调用recv获取数据,所以,此时你在hook头部应该判断是否有数据映射,如果有,就记录好offset依次cpymem,还有,不能单纯的判断recv ret=0,如果返回值是SOCKET_ERROR(-1),此时判断error值,很可能是block了,数据未返回,比如网络阻塞等,这里不能返回,等待约几十毫秒(我设的200ms)继续循环操作,这里跳出while的条件应当以ret=0,数据长度是否满足Content-Length,以及 chunked的结束标记{ 13, 10, 48, 13, 10 }等来判断。 这里的多线程的意思是,你hook了recv函数,但是调用方是用多线程来调用recv的,这不是你能控制的,而是调用方的操作。你要源码的话,我这里有一份,不过是其他语言的,大概意思都很好理解,在这里就不贴了,当时是别人花1千让我写的。你要的话就免费送你了, 非常非常感谢!!!真的,看了您的整个思路,终于实现了我想要的功能,一开始没有看懂所以才会导致出错,真的非常感谢,至于源码,如果您方便的话,麻烦还是发我参考一下,其他语言没关系,估计我一些细节上还没考虑得很周到,需要再借鉴一下。我邮箱[email protected]再次表示感谢! 估计我一些细节上还没考虑得很周到,需要再借鉴一下。我邮箱[email protected]您好。终于找到类似问题的帖子了!我已经通过HOOK 得到了响应包的buf,然后想通过修改它的回包状态码为301或者302,Location到一个指定的网址。我用的是VC++(vs2010)做的,hook的是NtDeviceIoControlFile得到了回包的内容。但是接下来不会修改回包状态码及其Location的代码。您能帮我分析一下吗?谢谢! 您好。终于找到类似问题的帖子了!我已经通过HOOK 得到了响应包的buf,然后想通过修改它的回包状态码为301或者302,Location到一个指定的网址。我用的是VC++(vs2010)做的,hook的是NtDeviceIoControlFile得到了回包的内容。但是接下来不会修改回包状态码及其Location的代码。您能帮我分析一下吗?谢谢! CScrollView的OnDraw显示不出来图像 自己写的类怎么在 "建立类向导"中一个也找不到. 位图与调色板 如何通过点击一个按扭来直接打开这日志 如何实现像我的电脑中地址栏那样把系统的树结构显示到下拉列表中呢? 那里有'Iphlpapi.h'文件下载?高分! 工作线程里的消息循环中消息为什么不删除啊??? 100分求BCGSOFT Library 类库,希望各位大哥能成全小弟,实在没有钱呀! mfc写的程序内存资源都占用这么多吗? 给“masterz”的问题 MFC执行本地html(带javascript),不显示界面 ADO里Open和Close的问题
int WINAPI HookRecv( IN SOCKET s, __out_bcount_part(len, return) __out_data_source(NETWORK) char FAR * buf, IN int len, IN int flags)
{
//int nRecvBufLen = 2 * 1024 * 10; //设置为2m
//setsockopt(s, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBufLen, sizeof(int));
int nRet = 0;
nRet = SysRecv(s, buf, len, flags);
if (nRet <= 0)
return nRet; CString str = buf;
CString str1 = "";
if (str.Mid(0, 4) == "HTTP")
{
//分析包头(这里分析包头发现Content-Length有16k, 但是本次实际收到的数据只有4k,意味着服务器自动分包了)
OperateRecvPackageEx(buf, nRet);
}
return nRet;
}
你说的情况,可以直接在返回数据后判断是否
HTTP/1.1 200 OK
如果是,那就解析文件头,里面包含有长度,编码类型,传输类型,是否GZIP压缩,是否是chunked编码等,
如果没有Content-Length,那就判断是否是chunked,都没有,那直接就检测Connection是否是close。
如果是,那数据就到头了,然后就合并所有接收到的数据,返回给调用方即可。我的框架是,
建立socket句柄的数据映射,可以是list,map,随意,因为是多线程的,这点是必须的。
结构大致如下
myrevc_
{
申请新映射或者,如果有,就根据调用方提供的缓存大小依次返回数据,offset控制好即可,数据返回完毕就删除映射,。
调用原始recv,
判断网页类型,超文本协议,获取文件长度,编码类型等等。
这里不考虑大文件,所以循环调用原始recv,读取出所有数据,直到结束,然后合并,解码,dosameting。
返回调用方剩余的缓存区大小。
}
WSARecv大同小异,OVERLAPPED也不影响,因为是很早以前的东西,不是用vc写的,所以源码就不贴出来了。
谢谢两位 如果我把数据先保存下来 然后等数据齐了再解压 这样是不是就没办法实现修改返回数据包的功能了?因为前面的数据都已经传上去了你不用管调用方如何,直接在hook内循环调用原始recv获取到所有数据,然后调用在下一次调用的时候,直接判断s句柄,依次copymem就行了,
谢谢两位 如果我把数据先保存下来 然后等数据齐了再解压 这样是不是就没办法实现修改返回数据包的功能了?因为前面的数据都已经传上去了你不用管调用方如何,直接在hook内循环调用原始recv获取到所有数据,然后调用在下一次调用的时候,直接判断s句柄,依次copymem就行了,
谢谢回答 我昨天晚上也在尝试直接在hook里面循环调用原始recv来获取数据 经测试这种方法是可行的 不过测试中发现会导致浏览器不稳定 特别是浏览数据比较多的页面更容易奔溃 正在找问题所在 怀疑是内存管理有问题 因为我每次都动态new了200k的内存用来存储一个完整的数据包 不知道您在实现中有碰到这样的情况么?
是否注意到上面的问题?暂存数据的时候,要调用方再次recv接收完毕才能释放内存,还要注意多线程问题,做好临界区或读写锁。
是否注意到上面的问题?暂存数据的时候,要调用方再次recv接收完毕才能释放内存,还要注意多线程问题,做好临界区或读写锁。
我现在还没做gzip以及chunked等参数的处理,纯粹是把多个数据包全部收取再合并成一个返回调用方,我把代码贴一下,麻烦帮我看一下哪里有问题 因为总会导致浏览器奔溃 不会是这种强行去多次循环读取数据的方式 会破坏结构吧?另外,您提到的多线程问题,我目前只hook处理recv 也需要处理多线程么?用什么样的方式来处理呢?
int WINAPI HookRecv( IN SOCKET s, __out_bcount_part(len, return) __out_data_source(NETWORK) char FAR * buf, IN int len, IN int flags)
{
int nRealLen=0, nLen=0, nTotalLen=0;
CString strBuffer="", strHeader="";
BOOL bRet = FALSE;
char *pBuffer = NULL;
char *pPoint = NULL; try
{
do
{
//循环调用系统的recv方法
nRealLen = SysRecv(s, buf, len, flags);
if (nRealLen <= 0)
break;
strBuffer = buf;
if (strBuffer.Mid(0, 4) == "HTTP")
{//新的包头
//分离包头和包体
nLen = strBuffer.Find("\r\n\r\n");
if (nLen == -1)
break;
strHeader = str.Left(nLen + 4);
//解析包头
RESPONSEHEADER resHttpHead;
bRet = ParseResHttpHead(strHeader, &resHttpHead);
if (!bRet)
break; //只处理html类型页面
if (resHttpHead.strContentType.Find("text/html") == -1)
break; //申请临时存储内存(200kb)
pBuffer = new char[nMaxBufLen];
memset(pBuffer, 0, nMaxBufLen);
//将首地址赋给临时指针
pPoint = pBuffer;
if (pPoint == NULL)
break;
} if (nRealLen > (nMaxBufLen-nTotalLen))
{//当前内容超过临时内存剩余大小
break;
} //将缓冲区内容拷贝到临时内存
memcpy(pPoint, buf, nRealLen);
//指针偏移
pPoint += nRealLen;
nTotalLen += nRealLen; } while (nRealLen>0);
}
catch (CException* e)
{
e->Delete();
} if (nTotalLen > 0 && pBuffer)
{
//将临时内存中的数据拷贝到系统缓冲区,并设置数据大小
memcpy(buf, pBuffer, nTotalLen);
nRealLen = nTotalLen; delete[] pBuffer;
pBuffer = NULL;
} return nRealLen;
}
推荐你用我的思路框架来设计,
因为recv第一次调用,你获取完所有数据之后,需要做一个socket句柄的数据映射,如果第一次缓冲区不够存放,调用方会接二连三的调用recv获取数据,所以,此时你在hook头部应该判断是否有数据映射,如果有,就记录好offset依次cpymem,还有,不能单纯的判断recv ret=0,如果返回值是SOCKET_ERROR(-1),此时判断error值,很可能是block了,数据未返回,比如网络阻塞等,这里不能返回,等待约几十毫秒(我设的200ms)继续循环操作,这里跳出while的条件应当以ret=0,数据长度是否满足Content-Length,以及 chunked的结束标记{ 13, 10, 48, 13, 10 }等来判断。
我邮箱[email protected]
再次表示感谢!
我邮箱[email protected]
您好。终于找到类似问题的帖子了!
我已经通过HOOK 得到了响应包的buf,然后想通过修改它的回包状态码为301或者302,Location到一个指定的网址。
我用的是VC++(vs2010)做的,hook的是NtDeviceIoControlFile得到了回包的内容。但是接下来不会修改回包状态码及其Location的代码。您能帮我分析一下吗?谢谢!
我已经通过HOOK 得到了响应包的buf,然后想通过修改它的回包状态码为301或者302,Location到一个指定的网址。
我用的是VC++(vs2010)做的,hook的是NtDeviceIoControlFile得到了回包的内容。但是接下来不会修改回包状态码及其Location的代码。您能帮我分析一下吗?谢谢!