修复10年前游戏的BUG

· 2026-05-28 08:00 · 2 阅读

原创 huoji 2026-05-28 08:00 北京

前言

这几天在跟朋友玩《异形:殖民军》这款游戏,这款游戏于2013年发售,制作完后制作组就跑路了。可以简单理解为这是一款太空版支持联机过剧情的使命召唤like游戏。我们两个下的都是FLT修改版本,本来想以前走hamachi局域网联机。

但是意外发生了,我们死活联机不上。提示找不到游戏。随后我们试了一下tun方案/对战平台方案,完全没办法联机。

可是我记得十年前玩的时候是可以正常联机的。问题出在哪?

联机流程

由于游戏早就死了,steam买不值得,我们用的是盗版,盗版走的是局域网联机方案,所谓局域网联机方案,一般指的是用hamachi或者对战平台或者各种联机工具 建立一个虚拟局域网,大家都有一样的虚拟局域网ip

这个虚拟机的网卡就是假的局域网,从而让大家走“局域网联机”

理论上我们应该连的上,所以对这个网卡进行抓包,发现完全没游戏的数据包进来(游戏数据包是UPD,这里只有ICMP,是测延迟用的)

传统游戏的局域网联机逻辑是,游戏对所有网卡的0.0.0.0 发一个UDP广播包,255.255.255.255 这个包会在整个局域网进行广播,然后如果有客户端就会 回包。
这个游戏确实监听了UDP端口,并且等待广播包

所以 问题很明显,游戏并没有对这个网卡发包。打开procmon,我们看看游戏发了什么包:

我们可以看到,这个是第一个问题,这个游戏广播的包是我的物理网卡地址,并不是TUN的卡的地址。那肯定是没有人回复的。
这个问题很好解决,根据我多年的零信任开发经验,游戏应该是通过一个叫做 越点 的机制去判断当前可用网卡的,我们只需要把虚拟网卡的越点设置为1就行

这样游戏就会优先考虑虚拟网卡的IP发包。但是依然连不上
再次抓包,发现:

解读一下,游戏的广播包服务端确实返回了回复了,我的客户端也即将链接,但是我的客户端莫名其妙的链到了25.16.24.136这个完全摸不着头脑的国外地址! 按理说应该直接链接10.100.239.2这个我的朋友的虚拟网卡IP的

经过一段时间的摸索,我发现,这个25.16.245.136是我朋友的一个虚拟网卡的IP地址,说明: 游戏服务端收到信息了,但是回复的网卡IP错误!理论上,应该回复他的当前包过来的绑定的IP但是为什么会回复这个,不知道。

临时解决方法是,禁用这个虚拟网卡,祈祷游戏能找到真的地址
禁用虚拟网卡后,我们发现更完蛋了,游戏服务端返回的是电脑的物理网卡地址
 

这个是不可能通的,除非开零信任。零信任这个时候确实派上用场了。但是肯定不能为了一个游戏装这玩意。
因此有必要去代码层看看了

深入代码层

让我们直接逆向这个游戏,看看为什么会这样吧拖入IDA,对sento打断点,连接游戏看看:

构造255.255.255.255的包

发送:

可以看到,发送的socket是一个socket,而不是枚举网卡逐个发送

这就导致了第一个问题,广播包没广播对网卡

对于第二个问题,我们抓一个包看看:
游戏服务器会返回一个包里面带了游戏服务端的IP地址

这一段是服务端的IP地址:

这个IP地址很明显也是错误的
根据服务端代码,问题出在得到网卡地址的这里,服务端收到包是能知道哪个socket的,但是他的网络和引擎层不是一个socket,他的网络层是获取不到的,所以他就只能,取一个本机 IP 发出去….毕竟,2013年的时候哪有那么复杂的网卡局域网联机环境?

而这个IP就是纯随机的来源。

修复这个bug

我们有几个修复方案,比如改包把IP改成自己的,起一个假的转发代理服务器等。但是最直接的办法是hook,我跟朋友写了两个方案,我的方案是客户端的方案,朋友的是服务端方案

客户端方案:
通过hook sockets,进行改包,我用的是minihook:

