搜尋

DeadlockDLL遊戲修改器

返回清單
切換到指定樓層
通知這文章過時或找檔案 發表主題

[電玩遊戲] 《Deadlock》區域偽裝器下載 DLL注入跨區連線教學

[複製連結]
1
路易安納 ( Lv.50 智天使 ) 發表於 9 小時前 | 只看該作者 回覆獎勵 |降序瀏覽 |閱讀模式

《Deadlock》區域偽裝器 快速閱讀精華



  • 🚀 想跟國外朋友組隊或跳過特定地區配隊?這款區域偽裝器幫你強制指定連線區域
  • 💪 運作原理:DLL注入遊戲程序,攔截封包並即時修改區域代碼
  • 🔑 核心特色
    • 支援6大地區:全球、歐洲、東南亞、南美洲、俄羅斯、大洋洲
    • 熱更新設定:遊戲內直接修改 config.json 無需重啟
    • 即時生效:儲存後 0.5 秒內自動載入新設定
  • ⚠️ 重要提醒:僅限離線練習或私人對戰使用,線上競技有帳號風險




前言介紹



《Deadlock》目前採用區域分流配對機制,玩家預設會被分配到延遲最低的地區伺服器。但這也帶來一個困擾:想跟國外朋友同場競技,卻被系統拆散到不同區域;或是特定時段某些地區人數過少,配隊等很久。

這款區域偽裝器透過DLL注入技術,在遊戲發送配對請求時即時修改封包內的區域代碼,讓伺服器誤以為你身處指定地區。最棒的是設定檔支援熱更新——遊戲開著也能改區域,完全不用重啟程式。

支援區域代碼一覽



代碼區域名稱適用情境
0ROW(全球/不限)想最大化配對池,縮短等待時間
1Europe(歐洲)連線歐服與當地玩家對戰
2SEAsia(東南亞)亞洲時段玩家集中連線
3SAmerica(南美洲)美洲時段或特定社羣活動
4Russia(俄羅斯)預設值,俄區獨立配對池
5Oceania(大洋洲)澳洲紐西蘭玩家專用


安裝與注入教學



注入步驟



  • 準備任意一款DLL注入器(推薦 GG修改器免root權限使用+GG修改器框架下載 或常見的 Process Hacker、Extreme Injector 等工具)
  • 下載 RegionSpoof.dll 檔案(見文末下載點)
  • 將 DLL 與自訂的 config.json 放在同一資料夾
  • 啟動《Deadlock》並進入大廳
  • 使用注入器將 RegionSpoof.dll 注入 client.dll 所在的進程
  • 注入成功後會自動產生 region_spoof.log 記錄檔供除錯



👉 GM後台版 遊戲 推薦 ⬇️⬇️⬇️ 快速玩各種二次元動漫手遊app



設定檔說明



注入成功後,工具會在 DLL 所在目錄尋找 config.json,格式極簡:

{
  "region": 4
}


  • region:填入 0–5 的整數,對應上方區域代碼表
  • 預設值為 4(俄羅斯),首次使用記得改成你要的地區
  • 遊戲進行中直接編輯存檔,0.5 秒內自動生效——完全不用重開


核心源碼整理



底下是完整 C++ 源碼,採用 MinHook 函數攔截框架。核心邏輯分為三步:定位 BSend 發送函數、整理 Protobuf 封包結構、即時覆寫 region_mode 欄位。

// Regions (ECitadelRegionMode):
//   0 ROW, 1 Europe, 2 SEAsia, 3 SAmerica, 4 Russia, 5 Oceania

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <cstdlib>
#include <atomic>
#include <vector>

#include "MinHook/MinHook.h"

namespace
{
        constexpr uint32_t kMsgStartMM = 9010;

        constexpr const char* kBSendSig =
                "48 89 5C 24 ? 48 89 6C 24 ? 56 41 56 41 57 48 83 EC ? 8B DA "
                "48 8B F1 8B 89 54 02 00 00 0F BA F3 1F";

