【问题标题】:Intercepting winsock recvfrom function gives invalid address error拦截winsock recvfrom函数给出无效地址错误
【发布时间】:2017-12-27 19:19:34
【问题描述】:

我正在尝试拦截 winsock2 调用以解决同一主机上的进程之间的 UDP 数据包间歇性消失的情况。当它们“消失”时,它们会消失大约 20 秒,这足以中止正在运行的进程。

我设法让 DLL 注入工作,并且正确拦截了 2 个 winsock 调用(我希望如此),因为我可以进行简单的打印,但我需要能够处理地址信息,以便我可以跟踪谁发送了什么给谁...

不幸的是,我注入的上游进程显然是调用 recvfrom (是的,不是 WSA... 等价物,这是旧移植的 POSIX 代码),“from”和“fromlen”参数为 NULL。如果我根本不摆弄他们的接收作品。如果我执行以下操作,我会收到“无效地址”错误(Winsock 错误 10014)。

我在这里做了一些愚蠢的事情吗?并不是说我会感到惊讶.... 是的,使用所需的调试重建目标应用程序会更容易,但是由于数据中心迁移,构建环境已关闭,我需要弹药说“这不是申请。”

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include "mhook.h"
#include <winsock2.h>

// typedefs for function pointers...

typedef int(WINAPI *rcvfrom_ptr) (
SOCKET          s,
char            *buf,
int             len,
int             flags,
struct sockaddr *from,
int             *fromlen
);

typedef int(WINAPI *sendto_ptr) (
_In_       SOCKET                s,
_In_ const char                  *buf,
_In_       int                   len,
_In_       int                   flags,
_In_       const struct sockaddr *to,
_In_       int                   tolen
);

// Function pointers for original calls.

rcvfrom_ptr orig_rcvfrom;
sendto_ptr orig_sendto;

//
// Helper functions.
//

typedef union sockaddrs {
    struct sockaddr from;
    struct sockaddr_in in_from;
    // Need to verify Ipv6 support. may need to remigrate back to VS 2015
    //struct sockaddr_in6 in6_from;
} tsockaddrs;

char *printaddr(char *buff,const int buffsz, const tsockaddrs *addr)
{
    ...
}

// Shim functions.
//
// Still working on getting them to actually work and do what I need. 
// But I may as well develop the skeleton

int WINAPI Myrecvfrom(SOCKET          s,
                char            *buf,
                int             len,
                int             flags,
                struct sockaddr *from,
                int             *fromlen
)
{
    int result;
    struct sockaddr *all_froms;
    char addrbuff[100] = "";
    int newfromlen = sizeof(struct sockaddr);

    all_froms = (struct sockaddr *)malloc(sizeof(struct sockaddr));
    memset((void *)all_froms,0,sizeof(struct sockaddr));

    printf("Receiving Packet!\n");
    if (from == NULL) {
        printf("\tFrom addr == null, using internal structures\n");
        result =  (orig_rcvfrom)(s, buf, len, flags, all_froms, &newfromlen);
    } else {
        printf("\tFrom addr != null, using passed structures\n");
        result =  (orig_rcvfrom)(s, buf, len, flags, from, fromlen);
        memcpy_s((void*)&all_froms,sizeof(all_froms),(void *)from,*fromlen);
        if (fromlen != NULL) {
            newfromlen=*fromlen;
        } else { 
            newfromlen=sizeof(struct sockaddr);
        }
    }

    if (result >0) {printf("received %d bytes\n",result);}
    else if (result == SOCKET_ERROR) {printf("Socket Error %d occurred!\n",WSAGetLastError());}
    if (newfromlen >0) {
        if (printaddr(addrbuff,sizeof(addrbuff),(tsockaddrs *)all_froms)!=NULL) {
            printf("received %d bytes from on port %d from host %s\n",result,((tsockaddrs *)(all_froms))->in_from.sin_port,addrbuff);
        }
        if (from != NULL) {
            memcpy_s((void*)from,sizeof(struct sockaddr),(void*)&all_froms,newfromlen);
        }
        else
        {

        }
        if (fromlen != NULL) *fromlen=newfromlen;
    }
    else {
            printf("received %d bytes from unknown port and host\n",result);
    }

    if (all_froms != NULL) {free(all_froms);}
    return result;
}

int WINAPI Mysendto(SOCKET                s,
    const char                  *buf,
    int                   len,
    int                   flags,
    const struct sockaddr *to,
    int                   tolen
)
{
    printf("Sending packet!\n");

    return orig_sendto(s, buf, len, flags, to, tolen);
}

BOOL AttachHooks(void)
{
    BOOL sethooks;
    orig_rcvfrom = (rcvfrom_ptr)GetProcAddress(GetModuleHandle(L"ws2_32"), "recvfrom");
    sethooks = Mhook_SetHook((PVOID*)&orig_rcvfrom, Myrecvfrom);
    if (sethooks) {
        orig_sendto = (sendto_ptr)GetProcAddress(GetModuleHandle(L"ws2_32"), "sendto");
        sethooks &= Mhook_SetHook((PVOID*)&orig_sendto, Mysendto);
    }
    return sethooks;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{

    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        printf_s("This is an attached DLL!\n");
        AttachHooks();
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

【问题讨论】:

  • UDP 数据包消失:这意味着它们是由源发送的,但它们从未到达目的地。这在 UDPPoV 中是可以的。如果你正在调整recvfrom(注意:这个函数非常好,我觉得WSARecvFrom 只是它的一个包装器)你也在目标端做它,如果数据包没有达到它,您发现新事物的机会很小。另外:你怎么称呼Myrecvfrom?什么参数(fromfromLen 仍然为 0)?
  • 错误 10014 的完整描述是“系统在尝试在调用中使用指针参数时检测到无效的指针地址。”这个由于注入代码的进程内存映射问题而不是winsock代码,似乎与内存冲突有关。
  • @christifati -- 我正在注入这个 DLL 并覆盖 winsock2 recvfrom。我的目标是最终证明 process1 发送的数据包永远不会到达 process 2,(反之亦然)。
  • @Frankie_C 理论上,注入的DLL中的堆不会相同吗?如果没有,关于如何获取地址数据的任何想法?我想我可以使用 MSG_PEEK 对套接字进行完全并行读取...
  • 我知道 dll 注入的目的,但这就是我的意思。如果您从源发送一些消息,但recvfrom 没有在目标上捕获它(意味着它在两者之间的某个地方被丢弃),那么您在目标上运行的所有代码(例如Myrecvfrom)都是无用的,因为它赢了不被执行。现在,原始代码如何调用recvfrom?你有sn-p吗?发件人是否有可能是 IPv6

标签: c windows visual-studio-2010 winsock2


【解决方案1】:

问题的原因是回复的实际大小大于“struct sockaddr”的大小。它实际上是一个 SOCKADDR_IN6 结构回来了。使用 200 字节的任意缓冲区而不是 28 字节的 sockaddr 结构,我能够提取数据。

在这个过程中,我最终转换为“偷看”接收到的数据,而不是在数据被拉入后对其进行处理。当有源代码的 PC 完成安装更新时,我会发布它。

在家工作是相当孤立的,反正我办公室里没有人住在winsock。在 cmets 中“聊天”真的很有帮助。

【讨论】:

    猜你喜欢
    • 2011-05-15
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-01
    • 1970-01-01
    相关资源
    最近更新 更多