最新消息:用博客记录点滴生活。与您共同关注互联网,分享互联网。
VC这款游戏有很多BUG,比如在多核心处理器的计算机上很容易死机,全屏的话基本上就得重启,而且有时候鼠标不能动,必须来回按ESC/Resume才能解决(有时候RP不好就直接黑屏了)。这都是多核CPU造成的问题。解决方法倒是也容易,打开任务管理器,找到gta-vc.exe进程,右键“关系设置”,然后只勾选一个CPU(通常是CPU0),点确定即可。 可是每回进游戏都得再切出来一次调试,实在是很麻烦,下面我就讲讲如何修改gta-vc.exe,让它启动时自动设置为在CPU0上运行。 本文对读者要求较高,仅作抛砖引玉之用,看不懂过程的或者懒得看的可以直接略,后面有修改好的gta-vc.exe。
1.分析任务管理器的内部实现
首先要分析taskmgr.exe,也就是系统的任务管理器,看看他是怎么实现为进程指定CPU运行的,既然要操作进程,那么它内部肯定需要用OpenProcess函数打开进程,然后用返回的句柄操作,那么我们就用OD调试之,给OpenProcess下断(注意要暂停刷新,否则都会一直断在OpenProcess里面)下好断之后,如上操作一遍,勾选CPU0,然后点确定,这时就断在了OpenProcess里,返回程序领空,来看看关键代码。
0100BA26 /$ 55 PUSH EBP
0100BA27 |. 8BEC MOV EBP,ESP
0100BA29 |. 51 PUSH ECX
0100BA2A |. 53 PUSH EBX
0100BA2B |. 56 PUSH ESI
0100BA2C |. 57 PUSH EDI
0100BA2D |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; /ProcessId
0100BA30 |. 33DB XOR EBX,EBX ; |
0100BA32 |. 53 PUSH EBX ; |Inheritable =& FALSE
0100BA33 |. 68
PUSH 600 ; |Access = SET_INFORMATION|QUERY_INFORMATION
0100BA38 |. 8BF1 MOV ESI,ECX ; |
0100BA3A |. FF15
CALL DWORD PTR DS:[&&kernel32.OpenProces&; \OpenProcess
0100BA40 |. 8BF8 MOV EDI,EAX
0100BA42 |. 85FF TEST EDI,EDI
0100BA44 |. 74 4E JE SHORT taskmgr.0100BA94
0100BA46 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
0100BA49 |. 50 PUSH EAX ; /pSystemAffinityMask
0100BA4A |. 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8] ; |
0100BA4D |. 50 PUSH EAX ; |pProcessAffinityMask
0100BA4E |. 57 PUSH EDI ; |hProcess
0100BA4F |. FF15
CALL DWORD PTR DS:[&&kernel32.GetProcess&; \GetProcessAffinityMask
0100BA55 |. 85C0 TEST EAX,EAX
0100BA57 |. 74 30 JE SHORT taskmgr.0100BA89
0100BA59 |. 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8]
0100BA5C |. 50 PUSH EAX ; /lParam
0100BA5D |. 68 5BB60001 PUSH taskmgr.0100B65B ; |DlgProc = taskmgr.0100B65B
0100BA62 |. FF76 04 PUSH DWORD PTR DS:[ESI+4] ; |hOwner
0100BA65 |. 6A 7C PUSH 7C ; |pTemplate = 7C
0100BA67 |. FF35 705D0101 PUSH DWORD PTR DS:[1015D70] ; |hInst =
0100BA6D |. FF15 FC130001 CALL DWORD PTR DS:[&&user32.DialogBoxPar&; \DialogBoxParamW
0100BA73 |. 83F8 01 CMP EAX,1
0100BA76 |. 75 0E JNZ SHORT taskmgr.0100BA86
0100BA78 |. FF75 08 PUSH DWORD PTR SS:[EBP+8]
0100BA7B |. 57 PUSH EDI
0100BA7C |. FF15 0C110001 CALL DWORD PTR DS:[&&kernel32.SetProcess&; kernel32.SetProcessAffinityMask
0100BA82 |. 85C0 TEST EAX,EAX
0100BA84 |. 74 03 JE SHORT taskmgr.0100BA89
0100BA86 |& 33DB XOR EBX,EBX
0100BA88 |. 43 INC EBX
0100BA89 |& 57 PUSH EDI ; /hObject
0100BA8A |. FF15 5C110001 CALL DWORD PTR DS:[&&kernel32.CloseHandl&; \CloseHandle
0100BA90 |. 85DB TEST EBX,EBX
0100BA92 |. 75 14 JNZ SHORT taskmgr.0100BAA8
0100BA94 |& FF15
CALL DWORD PTR DS:[&&kernel32.GetLastErr&; [GetLastError
0100BA9A |. 50 PUSH EAX ; /Arg3
0100BA9B |. 68
PUSH 7568 ; |Arg2 =
0100BAA0 |. FF76 04 PUSH DWORD PTR DS:[ESI+4] ; |Arg1
0100BAA3 |. E8 789AFFFF CALL taskmgr. ; \taskmgr.
0100BAA8 |& 5F POP EDI
0100BAA9 |. 5E POP ESI
0100BAAA |. 8BC3 MOV EAX,EBX
0100BAAC |. 5B POP EBX
0100BAAD |. C9 LE***E
0100BAAE \. C2 0400 RETN 4
程序逻辑很简单,先调用OpenProcess打开进程,取得句柄,然后GetProcessAffinityMask,如果失败则设置错误信息然后返回,成功的话调用DialogBoxParamW从资源创建对话框,(也就是“关系设置”窗口),并将当前的CPU信息显示上去,知道点下“确定”,DialogBoxParamW才返回。如果用户修改了原先的CPU关系设置,那么就会调用SetProcessAffinityMask设置当前进程;如果没有,则直接关闭进程句柄,函数返回。
由此我们可以知道,用GetProcessAffinityMask可以取得一个进程的CPU设置,用SetProcessAffinityMask则可以对其进行设置,我们要是自动设置gta-vc.exe在CPU0上运行的话,显然是要用到后者,上MSDN查查这个函数,上面把用法什么的写的很详细,详见:
2.修改启动程序gta-vc.exe
经过一系列搜索,得知只要如此调用:SetProcessAffinityMask(ProcessHandle, 1)即可把对应的进程设置为在CPU0上运行,下面就是要自己修改gta-vc.exe,让它自己执行这个函数。 先用eXeScope看一下gta-vc.exe的导入表,我找到了Direct3DCreate函数,由d3d8.dll导出,显然这个函数是跟DirectX相关的,应该是在初始化阶段被调用。下面用OD断一下,看看能不能利用这个函数。
下断,然后运行,马上就断了下来,然后回到gta-vc.exe领空,可见调用代码如下:
& \8B&MOV EAX,DWORD PTR SS:[ESP+444] ; 案例 0 --& 分支 0065B5DA
0065B84C . 55 PUSH EBP
0065B84D . 6A 78 PUSH 78
0065B84F . 8B08 MOV ECX,DWORD PTR DS:[EAX]
. 890D A4977800 MOV DWORD PTR DS:[7897A4],ECX
. E8 007D0000 CALL &JMP.&d3d8.Direct3DCreate8&
0065B85C . 33FF XOR EDI,EDI
0065B85E . A3 B4977800 MOV DWORD PTR DS:[7897B4],EAX
. 3BC7 CMP EAX,EDI
. 75 0C JNZ SHORT gta-vc-b.
. 5D POP EBP
. 5F POP EDI
. 33C0 XOR EAX,EAX
0065B86B . 5E POP ESI
0065B86C . 81C4
ADD ESP,430
看到了这句:
. E8 007D0000 CALL &JMP.&d3d8.Direct3DCreate8&
看来可以修改这里,插入一小段代码调用SetProcessAffinityMask(ProcessHandle, 1),为了不影响程序原本的功能,我们往下看看,找一段空字节插入代码,然后用JMP修改程序流程就行了。往下拉了一段,果然在的地方找到一堆NOP指令,看起来够长,把调用SetProcessAffinityMask的代码加在这里就行了,然后把原本的CALL &JMP.&d3d8.Direct3DCreate8&修改成JMP跳转到我们自己加的这段代码处,执行完再JMP回去即可。
但是在此之前还有个问题需要处理,那就是得处理SetProcessAffinityMask的地址,gta-vc.exe原版并没有导入SetProcessAffinityMask函数,虽然我们也可以用OD直接改成“call SetProcessAffinityMask”,不过这样的话是用的是硬编码,可能不支持VISTA/7及以上系统,所以我们还得自己给gta-vc.exe导入这个函数。
用LordPE载入之,找到导入表,然后右键“添加导入表”,DLL是kernel32.dll,函数名即SetProcessAffinityMask,然后点“+”,记下ThunkRVA(我们后面调用要用到),确定即可。 我添加的ThunkRVA值为,关掉LordPE,重新用OD载入,现在可以开始修改了。 按照上面的步骤再操作一遍,找到我们之前找好的那一段NOP(),在这里加入如下代码:
call dword ptr [00A14026]
大家肯定觉得奇怪,00A14026是哪里来的?实际上这个就是我们加入的导入函数SetProcessAffinityMask的ThunkVA,前面我们知道ThunkRVA是,我们在OD里用Ctrl-G呼出前往窗口,选择RVA,然后输入,确定。之后就跳到了00A14026,OD就已经为我们把RVA转换成VA了,所以这个00A14026就是导入Thunk的真实地址。 调用完之后我们还得正常调用Direct3DCreate8,但是这段NOP不够用了,得先short jmp到后面的另一小段NOP:
0065C85D JMP SHORT
call 0066355C
都搞定了我们还得JMP回去,让程序正常执行:
jmp 0065B85C
最后把原始的CALL &JMP.&d3d8.Direct3DCreate8&改成JMP ,让它执行到这里时跳转到,执行完我们自己的代码后再JMP回来。都改好了,OD主界面右键“复制到可执行文件-所有修改-全部复制”,然后再右键“保存文件”,保存成gta-vc.exe(最好提前备份原版文件)。
至此便大功告成,运行游戏,再使用任务管理器看一看“关系设置”,会发现已经自动设置为在CPU0上运行,不用每回再手动改了,我的目的也就达到了。游戏功能没有任何影响。
改好的gta-vc.exe下载地址(把图标修改了):
本文转至百度贴吧:
正文部分到此结束
文章标题 : 侠盗猎车手罪恶都市死机以及鼠标不能动完美解决方法 - 777's Blog
本文链接 : http://www.777s.me/gta-vc-cpu.html
版权声明 : 原创文章转载时,请务必以超链接形式标明文章原始出处
本站遵循 :
不知道叫什么侠盗飞车罪恶都市侠盗无双0.3怎么变奥特曼里面都没有_百度知道这两天我在玩《侠盗猎车—罪恶都市》可总是死机。_百度知道