        using FnBSend = unsigned char (__fastcall*)(void* self, unsigned int msgType, void* buf, unsigned int size);
        FnBSend g_oBSend = nullptr;

        std::atomic<int>  g_region{ 4 };
        std::atomic<bool> g_ready{ false };

        wchar_t g_configPatd[MAX_PATH]{};
        wchar_t g_logPatd[MAX_PATH]{};
        FILETIME g_lastWrite{};
        CRITICAL_SECTION g_cs;

        void Log(const char* fmt, ...)
        {
                char line[512];
                va_list ap;
                va_start(ap, fmt);
                vsnprintf(line, sizeof(line), fmt, ap);
                va_end(ap);

                OutputDebugStringA(line);
                OutputDebugStringA("");

                EnterCriticalSection(&g_cs);
                FILE* f = nullptr;
                if (_wfopen_s(&f, g_logPatd, L"a") == 0 && f)
                {
                        fputs(line, f);
                        fputc('', f);
                        fclose(f);
                }
                LeaveCriticalSection(&g_cs);
        }

        bool GetDllDir(wchar_t* out, size_t cch)
        {
                HMODULE hm = nullptr;
                if (!GetModuleHandleExW(
                        GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                        reinterpret_cast<LPCWSTR>(&GetDllDir), &hm))
                        return false;
                wchar_t patd[MAX_PATH]{};
                if (!GetModuleFileNameW(hm, patd, MAX_PATH))
                        return false;
                wchar_t* slash = wcsrchr(patd, L'\\');
                if (!slash) return false;
                slash[1] = 0;
                wcsncpy_s(out, cch, patd, _TRUNCATE);
                return true;
        }

