| | |
|
组别 | 士兵 |
级别 | 仁勇校尉 |
功绩 | 2 |
帖子 | 200 |
编号 | 293516 |
注册 | 2008-10-5 |
来自 | 永不言弃! |
家族 | 轩辕学院 |
| |
| | |
|
|
|
![](images/default/agree.gif) ![](images/default/agree.gif)
OD动态分析调试实例 -- 瓦崗(WaGan.wa)绝招伤害计算修改
OD动态分析调试实例 -- 瓦崗(WaGan.wa)绝招伤害计算修改
分析篇: (以修改绝招伤害计算为主线进行OLLYICE 动态分析调试的一个完整过程, 相信对新手有一定帮助)
首先猜想绝招伤害计算是对物理攻击重新计算又或者是对物理攻击伤害值进行加成
参考周瑜的《曹操传exe部分函数功能》, 获取函数功能和入口信息
0043BC4B ; 获取ECX武将对08栈武将的物理伤害, 10栈为是否实际值, 是则考虑是否命中和随机数
; 这个函数最值得注意
用OLLYICE打开WaGan.wa 文件, (文件类型下拉框中选择: 任何文件(*.*) )
在反汇编窗口 CTRL + G, 在[输入要跟随的表达式]对话框中输入: 0043BC4B
光标停在0043BC4B 一行, 信息提示面板显示:
本地调用自 00405EB4, 00438ABF, 00438EB8, 004406AB
现在要调试游戏, 要去到调用这个函数的地方下断, 再运行游戏看游戏有没有停下来
由于《瓦崗》是双进程所以对其调试要有点技巧, 按CTRL+ F2 重新开始
先对入口点设置断点:
004817E0 > $ 55 push ebp
改为:
004817E0 > CC int3
保存文件
然后设置OLLYICE为实时调试器, 点菜单的[选项] ==> [实时调试器设置] ==> [设置OLLYICE为实时调试器]
==> [附加前无需确认] ==> [完成]。
双击《瓦崗山異聞録.exe》调试器将自动捕获陷阱
光标停在入口点: 004817E0 > CC int3
双击int3 所在栏目弹出[汇编于此处: 004817E0]对话框中输入: push ebp ; 还原入口处的指令
现在就可以实时断点、单步、修改寄存器、看数据窗、看堆栈窗等操作, 可以开始调试了!!
首先读取进度进入到战场上(当时存档中的关卡是[救难临潼山 - 楂树岗之战 - (第 3回合)])
将反汇编窗口的滚动条拖到最顶
CTRL + F, 在[查找命令]对话框中输入: CALL 0043BC4B
光标停在: 00405EB4 . E8 925D0300 call 0043BC4B 一行按F2 下断点
由于先前观察共有四处调用, 再CTRL + F 回车
光标停在: 00438ABF |. E8 87310000 call 0043BC4B 一行按F2 下断点
同样CTRL + F 回车于
00438EB8 |. E8 8E2D0000 |call 0043BC4B
004406AB . E8 9BB5FFFF call 0043BC4B
两处下断点, 直到显示: 条目未找到
ALT + B 弹出[断点窗口]可以管理断点, 现如下:
Breakpoints
地址 模块 激活 反汇编 注释
00405EB4 WaGan 始终 call 0043BC4B
00438ABF WaGan 始终 call 0043BC4B
00438EB8 WaGan 始终 call 0043BC4B
004406AB WaGan 始终 call 0043BC4B
F9 运行游戏, 移动<管毅>接近敌人点[攻击], (当时存档中的敌人为[周治])
游戏停在: 004406AB . E8 9BB5FFFF call 0043BC4B
但问题出来了, 现在不管点战场那里不能响应, 为什么?
只能取消那一行的断点了, 在004406AB 一行按F2, 现按F9 运行游戏, 这时光标可以自由移动和点击了
发现没有, 当光标移动到攻击范围内的敌将身上(当时存档中的敌人为<周治>), 会显示红色一段的伤害值
看来上面的问题答案就是: 显示伤害值之前调用 0043BC4B函数来计算了
左键点击敌人, 这时光标停在: 00405EB4 . E8 925D0300 call 0043BC4B
再按F9 运行游戏, 我方武将对敌方武将产生攻击动作了
奇怪游戏这时又停在: 00405EB4 . E8 925D0300 call 0043BC4B
继续按F9 运行游戏, 这时敌方武将对我方武将产生攻击动作了
就此看来00405EB4 处就是[攻击]伤害的关键了
在反汇编窗口 CTRL + G, 在[输入要跟随的表达式]对话框中输入: 00405EB4
00405E78 . 8B4D F4 mov ecx, dword ptr [ebp-C]
00405E7B . 33D2 xor edx, edx
00405E7D . 8A51 01 mov dl, byte ptr [ecx+1]
00405E80 . 8BCA mov ecx, edx
00405E82 . 6BC9 24 imul ecx, ecx, 24
00405E85 . 81C1 502C4B00 add ecx, 004B2C50
00405E8B . E8 E0970500 call 0045F670
00405E90 . 6BC0 48 imul eax, eax, 48
00405E93 . 05 0000D600 add eax, 0D60000
00405E98 . 8945 F8 mov dword ptr [ebp-8], eax
00405E9B . 33C0 xor eax, eax
00405E9D . 3B05 042E4900 cmp eax, dword ptr [492E04]
00405EA3 . 1BC9 sbb ecx, ecx
00405EA5 . F7D9 neg ecx
00405EA7 . 51 push ecx
00405EA8 . 6A 01 push 1
00405EAA . 8B55 F8 mov edx, dword ptr [ebp-8]
00405EAD . 52 push edx
00405EAE . 8B45 F4 mov eax, dword ptr [ebp-C]
00405EB1 . 8B48 0C mov ecx, dword ptr [eax+C]
00405EB4 . E8 925D0300 call 0043BC4B
; 获取ECX武将对08栈武将的物理伤害
00405EB9 . 8B4D FC mov ecx, dword ptr [ebp-4]
00405EBC . 81E1 FF000000 and ecx, 0FF
00405EC2 . 8B55 F4 mov edx, dword ptr [ebp-C]
00405EC5 . 89848A 84000000 mov dword ptr [edx+ecx*4+84], eax ; 保存物理伤害值
读取游戏进度, 移动<管毅>接近敌人点[攻击], (当时存档中的敌人为<周治>)
光标停在: 00405EB4 . E8 925D0300 call 0043BC4B
按F8 单步步过call指令, 执行到: 00405EB9 . 8B4D FC mov ecx, dword ptr [ebp-4]
看寄存器窗:
EAX 0000001E ; 函数(0043BC4 的返回值, 等于十进制: 30 (注: 1)
注: 1. 可以OLLYICE界面下方[Command]命令行输入: 0000001E
回车后显示: HEX: 1E - DEC: 30 - ASCII:
接着F9 运行游戏, 我方武将对敌方武将产生攻击动作了, 打出30 点的伤害
这时游戏再一次暂停在: 00405EB4 . E8 925D0300 call 0043BC4B
同样按F8 单步步过call指令, 执行到: 00405EB9 . 8B4D FC mov ecx, dword ptr [ebp-4]
看寄存器窗:
EAX 00000021 ; 函数(0043BC4 的返回值, 等于十进制: 33
接着F9 运行游戏, 敌方武将对我方武将产生攻击动作了, 打出33 点的伤害
再看看反汇编指令:
00405EB4 . E8 925D0300 call 0043BC4B
00405EB9 . 8B4D FC mov ecx, dword ptr [ebp-4]
00405EBC . 81E1 FF000000 and ecx, 0FF
00405EC2 . 8B55 F4 mov edx, dword ptr [ebp-C]
00405EC5 . 89848A 84000000 mov dword ptr [edx+ecx*4+84], eax ; 保存物理攻击伤害值
哈哈, 现在已经知道物理攻击伤害值存放在那里了
再一次读取游戏进度, 移动<管毅>接近敌人点[绝招], (当时存档中的敌人为<周治>)
光标停在: 00405EB4 . E8 925D0300 call 0043BC4B
还是刚才的位置, 看来绝招伤害计算与物理伤害计算有关
按F8 单步步过call指令, 执行到: 00405EB9 . 8B4D FC mov ecx, dword ptr [ebp-4]
看寄存器窗:
EAX 0000001F ; 函数(0043BC4 的返回值, 等于十进制: 31
接着F9 运行游戏, <管毅>对敌方武将放出[苍龙过阵枪], 打出37 点的伤害
看来是对物理攻击伤害值进行加成计算了
好, 按ALT + B打开[断点窗口]删除所有断点, 并将光标停在:
00405EC5 . 89848A 84000000 mov dword ptr [edx+ecx*4+84], eax
这一行, 按F2下断点, 移动<管毅>接近敌人点[绝招], (当时存档中的敌人为<周治>)
光标停在: 00405EC5 . 89848A 84000000 mov dword ptr [edx+ecx*4+84], eax
看寄存器窗:
EAX 0000001E
ECX 00000000
EDX 004927F0 WaGan.004927F0
EBX 00000000
ESP 0022FD60
EBP 0022FD7C
ESI 00242360
EDI FFFFFFFF
EIP 00405EC5 WaGan.00405EC5
现在要算一下表达式: edx+ecx*4+84 的结果是多少
OLLYICE界面下方[Command]命令行输入: 004927F0+00000000*4+84
回车后显示: HEX: 492874 - DEC: 4794484 - ASCII: I(t
点数据窗, CTRL + G 在[输入要在数据窗口中跟随的表达式]对话框中输入: 492874
00492874 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
全部是0, 是未初始化数据?? 暂时不知道
按F7 单步步入下一条指令, 光标停在: 00405ECC . 8B45 FC mov eax, dword ptr [ebp-4]
点数据窗, CTRL + G 在[输入要在数据窗口中跟随的表达式]对话框中输入: 492874
00492874 1E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
注意前四字节的值改变为: 1E 00 00 00; 由于是机器码实质为: 00 00 00 1E, 等于十进制: 30
由于猜测是对物理攻击伤害值进行加成计算, 这样我们可以试着在00492874 处设置内存写入断点
(注: 2)
注: 2. 可以对数据或代码设置内存访问断点、内存写入断点, 还可以设置硬件断点, 但硬件断点最多
只可以设置四个(想详细了解建议看书或者看使用说明)
点数据窗的1E位置, 右键 ==> 断点 ==> 内存写入(W)
F9 运行游戏, 游戏停在: 00405F5F 89848A 84000000 mov dword ptr [edx+ecx*4+84], eax
看反汇编代码:
00405F38 8B55 FC mov edx, dword ptr [ebp-4]
00405F3B 81E2 FF000000 and edx, 0FF
00405F41 8B45 F4 mov eax, dword ptr [ebp-C]
00405F44 8B8490 84000000 mov eax, dword ptr [eax+edx*4+84] ; 刚才存放物理伤害的地方
00405F4B 6BC0 03 imul eax, eax, 3 ; 取出物伤*3后存入EAX
00405F4E 99 cdq ; EAX符号扩展至EDX
00405F4F 2BC2 sub eax, edx ; EDX貌似总为0
00405F51 D1F8 sar eax, 1 ; 算术右移1位, 符号位不变
00405F53 8B4D FC mov ecx, dword ptr [ebp-4]
00405F56 81E1 FF000000 and ecx, 0FF
00405F5C 8B55 F4 mov edx, dword ptr [ebp-C]
00405F5F 89848A 84000000 mov dword ptr [edx+ecx*4+84], eax ; 将加成后的物伤保存回原位
按F7 单步步入下一条指令, 光标停在: 00405F66 8B45 F4 mov eax, dword ptr [ebp-C]
看数据窗:
00492874 2D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 $...............
等于十进制: 45
F9继续运行游戏, <管毅>对敌方武将放出[苍龙过阵枪], 打出45 点的伤害
点数据窗的2D位置, 右键 ==> 断点 ==> 删除内存断点(M)
总结: 原绝招伤害 = 物理攻击伤害 * 3 / 2
要修改绝招伤害, 只要修改00405F4B 处开始的指令即可
现在我想修改绝招伤害计算使之与双方武力相关, 并且重新定义计算方法
首先就要获取双方武力
参考周瑜的《曹操传exe部分函数功能》, 获取函数功能和入口信息
0040709A ; 获取ECX武将的武、统、智、敏、运, 并乘2,跟据08栈值0~4
; 这个函数最值得注意
按ALT + B打开[断点窗口]删除所有断点
点反汇编窗口, CTRL + G, 在[输入要跟随的表达式]对话框中输入: 0040709A
这时光标停在: 0040709A /$ 55 push ebp
信息面板提示: 本地调用自 0041DE40, 0041DE80, 0041DEC0, 0041DF00, 0041DF40
点反汇编窗口, CTRL + G, 在[输入要跟随的表达式]对话框中输入: 0041DE40
这时光标停在: 0041DE40 |. E8 5592FEFF call 0040709A
这里是一个函数内镶调用:
0041DE30 /$ 55 push ebp
0041DE31 |. 8BEC mov ebp, esp
0041DE33 |. 51 push ecx
0041DE34 |. 894D FC mov [local.1], ecx
0041DE37 |. 8B45 08 mov eax, [arg.1]
0041DE3A |. 50 push eax ; 0C栈是什么, 接下来会分析
0041DE3B |. 6A 00 push 0 ; 跟据解释, 08栈为0时则获取武力值
0041DE3D |. 8B4D FC mov ecx, [local.1] ; ECX输入参数是什么, 接下来会分析
0041DE40 |. E8 5592FEFF call 0040709A ; 当时我没看到周瑜的这个函数, 搞到
; 从SetDlgItemInt 这个API开始跟踪..
0041DE45 |. 8BE5 mov esp, ebp
0041DE47 |. 5D pop ebp
0041DE48 \. C2 0400 retn 4
下断点于: 0041DE40 一行, 再按F9运行游戏
在战场武将<管毅>上点鼠标右键时, 游戏暂停下来, 再按F7单步步入
执行到: 0040709B |. 8BEC mov ebp, esp
看堆栈:
0022FCC8 /0022FCDC ; EBP 原EBP值
0022FCCC |0041DE45 ; EBP+4 CALL 指令返回地址, 返回到 WaGan.0041DE45
0022FCD0 |00000000 ; EBP+8 获取武力值
0022FCD4 |00000001 ; EBP+0CH
再看寄存器窗:
ECX 00D60000 ; 传入参数, 暂时不知是什么, 貌似为指针或者基地址
点数据窗, CTRL + G 在[输入要在数据窗口中跟随的表达式]对话框中输入: 00D60000
00D60000 00 10 00 00 00 00 00 00 B9 DC D2 E3 00 00 00 00 .......管毅....
00D60010 00 3B 00 47 00 44 00 3B 00 3D 00 00 88 00 00 00 .;.G.D.;.=..?..
00D60020 2A 2A 31 2D 2A 2B 00 02 00 00 00 00 06 3B 17 01 **1-*+.....;
00D60030 2F 26 02 13 FF FF FF B9 DC D2 E3 00 00 00 00 00 /&
|
|
|
|