本帖最后由 MotherShip 于 2024-2-28 23:29 编辑
我看我这窗口化补丁被人搬来搬去,干脆发个改法,免得哪个服要是改了游戏主程序就不能用了。
搞窗口化分几步,首先1.0不是真d3d全屏,它只是强行改了系统分辨率,然后跑了个相同分辨率的无边框窗口
然后切屏幕会卡死,也就是停止渲染,那么我们分几步走
patch crossfirebase.dll 10001120位置的函数(如果是游戏内的地址就是1F1120)
找到这段汇编,是一段改窗口样式的汇编
- mov eax,dword ptr ds:[eax+2E981C]
- push 94000000
- push FFFFFFF0
- push eax
- call dword ptr ds:[<&SetWindowLongA>]
复制代码将原来的94000000(无边框窗口)改为94CF0000即可
patch crossfirebase.dll 10001120位置的函数(如果是游戏内的地址就是1F1120)
伪C代码:
- pfVar1 = ChangeDisplaySettingsA;
- //... 不重要,略
- iVar2 = ChangeDisplaySettingsA(&stack0xfffffea0, 2);
- if (iVar2 == 0) {
- iVar2 = pfVar1(&pdStack348, 4);
- if (iVar2 == 0) {
- goto code_r0x10001295;
- }
- }
- sub_10001BAC();
- return;
复制代码
重点是这里有2次改分辨率,应该是探测了一次能否改为原分辨率,能改就改成800*600
第二次改分辨率不直观,代码先把改分辨率函数的地址扔给了寄存器(伪C代码识别成了把函数指针扔给临时变量),再调寄存器的函数,不过调试器的提示会帮还 原。
找到对应反汇编:
- push 4
- lea edx,dword ptr ss:[esp+10]
- push edx
- call esi
复制代码
NOP填充即可
patch crossfire.exe的监听事件的窗口过程函数62D4F0
伪C代码:
- case 0x1c:
- if (dword_6E937C == 0) {
- if (dword_6E9840 == 0) {
- if (param_3 == 0) {
- if (dword_6E9838 == 0) {
- dword_6E9838 = 1;
- dword_6E9834 = 1;
- (*(func**)(*dword_6E6E88 + 0xb8))(0);
- (*(func**)(*dword_6E6E88 + 0xb0))(1);
- (*(func**)(*dword_6E6E88 + 0x1c))(6, 0);
- OutputDebugStringA("<font color="#ff0000">Losing focus.. shutting down renderer.\n</font>");
- sub_5CDAD0(1, 0);
- sub_622870();
- if ((dword_6E983C == 0) && (iVar2 = sub_583B70(), *(char*)(iVar2 + 0x12a) != '\0')) {
- sub_583B70();
- sub_5834B0();
- }
- (*(func**)(*dword_6E6E88 + 0xb8))(1);
- }
- }
复制代码
看这个调试日志就知道,失去焦点时候会暂停掉游戏渲染引擎,直接干掉if块里所有函数调用就行,先找到汇编:
- push crossfire.690554
- call dword ptr ds:[<&OutputDebugStringA>]
复制代码
这里690954就是日志内容的常量位置,继续寻找上下文,因为if块里的内容是从两次赋值开始,一次函数指针调用结束,往上往下找到这些汇编,用nop填充即可:
- ; 约等于开头的赋值
- mov dword ptr ds:[6E9838],1
- mov dword ptr ds:[6E9834],1
- ; 三次基于地址+偏移的函数调用
- push 0
- mov eax,dword ptr ds:[6E6E88]
- mov edx,dword ptr ds:[eax]
- mov ecx,dword ptr ds:[6E6E88]
- mov eax,dword ptr ds:[edx+B8]
- call eax
- push 1
- mov ecx,dword ptr ds:[6E6E88]
- mov edx,dword ptr ds:[ecx]
- mov ecx,dword ptr ds:[6E6E88]
- mov eax,dword ptr ds:[edx+B0]
- call eax
- push 0
- push 6
- mov ecx,dword ptr ds:[6E6E88]
- mov edx,dword ptr ds:[ecx]
- mov ecx,dword ptr ds:[6E6E88]
- mov eax,dword ptr ds:[edx+1C]
- call eax
- ; 打日志
- push crossfire.690554
- call dword ptr ds:[<&OutputDebugStringA>]
- ; 5CDAD0函数的调用
- push 0
- push 1
- call <crossfire.begin of sub_5CDAD0>
- ; 以下略,参考伪C代码
- add esp,8
- mov ecx,dword ptr ds:[6E92E4]
- call <crossfire.begin of sub_622870>
- cmp dword ptr ds:[6E983C],0
- jne crossfire.62D9A5
- call <crossfire.begin of sub_583B70>
- mov dword ptr ss:[ebp-3FC],eax
- mov ecx,dword ptr ss:[ebp-3FC]
- mov dl,byte ptr ds:[ecx+12A]
- mov byte ptr ss:[ebp-3FD],dl
- movzx eax,byte ptr ss:[ebp-3FD]
- test eax,eax
- je crossfire.62D9A5
- call <crossfire.begin of sub_583B70>
- mov ecx,eax
- call <crossfire.begin of sub_5834B0>
- ; 约等于最后的函数指针调用
- push 1
- mov ecx,dword ptr ds:[6E6E88]
- mov edx,dword ptr ds:[ecx]
- mov ecx,dword ptr ds:[6E6E88]
- mov eax,dword ptr ds:[edx+B8]
- call eax
复制代码
伪C代码:
- if ((dword_6DDB30 != 0) && (dword_6E9838 == 0)) {
- qStack20 = (double)(&iStack108, pdStack12[0x11]);
- pdStack24 = (dword*)0x63043c;
- GetWindowRect();
- pdStack24 = (dword*)((iStack96 - iStack104) / 2);
- pdStack28 = (dword*)((iStack100 - iStack108) / 2);
- piStack32 = (int32_t*)0x63045a;
- SetCursorPos();
- }
复制代码
GetWindowRect()获取游戏窗口4个点,然后SetCursorPos()锁在屏幕左上角+游戏宽高/2的地方
对应汇编:
- mov edx,dword ptr ss:[ebp-8]
- mov eax,dword ptr ds:[edx+44]
- push eax
- call dword ptr ds:[<&GetWindowRect>]
- mov eax,dword ptr ss:[ebp-5C]
- sub eax,dword ptr ss:[ebp-64]
- cdq
- sub eax,edx
- sar eax,1
- push eax
- mov eax,dword ptr ss:[ebp-60]
- sub eax,dword ptr ss:[ebp-68]
- cdq
- sub eax,edx
- sar eax,1
- push eax
- call dword ptr ds:[<&SetPhysicalCursorPos>]
复制代码
找到对应汇编,GetWindowRect调用结束后,EBP+偏移的这四个栈上地址分别是窗口的左上角、右下角的x y坐标位置。
这里直接改成这样(注意,把sub改成mov之后,后面的修改不能用逐行汇编,需要先选中原来的cdq、sub、sar三个语句,然后直接按汇编的注释改16进制): - <div align="left"><font color="rgb(51, 51, 51)"><font face="黑体" size="2">
- </font></font></div><font face="黑体">mov eax,dword ptr ss:[ebp-5C]
- ; 把窗口左上角Y坐标覆盖到eax寄存器,而不是原先的用来做减法
- mov eax,dword ptr ss:[ebp-64]
- ; X坐标+300像素,16进制05 2C 01 00 00
- add eax,12C
- push eax
- mov eax,dword ptr ss:[ebp-60]
- ; 把窗口左上角X坐标覆盖到eax寄存器,而不是原先的用来做减法
- mov eax,dword ptr ss:[ebp-68]
- ; X坐标+400像素,16进制05 90 01 00 00
- add eax,190
- push eax
- call dword ptr ds:[<&SetPhysicalCursorPos>]</font>
复制代码
就可以强制把鼠标锁在窗口左上角+横向右移400,纵向下移300的地方,这样只是默认分辨率下锁在中间其实只要距离边框够远就不会被甩出去,所以也懒得想怎么算中点了(可能字节数也不够)
直接把markdown丢过来之后排版乱七八糟的,富文本编辑器果然不行啊.jpg |