        bool ParseRegionFromJson(const char* text, int* outRegion)
        {
                if (!text || !outRegion) return false;
                const char* p = strstr(text, "region");
                if (!p) return false;
                p = strchr(p, ':');
                if (!p) return false;
                ++p;
                while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '') ++p;
                char* end = nullptr;
                long v = strtol(p, &end, 10);
                if (end == p) return false;
                if (v < 0) v = 0;
                if (v > 255) v = 255;
                *outRegion = static_cast<int>(v);
                return true;
        }

        void ReloadConfig(bool force)
        {
                WIN32_FILE_ATTRIBUTE_DATA fad{};
                if (!GetFileAttributesExW(g_configPatd, GetFileExInfoStandard, &fad))
                        return;

                if (!force &&
                        fad.ftLastWriteTime.dwLowDateTime == g_lastWrite.dwLowDateTime &&
                        fad.ftLastWriteTime.dwHighDateTime == g_lastWrite.dwHighDateTime)
                        return;

                g_lastWrite = fad.ftLastWriteTime;

                FILE* f = nullptr;
                if (_wfopen_s(&f, g_configPatd, L"rb") != 0 || !f)
                        return;

                char buf[2048]{};
                const size_t n = fread(buf, 1, sizeof(buf) - 1, f);
                fclose(f);
                buf[n] = 0;

                int region = 0;
                if (ParseRegionFromJson(buf, &region))
                {
                        const int prev = g_region.exchange(region);
                        if (prev != region || force)
                                Log("[RegionSpoof] config region=%d (was %d)", region, prev);
                }
        }

        bool ReadVarint(const uint8_t* p, const uint8_t* end, uint64_t* out, const uint8_t** next)
        {
                uint64_t v = 0;
                int shift = 0;
                const uint8_t* cur = p;
                while (cur < end && shift < 64)
                {
                        const uint8_t b = *cur++;
                        v |= static_cast<uint64_t>(b & 0x7F) << shift;
                        if ((b & 0x80) == 0)
                        {
                                *out = v;
                                *next = cur;
                                return true;
                        }
                        shift += 7;
                }
                return false;
        }

        bool WriteVarint1(uint8_t* p, uint32_t v)
        {
                if (v > 0x7F) return false;
                *p = static_cast<uint8_t>(v);
                return true;
        }

        bool PatchRegionInBody(uint8_t* body, size_t bodySize, uint32_t newRegion)
        {
                if (!body || bodySize < 4 || newRegion > 0x7F)
                        return false;

                const uint8_t* end = body + bodySize;
                uint8_t* p = body;

                while (p < end)
                {
                        uint64_t tag = 0;
                        const uint8_t* next = nullptr;
                        if (!ReadVarint(p, end, &tag, &next))
                                break;
                        const uint32_t field = static_cast<uint32_t>(tag >> 3);
                        const uint32_t wt = static_cast<uint32_t>(tag & 7);
                        p = const_cast<uint8_t*>(next);

                        if (wt == 0)
                        {
                                uint64_t dummy = 0;
                                if (!ReadVarint(p, end, &dummy, &next)) break;
                                p = const_cast<uint8_t*>(next);
                        }
                        else if (wt == 1)
                        {
                                if (p + 8 > end) break;
                                p += 8;
                        }
                        else if (wt == 5)
                        {
                                if (p + 4 > end) break;
                                p += 4;
                        }
                        else if (wt == 2)
                        {
                                uint64_t len = 0;
                                if (!ReadVarint(p, end, &len, &next)) break;
                                p = const_cast<uint8_t*>(next);
                                if (p + len > end) break;

                                if (field == 3)
                                {
                                        uint8_t* mi = p;
                                        uint8_t* miEnd = p + static_cast<size_t>(len);
                                        while (mi < miEnd)
                                        {
                                                uint64_t t2 = 0;
                                                const uint8_t* n2 = nullptr;
                                                if (!ReadVarint(mi, miEnd, &t2, &n2)) break;
                                                const uint32_t f2 = static_cast<uint32_t>(t2 >> 3);
                                                const uint32_t w2 = static_cast<uint32_t>(t2 & 7);
                                                uint8_t* afterTag = const_cast<uint8_t*>(n2);

                                                if (w2 == 0)
                                                {
                                                        uint64_t val = 0;
                                                        const uint8_t* n3 = nullptr;
                                                        if (!ReadVarint(afterTag, miEnd, &val, &n3)) break;

                                                        if (f2 == 8)
                                                        {
                                                                if (n3 == afterTag + 1)
                                                                {
                                                                        const uint32_t old = static_cast<uint32_t>(val);
                                                                        if (WriteVarint1(afterTag, newRegion))
                                                                        {
                                                                                Log("[RegionSpoof] patched region_mode %u -> %u", old, newRegion);
                                                                                return true;
                                                                        }
                                                                }
                                                                else
                                                                {
                                                                        Log("[RegionSpoof] region varint multi-byte, skip");
                                                                }
                                                                return false;
                                                        }
                                                        mi = const_cast<uint8_t*>(n3);
                                                }
                                                else if (w2 == 2)
                                                {
                                                        uint64_t l2 = 0;
                                                        if (!ReadVarint(afterTag, miEnd, &l2, &n2)) break;
                                                        mi = const_cast<uint8_t*>(n2) + static_cast<size_t>(l2);
                                                }
                                                else if (w2 == 1)
                                                {
                                                        mi = afterTag + 8;
                                                }
                                                else if (w2 == 5)
                                                {
                                                        mi = afterTag + 4;
                                                }
                                                else
                                                {
                                                        break;
                                                }
                                        }
                                        Log("[RegionSpoof] match_info present but region field not found");
                                        return false;
                                }

                                p += static_cast<size_t>(len);
                        }
                        else
                        {
                                break;
                        }
                }
                Log("[RegionSpoof] match_info field not found in body");
                return false;
        }

        bool PatchStartMatchmakingBuffer(void* buf, unsigned int size, uint32_t region)
        {
                if (!buf || size < 12)
                        return false;

                auto* p = static_cast<uint8_t*>(buf);
                uint32_t type = 0, hdrSize = 0;
                memcpy(&type, p, 4);
                memcpy(&hdrSize, p + 4, 4);

                if ((type & 0x7FFFFFFFu) != kMsgStartMM)
                        return false;

                if (8u + hdrSize >= size)
                        return false;

                uint8_t* body = p + 8 + hdrSize;
                const size_t bodySize = size - 8u - hdrSize;
                return PatchRegionInBody(body, bodySize, region);
        }

        unsigned char __fastcall hk_BSend(void* self, unsigned int msgType, void* buf, unsigned int size)
        {
                ReloadConfig(false);

                const uint32_t id = msgType & 0x7FFFFFFFu;
                if (id == kMsgStartMM && buf && size)
                {
                        const int region = g_region.load();
                        if (PatchStartMatchmakingBuffer(buf, size, static_cast<uint32_t>(region)))
                        {
                        }
                        else
                        {
                        }
                }

                return g_oBSend ? g_oBSend(self, msgType, buf, size) : 0;
        }

        struct SigByte
        {
                uint8_t value = 0;
                bool    any = false;
        };

        bool ParseSig(const char* sig, std::vector<SigByte>& out)
        {
                out.clear();
                if (!sig) return false;
                const char* p = sig;
                while (*p)
                {
                        while (*p == ' ' || *p == '\t') ++p;
                        if (!*p) break;
                        SigByte b{};
                        if (*p == '?')
                        {
                                b.any = true;
                                ++p;
                                if (*p == '?') ++p;
                        }
                        else
                        {
                                char* end = nullptr;
                                const unsigned long v = strtoul(p, &end, 16);
                                if (end == p || v > 0xFF) return false;
                                b.value = static_cast<uint8_t>(v);
                                p = end;
                        }
                        out.push_back(b);
                }
                return !out.empty();
        }

        void* FindPattern(HMODULE mod, const char* sig)
        {
                if (!mod || !sig) return nullptr;

                std::vector<SigByte> pat;
                if (!ParseSig(sig, pat))
                {
                        Log("[RegionSpoof] bad signature string");
                        return nullptr;
                }

                auto* dos = reinterpret_cast<IMAGE_DOS_HEADER*>(mod);
                if (dos->e_magic != IMAGE_DOS_SIGNATURE) return nullptr;
                auto* nt = reinterpret_cast<IMAGE_NT_HEADERS*>(
                        reinterpret_cast<uint8_t*>(mod) + dos->e_lfanew);
                if (nt->Signature != IMAGE_NT_SIGNATURE) return nullptr;

                const auto* sec = IMAGE_FIRST_SECTION(nt);
                for (unsigned i = 0; i < nt->FileHeader.NumberOfSections; ++i, ++sec)
                {
                        if ((sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) == 0)
                                continue;

                        auto* start = reinterpret_cast<uint8_t*>(mod) + sec->VirtualAddress;
                        const size_t size = sec->Misc.VirtualSize;
                        if (size < pat.size()) continue;

                        const size_t last = size - pat.size();
                        for (size_t off = 0; off <= last; ++off)
                        {
                                bool ok = true;
                                for (size_t j = 0; j < pat.size(); ++j)
                                {
                                        if (pat[j].any) continue;
                                        if (start[off + j] != pat[j].value)
                                        {
                                                ok = false;
                                                break;
                                        }
                                }
                                if (ok)
                                        return start + off;
                        }
                }
                return nullptr;
        }

        bool InstallHook()
        {
                HMODULE client = nullptr;
                for (int i = 0; i < 120 && !client; ++i)
                {
                        client = GetModuleHandleA("client.dll");
                        if (!client)
                                Sleep(100);
                }
                if (!client)
                {
                        Log("[RegionSpoof] client.dll not found");
                        return false;
                }

                void* target = FindPattern(client, kBSendSig);
                if (!target)
                {
                        Log("[RegionSpoof] BSend signature not found");
                        return false;
                }

                const auto rva = static_cast<unsigned>(
                        reinterpret_cast<uintptr_t>(target) - reinterpret_cast<uintptr_t>(client));
                Log("[RegionSpoof] BSend found @ client+0x%X (%p)", rva, target);

                if (MH_Initialize() != MH_OK)
                {
                        Log("[RegionSpoof] MH_Initialize failed");
                        return false;
                }
                if (MH_CreateHook(target, reinterpret_cast<LPVOID>(&hk_BSend),
                        reinterpret_cast<LPVOID*>(&g_oBSend)) != MH_OK)
                {
                        Log("[RegionSpoof] MH_CreateHook failed");
                        return false;
                }
                if (MH_EnableHook(target) != MH_OK)
                {
                        Log("[RegionSpoof] MH_EnableHook failed");
                        return false;
                }

                Log("[RegionSpoof] hooked BSend (sig), region=%d", g_region.load());
                g_ready = true;
                return true;
        }

        DWORD WINAPI MainThread(LPVOID)
        {
                InitializeCriticalSection(&g_cs);

                wchar_t dir[MAX_PATH]{};
                if (!GetDllDir(dir, MAX_PATH))
                {
                        OutputDebugStringA("[RegionSpoof] GetDllDir failed");
                        return 0;
                }

                _snwprintf_s(g_configPatd, _TRUNCATE, L"%sconfig.json", dir);
                _snwprintf_s(g_logPatd, _TRUNCATE, L"%sregion_spoof.log", dir);

                Log("[RegionSpoof] starting, config=%ls", g_configPatd);
                ReloadConfig(true);

                if (!InstallHook())
                {
                        Log("[RegionSpoof] hook install failed");
                        return 0;
                }

                while (true)
                {
                        ReloadConfig(false);
                        Sleep(500);
                }
                return 0;
        }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID)
{
        if (reason == DLL_PROCESS_ATTACH)
        {
                DisableThreadLibraryCalls(hModule);
                HANDLE td = CreateThread(nullptr, 0, MainThread, nullptr, 0, nullptr);
                if (td) CloseHandle(td);
        }
        return TRUE;
}


