C++ WinSock send()钩子导致访问冲突

C++ WinSock send()钩子导致访问冲突,c++,hook,winsock,inline-assembly,C++,Hook,Winsock,Inline Assembly,我想写一个“中间人”程序来帮助我调试正在开发的网络应用程序。经过一些谷歌搜索(我根本不知道怎么做),我想到了我必须创建一个钩子(我以前在其他语言中使用过钩子,但它们要简单得多)来拦截WinSock的send。根据各种文章,我必须修改函数的前5个字节以跳转到我的函数,做一些工作,然后跳回。我在网上找到了它,并在控制台应用程序中重写了它。以下是我的想法: #include "stdafx.h" #include <iostream> #include <WinSock2.h>

我想写一个“中间人”程序来帮助我调试正在开发的网络应用程序。经过一些谷歌搜索(我根本不知道怎么做),我想到了我必须创建一个钩子(我以前在其他语言中使用过钩子,但它们要简单得多)来拦截WinSock的
send
。根据各种文章,我必须修改函数的前5个字节以跳转到我的函数,做一些工作,然后跳回。我在网上找到了它,并在控制台应用程序中重写了它。以下是我的想法:

#include "stdafx.h"
#include <iostream>
#include <WinSock2.h>
#include <windows.h>

#pragma comment(lib, "ws2_32.lib")
#define JMP(frm, to) (int)(((int)to - (int)frm) - 5);

#define DEF_PORT 27015

using namespace std;

bool HookSend();
void UnhookSend();

DWORD SendOriginal          = 0;
DWORD SendReturn            = 0;
DWORD *SendHookFunc         = 0;
DWORD OldProtection         = 0;

char* send_buffer;
int send_sizeofdata         = 0;
SOCKET send_s;
int send_flags              = 0;

HINSTANCE hWinSock          = 0;

