Skip to content

Commit 3d66508

Browse files
committed
init repository
0 parents  commit 3d66508

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2253
-0
lines changed

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
bin/*
2+
!bin/Readme.txt
3+
mingw32/*
4+
mingw64/*
5+
!mingw32/.keep
6+
!mingw64/.keep
7+
.vscode

Makefile

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
subdir = hookdll injector injciv6
2+
cleandir = $(addprefix _clean_, $(subdir))
3+
4+
all: $(subdir)
5+
@ echo Make done !
6+
7+
$(subdir):
8+
$(MAKE) -C $@
9+
10+
$(cleandir):
11+
$(MAKE) clean -C $(patsubst _clean_%, %, $@)
12+
13+
.PHONY: clean $(subdir)
14+
15+
clean: $(cleandir)
16+
@ del bin\*.exe bin\*.dll
17+
@ echo Clean done !

Readme.md

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# 文明6联机-基于IP的游戏发现
2+
3+
> 改自:Hook文明6游戏sendto函数dll和注入程序
4+
5+
原仓库:[https://gitcode.net/PeaZomboss/miscellaneous](https://gitcode.net/PeaZomboss/miscellaneous)
6+
7+
> xaxys:
8+
>
9+
> 原作者使用 hook 方式使得 255.255.255.255 的三层广播包发到所有网卡,本人直接修改发包,使得游戏发现的 UDP 包直接单播到指服务器 IP,对于稳定的局域网,效果更好
10+
>
11+
> IPv6 正在支持,实现原理同 Clash 的 FakeIP, 还没调试完,若成功,将不再需要局域网,直接公网上单播 UDP 包,实现公网联机
12+
>
13+
> 使用方法:见 `bin\Readme.txt` 或 Release 中的 `Readme.txt`
14+
15+
仅支持Windows下的x86和x64平台
16+
17+
请确保熟悉基础的Windows命令行操作
18+
19+
## 目录说明
20+
21+
- bin存放编译后的二进制文件输出目录
22+
- inc存放头文件
23+
- src存放源代码
24+
- hookdll存放dll的代码和Makefile
25+
- injector存放注入程序的代码和Makefile
26+
- utils存放实用程序代码
27+
- test存放测试用代码
28+
29+
## 编译方法
30+
31+
首先确保同时安装了x86和x64的*MinGW-w64*工具链,已经有的可以略过
32+
下载地址<https://github.com/niXman/mingw-builds-binaries/releases>
33+
注意要下载两个,一个带**i686**前缀,一个带**x86_64**前缀
34+
将它们分别解压到不同目录,然后将二者的bin目录都设置环境变量
35+
36+
当然如果你用msys2也可以,会配置完全没问题
37+
38+
切换工作目录到当前目录,运行`mingw32-make`即可
39+
如果你单独安装了*GNU make*,那么可以直接运行`make`
40+
41+
> xaxys:
42+
>
43+
> 下载上面的两个压缩包,一个解压到本文件夹下的 mingw32, 一个解压到本文件夹下的 mingw64
44+
>
45+
> 然后运行 env.bat, 会自动设置环境变量, 开箱即用
46+
47+
---
48+
49+
要编译utils下的辅助程序,请到[Lazarus官网](https://www.lazarus-ide.org/)下载并安装最新版的*Lazarus IDE*
50+
51+
然后用Lazarus打开auxtool.lpi工程文件,在菜单栏中依次选择**运行-构建**即可,exe会生成在bin目录下
52+
53+
## 使用方法
54+
55+
成功编译之后,切换到bin目录,运行injector32.exe或者injector64.exe,具体视游戏而定
56+
57+
例如你要注入文明6,那么请使用`injector64.exe -x=CivilizationVI.exe`或者`injector64.exe -x=CivilizationVI_DX12.exe`
58+
59+
针对文明6,现在可以直接双击`injciv6.exe`来注入,根据提示即可知道结果
60+
61+
如果游戏以管理员权限运行,injector也要以管理员权限运行
62+
63+
> xaxys:
64+
>
65+
> 双击 injciv6.exe 自动注入正在运行的 文明6 进程(一个进程不要多次注入)
66+
>
67+
> 双击 civ6remove.exe 解除注入
68+
>
69+
> 第一次注入后,会在 文明6 目录下生成一个 injciv6-config.txt 文件,用于配置要连接的服务器地址。
70+
>
71+
> injciv6-config.txt 文件默认只有一行,初始为 255.255.255.255
72+
>
73+
> 请改成要连接的服务器地址,如 192.168.1.100, 或 2001::1234:5678:abcd:ef01, 或 abc.com 等
74+
>
75+
> 要使配置生效,请解除注入后重新注入。
76+
>
77+
> 然后就可以使用基于 IP 的游戏发现功能了。
78+
>
79+
> 注:文明6 目录一般为 \Sid Meier's Civilization VI\Base\Binaries\Win64Steam
80+

bin/Readme.txt

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
使用方法:
2+
3+
双击 injciv6.exe 自动注入正在运行的 文明6 进程(一个进程不要多次注入)
4+
双击 civ6remove.exe 解除注入
5+
6+
第一次注入后,会在 文明6 目录下生成一个 injciv6-config.txt 文件,用于配置要连接的服务器地址。
7+
injciv6-config.txt 文件默认只有一行,初始为 255.255.255.255
8+
请改成要连接的服务器地址,如 192.168.1.100, 或 2001::1234:5678:abcd:ef01, 或 abc.com 等
9+
10+
要使配置生效,请解除注入后重新注入。
11+
12+
然后就可以使用基于 IP 的游戏发现功能了。
13+
14+
注:文明6 目录一般为 \Sid Meier's Civilization VI\Base\Binaries\Win64Steam

env.bat

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@echo off
2+
setlocal
3+
set MINGW32=%~dp0mingw32
4+
set MINGW64=%~dp0mingw64
5+
set PATH=%PATH%;%MINGW32%\bin;%MINGW64%\bin
6+
echo Environment variables set. Entering bash...
7+
cmd
8+
endlocal
9+
pause

hookdll/Makefile

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
vpath %.cpp ../src
2+
cxx = g++
3+
cxxflags = -c -O1 -I ../inc
4+
linkflags = -shared -static -l ws2_32
5+
cxx32prefix = i686-w64-mingw32-
6+
cxx64prefix = x86_64-w64-mingw32-
7+
objdir = ./obj/
8+
bindir = ../bin/
9+
src = hookdll.cpp fkhook.cpp inlinehook.cpp
10+
obj32 = $(patsubst %.cpp, $(objdir)%_32.o, $(src))
11+
obj64 = $(patsubst %.cpp, $(objdir)%_64.o, $(src))
12+
target32 = $(bindir)hookdll32.dll
13+
target64 = $(bindir)hookdll64.dll
14+
15+
all: check $(target32) $(target64)
16+
17+
$(target32): $(obj32)
18+
$(cxx32prefix)$(cxx) -o $@ $^ $(linkflags)
19+
20+
$(target64): $(obj64)
21+
$(cxx64prefix)$(cxx) -o $@ $^ $(linkflags)
22+
23+
$(objdir)%_32.o: %.cpp
24+
$(cxx32prefix)$(cxx) $(cxxflags) -o $@ $<
25+
26+
$(objdir)%_64.o: %.cpp
27+
$(cxx64prefix)$(cxx) $(cxxflags) -o $@ $<
28+
29+
.PHONY: check clean
30+
31+
check:
32+
@ if not exist obj md obj
33+
34+
clean:
35+
@ if exist obj del obj\*.o

hookdll/hookdll.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <windows.h>
2+
#include "inlinehook.h"
3+
#include "fkhook.h"
4+
5+
#ifdef _MSC_VER
6+
#pragma comment (lib, "ws2_32.lib")
7+
#endif
8+
9+
BOOL APIENTRY DllMain(HINSTANCE hinstdll, DWORD reason, LPVOID reserved)
10+
{
11+
if (reason == DLL_PROCESS_ATTACH) {
12+
hook();
13+
}
14+
else if (reason == DLL_PROCESS_DETACH) {
15+
unhook();
16+
}
17+
return TRUE;
18+
}

hookdll/obj/fkhook_32.o

37.5 KB
Binary file not shown.

hookdll/obj/fkhook_64.o

37.5 KB
Binary file not shown.

hookdll/obj/hookdll_32.o

782 Bytes
Binary file not shown.

hookdll/obj/hookdll_64.o

819 Bytes
Binary file not shown.

hookdll/obj/inlinehook_32.o

2.12 KB
Binary file not shown.

hookdll/obj/inlinehook_64.o

2.49 KB
Binary file not shown.

inc/fkhook.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
3+
#include "inlinehook.h"
4+
5+
void hook();
6+
void unhook();

inc/inject.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
#include <windows.h>
3+
4+
bool inject_dll(DWORD pid, const char *dll_path);
5+
DWORD find_pid_by_name(const char *name);
6+
HMODULE find_module_handle_from_pid(DWORD pid, const char *module_name);
7+
bool remove_module(DWORD pid, HMODULE module_handle);

inc/inlinehook.h

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
3+
#include <windows.h>
4+
5+
#define HOOK_JUMP_LEN 5
6+
7+
class InlineHook
8+
{
9+
private:
10+
void *old_entry; // 存放原来的代码和跳转回去的代码
11+
char hook_entry[HOOK_JUMP_LEN]; // hook跳转的代码
12+
void *func_ptr; // 被hook函数的地址
13+
public:
14+
InlineHook(HMODULE hmodule, const char *name, void *fake_func, int entry_len);
15+
~InlineHook();
16+
void hook();
17+
void unhook();
18+
void *get_old_entry();
19+
};

inc/platform.h

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
#if defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64)
4+
#define _CPU_X64
5+
#elif defined(__i386__) || defined(_M_IX86)
6+
#define _CPU_X86
7+
#else
8+
#error "Unsupported CPU"
9+
#endif

injciv6/Makefile

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
vpath %.cpp ../src
2+
cxx = g++
3+
cxxflags = -c -O1 -I ../inc
4+
cxx64prefix = x86_64-w64-mingw32-
5+
objdir = ./obj/
6+
bindir = ../bin/
7+
src_inject = injciv6.cpp inject.cpp
8+
src_remove = civ6remove.cpp inject.cpp
9+
obj_inject = $(patsubst %.cpp, $(objdir)%.o, $(src_inject))
10+
obj_remove = $(patsubst %.cpp, $(objdir)%.o, $(src_remove))
11+
target_inject = $(bindir)injciv6.exe
12+
target_remove = $(bindir)civ6remove.exe
13+
14+
all: check $(target_inject) $(target_remove)
15+
16+
$(target_inject): $(obj_inject)
17+
$(cxx64prefix)$(cxx) -o $@ $^ -static -mwindows
18+
19+
$(target_remove): $(obj_remove)
20+
$(cxx64prefix)$(cxx) -o $@ $^ -static -mwindows
21+
22+
$(objdir)%.o: %.cpp
23+
$(cxx64prefix)$(cxx) $(cxxflags) -o $@ $<
24+
25+
.PHONY: check clean
26+
27+
check:
28+
@ if not exist obj md obj
29+
30+
clean:
31+
@ if exist obj del obj\*.o

injciv6/civ6remove.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <shlobj.h>
2+
#include "inject.h"
3+
#include "injciv6.h"
4+
5+
int main(int argc, char *argv[])
6+
{
7+
bool isadmin = IsUserAnAdmin();
8+
int msgres = 0;
9+
if (!isadmin) {
10+
retry_runas:
11+
if (runas_admin(argv[0])) // 成功运行就退出自己
12+
return 0;
13+
msgres = MessageBoxW(0, L"请允许管理员权限", L"错误", MB_ICONERROR | MB_RETRYCANCEL);
14+
if (msgres == IDRETRY)
15+
goto retry_runas;
16+
return 0;
17+
}
18+
DWORD pid = 0;
19+
HMODULE module_handle = 0;
20+
pid = get_civ6_proc();
21+
if (pid == 0) {
22+
MessageBoxW(0, L"找不到游戏进程", L"错误", MB_ICONERROR);
23+
return 0;
24+
}
25+
module_handle = find_module_handle_from_pid(pid, "hookdll64.dll");
26+
if (module_handle == 0) {
27+
MessageBoxW(0, L"当前没有注入DLL", L"错误", MB_ICONERROR);
28+
return 0;
29+
}
30+
if (remove_module(pid, module_handle))
31+
MessageBoxW(0, L"成功移除DLL!", L"成功", MB_OK);
32+
else
33+
msgres = MessageBoxW(0, L"移除失败", L"错误", MB_ICONERROR);
34+
}

injciv6/injciv6.cpp

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include <stdio.h>
2+
#include <shlobj.h>
3+
#include "inject.h"
4+
#include "injciv6.h"
5+
6+
int main(int argc, char *argv[])
7+
{
8+
char dll_path[MAX_PATH];
9+
strcpy(dll_path, argv[0]);
10+
int pos = strlen(dll_path) - 1;
11+
while (pos > 0) {
12+
if (dll_path[pos] == '\\')
13+
break;
14+
pos--;
15+
}
16+
dll_path[pos + 1] = '\0';
17+
strcat(dll_path, "hookdll64.dll");
18+
FILE *fp = fopen(dll_path, "rb");
19+
if (fp == NULL) {
20+
MessageBoxW(0, L"找不到hookdll64.dll", L"错误", MB_ICONERROR);
21+
return 0;
22+
}
23+
fclose(fp);
24+
int msgres = 0;
25+
bool isadmin = IsUserAnAdmin(); // 检测当前是否有管理员权限,需要shlobj.h
26+
DWORD civ6pid = 0;
27+
while (1) {
28+
civ6pid = get_civ6_proc();
29+
if (civ6pid != 0)
30+
break;
31+
msgres = MessageBoxW(0, L"请先运行游戏,然后点击重试", L"错误", MB_RETRYCANCEL | MB_ICONERROR);
32+
if (msgres != IDRETRY)
33+
return 0;
34+
}
35+
retry_inject:
36+
// 尝试注入
37+
if (inject_dll(civ6pid, dll_path)) {
38+
MessageBoxW(0, L"注入成功!", L"成功", MB_OK);
39+
return 0;
40+
}
41+
// 如果管理员权限也失败了,那就不知道什么情况了
42+
if (isadmin) {
43+
// 一般情况下是走不到这里来的
44+
msgres = MessageBoxW(0, L"注入失败", L"错误", MB_RETRYCANCEL | MB_ICONERROR);
45+
if (msgres == IDRETRY)
46+
goto retry_inject;
47+
return 0;
48+
}
49+
// 有的时候比如steam运行游戏可能是带管理员权限的,这个时候要注入程序也要有管理员权限
50+
msgres = MessageBoxW(0, L"注入失败,是否以管理员权限重试?", L"错误", MB_ICONERROR | MB_RETRYCANCEL);
51+
if (msgres == IDRETRY) {
52+
retry_runas:
53+
if (runas_admin(argv[0])) // 成功运行就退出自己
54+
return 0;
55+
msgres = MessageBoxW(0, L"请在弹出的窗口中点击“是”", L"错误", MB_ICONERROR | MB_RETRYCANCEL);
56+
if (msgres == IDRETRY)
57+
goto retry_runas;
58+
}
59+
}

injciv6/injciv6.h

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include <shellapi.h>
4+
#include "inject.h"
5+
6+
inline bool runas_admin(const char *exename)
7+
{
8+
SHELLEXECUTEINFOA sei;
9+
memset(&sei, 0, sizeof(sei));
10+
sei.cbSize = sizeof(sei);
11+
sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
12+
sei.lpVerb = "runas";
13+
sei.lpFile = exename;
14+
sei.nShow = SW_SHOWNORMAL;
15+
return ShellExecuteExA(&sei);
16+
}
17+
18+
inline DWORD get_civ6_proc()
19+
{
20+
DWORD pid = find_pid_by_name("CivilizationVI.exe");
21+
if (pid == 0)
22+
pid = find_pid_by_name("CivilizationVI_DX12.exe");
23+
return pid;
24+
}

injciv6/obj/civ6remove.o

1.85 KB
Binary file not shown.

injciv6/obj/injciv6.o

2.18 KB
Binary file not shown.

injciv6/obj/inject.o

2.66 KB
Binary file not shown.

0 commit comments

Comments
 (0)