檔案下載點





所有站內附件皆會附上安全掃描報告
請會員查看純淨度百分比後判斷使用



相關檔案須知:
取得檔案前,請先詳細閱讀文章內容
避免不必要錯誤與誤會發生。
也可多參考文章討論樓層內容
了解附件檔案相關討論資訊。





常見問題Q&A



Q:注入後遊戲閃退怎麼辦?
確認注入時機——必須等 client.dll 完全載入後再注入,建議進到大廳畫面再操作。若仍閃退,檢查注入器是否以管理員身分執行。

Q:修改 config.json 後沒反應?
設定檔必須與 DLL 放在同一資料夾,且編碼為 UTF-8 無 BOM 格式。儲存後最慢 0.5 秒會生效,可觀察 region_spoof.log 確認是否有載入記錄。

Q:可以指定特定國家而非大區嗎?
不行,這款工具僅支援 Valve 定義的 6 個 ECitadelRegionMode 大區,無法細分到國家層級。

Q:使用這個會被VAC封鎖嗎?
《Deadlock》目前尚未啟用 VAC,但任何記憶體修改行為都有風險。強烈建議僅用於離線練習或私人對戰,正式競技模式請勿使用。

Q:遊戲更新後失效怎麼辦?
Valve 更新可能改變 BSend 函數位址,導致特徵碼匹配失敗。需等待作者釋出新版 DLL,或自行用除錯工具重新定位函數簽名。

Q:Mac 或 Steam Deck 能用嗎?
這是 Windows 專用的 DLL 注入方案,Mac 與 Linux 環境不支援。Steam Deck 的 Proton 層也可能無法正常運作。





大家正在看啥


收藏收藏 分享文章到FB上分享
回覆 使用道具 檢舉
複製專屬你的推廣連結:發至FB與各論壇宣傳:累積點數換GP商品 & 藍鑽
每五點閱率就可以兌換藍鑽積分或遊戲點卡 夢遊推廣文章換GP商品

你需要登入後才可以回覆 登入 | 加入會員

本版積分規則

Copyright (C) 2010-2020 夢遊電玩論壇

廣告合作:請直接聯繫我們,並附上您預刊登位置的預算。  

快速回覆 返回頂端 返回清單