fkhook.cpp 6.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#include <winsock2.h>
#include "fkhook.h"
#include "platform.h"
#include <vector>

#ifdef _CPU_X86
#define SENDTO_ENTRY_LEN 5
#define SELECT_ENTRY_LEN 7
#define RECVFROM_ENTRY_LEN 5
#endif
#ifdef _CPU_X64
#define SENDTO_ENTRY_LEN 7
#define SELECT_ENTRY_LEN 7
#define RECVFROM_ENTRY_LEN 7
#endif

typedef int WINAPI(*sendto_func) (SOCKET, const char *, int, int, const sockaddr *, int);
typedef int WINAPI(*select_func) (int, fd_set *, fd_set *, fd_set *, const TIMEVAL *);
typedef int WINAPI(*recvfrom_func) (SOCKET, char *, int, int, sockaddr *, int *);

static InlineHook *sendto_hook = NULL;
static InlineHook *select_hook = NULL;
static InlineHook *recvfrom_hook = NULL;
static sendto_func _sendto = NULL;
static select_func _select = NULL;
static recvfrom_func _recvfrom = NULL;
static SOCKET origin_sock = 0, fake_sock = 0;
static std::vector<SOCKET> socks;

// 枚举当前所有可用网卡的IPv4地址
static const std::vector<in_addr> &enum_addr()
{
    static std::vector<in_addr> list;
    hostent *phost = gethostbyname(""); // 获取本机网卡
    if (phost) {
        char **ppc = phost->h_addr_list; // 获取地址列表
        int addr_num = 0;
        while (*ppc)
            addr_num++, ppc++; // 获取地址个数
        if (addr_num == list.size()) // 数量相同直接返回
            return list;
        ppc = phost->h_addr_list;
        list.clear();
        // 遍历列表添加到容器
        while (*ppc) {
            in_addr addr;
            memcpy(&addr, *ppc, sizeof(in_addr));
            list.push_back(addr);
            ppc++;
        }
    }
    return list;
}

// hook后替换的函数
static int WINAPI fake_sendto(SOCKET s, const char *buf, int len, int flags, const sockaddr *to, int tolen)
{
    sockaddr_in *toaddr = (sockaddr_in *)to;
    if (toaddr->sin_addr.S_un.S_addr != INADDR_BROADCAST) {
        return _sendto(s, buf, len, flags, to, tolen); // 非广播直接原样发送
    }
    else {
        int result = -1;
        origin_sock = s; // 暂存这个socket
        const std::vector<in_addr> &list = enum_addr();
        if (socks.size() != list.size()) {
            sockaddr_in addr_self;
            addr_self.sin_family = AF_INET;
            int namelen = sizeof(sockaddr_in);
            getsockname(s, (sockaddr *)&addr_self, &namelen); // 获取原sockaddr
            if (addr_self.sin_port == 0) {
                // 如果没有端口号,先原样发送,这样系统才会分配一个端口号
                result = _sendto(s, buf, len, flags, to, tolen);
                getsockname(s, (sockaddr *)&addr_self, &namelen); // 重新获取
            }
            for (int i = 0; i < socks.size(); i++)
                closesocket(socks[i]);
            socks.clear();
            for (int i = 0; i < list.size(); i++) {
Peacoor Zomboss's avatar
Peacoor Zomboss 已提交
80
                addr_self.sin_addr = list[i]; // 把新的地址换上去,然后绑定
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
                SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
                BOOL opt = TRUE;
                setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(BOOL)); // 广播
                setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(BOOL)); // 重用地址端口
                bind(sock, (sockaddr *)&addr_self, sizeof(sockaddr)); // 绑定到地址端口
                socks.push_back(sock);
            }
        }
        // 向列表中的每一个地址转发广播
        for (int i = 0; i < socks.size(); i++) {
            result = _sendto(socks[i], buf, len, flags, to, tolen);
        }
        return result;
    }
    return -1;
}

static int WINAPI fake_select(int n, fd_set *rd, fd_set *wr, fd_set *ex, const TIMEVAL *timeout)
{
    if (rd && rd->fd_count == 1 && origin_sock == rd->fd_array[0]) {
        fd_set fds;
        FD_ZERO(&fds);
        for (int i = 0; i < socks.size(); i++)
            FD_SET(socks[i], &fds);
        int r = _select(0, &fds, NULL, NULL, timeout);
        if (r > 0) {
            fake_sock = fds.fd_array[0];
            return fds.fd_count;
        }
        fake_sock = 0;
Peacoor Zomboss's avatar
Peacoor Zomboss 已提交
111 112
        rd->fd_count = 0;
        return 0;
113
    }
Peacoor Zomboss's avatar
Peacoor Zomboss 已提交
114
    return _select(n, rd, wr, ex, timeout);
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
}

static int WINAPI fake_recvfrom(SOCKET s, char *buf, int len, int flags, sockaddr *from, int *fromlen)
{
    if (s == origin_sock && fake_sock != 0) {
        return _recvfrom(fake_sock, buf, len, flags, from, fromlen);
    }
    else
        return _recvfrom(s, buf, len, flags, from, fromlen);
}

void hook_sendto()
{
    if (!sendto_hook) {
        sendto_hook = new InlineHook(GetModuleHandleA("ws2_32.dll"), "sendto", (void *)fake_sendto, SENDTO_ENTRY_LEN);
        _sendto = (sendto_func)sendto_hook->get_old_entry();
        sendto_hook->hook();
    }
}

void unhook_sendto()
{
    if (sendto_hook) {
        sendto_hook->unhook();
        delete sendto_hook;
        sendto_hook = NULL;
    }
}

void hook_select()
{
    if (!select_hook) {
        select_hook = new InlineHook(GetModuleHandleA("ws2_32.dll"), "select", (void *)fake_select, SELECT_ENTRY_LEN);
        _select = (select_func)select_hook->get_old_entry();
        select_hook->hook();
    }
}
void unhook_select()
{
    if (select_hook) {
        select_hook->unhook();
        delete select_hook;
        select_hook = NULL;
    }
}

void hook_recvfrom()
{
    if (!recvfrom_hook) {
        recvfrom_hook = new InlineHook(GetModuleHandleA("ws2_32.dll"), "recvfrom", (void *)fake_recvfrom, RECVFROM_ENTRY_LEN);
        _recvfrom = (recvfrom_func)recvfrom_hook->get_old_entry();
        recvfrom_hook->hook();
    }
}

void unhook_recvfrom()
{
    if (recvfrom_hook) {
        recvfrom_hook->unhook();
        delete recvfrom_hook;
        recvfrom_hook = NULL;
    }
}

void hook()
{
    hook_sendto();
    hook_select();
    hook_recvfrom();
}

void unhook()
{
    unhook_sendto();
    unhook_select();
    unhook_recvfrom();
    for (int i = 0; i < socks.size(); i++)
        closesocket(socks[i]);
    socks.clear();
}