解决方案 »

  1.   

    谢谢回答 是的 我的确是有知道文件的大小 也就是16k 但每次只能收4k 因为是用的hook 我必须还得往上层传 但是包没收完不能解压 那我是传呢还是不传呢?
      

  2.   

     赵老师 你好 共享内存可以很好的实现我需要的逻辑么? 我把我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;
    }
      

  3.   

    谢谢回答 是的 我的确是有知道文件的大小 也就是16k 但每次只能收4k 因为是用的hook 我必须还得往上层传 但是包没收完不能解压 那我是传呢还是不传呢?肯定要往上传了,但你在共享的内存空间里把数据先保存下来,这样接收完后就能解压了
      

  4.   

    这个东西我做过,是直接修改网页数据的。
    你说的情况,可以直接在返回数据后判断是否
    HTTP/1.1 200 OK
    如果是,那就解析文件头,里面包含有长度,编码类型,传输类型,是否GZIP压缩,是否是chunked编码等,
    如果没有Content-Length,那就判断是否是chunked,都没有,那直接就检测Connection是否是close。
    如果是,那数据就到头了,然后就合并所有接收到的数据,返回给调用方即可。我的框架是,
    建立socket句柄的数据映射,可以是list,map,随意,因为是多线程的,这点是必须的。
    结构大致如下
    myrevc_
    {
    申请新映射或者,如果有,就根据调用方提供的缓存大小依次返回数据,offset控制好即可,数据返回完毕就删除映射,。
    调用原始recv,
    判断网页类型,超文本协议,获取文件长度,编码类型等等。
    这里不考虑大文件,所以循环调用原始recv,读取出所有数据,直到结束,然后合并,解码,dosameting。
    返回调用方剩余的缓存区大小。
    }
    WSARecv大同小异,OVERLAPPED也不影响,因为是很早以前的东西,不是用vc写的,所以源码就不贴出来了。
      

  5.   


    谢谢两位  如果我把数据先保存下来 然后等数据齐了再解压  这样是不是就没办法实现修改返回数据包的功能了?因为前面的数据都已经传上去了你不用管调用方如何,直接在hook内循环调用原始recv获取到所有数据,然后调用在下一次调用的时候,直接判断s句柄,依次copymem就行了,
      

  6.   

    还有一点需要注意的就是,在返回给调用方数据的时候,一定要把协议头改成正确的,比如gbk你转换成了UNICODE操作,GZIP解压了,chunked解码了,等等,这些都需要修改http的协议头,如果不修改则可能出现乱码等情况。一般去掉chunked属性,即删除Transfer-Encoding。填对Content-Length即可。这个如果不改正确,则可能出现内存错误(数据长度不对,越界),网页显示不完整等情况。
      

  7.   


    谢谢两位  如果我把数据先保存下来 然后等数据齐了再解压  这样是不是就没办法实现修改返回数据包的功能了?因为前面的数据都已经传上去了你不用管调用方如何,直接在hook内循环调用原始recv获取到所有数据,然后调用在下一次调用的时候,直接判断s句柄,依次copymem就行了,
    谢谢回答 我昨天晚上也在尝试直接在hook里面循环调用原始recv来获取数据 经测试这种方法是可行的 不过测试中发现会导致浏览器不稳定 特别是浏览数据比较多的页面更容易奔溃 正在找问题所在 怀疑是内存管理有问题 因为我每次都动态new了200k的内存用来存储一个完整的数据包 不知道您在实现中有碰到这样的情况么?
      

  8.   


    是否注意到上面的问题?暂存数据的时候,要调用方再次recv接收完毕才能释放内存,还要注意多线程问题,做好临界区或读写锁。
      

  9.   


    是否注意到上面的问题?暂存数据的时候,要调用方再次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;
    }
      

  10.   

    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 }等来判断。
      

  11.   

    这里的多线程的意思是,你hook了recv函数,但是调用方是用多线程来调用recv的,这不是你能控制的,而是调用方的操作。你要源码的话,我这里有一份,不过是其他语言的,大概意思都很好理解,在这里就不贴了,当时是别人花1千让我写的。你要的话就免费送你了,
      

  12.   

    非常非常感谢!!!真的,看了您的整个思路,终于实现了我想要的功能,一开始没有看懂所以才会导致出错,真的非常感谢,至于源码,如果您方便的话,麻烦还是发我参考一下,其他语言没关系,估计我一些细节上还没考虑得很周到,需要再借鉴一下。
    我邮箱[email protected]
    再次表示感谢!
      

  13.   

    估计我一些细节上还没考虑得很周到,需要再借鉴一下。
    我邮箱[email protected]
    您好。终于找到类似问题的帖子了!
    我已经通过HOOK 得到了响应包的buf,然后想通过修改它的回包状态码为301或者302,Location到一个指定的网址。
    我用的是VC++(vs2010)做的,hook的是NtDeviceIoControlFile得到了回包的内容。但是接下来不会修改回包状态码及其Location的代码。您能帮我分析一下吗?谢谢!
      

  14.   

    您好。终于找到类似问题的帖子了!
    我已经通过HOOK 得到了响应包的buf,然后想通过修改它的回包状态码为301或者302,Location到一个指定的网址。
    我用的是VC++(vs2010)做的,hook的是NtDeviceIoControlFile得到了回包的内容。但是接下来不会修改回包状态码及其Location的代码。您能帮我分析一下吗?谢谢!