1、申请ID:wynick27
2、个人邮箱:wynick27@gmail.com
3、原创技术文章:恐怖黎明大箱子修改方法
http://tieba.baidu.com/p/4520543789
自从出了mod工具后我就开始研究大箱子工具,结果发现游戏的关于共享箱子的逻辑部分都是写死的,在游戏dll和exe里面,然后我就开始调试游戏主程序,今天终于有了进展。
目前我是把游戏箱子的4个按钮改了,第一页功能不变,第二页的功能改成了向下翻页,第三页改成了向前翻页,因为同一个按钮不能连点两次,所以我把第四页改成无作用。然后把总页数改成了8页,由于游戏存档格式是支持超过4页的,所以能够正确存档。
不过直接修改游戏UI是很困难的,不但每次更新都要跟着改,而且steam版必须先破解steamstub才行,所以我考虑把这个做成修改器通过按键实现,CE修改器是支持自动汇编的。
下面是修改关键位置讲解,需要OllyDbg或类似调试器或者CE,而且要有一定汇编基础
Game.dll需要修改两个函数,分别是
GAME::GameEngine::AddTransferSack
GAME::GameEngine::RestoreNumberOfTransferSack
game.dll中的函数全部导出了,修改起来很方便
GAME::GameEngine::AddTransferSack这个函数用来给共享箱子添加一页,代码如下:
[Asm] 纯文本查看 复制代码 014DC450 G>/$ 55 push ebp
014DC451 |. 8BEC mov ebp,esp
014DC453 |. 6A FF push -1
014DC455 |. 68 9F066701 push Game.0167069F ; SE 句柄安装
014DC45A |. 64:A1 00000000 mov eax,dword ptr fs:[0]
014DC460 |. 50 push eax
014DC461 |. 64:8925 00000000 mov dword ptr fs:[0],esp
014DC468 |. 51 push ecx
014DC469 |. 8B81 64280000 mov eax,dword ptr ds:[ecx+2864]
014DC46F |. 2B81 60280000 sub eax,dword ptr ds:[ecx+2860]
014DC475 |. 56 push esi
014DC476 |. 8DB1 60280000 lea esi,dword ptr ds:[ecx+2860]
014DC47C |. C1F8 02 sar eax,2
014DC47F |. 83F8 04 cmp eax,4
014DC482 73 41 jnb short Game.014DC4C5
014DC484 |. 6A 34 push 34 ; /Arg1 = 00000034
014DC486 |. E8 CF811800 call Game.0166465A ; \Game.1006465A
014DC48B |. 83C4 04 add esp,4
014DC48E |. 8945 F0 mov [local.4],eax
014DC491 |. 8BC8 mov ecx,eax
014DC493 |. C745 FC 00000000 mov [local.1],0
014DC49A |. E8 B1200200 call Game.GAME::InventorySack::InventorySack
014DC49F |. C745 FC FFFFFFFF mov [local.1],-1
注意014DC47F这行的cmp eax,4就是硬编码的箱子页数,大于这个数是无法添加的,我们进行如下修改
[Asm] 纯文本查看 复制代码 014DC47F |. 83F8 04 cmp eax,4
014DC482 90 nop
014DC483 90 nop
修改为空指令
接下来是这个函数GAME::GameEngine::RestoreNumberOfTransferSack,是读取共享箱子文件时调用的
[Asm] 纯文本查看 复制代码 014DC4E0 G> $ 55 push ebp
014DC4E1 . 8BEC mov ebp,esp
014DC4E3 . 6A FF push -1
014DC4E5 . 68 9F066701 push Game.0167069F ; SE 句柄安装
014DC4EA . 64:A1 00000000 mov eax,dword ptr fs:[0]
014DC4F0 . 50 push eax
014DC4F1 . 64:8925 00000000 mov dword ptr fs:[0],esp
014DC4F8 . 51 push ecx
014DC4F9 . 8B81 64280000 mov eax,dword ptr ds:[ecx+2864]
...
...
014DC520 > /8B47 04 mov eax,dword ptr ds:[edi+4]
014DC523 . |2B07 sub eax,dword ptr ds:[edi]
014DC525 . |C1F8 02 sar eax,2
014DC528 |83F8 04 cmp eax,4
014DC52B |73 30 jnb short Game.014DC55D
014DC52D . |6A 34 push 34 ; /Arg1 = 00000034
014DC52F . |E8 26811800 call Game.0166465A ; \Game.1006465A
014DC534 . |83C4 04 add esp,4
014DC537 . |8945 F0 mov dword ptr ss:[ebp-10],eax
014DC53A . |8BC8 mov ecx,eax
014DC53C . |C745 FC 00000000 mov dword ptr ss:[ebp-4],0
014DC543 . |E8 08200200 call Game.GAME::InventorySack::InventorySack
014DC548 . |C745 FC FFFFFFFF mov dword ptr ss:[ebp-4],-1
还是014DC528这行的cmp eax,4
修改为
[Asm] 纯文本查看 复制代码 014DC528 83F8 04 cmp eax,4
014DC52B 90 nop
014DC52C 90 nop
这样游戏就可以读取多于4页的箱子了
第三个关键位置就是按下按钮的回调函数,这段对应了7种情况,分别是4页箱子按钮和3个购买按钮
[Asm] 纯文本查看 复制代码 01136E70 /. 55 push ebp
01136E71 |. 8BEC mov ebp,esp
01136E73 |. 83E4 F8 and esp,FFFFFFF8
01136E76 |. 51 push ecx
01136E77 |. 837D 08 00 cmp [arg.1],0
01136E7B |. 56 push esi
01136E7C |. 8BF1 mov esi,ecx
01136E7E |. 0F85 46010000 jnz Grim_Daw.01136FCA
01136E84 |. 8B4D 0C mov ecx,[arg.2]
01136E87 |. 8D46 30 lea eax,dword ptr ds:[esi+30]
01136E8A |. 3BC8 cmp ecx,eax
01136E8C |. 75 33 jnz short Grim_Daw.01136EC1
01136E8E |. 8B0D 040F2401 mov ecx,dword ptr ds:[<&Game.GAME::gGameEngine>] ; Game.GAME::gGameEngine
01136E94 |. 6A 00 push 0 ; /Arg1 = 00000000
01136E96 |. 8B09 mov ecx,dword ptr ds:[ecx] ; |
01136E98 |. FF15 48272401 call dword ptr ds:[<&Game.GAME::GameEngine::SetSelected>; \GAME::GameEngine::SetSelectedTransferSackNumber
01136E9E |. C786 F40A0000 00000000 mov dword ptr ds:[esi+AF4],0
01136EA8 |. 8B86 EC0A0000 mov eax,dword ptr ds:[esi+AEC]
01136EAE |. 2B86 E80A0000 sub eax,dword ptr ds:[esi+AE8]
01136EB4 |. C1F8 02 sar eax,2
位置如上,可通过GAME::GameEngine::SetSelectedTransferSackNumber反向查找得到
01136ECB |. 8B0D 040F2401 mov ecx,dword ptr ds:[<&Game.GAME::gGameEngine>] ; Game.GAME::gGameEngine
以下代码是用来切换箱子页数的,需要修改
[Asm] 纯文本查看 复制代码 01136ED1 6A 01 push 1
01136ED3 8B09 mov ecx,dword ptr ds:[ecx]
01136ED5 FF15 48272401 call dword ptr ds:[<&Game.GAME::GameEngine::SetSelected>; Game.GAME::GameEngine::SetSelectedTransferSackNumber
修改为
[Asm] 纯文本查看 复制代码 01136ED1 E9 29821000 jmp Grim_Daw.0123F0FF
01136ED6 90 nop
01136ED7 90 nop
01136ED8 90 nop
01136ED9 90 nop
01136EDA 90 nop
[Asm] 纯文本查看 复制代码
01136EDB |. C786 F40A0000 01000000 mov dword ptr ds:[esi+AF4],1
01136EE5 |. 8B86 EC0A0000 mov eax,dword ptr ds:[esi+AEC]
01136EEB |. 2B86 E80A0000 sub eax,dword ptr ds:[esi+AE8]
01136EF1 |. C1F8 02 sar eax,2
01136EF4 |. 83F8 01 cmp eax,1
01136EF7 |. EB 36 jmp short Grim_Daw.01136F2F
01136EF9 |> 8D86 F8020000 lea eax,dword ptr ds:[esi+2F8]
01136EFF |. 3BC8 cmp ecx,eax
01136F01 |. 75 4F jnz short Grim_Daw.01136F52
01136F03 |. 8B0D 040F2401 mov ecx,dword ptr ds:[<&Game.GAME::gGameEngine>] ; Game.GAME::gGameEngine
同样这是第三页的
[Asm] 纯文本查看 复制代码 01136F09 6A 02 push 2
01136F0B 8B09 mov ecx,dword ptr ds:[ecx]
01136F0D FF15 48272401 call dword ptr ds:[<&Game.GAME::GameEngine::SetSelected>; Game.GAME::GameEngine::SetSelectedTransferSackNumber
修改为
[Asm] 纯文本查看 复制代码 01136F09 E9 22821000 jmp Grim_Daw.0123F130
01136F0E 90 nop
01136F0F 90 nop
01136F10 90 nop
01136F11 90 nop
01136F12 90 nop
01136F13 |. C786 F40A0000 02000000 mov dword ptr ds:[esi+AF4],2
01136F1D |. 8B86 EC0A0000 mov eax,dword ptr ds:[esi+AEC]
01136F23 |. 2B86 E80A0000 sub eax,dword ptr ds:[esi+AE8]
可以看到修改的代码是跳转到其他地方的,因为地方不够,我们需要补充一些代码:
[Asm] 纯文本查看 复制代码 0123F0FF 83BE F40A0000 00 cmp dword ptr ds:[esi+AF4],0
0123F106 7F 05 jg short Grim_Daw.0123F10D
0123F108 ^ E9 877DEFFF jmp Grim_Daw.01136E94
0123F10D 52 push edx
0123F10E 8B96 F40A0000 mov edx,dword ptr ds:[esi+AF4]
0123F114 4A dec edx
0123F115 52 push edx
0123F116 8B09 mov ecx,dword ptr ds:[ecx]
0123F118 FF15 48272401 call dword ptr ds:[<&Game.GAME::GameEngine::SetSelected>; Game.GAME::GameEngine::SetSelectedTransferSackNumber
0123F11E 8996 F40A0000 mov dword ptr ds:[esi+AF4],edx
0123F124 5A pop edx
0123F125 ^ E9 BB7DEFFF jmp Grim_Daw.01136EE5
上面的代码用来把当前箱子页号减1
[Asm] 纯文本查看 复制代码 0123F12A 00 db 00
0123F12B 00 db 00
0123F12C 00 db 00
0123F12D 00 db 00
0123F12E 00 db 00
0123F12F 00 db 00
0123F130 52 push edx
0123F131 8B96 F40A0000 mov edx,dword ptr ds:[esi+AF4]
0123F137 42 inc edx
0123F138 52 push edx
0123F139 8B09 mov ecx,dword ptr ds:[ecx]
0123F13B FF15 48272401 call dword ptr ds:[<&Game.GAME::GameEngine::SetSelected>; Game.GAME::GameEngine::SetSelectedTransferSackNumber
0123F141 52 push edx
0123F142 8D8E C40A0000 lea ecx,dword ptr ds:[esi+AC4]
0123F148 E8 13C1FBFF call Grim_Daw.011FB260
0123F14D 5A pop edx
0123F14E ^ E9 CA7DEFFF jmp Grim_Daw.01136F1D
上面的代码用来把当前箱子页号加1
第四页的部分全部改为nop即可,如果想要增加添加页数的效果只要调用之前说的添加箱子页数的函数(位置01137220)
需要注意的是游戏不是固定基址,所以位置需要动态查找,而且以上所有研究内容版本为1.003GOG版,steam需要去除steamstub或者是进行注入反反调试才可以 |