├── .gitignore ├── .vscode └── c_cpp_properties.json ├── Makefile ├── README.txt ├── bin ├── hook.exe └── main.dll ├── include └── MinHook.h ├── lib └── libMinHook.a ├── login.json └── src ├── hook.cpp └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | **/.vscode/* 2 | !**/.vscode/c_cpp_properties.json -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win64", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "defines": [], 9 | "compilerPath": "/bin/x86_64-w64-mingw32-gcc", 10 | "cStandard": "c17", 11 | "cppStandard": "c++14", 12 | "intelliSenseMode": "windows-gcc-x64" 13 | } 14 | ], 15 | "version": 4 16 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MINGW_LIB ?= /usr/x86_64-w64-mingw32/lib 2 | VPATH = src lib $(MINGW_LIB) 3 | 4 | all: mkdir hook.exe main.dll 5 | 6 | .PHONY: mkdir 7 | mkdir: 8 | @mkdir -p bin 9 | 10 | hook.exe: hook.cpp libshlwapi.a 11 | x86_64-w64-mingw32-g++ -o bin/$@ $? 12 | 13 | main.dll: main.c libMinHook.a 14 | x86_64-w64-mingw32-gcc -o bin/$@ $? -I . -shared 15 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 干掉屑 IE, 让 Linux 也能玩上 B 服原神 !!! 2 | 3 | 特别声明: 本项目无任何窃取用户隐私行为, 所有代码公开透明, 提供编译好的文件仅为方便使用, 如果不放心, 可阅读代码自行编译 4 | 5 | 食用方法: 6 | 0. 准备好运行环境 (Wine, DXVK, Patch, etc) 7 | 1. 把 bin 目录下的 hook.exe 和 main.dll 放到 YuanShen.exe 的上级目录 (尽量不要放在同级或子目录) 8 | 3. 打开 https://sdk.biligame.com/login/?gameId=4963&appKey=fd1098c0489c4d00a08aa8a15e484d6c&sdk_ver=3.5.0 9 | 4. 按 F12 打开开发者工具 (Dev Tools) 切到控制台 (Console) 10 | 5. 控制台输入 loginSuccess=(data)=>{console.log(JSON.parse(data))} 回车 11 | 6. 登录,看控制台输出, 把 access_key, uid, unmae 的内容替换到 login.json 指定位置 12 | 7. 把 login.json 复制到 YuanShen.exe 所在目录 13 | 8. 修改 launch.bat 最后一行为 start ..\hook.exe "YuanShen.exe %*" ..\main.dll 14 | 9. 享受游戏时光~~~ 15 | 16 | 特殊注意: 17 | 1. login.json 务必是 UTF-8 编码, 且所有内容在第一行 18 | (只能读到第一行的内容, 不要格式化 !!!) 19 | (虽然是因为摆烂不想也不太会写多行读取) 20 | 2. 每次进游戏时都需要去第 3 步的网址登录一下, 不然会报 "渠道错误" 21 | (通常点了登录了就行, 正常登录成功不会有任何提示, 一般而言不需要再改 json) 22 | (大约一个月内 access_key 轻易是不会变的, 但是每次登录行为的有效期很短, 所以要手动去触发一下) 23 | 24 | 十分感谢: 25 | MinHook: https://github.com/TsudaKageyu/minhook 26 | m**n**2: 为避免 takedown, 不提供地址 27 | dawn: 为避免 takedown, 不提供地址 28 | A****-GC: 为避免 takedown, 不提供地址 29 | PCGameSDK: http://open.biligame.com/wiki/bili_pc_game/ 30 | -------------------------------------------------------------------------------- /bin/hook.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiE2035/gs_bili/9a5d36e44f00379e8090643b9bba7f6200b840a5/bin/hook.exe -------------------------------------------------------------------------------- /bin/main.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiE2035/gs_bili/9a5d36e44f00379e8090643b9bba7f6200b840a5/bin/main.dll -------------------------------------------------------------------------------- /include/MinHook.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) 32 | #error MinHook supports only x86 and x64 systems. 33 | #endif 34 | 35 | #include 36 | 37 | // MinHook Error Codes. 38 | typedef enum MH_STATUS 39 | { 40 | // Unknown error. Should not be returned. 41 | MH_UNKNOWN = -1, 42 | 43 | // Successful. 44 | MH_OK = 0, 45 | 46 | // MinHook is already initialized. 47 | MH_ERROR_ALREADY_INITIALIZED, 48 | 49 | // MinHook is not initialized yet, or already uninitialized. 50 | MH_ERROR_NOT_INITIALIZED, 51 | 52 | // The hook for the specified target function is already created. 53 | MH_ERROR_ALREADY_CREATED, 54 | 55 | // The hook for the specified target function is not created yet. 56 | MH_ERROR_NOT_CREATED, 57 | 58 | // The hook for the specified target function is already enabled. 59 | MH_ERROR_ENABLED, 60 | 61 | // The hook for the specified target function is not enabled yet, or already 62 | // disabled. 63 | MH_ERROR_DISABLED, 64 | 65 | // The specified pointer is invalid. It points the address of non-allocated 66 | // and/or non-executable region. 67 | MH_ERROR_NOT_EXECUTABLE, 68 | 69 | // The specified target function cannot be hooked. 70 | MH_ERROR_UNSUPPORTED_FUNCTION, 71 | 72 | // Failed to allocate memory. 73 | MH_ERROR_MEMORY_ALLOC, 74 | 75 | // Failed to change the memory protection. 76 | MH_ERROR_MEMORY_PROTECT, 77 | 78 | // The specified module is not loaded. 79 | MH_ERROR_MODULE_NOT_FOUND, 80 | 81 | // The specified function is not found. 82 | MH_ERROR_FUNCTION_NOT_FOUND 83 | } 84 | MH_STATUS; 85 | 86 | // Can be passed as a parameter to MH_EnableHook, MH_DisableHook, 87 | // MH_QueueEnableHook or MH_QueueDisableHook. 88 | #define MH_ALL_HOOKS NULL 89 | 90 | #ifdef __cplusplus 91 | extern "C" { 92 | #endif 93 | 94 | // Initialize the MinHook library. You must call this function EXACTLY ONCE 95 | // at the beginning of your program. 96 | MH_STATUS WINAPI MH_Initialize(VOID); 97 | 98 | // Uninitialize the MinHook library. You must call this function EXACTLY 99 | // ONCE at the end of your program. 100 | MH_STATUS WINAPI MH_Uninitialize(VOID); 101 | 102 | // Creates a hook for the specified target function, in disabled state. 103 | // Parameters: 104 | // pTarget [in] A pointer to the target function, which will be 105 | // overridden by the detour function. 106 | // pDetour [in] A pointer to the detour function, which will override 107 | // the target function. 108 | // ppOriginal [out] A pointer to the trampoline function, which will be 109 | // used to call the original target function. 110 | // This parameter can be NULL. 111 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); 112 | 113 | // Creates a hook for the specified API function, in disabled state. 114 | // Parameters: 115 | // pszModule [in] A pointer to the loaded module name which contains the 116 | // target function. 117 | // pszProcName [in] A pointer to the target function name, which will be 118 | // overridden by the detour function. 119 | // pDetour [in] A pointer to the detour function, which will override 120 | // the target function. 121 | // ppOriginal [out] A pointer to the trampoline function, which will be 122 | // used to call the original target function. 123 | // This parameter can be NULL. 124 | MH_STATUS WINAPI MH_CreateHookApi( 125 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); 126 | 127 | // Creates a hook for the specified API function, in disabled state. 128 | // Parameters: 129 | // pszModule [in] A pointer to the loaded module name which contains the 130 | // target function. 131 | // pszProcName [in] A pointer to the target function name, which will be 132 | // overridden by the detour function. 133 | // pDetour [in] A pointer to the detour function, which will override 134 | // the target function. 135 | // ppOriginal [out] A pointer to the trampoline function, which will be 136 | // used to call the original target function. 137 | // This parameter can be NULL. 138 | // ppTarget [out] A pointer to the target function, which will be used 139 | // with other functions. 140 | // This parameter can be NULL. 141 | MH_STATUS WINAPI MH_CreateHookApiEx( 142 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); 143 | 144 | // Removes an already created hook. 145 | // Parameters: 146 | // pTarget [in] A pointer to the target function. 147 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); 148 | 149 | // Enables an already created hook. 150 | // Parameters: 151 | // pTarget [in] A pointer to the target function. 152 | // If this parameter is MH_ALL_HOOKS, all created hooks are 153 | // enabled in one go. 154 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); 155 | 156 | // Disables an already created hook. 157 | // Parameters: 158 | // pTarget [in] A pointer to the target function. 159 | // If this parameter is MH_ALL_HOOKS, all created hooks are 160 | // disabled in one go. 161 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); 162 | 163 | // Queues to enable an already created hook. 164 | // Parameters: 165 | // pTarget [in] A pointer to the target function. 166 | // If this parameter is MH_ALL_HOOKS, all created hooks are 167 | // queued to be enabled. 168 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); 169 | 170 | // Queues to disable an already created hook. 171 | // Parameters: 172 | // pTarget [in] A pointer to the target function. 173 | // If this parameter is MH_ALL_HOOKS, all created hooks are 174 | // queued to be disabled. 175 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); 176 | 177 | // Applies all queued changes in one go. 178 | MH_STATUS WINAPI MH_ApplyQueued(VOID); 179 | 180 | // Translates the MH_STATUS to its name as a string. 181 | const char * WINAPI MH_StatusToString(MH_STATUS status); 182 | 183 | #ifdef __cplusplus 184 | } 185 | #endif 186 | -------------------------------------------------------------------------------- /lib/libMinHook.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiE2035/gs_bili/9a5d36e44f00379e8090643b9bba7f6200b840a5/lib/libMinHook.a -------------------------------------------------------------------------------- /login.json: -------------------------------------------------------------------------------- 1 | {"code":0,"data":{"access_key":"你的access_key","game_id":"4963","uid":你的uid,"uname":"你的uname"}} -------------------------------------------------------------------------------- /src/hook.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int inject_library(HANDLE hProcess, const char *dll) 6 | { 7 | auto loadlibrary = LoadLibraryA; // i actually had no idea that the address of kernel32 is the same between all processes 8 | auto mem = VirtualAllocEx(hProcess, NULL, strlen(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 9 | printf("LoadLibraryA %p\n", loadlibrary); 10 | printf("allocated path addr %p\n", mem); 11 | if (!mem) 12 | { 13 | printf("VirtualAllocEx epic fail GLE: 0x%x\n", GetLastError()); 14 | return 1; 15 | } 16 | WriteProcessMemory(hProcess, mem, dll, strlen(dll) + 1, NULL); 17 | 18 | auto new_thread = CreateRemoteThread( 19 | hProcess, 20 | NULL, 21 | NULL, 22 | (LPTHREAD_START_ROUTINE)loadlibrary, 23 | mem, 24 | NULL, 25 | NULL); 26 | if (new_thread == NULL) 27 | { 28 | printf("CreateRemoteThread epic fail GLE: 0x%x\n", GetLastError()); 29 | return 1; 30 | } 31 | 32 | printf("waiting for the dll loading thread to exit\n"); 33 | WaitForSingleObject(new_thread, INFINITE); 34 | printf("looks like the dll injected properly\n"); 35 | 36 | VirtualFreeEx(hProcess, mem, 0, MEM_RELEASE); 37 | 38 | CloseHandle(new_thread); 39 | return 0; 40 | } 41 | 42 | int main(int argc, char *argv[]) 43 | { 44 | if (argc < 3) 45 | { 46 | puts("Too few arguments!"); 47 | printf("Usage: %s Genshin_Command Dll_To_Inject_1 [Dll_To_Inject_2 ...]\n", argv[0]); 48 | return 1; 49 | } 50 | 51 | for (int i = 2; i < argc; i++) 52 | { 53 | if (!PathFileExistsA(argv[i])) 54 | { 55 | printf("DLL provided couldn't be found: %s\n"); 56 | return 1; 57 | } 58 | } 59 | 60 | // if (!SetCurrentDirectoryA(argv[1])) 61 | // { 62 | // printf("Failed to set working directory, GLE: %d\n", GetLastError()); 63 | // return 1; 64 | // } 65 | SetEnvironmentVariableW(L"__COMPAT_LAYER", L"RunAsInvoker"); // forcefully run as not admin 66 | 67 | STARTUPINFOA startup_info = {}; 68 | startup_info.cb = sizeof(startup_info); 69 | PROCESS_INFORMATION process_info = {}; 70 | 71 | SECURITY_ATTRIBUTES attrib = {}; 72 | attrib.nLength = sizeof(attrib); 73 | SECURITY_DESCRIPTOR desc = {}; 74 | 75 | BOOL created = CreateProcessA( 76 | // "YuanShen.exe", 77 | NULL, 78 | argv[1], 79 | NULL, 80 | NULL, 81 | FALSE, 82 | CREATE_SUSPENDED, 83 | NULL, 84 | NULL, 85 | &startup_info, 86 | &process_info); 87 | 88 | if (created == FALSE) 89 | { 90 | printf("CreateProcessW epic fail GLE 0x%x\n", GetLastError()); 91 | return 1; 92 | } 93 | 94 | for (int i = 2; i < argc; i++) 95 | { 96 | if (inject_library(process_info.hProcess, argv[i])) 97 | { 98 | printf("Error injecting %s!\n", argv[i]); 99 | TerminateProcess(process_info.hProcess, 1); 100 | return 1; 101 | } 102 | } 103 | 104 | if (ResumeThread(process_info.hThread) == -1) 105 | { 106 | printf("ResumeThread epic fail GLE: 0x%x\n", GetLastError()); 107 | return 1; 108 | } 109 | 110 | printf("everything seems to be good, cleaning up!\n"); 111 | 112 | CloseHandle(process_info.hProcess); 113 | CloseHandle(process_info.hThread); 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "include/MinHook.h" 8 | 9 | typedef void(__stdcall *LoginCallBackHandler)(char *, int); 10 | typedef int(__stdcall *SDKShowLoginPanel)(const char *, const bool, LoginCallBackHandler); 11 | typedef int(__stdcall *SDKInit)(const char *, HWND); 12 | 13 | #define SIZE 1024 14 | 15 | void OnLogin(void *pCallBack) 16 | { 17 | LoginCallBackHandler CallBack = pCallBack; 18 | 19 | // 读取 login.json, 格式参考 SDK 文档 20 | FILE *DataFile = fopen("login.json", "rb"); 21 | char data[SIZE]; 22 | fgets(data, SIZE, DataFile); 23 | // 烦死个人的转码 24 | char *pszMultiByte = data; 25 | int iSize; 26 | wchar_t *pwszUnicode; 27 | iSize = MultiByteToWideChar(CP_UTF8, 0, pszMultiByte, -1, NULL, 0); 28 | pwszUnicode = (wchar_t *)malloc(iSize * sizeof(wchar_t)); 29 | MultiByteToWideChar(CP_UTF8, 0, pszMultiByte, -1, pwszUnicode, iSize); 30 | // 显示数据用以确认 31 | MessageBoxW(NULL, pwszUnicode, L"登录数据", MB_OK | MB_SYSTEMMODAL); 32 | switch (MessageBoxW(NULL, L"是否登录?\n请务必确保数据正确!", L"登录确认", MB_YESNO | MB_SYSTEMMODAL)) 33 | { 34 | case 6: 35 | // 确认登录, 调用回调 36 | puts("yes"); 37 | CallBack(data, strlen(data)); 38 | break; 39 | default: 40 | // 其它操作, 一律取消 41 | puts("no"); 42 | char *data2 = "{\"code\":-2,\"data\":{\"message\":\"cancel\"}}"; 43 | CallBack(data2, strlen(data2)); 44 | } 45 | // 执行完毕, 停止线程 46 | _endthread(); 47 | } 48 | 49 | int __stdcall HookLogin(const char *szAppKey, const bool bBackToLogin, LoginCallBackHandler CallBack) 50 | { 51 | puts("Hooked: SDKShowLoginPanel"); 52 | // 开新线程, 防止阻塞 53 | _beginthread(OnLogin, 0, CallBack); 54 | return 0; 55 | } 56 | 57 | typedef HMODULE(WINAPI *OldLoadLibraryW)(LPCWSTR lpLibFileName); 58 | 59 | OldLoadLibraryW OrgLoadLibraryW = NULL; 60 | 61 | HMODULE WINAPI NewLoadLibraryW(LPCWSTR lpLibFileName) 62 | { 63 | // 烦死个人的转码 64 | wchar_t *pwszUnicode = lpLibFileName; 65 | int iSize; 66 | char *pszMultiByte; 67 | iSize = WideCharToMultiByte(CP_ACP, 0, pwszUnicode, -1, NULL, 0, NULL, NULL); 68 | pszMultiByte = (char *)malloc(iSize * sizeof(char)); 69 | WideCharToMultiByte(CP_ACP, 0, pwszUnicode, -1, pszMultiByte, iSize, NULL, NULL); 70 | // 找 PCGameSDK.dll 71 | if (strstr(pszMultiByte, "PCGameSDK.dll")) 72 | { 73 | puts("Hooking: PCGameSDK.dll"); 74 | HMODULE module = OrgLoadLibraryW(lpLibFileName); 75 | // 找 SDKShowLoginPanel 76 | SDKShowLoginPanel SDKLoginFunc = (SDKShowLoginPanel)GetProcAddress(module, "SDKShowLoginPanel"); 77 | SDKShowLoginPanel OrgLogin = NULL; 78 | // 找到了, Hook 掉 79 | if (MH_CreateHook(SDKLoginFunc, &HookLogin, (LPVOID *)(&OrgLogin)) != MH_OK) 80 | puts("Hook Create Error: PCGameSDK.dll"); 81 | else if (MH_EnableHook(SDKLoginFunc) != MH_OK) 82 | puts("Hook Enable Error: PCGameSDK.dll"); 83 | // Hook 成没成都得返回 HMODULE 84 | return module; 85 | } 86 | // 找没找到都得返回 HMODULE 87 | return OrgLoadLibraryW(lpLibFileName); 88 | } 89 | 90 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 91 | { 92 | if (ul_reason_for_call == DLL_PROCESS_ATTACH) 93 | { 94 | // 来个控制台, 但好像不咋好用, 总是没有输出, 不知道为啥, 蹲个能给修一下的 dalao 95 | AllocConsole(); 96 | freopen("CONIN$", "rb", stdin); 97 | freopen("CONOUT$", "wb", stdout); 98 | freopen("CONOUT$", "wb", stderr); 99 | // 初始化 MinHook 100 | puts("Init MinHook"); 101 | if (MH_Initialize() != MH_OK) 102 | { 103 | puts("Hook Init Error!"); 104 | return FALSE; 105 | } 106 | // PCGameSDK.dll 是动态加载的, 所以 Hook 掉 LoadLibraryW 107 | puts("Hooking: LoadLibraryW"); 108 | if (MH_CreateHook(&LoadLibraryW, &NewLoadLibraryW, (LPVOID *)(&OrgLoadLibraryW)) != MH_OK) 109 | { 110 | puts("Hook Create Error: LoadLibraryW"); 111 | return FALSE; 112 | } 113 | else if (MH_EnableHook(&LoadLibraryW) != MH_OK) 114 | { 115 | puts("Hook Enable Error: LoadLibraryW"); 116 | return FALSE; 117 | } 118 | } 119 | return TRUE; 120 | } 121 | --------------------------------------------------------------------------------