void __declspec(naked) __stdcall SendHook()
{
    __asm
    { 
        mov     edi,edi
        push    ebp
        mov     ebp, esp
        mov     eax, [ebp+0x08]         /* Param 1 : Socket */
        mov     send_s, eax
        mov     eax, [ebp+0x0C]         /* Param 2 : buffer */
        mov     [send_buffer], eax
        mov     eax, [ebp+0x10]         /*Param 3 : Size*/
        mov     send_sizeofdata, eax
        mov     eax, [ebp+0x14]         /*Param 4 : flags*/
        mov     send_flags, eax
        jmp     SendReturn
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsaData;
    SOCKET soket;
    sockaddr_in soketDesc;

    char buf[256];

    cout << "Packet Reader by Timothy Volpe" << endl;
    cout << "Program will read packets sent" << endl << endl;

    cout << "Loading WinSock" << endl;
    if((hWinSock = LoadLibrary("ws2_32.dll")) == NULL)
    {
        cout << "Failed to load WinSock library" << endl;
        return -1;
    }

    cout << "Starting WinSock API" << endl;

    if(WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR)
    {
        cout << "Failed to load WinSock API (Error:" << WSAGetLastError() << ")" << endl;
        cout << "Press enter to exit" << endl;
        cin.get();
        return -1;
    }

    cout << "Hooking send()" << endl;
    if(!HookSend())
    {
        cout << "Press enter to exit" << endl;
        cin.get();
        return -1;
    }
    cout << "Hooked successfully!" << endl;

    cout << "Creating socket" << endl;
    soket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(soket == INVALID_SOCKET)
    {
        cout << "Failed to create socket (Error:" << WSAGetLastError() << ")" << endl;
        UnhookSend();
        cout << "Press enter to exit" << endl;
        cin.get();
        return -1;
    }

    cout << "Connecting socket to port " << DEF_PORT << endl;
    soketDesc.sin_family        = AF_INET;
    soketDesc.sin_addr.s_addr   = inet_addr("127.0.0.1");
    soketDesc.sin_port          = htons(DEF_PORT);
    if(connect(soket, (SOCKADDR*)&soketDesc, sizeof(soketDesc)) == SOCKET_ERROR)
    {
        cout << "Failed to connect socket (Error:" << WSAGetLastError() << ")" << endl;
        UnhookSend();
        cout << "Press enter to exit" << endl;
        cin.get();
        return -1;
    }

    cout << "Enter some data to send (MAX 256):" << endl;
    cin.get(buf, 256); //Read 256 chars
    cout << "Sending \"" << buf << "\"" << endl;

    //Send the data
    send(soket, buf, (int)sizeof(buf), 0);

    //Close
    closesocket(soket);
    WSACleanup();

    UnhookSend();

    cout << endl << "Press enter to exit" << endl;
    cin.clear();
    cin.ignore();
    cin.get();

    return 0;
}

bool HookSend()
{
    //Get the new function's address
    SendHookFunc = (DWORD*)SendHook;
    //Get the send() function's address
    SendOriginal = (DWORD)GetProcAddress(hWinSock, "send");
    //Get the return address, which is 5 bytes past the start
    SendReturn = SendOriginal + 5;
    printf("SEND\tStart: %x\t Return: %x\n", SendOriginal, SendReturn);
    //Change protection for the first 5 bytes
    VirtualProtect((void*)SendOriginal, 0x05, PAGE_READWRITE, &OldProtection);
    *(BYTE*)(SendOriginal) = 0xe9;
    *(int*)(SendOriginal+1) = JMP(SendOriginal, SendHookFunc);

    return true;
}

void UnhookSend()
{
    cout << "Unhooking..." << endl;
    //Restore the old stuff
    *(WORD*)SendOriginal = 0xFF8B;
    *(BYTE*)(SendOriginal+1) = 0x55;
    *(WORD*)(SendOriginal+3) = 0xEC8B;
    //Restore protection
    VirtualProtect((void*)SendOriginal, 0x05, OldProtection, &OldProtection);
}
#包括“stdafx.h”
#包括
#包括
#包括
#pragma注释(lib,“ws2_32.lib”)
#定义JMP(frm,to)(int)((int)to-(int)frm)-5;
#定义DEF_端口27015
使用名称空间std;
bool-HookSend();
void UnhookSend();
DWORD SendOriginal=0;
DWORD SendReturn=0;
DWORD*SendHookFunc=0;
德沃德保护=0;
字符*发送缓冲区;
int send_sizeofdata=0;
套接字发送;
int send_flags=0;
HINSTANCE hWinSock=0;
void u declspec(裸体)u stdcall SendHook()
{
__asm
{ 
电子数据交换
推ebp
电动汽车
mov eax,[ebp+0x08]/*参数1:插座*/
mov发送,eax
mov eax,[ebp+0x0C]/*参数2:缓冲区*/
mov[send_buffer],eax
mov eax,[ebp+0x10]/*参数3:大小*/
mov发送大小数据,eax
mov eax,[ebp+0x14]/*参数4:标志*/
mov发送_标志,eax
jmp发送返回
}
}
int _tmain(int argc,_TCHAR*argv[]
{
WSADATA WSADATA;
插座式水槽;
Socketdesc的sockaddr_;
char-buf[256];

cout您没有检查对VirtualProtect的调用的返回值;我猜它不会成功,并且您可能没有必要的权限。您是否以“管理员”身份运行此代码,是否禁用了Windows UAC功能


更新您的代码以检查VirtualProtect的返回值,并让我们知道这是否揭示了什么。

很少需要以这种暴力方式调试实际的API调用本身。您可以使用Wireshark之类的数据包嗅探器来捕获和分析正在传输的网络流量。但是如果您必须为API调用设置错误,您实际上是在尝试手动实现迂回,因此您确实应该使用Microsoft的迂回库来正确实现真正的迂回。更好的选择是使用WinSock的内置调试功能,而不是挂接API函数。让操作系统处理对API调用和参数的挂接和记录你。

这感觉像是病毒会使用的代码。为什么你不能通过操作系统和防病毒软件似乎合法的东西来隧道流量?为什么不写一个LSP或使用迂回注入?你覆盖和跳过的原始函数的5个字节,它们是否对应于钩子路由的第一条指令ne?如果你感兴趣,我可以向你展示如何使用我们公司的钩子引擎进行钩子。关于许可证,你可以自由使用它:只有一个自动淡入淡出的对话框。它负责注入和参数解析。我的代码可能看起来可疑,因为我真的完全不知道怎么做。我想我不是技术黑客,但我是黑客我自己的程序…所以…?(我也得到了很多关于“奇怪”网站的教程…)我已经放弃了。当时这似乎是个好主意,我玩得很开心。但我并不真的需要它。如果我需要它,我会使用迂回,就像大家建议的那样:)我会检查返回值。据我所知,它总是以管理员的身份运行。我在我的机器上有一个帐户,它是一个管理员帐户。默认情况下,所有可执行文件都以管理员的身份运行。我禁用了UAC很久以前就讨厌那件事了……我承认,我确实是为了冒险才这么做的。但是我找不到太多关于如何实时查看网络上发送的所有数据包的信息。似乎没有必要为我可能再也不会做的事绕道而行。如果你只想查看传输的数据包,那么就使用数据包剪报fer,例如Wireshark。