#include "pch.h"
#include <cstdio>
#include <cstdarg>
#include <cstdint>
#include <cstring>
#include <vector>
#include <string>
#include "MinHook/include/MinHook.h"
namespace {
using sendto_t = int(WINAPI*)(SOCKET, const char*, int, int, const sockaddr*,
                              int);
using recvfrom_t = int(WINAPI*)(SOCKET, char*, int, int, sockaddr*, int*);
using bind_t = int(WINAPI*)(SOCKET, const sockaddr*, int);
using getsockname_t = int(WINAPI*)(SOCKET, sockaddr*, int*);
using gethostname_t = int(WINAPI*)(char*, int);
using gethostbyname_t = hostent*(WINAPI*)(const char*);
sendto_t RealSendTo = nullptr;
recvfrom_t RealRecvFrom = nullptr;
bind_t RealBind = nullptr;
getsockname_t RealGetSockName = nullptr;
gethostname_t RealGetHostName = nullptr;
gethostbyname_t RealGetHostByName = nullptr;
HMODULE g_Module = nullptr;
HANDLE g_WorkerThread = nullptr;
volatile bool g_Running = true;
bool g_LogPackets = true;
bool g_FixPayload = false;
uint32_t g_ForcedIp = 0;
std::vector<uint32_t> g_LocalIps;
CRITICAL_SECTION g_LogLock;
uint32_t ReadBe32(const char* p) {
    return (uint32_t(uint8_t(p[0])) << 24) | (uint32_t(uint8_t(p[1])) << 16) |
           (uint32_t(uint8_t(p[2])) << 8) | uint32_t(uint8_t(p[3]));
}
void WriteBe32(char* p, uint32_t ip) {
    p[0] = char((ip >> 24) & 0xff);
    p[1] = char((ip >> 16) & 0xff);
    p[2] = char((ip >> 8) & 0xff);
    p[3] = char(ip & 0xff);
}
std::string IpToString(uint32_t ip) {
    char buf[32];
    std::snprintf(buf, sizeof(buf), "%u.%u.%u.%u", (ip >> 24) & 0xff,
                  (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
    return buf;
}
uint32_t SockAddrIp(const sockaddr* addr) {
    if (!addr || addr->sa_family != AF_INET) {
        return 0;
    }
    const sockaddr_in* in = reinterpret_cast<const sockaddr_in*>(addr);
    return ntohl(in->sin_addr.s_addr);
}
uint16_t SockAddrPort(const sockaddr* addr) {
    if (!addr || addr->sa_family != AF_INET) {
        return 0;
    }
    const sockaddr_in* in = reinterpret_cast<const sockaddr_in*>(addr);
    return ntohs(in->sin_port);
}
void Log(const char* fmt, ...) {
    EnterCriticalSection(&g_LogLock);
    va_list args;
    va_start(args, fmt);
    std::vprintf(fmt, args);
    va_end(args);
    std::printf("\n");
    std::fflush(stdout);
    LeaveCriticalSection(&g_LogLock);
}
bool IsInterestingPacket(const char* buf, int len) {
    if (!buf || len <= 0) {
        return false;
    }
    if (len >= 2 && buf[0] == 'U' &&
        (buf[1] == 'D' || buf[1] == 'C' || buf[1] == 'F')) {
        return true;
    }
    if (len >= 2 && buf[0] == 'N' && buf[1] == 'F') {
        return true;
    }
    if (len > 200) {
        return true;
    }
    return false;
}
bool LooksLikeUsefulIp(uint32_t ip) {
    const uint8_t a = uint8_t((ip >> 24) & 0xff);
    const uint8_t b = uint8_t((ip >> 16) & 0xff);
    if (ip == 0 || ip == 0xffffffff || a == 0 || a == 127 || a >= 224) {
        return false;
    }
    if (a == 10 || a == 25 || (a == 172 && b >= 16 && b <= 31) ||
        (a == 192 && b == 168)) {
        return true;
    }
    return false;
}
void ScanPayloadIps(const char* tag, const char* buf, int len) {
    if (!buf || len < 4) {
        return;
    }
    int shown = 0;
    for (int i = 0; i <= len - 4; ++i) {
        const uint32_t be = ReadBe32(buf + i);
        if (LooksLikeUsefulIp(be)) {
            if (shown == 0) {
                std::printf("%s candidate IPs:", tag);
            }
            std::printf(" +0x%X=%s", i, IpToString(be).c_str());
            ++shown;
            if (shown >= 12) {
                std::printf(" ...");
                break;
            }
        }
    }
    if (shown > 0) {
        std::printf("\n");
    }
}
void DumpPacketPrefix(const char* tag, const char* buf, int len) {
    if (!buf || len <= 0) {
        return;
    }
    const int count = len < 64 ? len : 64;
    std::printf("%s first %d:", tag, count);
    for (int i = 0; i < count; ++i) {
        std::printf(" %02X", uint8_t(buf[i]));
    }
    std::printf("\n");
}
void AddLocalIp(uint32_t ip) {
    if (ip == 0 || ip == 0x7f000001) {
        return;
    }
    for (uint32_t existing : g_LocalIps) {
        if (existing == ip) {
            return;
        }
    }
    g_LocalIps.push_back(ip);
}
void RefreshLocalIps() {
    g_LocalIps.clear();
    HMODULE wsock32 = GetModuleHandleW(L"WSOCK32.dll");
    if (!wsock32) {
        wsock32 = LoadLibraryW(L"WSOCK32.dll");
    }
    auto realGetHostName =
        reinterpret_cast<gethostname_t>(GetProcAddress(wsock32, "gethostname"));
    auto realGetHostByName = reinterpret_cast<gethostbyname_t>(
        GetProcAddress(wsock32, "gethostbyname"));
    char name[256] = {};
    if (realGetHostName && realGetHostByName &&
        realGetHostName(name, sizeof(name)) == 0) {
        hostent* host = realGetHostByName(name);
        if (host && host->h_addrtype == AF_INET) {
            for (char** addr = host->h_addr_list; addr && *addr; ++addr) {
                AddLocalIp(ntohl(*reinterpret_cast<uint32_t*>(*addr)));
            }
        }
    }
}
int ReplaceIpsInPayload(char* buf, int len, uint32_t replacement) {
    if (!buf || len < 4 || replacement == 0) {
        return 0;
    }
    int replaced = 0;
    for (int i = 0; i <= len - 4; ++i) {
        const uint32_t value = ReadBe32(buf + i);
        for (uint32_t localIp : g_LocalIps) {
            if (value == localIp && value != replacement) {
                WriteBe32(buf + i, replacement);
                ++replaced;
            }
        }
    }
    return replaced;
}
int WINAPI HookSendTo(SOCKET s, const char* buf, int len, int flags,
                      const sockaddr* to, int tolen) {
    const uint32_t toIp = SockAddrIp(to);
    const uint16_t toPort = SockAddrPort(to);
    if (g_LogPackets && IsInterestingPacket(buf, len)) {
        Log("sendto s=%p to=%s:%u len=%d", reinterpret_cast<void*>(s),
            IpToString(toIp).c_str(), toPort, len);
        DumpPacketPrefix("  send", buf, len);
        ScanPayloadIps("  send", buf, len);
    }
    if (g_FixPayload && g_ForcedIp && buf && len > 0) {
        std::vector<char> copy(buf, buf + len);
        const int changed = ReplaceIpsInPayload(copy.data(), len, g_ForcedIp);
        if (changed > 0) {
            Log("sendto fixed %d payload IP(s) -> %s", changed,
                IpToString(g_ForcedIp).c_str());
            return RealSendTo(s, copy.data(), len, flags, to, tolen);
        }
    }
    return RealSendTo(s, buf, len, flags, to, tolen);
}
int WINAPI HookRecvFrom(SOCKET s, char* buf, int len, int flags, sockaddr* from,
                        int* fromlen) {
    const int ret = RealRecvFrom(s, buf, len, flags, from, fromlen);
    if (ret <= 0) {
        return ret;
    }
    const uint32_t fromIp = SockAddrIp(from);
    const uint16_t fromPort = SockAddrPort(from);
    if (g_FixPayload && fromIp) {
        const int changed = ReplaceIpsInPayload(buf, ret, fromIp);
        if (changed > 0) {
            Log("recvfrom fixed %d payload IP(s) -> packet source %s", changed,
                IpToString(fromIp).c_str());
        }
    }
    if (g_LogPackets && IsInterestingPacket(buf, ret)) {
        Log("recvfrom s=%p from=%s:%u len=%d", reinterpret_cast<void*>(s),
            IpToString(fromIp).c_str(), fromPort, ret);
        DumpPacketPrefix("  recv", buf, ret);
        ScanPayloadIps("  recv", buf, ret);
    }
    return ret;
}
int WINAPI HookBind(SOCKET s, const sockaddr* name, int namelen) {
    const uint32_t ip = SockAddrIp(name);
    AddLocalIp(ip);
    Log("bind s=%p local=%s:%u", reinterpret_cast<void*>(s),
        IpToString(ip).c_str(), SockAddrPort(name));
    return RealBind(s, name, namelen);
}
int WINAPI HookGetSockName(SOCKET s, sockaddr* name, int* namelen) {
    const int ret = RealGetSockName(s, name, namelen);
    if (ret == 0) {
        const uint32_t ip = SockAddrIp(name);
        AddLocalIp(ip);
        Log("getsockname s=%p local=%s:%u", reinterpret_cast<void*>(s),
            IpToString(ip).c_str(), SockAddrPort(name));
    }
    return ret;
}
int WINAPI HookGetHostName(char* name, int namelen) {
    const int ret = RealGetHostName(name, namelen);
    if (ret == 0) {
        Log("gethostname -> %s", name);
    }
    return ret;
}
hostent* WINAPI HookGetHostByName(const char* name) {
    hostent* ret = RealGetHostByName(name);
    if (ret) {
        std::printf("gethostbyname %s ->", name ? name : "<null>");
        if (ret->h_addrtype == AF_INET) {
            for (char** addr = ret->h_addr_list; addr && *addr; ++addr) {
                const uint32_t ip = ntohl(*reinterpret_cast<uint32_t*>(*addr));
                AddLocalIp(ip);
                std::printf(" %s", IpToString(ip).c_str());
            }
        }
        std::printf("\n");
    }
    return ret;
}
bool HookExport(HMODULE module, const char* name, void* hook, void** original) {
    void* target = reinterpret_cast<void*>(GetProcAddress(module, name));
    if (!target) {
        Log("missing export: %s", name);
        return false;
    }
    MH_STATUS status = MH_CreateHook(target, hook, original);
    if (status != MH_OK && status != MH_ERROR_ALREADY_CREATED) {
        Log("MH_CreateHook(%s) failed: %d", name, status);
        return false;
    }
    status = MH_EnableHook(target);
    if (status != MH_OK && status != MH_ERROR_ENABLED) {
        Log("MH_EnableHook(%s) failed: %d", name, status);
        return false;
    }
    Log("hooked %s at %p", name, target);
    return true;
}
uint32_t ParseIp(const char* text) {
    unsigned int a = 0, b = 0, c = 0, d = 0;
    if (sscanf_s(text, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
        return 0;
    }
    if (a > 255 || b > 255 || c > 255 || d > 255) {
        return 0;
    }
    return (a << 24) | (b << 16) | (c << 8) | d;
}
void PrintHelp() {
    Log("commands:");
    Log("  help             show commands");
    Log("  log on|off       enable or disable packet logs");
    Log("  fix on|off       replace payload local IPs, default off");
    Log("  ip a.b.c.d       force replacement IP for outgoing sendto");
    Log("  local a.b.c.d    add an IP that should be replaced");
    Log("  ips              show local IPs detected by gethostbyname");
    Log("  refresh          refresh local IP list");
    Log("  quit             unhook and unload DLL");
}
void CommandLoop() {
    PrintHelp();
    char line[256] = {};
    while (g_Running && std::fgets(line, sizeof(line), stdin)) {
        line[strcspn(line, "\r\n")] = 0;
        if (_stricmp(line, "help") == 0) {
            PrintHelp();
        } else if (_stricmp(line, "log on") == 0) {
            g_LogPackets = true;
            Log("log on");
        } else if (_stricmp(line, "log off") == 0) {
            g_LogPackets = false;
            Log("log off");
        } else if (_stricmp(line, "fix on") == 0) {
            g_FixPayload = true;
            Log("fix on");
        } else if (_stricmp(line, "fix off") == 0) {
            g_FixPayload = false;
            Log("fix off");
        } else if (_strnicmp(line, "ip ", 3) == 0) {
            const uint32_t ip = ParseIp(line + 3);
            if (ip) {
                g_ForcedIp = ip;
                Log("forced IP = %s", IpToString(g_ForcedIp).c_str());
            } else {
                Log("bad ip");
            }
        } else if (_strnicmp(line, "local ", 6) == 0) {
            const uint32_t ip = ParseIp(line + 6);
            if (ip) {
                AddLocalIp(ip);
                Log("added local/replace source IP = %s",
                    IpToString(ip).c_str());
            } else {
                Log("bad ip");
            }
        } else if (_stricmp(line, "ips") == 0) {
            for (uint32_t ip : g_LocalIps) {
                Log("local %s", IpToString(ip).c_str());
            }
        } else if (_stricmp(line, "refresh") == 0) {
            RefreshLocalIps();
            Log("refreshed %u local IP(s)", unsigned(g_LocalIps.size()));
        } else if (_stricmp(line, "quit") == 0) {
            g_Running = false;
            break;
        } else if (line[0]) {
            Log("unknown command: %s", line);
        }
    }
}
DWORD WINAPI WorkerThread(LPVOID) {
    AllocConsole();
    FILE* file = nullptr;
    freopen_s(&file, "CONOUT$", "w", stdout);
    freopen_s(&file, "CONOUT$", "w", stderr);
    freopen_s(&file, "CONIN$", "r", stdin);
    SetConsoleTitleW(L"ACM LAN hook");
    Log("ACM LAN hook loaded");
    RefreshLocalIps();
    Log("local IP count: %u", unsigned(g_LocalIps.size()));
    for (uint32_t ip : g_LocalIps) {
        Log("local %s", IpToString(ip).c_str());
    }
    HMODULE wsock32 = GetModuleHandleW(L"WSOCK32.dll");
    if (!wsock32) {
        wsock32 = LoadLibraryW(L"WSOCK32.dll");
    }
    if (!wsock32) {
        Log("failed to load WSOCK32.dll");
        CommandLoop();
    } else if (MH_Initialize() == MH_OK) {
        HookExport(wsock32, "sendto", HookSendTo,
                   reinterpret_cast<void**>(&RealSendTo));
        HookExport(wsock32, "recvfrom", HookRecvFrom,
                   reinterpret_cast<void**>(&RealRecvFrom));
        HookExport(wsock32, "bind", HookBind,
                   reinterpret_cast<void**>(&RealBind));
        HookExport(wsock32, "getsockname", HookGetSockName,
                   reinterpret_cast<void**>(&RealGetSockName));
        HookExport(wsock32, "gethostname", HookGetHostName,
                   reinterpret_cast<void**>(&RealGetHostName));
        HookExport(wsock32, "gethostbyname", HookGetHostByName,
                   reinterpret_cast<void**>(&RealGetHostByName));
        CommandLoop();
        MH_DisableHook(MH_ALL_HOOKS);
        MH_Uninitialize();
    } else {
        Log("MH_Initialize failed");
        CommandLoop();
    }
    Log("unloading");
    FreeConsole();
    FreeLibraryAndExitThread(g_Module, 0);
    return 0;
}
}  // namespace
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
                      LPVOID lpReserved) {
    switch (ul_reason_for_call) {
        case DLL_PROCESS_ATTACH:
            g_Module = hModule;
            DisableThreadLibraryCalls(hModule);
            InitializeCriticalSection(&g_LogLock);
            g_WorkerThread =
                CreateThread(nullptr, 0, WorkerThread, nullptr, 0, nullptr);
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:
            if (lpReserved == nullptr) {
                g_Running = false;
            }
            DeleteCriticalSection(&g_LogLock);
            break;
    }
    return TRUE;
}

关键点在这,把朋友广播过来的错误包改成正确的IP包

    if (g_FixPayload && g_ForcedIp && buf && len > 0) {
        std::vector<char> copy(buf, buf + len);
        const int changed = ReplaceIpsInPayload(copy.data(), len, g_ForcedIp);
        if (changed > 0) {
            Log("sendto fixed %d payload IP(s) -> %s", changed,
                IpToString(g_ForcedIp).c_str());
            return RealSendTo(s, copy.data(), len, flags, to, tolen);
        }
    }

朋友的服务端的代码更粗暴,直接白加黑劫持游戏,把他的gethostbyname给hook了,从而发真的包给我

//
// created by AheadLib
// github:https://github.com/strivexjun/AheadLib-x86-x64
//
#include <windows.h>
#include <Shlwapi.h>
#pragma comment( lib, "Shlwapi.lib")
#pragma comment(linker, "/EXPORT:accept=_AheadLib_accept,@1")
#pragma comment(linker, "/EXPORT:bind=_AheadLib_bind,@2")
#pragma comment(linker, "/EXPORT:closesocket=_AheadLib_closesocket,@3")
#pragma comment(linker, "/EXPORT:connect=_AheadLib_connect,@4")
#pragma comment(linker, "/EXPORT:getpeername=_AheadLib_getpeername,@5")
#pragma comment(linker, "/EXPORT:getsockname=_AheadLib_getsockname,@6")
#pragma comment(linker, "/EXPORT:getsockopt=_AheadLib_getsockopt,@7")
#pragma comment(linker, "/EXPORT:htonl=_AheadLib_htonl,@8")
#pragma comment(linker, "/EXPORT:htons=_AheadLib_htons,@9")
#pragma comment(linker, "/EXPORT:inet_addr=_AheadLib_inet_addr,@10")
#pragma comment(linker, "/EXPORT:inet_ntoa=_AheadLib_inet_ntoa,@11")
#pragma comment(linker, "/EXPORT:ioctlsocket=_AheadLib_ioctlsocket,@12")
#pragma comment(linker, "/EXPORT:listen=_AheadLib_listen,@13")
#pragma comment(linker, "/EXPORT:ntohl=_AheadLib_ntohl,@14")
#pragma comment(linker, "/EXPORT:ntohs=_AheadLib_ntohs,@15")
#pragma comment(linker, "/EXPORT:recv=_AheadLib_recv,@16")
#pragma comment(linker, "/EXPORT:recvfrom=_AheadLib_recvfrom,@17")
#pragma comment(linker, "/EXPORT:select=_AheadLib_select,@18")
#pragma comment(linker, "/EXPORT:send=_AheadLib_send,@19")
#pragma comment(linker, "/EXPORT:sendto=_AheadLib_sendto,@20")
#pragma comment(linker, "/EXPORT:setsockopt=_AheadLib_setsockopt,@21")
#pragma comment(linker, "/EXPORT:shutdown=_AheadLib_shutdown,@22")
#pragma comment(linker, "/EXPORT:socket=_AheadLib_socket,@23")
#pragma comment(linker, "/EXPORT:MigrateWinsockConfiguration=_AheadLib_MigrateWinsockConfiguration,@24")
#pragma comment(linker, "/EXPORT:gethostbyaddr=_AheadLib_gethostbyaddr,@51")
#pragma comment(linker, "/EXPORT:gethostbyname=_AheadLib_gethostbyname,@52")
#pragma comment(linker, "/EXPORT:getprotobyname=_AheadLib_getprotobyname,@53")
#pragma comment(linker, "/EXPORT:getprotobynumber=_AheadLib_getprotobynumber,@54")
#pragma comment(linker, "/EXPORT:getservbyname=_AheadLib_getservbyname,@55")
#pragma comment(linker, "/EXPORT:getservbyport=_AheadLib_getservbyport,@56")
#pragma comment(linker, "/EXPORT:gethostname=_AheadLib_gethostname,@57")
#pragma comment(linker, "/EXPORT:WSAAsyncSelect=_AheadLib_WSAAsyncSelect,@101")
#pragma comment(linker, "/EXPORT:WSAAsyncGetHostByAddr=_AheadLib_WSAAsyncGetHostByAddr,@102")
#pragma comment(linker, "/EXPORT:WSAAsyncGetHostByName=_AheadLib_WSAAsyncGetHostByName,@103")
#pragma comment(linker, "/EXPORT:WSAAsyncGetProtoByNumber=_AheadLib_WSAAsyncGetProtoByNumber,@104")
#pragma comment(linker, "/EXPORT:WSAAsyncGetProtoByName=_AheadLib_WSAAsyncGetProtoByName,@105")
#pragma comment(linker, "/EXPORT:WSAAsyncGetServByPort=_AheadLib_WSAAsyncGetServByPort,@106")
#pragma comment(linker, "/EXPORT:WSAAsyncGetServByName=_AheadLib_WSAAsyncGetServByName,@107")
#pragma comment(linker, "/EXPORT:WSACancelAsyncRequest=_AheadLib_WSACancelAsyncRequest,@108")
#pragma comment(linker, "/EXPORT:WSASetBlockingHook=_AheadLib_WSASetBlockingHook,@109")
#pragma comment(linker, "/EXPORT:WSAUnhookBlockingHook=_AheadLib_WSAUnhookBlockingHook,@110")
#pragma comment(linker, "/EXPORT:WSAGetLastError=_AheadLib_WSAGetLastError,@111")
#pragma comment(linker, "/EXPORT:WSASetLastError=_AheadLib_WSASetLastError,@112")
#pragma comment(linker, "/EXPORT:WSACancelBlockingCall=_AheadLib_WSACancelBlockingCall,@113")
#pragma comment(linker, "/EXPORT:WSAIsBlocking=_AheadLib_WSAIsBlocking,@114")
#pragma comment(linker, "/EXPORT:WSAStartup=_AheadLib_WSAStartup,@115")
#pragma comment(linker, "/EXPORT:WSACleanup=_AheadLib_WSACleanup,@116")
#pragma comment(linker, "/EXPORT:__WSAFDIsSet=_AheadLib___WSAFDIsSet,@151")
#pragma comment(linker, "/EXPORT:WEP=_AheadLib_WEP,@500")
#pragma comment(linker, "/EXPORT:WSApSetPostRoutine=_AheadLib_WSApSetPostRoutine,@1000")
#pragma comment(linker, "/EXPORT:inet_network=_AheadLib_inet_network,@1100")
#pragma comment(linker, "/EXPORT:getnetbyname=_AheadLib_getnetbyname,@1101")
#pragma comment(linker, "/EXPORT:rcmd=_AheadLib_rcmd,@1102")
#pragma comment(linker, "/EXPORT:rexec=_AheadLib_rexec,@1103")
#pragma comment(linker, "/EXPORT:rresvport=_AheadLib_rresvport,@1104")
#pragma comment(linker, "/EXPORT:sethostname=_AheadLib_sethostname,@1105")
#pragma comment(linker, "/EXPORT:dn_expand=_AheadLib_dn_expand,@1106")
#pragma comment(linker, "/EXPORT:WSARecvEx=_AheadLib_WSARecvEx,@1107")
#pragma comment(linker, "/EXPORT:s_perror=_AheadLib_s_perror,@1108")
#pragma comment(linker, "/EXPORT:GetAddressByNameA=_AheadLib_GetAddressByNameA,@1109")
#pragma comment(linker, "/EXPORT:GetAddressByNameW=_AheadLib_GetAddressByNameW,@1110")
#pragma comment(linker, "/EXPORT:EnumProtocolsA=_AheadLib_EnumProtocolsA,@1111")
#pragma comment(linker, "/EXPORT:EnumProtocolsW=_AheadLib_EnumProtocolsW,@1112")
#pragma comment(linker, "/EXPORT:GetTypeByNameA=_AheadLib_GetTypeByNameA,@1113")
#pragma comment(linker, "/EXPORT:GetTypeByNameW=_AheadLib_GetTypeByNameW,@1114")
#pragma comment(linker, "/EXPORT:GetNameByTypeA=_AheadLib_GetNameByTypeA,@1115")
#pragma comment(linker, "/EXPORT:GetNameByTypeW=_AheadLib_GetNameByTypeW,@1116")
#pragma comment(linker, "/EXPORT:SetServiceA=_AheadLib_SetServiceA,@1117")
#pragma comment(linker, "/EXPORT:SetServiceW=_AheadLib_SetServiceW,@1118")
#pragma comment(linker, "/EXPORT:GetServiceA=_AheadLib_GetServiceA,@1119")
#pragma comment(linker, "/EXPORT:GetServiceW=_AheadLib_GetServiceW,@1120")
#pragma comment(linker, "/EXPORT:NPLoadNameSpaces=_AheadLib_NPLoadNameSpaces,@1130")
#pragma comment(linker, "/EXPORT:TransmitFile=_AheadLib_TransmitFile,@1140")
#pragma comment(linker, "/EXPORT:AcceptEx=_AheadLib_AcceptEx,@1141")
#pragma comment(linker, "/EXPORT:GetAcceptExSockaddrs=_AheadLib_GetAcceptExSockaddrs,@1142")
#include <string>
// --- ??核心 ---
std::string GetTargetIPFromConfig() {
    char szPath[MAX_PATH];
    GetModuleFileNameA(NULL, szPath, MAX_PATH);
    // 配置路?:与 exe 同目?的 hostip.config
    std::string configPath = std::string(szPath).substr(0, std::string(szPath).find_last_of("\\/")) + "\\hostip.config";
    char szIP[64] = { 0 };
    GetPrivateProfileStringA("Network", "TargetIP", "", szIP, sizeof(szIP), configPath.c_str());
    return std::string(szIP);
}
extern PVOID pfnAheadLib_gethostbyname;
// 核心 Hook 函?,使用 __stdcall 保??平衡
extern "C" struct hostent* __stdcall My_gethostbyname_Hook(const char* name) {
    // ?制?型??,使用全局?量 pfnAheadLib_gethostbyname
    typedef struct hostent* (__stdcall *pfn_orig)(const char*);
    pfn_orig pOrig = (pfn_orig)pfnAheadLib_gethostbyname;
    struct hostent* pResult = pOrig(name);
    std::string targetIP = GetTargetIPFromConfig();
    if (!targetIP.empty()) {
        unsigned long ip = inet_addr(targetIP.c_str());
        if (ip != INADDR_NONE) {
            if (pResult && pResult->h_addrtype == AF_INET) {
                // 原始请求成功,直接修改其缓存的 IP
                *(unsigned long*)pResult->h_addr_list[0] = ip;
            } else {
                // 原始请求失败(如域名已失效),构造一个假的 hostent 结构体返回
                static struct hostent fake_hostent;
                static char* fake_aliases[] = { NULL };
                static unsigned long fake_ip;
                static char* fake_addr_list[] = { (char*)&fake_ip, NULL };
                static char fake_name[256];
                fake_ip = ip;
                if (name) {
                    strncpy(fake_name, name, sizeof(fake_name) - 1);
                    fake_name[sizeof(fake_name) - 1] = '\0';
                } else {
                    fake_name[0] = '\0';
                }
                fake_hostent.h_name = fake_name;
                fake_hostent.h_aliases = fake_aliases;
                fake_hostent.h_addrtype = AF_INET;
                fake_hostent.h_length = 4;
                fake_hostent.h_addr_list = fake_addr_list;
                pResult = &fake_hostent;
            }
        }
    }
    return pResult;
}
PVOID pfnAheadLib_accept;
PVOID pfnAheadLib_bind;
PVOID pfnAheadLib_closesocket;
PVOID pfnAheadLib_connect;
PVOID pfnAheadLib_getpeername;
PVOID pfnAheadLib_getsockname;
PVOID pfnAheadLib_getsockopt;
PVOID pfnAheadLib_htonl;
PVOID pfnAheadLib_htons;
PVOID pfnAheadLib_inet_addr;
PVOID pfnAheadLib_inet_ntoa;
PVOID pfnAheadLib_ioctlsocket;
PVOID pfnAheadLib_listen;
PVOID pfnAheadLib_ntohl;
PVOID pfnAheadLib_ntohs;
PVOID pfnAheadLib_recv;
PVOID pfnAheadLib_recvfrom;
PVOID pfnAheadLib_select;
PVOID pfnAheadLib_send;
PVOID pfnAheadLib_sendto;
PVOID pfnAheadLib_setsockopt;
PVOID pfnAheadLib_shutdown;
PVOID pfnAheadLib_socket;
PVOID pfnAheadLib_MigrateWinsockConfiguration;
PVOID pfnAheadLib_gethostbyaddr;
PVOID pfnAheadLib_gethostbyname;
PVOID pfnAheadLib_getprotobyname;
PVOID pfnAheadLib_getprotobynumber;
PVOID pfnAheadLib_getservbyname;
PVOID pfnAheadLib_getservbyport;
PVOID pfnAheadLib_gethostname;
PVOID pfnAheadLib_WSAAsyncSelect;
PVOID pfnAheadLib_WSAAsyncGetHostByAddr;
PVOID pfnAheadLib_WSAAsyncGetHostByName;
PVOID pfnAheadLib_WSAAsyncGetProtoByNumber;
PVOID pfnAheadLib_WSAAsyncGetProtoByName;
PVOID pfnAheadLib_WSAAsyncGetServByPort;
PVOID pfnAheadLib_WSAAsyncGetServByName;
PVOID pfnAheadLib_WSACancelAsyncRequest;
PVOID pfnAheadLib_WSASetBlockingHook;
PVOID pfnAheadLib_WSAUnhookBlockingHook;
PVOID pfnAheadLib_WSAGetLastError;
PVOID pfnAheadLib_WSASetLastError;
PVOID pfnAheadLib_WSACancelBlockingCall;
PVOID pfnAheadLib_WSAIsBlocking;
PVOID pfnAheadLib_WSAStartup;
PVOID pfnAheadLib_WSACleanup;
PVOID pfnAheadLib___WSAFDIsSet;
PVOID pfnAheadLib_WEP;
PVOID pfnAheadLib_WSApSetPostRoutine;
PVOID pfnAheadLib_inet_network;
PVOID pfnAheadLib_getnetbyname;
PVOID pfnAheadLib_rcmd;
PVOID pfnAheadLib_rexec;
PVOID pfnAheadLib_rresvport;
PVOID pfnAheadLib_sethostname;
PVOID pfnAheadLib_dn_expand;
PVOID pfnAheadLib_WSARecvEx;
PVOID pfnAheadLib_s_perror;
PVOID pfnAheadLib_GetAddressByNameA;
PVOID pfnAheadLib_GetAddressByNameW;
PVOID pfnAheadLib_EnumProtocolsA;
PVOID pfnAheadLib_EnumProtocolsW;
PVOID pfnAheadLib_GetTypeByNameA;
PVOID pfnAheadLib_GetTypeByNameW;
PVOID pfnAheadLib_GetNameByTypeA;
PVOID pfnAheadLib_GetNameByTypeW;
PVOID pfnAheadLib_SetServiceA;
PVOID pfnAheadLib_SetServiceW;
PVOID pfnAheadLib_GetServiceA;
PVOID pfnAheadLib_GetServiceW;
PVOID pfnAheadLib_NPLoadNameSpaces;
PVOID pfnAheadLib_TransmitFile;
PVOID pfnAheadLib_AcceptEx;
PVOID pfnAheadLib_GetAcceptExSockaddrs;
static
HMODULE g_OldModule = NULL;
VOID WINAPI Free()
{
    if (g_OldModule)
    {
        FreeLibrary(g_OldModule);
    }
}
BOOL WINAPI Load()
{
    TCHAR tzPath[MAX_PATH];
    TCHAR tzTemp[MAX_PATH * 2];
    //
    // ?里是否?系?目?或?前目?加?原始DLL
    //
    //GetModuleFileName(NULL,tzPath,MAX_PATH); //?取本目?下的
    //PathRemoveFileSpec(tzPath);
    GetSystemDirectory(tzPath, MAX_PATH); //默??取系?目?的
    lstrcat(tzPath, TEXT("\\wsock32.dll"));
    g_OldModule = LoadLibrary(tzPath);
    if (g_OldModule == NULL)
    {
        wsprintf(tzTemp, TEXT("?法找到模? %s,程序?法正常?行"), tzPath);
        MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);
    }
    return (g_OldModule != NULL);
}
FARPROC WINAPI GetAddress(PCSTR pszProcName)
{
    FARPROC fpAddress;
    CHAR szProcName[64];
    TCHAR tzTemp[MAX_PATH];
    fpAddress = GetProcAddress(g_OldModule, pszProcName);
    if (fpAddress == NULL)
    {
        if (HIWORD(pszProcName) == 0)
        {
            wsprintfA(szProcName, "#%d", pszProcName);
            pszProcName = szProcName;
        }
        wsprintf(tzTemp, TEXT("?法找到函? %hs,程序?法正常?行"), pszProcName);
        MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);
        ExitProcess(-2);
    }
    return fpAddress;
}
BOOL WINAPI Init()
{
    pfnAheadLib_accept = GetAddress("accept");
    pfnAheadLib_bind = GetAddress("bind");
    pfnAheadLib_closesocket = GetAddress("closesocket");
    pfnAheadLib_connect = GetAddress("connect");
    pfnAheadLib_getpeername = GetAddress("getpeername");
    pfnAheadLib_getsockname = GetAddress("getsockname");
    pfnAheadLib_getsockopt = GetAddress("getsockopt");
    pfnAheadLib_htonl = GetAddress("htonl");
    pfnAheadLib_htons = GetAddress("htons");
    pfnAheadLib_inet_addr = GetAddress("inet_addr");
    pfnAheadLib_inet_ntoa = GetAddress("inet_ntoa");
    pfnAheadLib_ioctlsocket = GetAddress("ioctlsocket");
    pfnAheadLib_listen = GetAddress("listen");
    pfnAheadLib_ntohl = GetAddress("ntohl");
    pfnAheadLib_ntohs = GetAddress("ntohs");
    pfnAheadLib_recv = GetAddress("recv");
    pfnAheadLib_recvfrom = GetAddress("recvfrom");
    pfnAheadLib_select = GetAddress("select");
    pfnAheadLib_send = GetAddress("send");
    pfnAheadLib_sendto = GetAddress("sendto");
    pfnAheadLib_setsockopt = GetAddress("setsockopt");
    pfnAheadLib_shutdown = GetAddress("shutdown");
    pfnAheadLib_socket = GetAddress("socket");
    pfnAheadLib_MigrateWinsockConfiguration = GetAddress("MigrateWinsockConfiguration");
    pfnAheadLib_gethostbyaddr = GetAddress("gethostbyaddr");
    pfnAheadLib_gethostbyname = GetAddress("gethostbyname");
    pfnAheadLib_getprotobyname = GetAddress("getprotobyname");
    pfnAheadLib_getprotobynumber = GetAddress("getprotobynumber");
    pfnAheadLib_getservbyname = GetAddress("getservbyname");
    pfnAheadLib_getservbyport = GetAddress("getservbyport");
    pfnAheadLib_gethostname = GetAddress("gethostname");
    pfnAheadLib_WSAAsyncSelect = GetAddress("WSAAsyncSelect");
    pfnAheadLib_WSAAsyncGetHostByAddr = GetAddress("WSAAsyncGetHostByAddr");
    pfnAheadLib_WSAAsyncGetHostByName = GetAddress("WSAAsyncGetHostByName");
    pfnAheadLib_WSAAsyncGetProtoByNumber = GetAddress("WSAAsyncGetProtoByNumber");
    pfnAheadLib_WSAAsyncGetProtoByName = GetAddress("WSAAsyncGetProtoByName");
    pfnAheadLib_WSAAsyncGetServByPort = GetAddress("WSAAsyncGetServByPort");
    pfnAheadLib_WSAAsyncGetServByName = GetAddress("WSAAsyncGetServByName");
    pfnAheadLib_WSACancelAsyncRequest = GetAddress("WSACancelAsyncRequest");
    pfnAheadLib_WSASetBlockingHook = GetAddress("WSASetBlockingHook");
    pfnAheadLib_WSAUnhookBlockingHook = GetAddress("WSAUnhookBlockingHook");
    pfnAheadLib_WSAGetLastError = GetAddress("WSAGetLastError");
    pfnAheadLib_WSASetLastError = GetAddress("WSASetLastError");
    pfnAheadLib_WSACancelBlockingCall = GetAddress("WSACancelBlockingCall");
    pfnAheadLib_WSAIsBlocking = GetAddress("WSAIsBlocking");
    pfnAheadLib_WSAStartup = GetAddress("WSAStartup");
    pfnAheadLib_WSACleanup = GetAddress("WSACleanup");
    pfnAheadLib___WSAFDIsSet = GetAddress("__WSAFDIsSet");
    pfnAheadLib_WEP = GetAddress("WEP");
    pfnAheadLib_WSApSetPostRoutine = GetAddress("WSApSetPostRoutine");
    pfnAheadLib_inet_network = GetAddress("inet_network");
    pfnAheadLib_getnetbyname = GetAddress("getnetbyname");
    pfnAheadLib_rcmd = GetAddress("rcmd");
    pfnAheadLib_rexec = GetAddress("rexec");
    pfnAheadLib_rresvport = GetAddress("rresvport");
    pfnAheadLib_sethostname = GetAddress("sethostname");
    pfnAheadLib_dn_expand = GetAddress("dn_expand");
    pfnAheadLib_WSARecvEx = GetAddress("WSARecvEx");
    pfnAheadLib_s_perror = GetAddress("s_perror");
    pfnAheadLib_GetAddressByNameA = GetAddress("GetAddressByNameA");
    pfnAheadLib_GetAddressByNameW = GetAddress("GetAddressByNameW");
    pfnAheadLib_EnumProtocolsA = GetAddress("EnumProtocolsA");
    pfnAheadLib_EnumProtocolsW = GetAddress("EnumProtocolsW");
    pfnAheadLib_GetTypeByNameA = GetAddress("GetTypeByNameA");
    pfnAheadLib_GetTypeByNameW = GetAddress("GetTypeByNameW");
    pfnAheadLib_GetNameByTypeA = GetAddress("GetNameByTypeA");
    pfnAheadLib_GetNameByTypeW = GetAddress("GetNameByTypeW");
    pfnAheadLib_SetServiceA = GetAddress("SetServiceA");
    pfnAheadLib_SetServiceW = GetAddress("SetServiceW");
    pfnAheadLib_GetServiceA = GetAddress("GetServiceA");
    pfnAheadLib_GetServiceW = GetAddress("GetServiceW");
    pfnAheadLib_NPLoadNameSpaces = GetAddress("NPLoadNameSpaces");
    pfnAheadLib_TransmitFile = GetAddress("TransmitFile");
    pfnAheadLib_AcceptEx = GetAddress("AcceptEx");
    pfnAheadLib_GetAcceptExSockaddrs = GetAddress("GetAcceptExSockaddrs");
    return TRUE;
}    
DWORD WINAPI ThreadProc(LPVOID lpThreadParameter)
{
    HANDLE hProcess;
    PVOID addr1 = reinterpret_cast<PVOID>(0x00401000);
    BYTE data1[] = { 0x90, 0x90, 0x90, 0x90 };
    //
    // ??VMP3.x 的?存保?
    //
    hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, GetCurrentProcessId());
    if (hProcess)
    {
        WriteProcessMemory(hProcess, addr1, data1, sizeof(data1), NULL);
        CloseHandle(hProcess);
    }
    return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        DisableThreadLibraryCalls(hModule);
        if (Load() && Init())
        {
            TCHAR szAppName[MAX_PATH] = TEXT("MyApp.exe");//?修改宿主?程名
            TCHAR szCurName[MAX_PATH];
            GetModuleFileName(NULL, szCurName, MAX_PATH);
            PathStripPath(szCurName);
            //是否判?宿主?程名
            if (StrCmpI(szCurName, szAppName) == 0)
            {
                //???丁?程或者其他操作
                HANDLE hThread = CreateThread(NULL, NULL, ThreadProc, NULL, NULL, NULL);
                if (hThread)
                {
                    CloseHandle(hThread);
                }
            }
        }
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
        Free();
    }
    return TRUE;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_accept(void)
{
    __asm jmp pfnAheadLib_accept;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_bind(void)
{
    __asm jmp pfnAheadLib_bind;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_closesocket(void)
{
    __asm jmp pfnAheadLib_closesocket;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_connect(void)
{
    __asm jmp pfnAheadLib_connect;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_getpeername(void)
{
    __asm jmp pfnAheadLib_getpeername;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_getsockname(void)
{
    __asm jmp pfnAheadLib_getsockname;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_getsockopt(void)
{
    __asm jmp pfnAheadLib_getsockopt;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_htonl(void)
{
    __asm jmp pfnAheadLib_htonl;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_htons(void)
{
    __asm jmp pfnAheadLib_htons;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_inet_addr(void)
{
    __asm jmp pfnAheadLib_inet_addr;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_inet_ntoa(void)
{
    __asm jmp pfnAheadLib_inet_ntoa;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_ioctlsocket(void)
{
    __asm jmp pfnAheadLib_ioctlsocket;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_listen(void)
{
    __asm jmp pfnAheadLib_listen;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_ntohl(void)
{
    __asm jmp pfnAheadLib_ntohl;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_ntohs(void)
{
    __asm jmp pfnAheadLib_ntohs;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_recv(void)
{
    __asm jmp pfnAheadLib_recv;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_recvfrom(void)
{
    __asm jmp pfnAheadLib_recvfrom;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_select(void)
{
    __asm jmp pfnAheadLib_select;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_send(void)
{
    __asm jmp pfnAheadLib_send;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_sendto(void)
{
    __asm jmp pfnAheadLib_sendto;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_setsockopt(void)
{
    __asm jmp pfnAheadLib_setsockopt;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_shutdown(void)
{
    __asm jmp pfnAheadLib_shutdown;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_socket(void)
{
    __asm jmp pfnAheadLib_socket;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_MigrateWinsockConfiguration(void)
{
    __asm jmp pfnAheadLib_MigrateWinsockConfiguration;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_gethostbyaddr(void)
{
    __asm jmp pfnAheadLib_gethostbyaddr;
}
/*
EXTERN_C __declspec(naked) void __cdecl AheadLib_gethostbyname(void)
{
    __asm jmp pfnAheadLib_gethostbyname;
}
*/
EXTERN_C __declspec(naked) void __cdecl AheadLib_getprotobyname(void)
{
    __asm jmp pfnAheadLib_getprotobyname;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_getprotobynumber(void)
{
    __asm jmp pfnAheadLib_getprotobynumber;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_getservbyname(void)
{
    __asm jmp pfnAheadLib_getservbyname;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_getservbyport(void)
{
    __asm jmp pfnAheadLib_getservbyport;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_gethostname(void)
{
    __asm jmp pfnAheadLib_gethostname;
}
// 修改原本的 naked ??
EXTERN_C __declspec(naked) void __cdecl AheadLib_gethostbyname(void)
{
    __asm {
        push [esp+4]    // ?入??
        call My_gethostbyname_Hook
        ret 4           // 恢复?平衡
    }
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAAsyncSelect(void)
{
    __asm jmp pfnAheadLib_WSAAsyncSelect;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAAsyncGetHostByAddr(void)
{
    __asm jmp pfnAheadLib_WSAAsyncGetHostByAddr;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAAsyncGetHostByName(void)
{
    __asm jmp pfnAheadLib_WSAAsyncGetHostByName;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAAsyncGetProtoByNumber(void)
{
    __asm jmp pfnAheadLib_WSAAsyncGetProtoByNumber;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAAsyncGetProtoByName(void)
{
    __asm jmp pfnAheadLib_WSAAsyncGetProtoByName;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAAsyncGetServByPort(void)
{
    __asm jmp pfnAheadLib_WSAAsyncGetServByPort;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAAsyncGetServByName(void)
{
    __asm jmp pfnAheadLib_WSAAsyncGetServByName;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSACancelAsyncRequest(void)
{
    __asm jmp pfnAheadLib_WSACancelAsyncRequest;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSASetBlockingHook(void)
{
    __asm jmp pfnAheadLib_WSASetBlockingHook;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAUnhookBlockingHook(void)
{
    __asm jmp pfnAheadLib_WSAUnhookBlockingHook;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAGetLastError(void)
{
    __asm jmp pfnAheadLib_WSAGetLastError;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSASetLastError(void)
{
    __asm jmp pfnAheadLib_WSASetLastError;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSACancelBlockingCall(void)
{
    __asm jmp pfnAheadLib_WSACancelBlockingCall;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAIsBlocking(void)
{
    __asm jmp pfnAheadLib_WSAIsBlocking;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSAStartup(void)
{
    __asm jmp pfnAheadLib_WSAStartup;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSACleanup(void)
{
    __asm jmp pfnAheadLib_WSACleanup;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib___WSAFDIsSet(void)
{
    __asm jmp pfnAheadLib___WSAFDIsSet;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WEP(void)
{
    __asm jmp pfnAheadLib_WEP;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSApSetPostRoutine(void)
{
    __asm jmp pfnAheadLib_WSApSetPostRoutine;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_inet_network(void)
{
    __asm jmp pfnAheadLib_inet_network;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_getnetbyname(void)
{
    __asm jmp pfnAheadLib_getnetbyname;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_rcmd(void)
{
    __asm jmp pfnAheadLib_rcmd;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_rexec(void)
{
    __asm jmp pfnAheadLib_rexec;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_rresvport(void)
{
    __asm jmp pfnAheadLib_rresvport;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_sethostname(void)
{
    __asm jmp pfnAheadLib_sethostname;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_dn_expand(void)
{
    __asm jmp pfnAheadLib_dn_expand;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_WSARecvEx(void)
{
    __asm jmp pfnAheadLib_WSARecvEx;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_s_perror(void)
{
    __asm jmp pfnAheadLib_s_perror;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetAddressByNameA(void)
{
    __asm jmp pfnAheadLib_GetAddressByNameA;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetAddressByNameW(void)
{
    __asm jmp pfnAheadLib_GetAddressByNameW;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_EnumProtocolsA(void)
{
    __asm jmp pfnAheadLib_EnumProtocolsA;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_EnumProtocolsW(void)
{
    __asm jmp pfnAheadLib_EnumProtocolsW;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetTypeByNameA(void)
{
    __asm jmp pfnAheadLib_GetTypeByNameA;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetTypeByNameW(void)
{
    __asm jmp pfnAheadLib_GetTypeByNameW;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetNameByTypeA(void)
{
    __asm jmp pfnAheadLib_GetNameByTypeA;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetNameByTypeW(void)
{
    __asm jmp pfnAheadLib_GetNameByTypeW;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_SetServiceA(void)
{
    __asm jmp pfnAheadLib_SetServiceA;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_SetServiceW(void)
{
    __asm jmp pfnAheadLib_SetServiceW;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetServiceA(void)
{
    __asm jmp pfnAheadLib_GetServiceA;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetServiceW(void)
{
    __asm jmp pfnAheadLib_GetServiceW;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_NPLoadNameSpaces(void)
{
    __asm jmp pfnAheadLib_NPLoadNameSpaces;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_TransmitFile(void)
{
    __asm jmp pfnAheadLib_TransmitFile;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_AcceptEx(void)
{
    __asm jmp pfnAheadLib_AcceptEx;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_GetAcceptExSockaddrs(void)
{
    __asm jmp pfnAheadLib_GetAcceptExSockaddrs;
}

关键点:

// 核心 Hook 函?,使用 __stdcall 保??平衡
extern "C" struct hostent* __stdcall My_gethostbyname_Hook(const char* name) {
    // ?制?型??,使用全局?量 pfnAheadLib_gethostbyname
    typedef struct hostent* (__stdcall *pfn_orig)(const char*);
    pfn_orig pOrig = (pfn_orig)pfnAheadLib_gethostbyname;
    struct hostent* pResult = pOrig(name);
    std::string targetIP = GetTargetIPFromConfig();
    if (!targetIP.empty()) {
        unsigned long ip = inet_addr(targetIP.c_str());
        if (ip != INADDR_NONE) {
            if (pResult && pResult->h_addrtype == AF_INET) {
                // 原始请求成功,直接修改其缓存的 IP
                *(unsigned long*)pResult->h_addr_list[0] = ip;
            } else {
                // 原始请求失败(如域名已失效),构造一个假的 hostent 结构体返回
                static struct hostent fake_hostent;
                static char* fake_aliases[] = { NULL };
                static unsigned long fake_ip;
                static char* fake_addr_list[] = { (char*)&fake_ip, NULL };
                static char fake_name[256];
                fake_ip = ip;
                if (name) {
                    strncpy(fake_name, name, sizeof(fake_name) - 1);
                    fake_name[sizeof(fake_name) - 1] = '\0';
                } else {
                    fake_name[0] = '\0';
                }
                fake_hostent.h_name = fake_name;
                fake_hostent.h_aliases = fake_aliases;
                fake_hostent.h_addrtype = AF_INET;
                fake_hostent.h_length = 4;
                fake_hostent.h_addr_list = fake_addr_list;
                pResult = &fake_hostent;
            }
        }
    }
    return pResult;
}

结论

通过这样修改后,我们终于可以愉快联机了

要是以后有人玩《Aliens: Colonial Marines》出现一样的问题,可以看看这个咋修。

跳转微信打开