| 
 To 小行者:很遗憾,我没有学过编译原理,只学过汇编语言。推荐参考书目:《IBM PC汇编语言程序设计》沈美明 温冬婵 编著,清华大学出版社,1991年6月第一版。 
最近我发的帖子基本由浅到深,总结了上个月做修改器的经验与方法。如果能看懂博雅张生关于增加策略伤害系数种类的帖子,便可以跟着学习下去。 
另外,一句话中加上太多空格,会让人看的很吃力。 
 
exe修改举例——破浪履补丁 
将使用补丁前后的exe文件加以比较,可以看出该补丁更改了8个地方,分别是: 
自0x3EBCF起0xEF字节 
自0x375DD起0x0A字节 
自0x398FE起0x1C字节 
自0x3B09C起0x13字节 
自0x40213起0x0A字节 
自0x50926起0x0F字节 
自0x50B51起0x0F字节 
自0x8AA98起0x08字节 
下面分别加以介绍: 
 
曹操传中关于地形的两个函数,原本功能分别为: 
  函数名          ecx            ebp+08       返回值 
:0043F7CF   武将战场属性地址    地形编号  al,武将在该地形上消耗行动力(考虑宝物效果) 
:0043F84D   武将战场属性地址              al,武将在当前地形上的攻防加成 
该补丁将这两个函数合并为一个函数,其功能为: 
  函数名          ecx            ebp+08       返回值 
:0043F7CF   武将战场属性地址    地形编号  al,武将在该地形上消耗行动力(考虑宝物效果) 
                                          dl,武将在当前地形上的攻防加成(考虑宝物效果) 
 
具体介绍新函数的代码: 
:0043F7CF 55                      push ebp 
:0043F7D0 8BEC                    mov ebp, esp               //函数头,保存ebp和esp值 
:0043F7D2 83EC14                  sub esp, 00000014          //函数中可用内存为5个dword,地址ebp-04,ebp-08,...,ebp-14 
:0043F7D5 894DEC                  mov dword ptr [ebp-14], ecx//保存武将战场属性地址 
:0043F7D8 E893BCFFFF              call 0043B470              //获取武将职业于al 
:0043F7DD 25FF000000              and eax, 000000FF 
:0043F7E2 8945FC                  mov dword ptr [ebp-04], eax//保存武将职业 
:0043F7E5 83F81B                  cmp eax, 0000001B          //检测武将职业是否超过最大职业数 
:0043F7E8 7C0A                    jl 0043F7F4                //未超过,继续执行 
:0043F7EA 0CFF                    or al, FF 
:0043F7EC 80E200                  and dl, 00 
:0043F7EF E98C000000              jmp 0043F880               //超过,此职业无效,设定行动消耗为FF,攻防加成为0,结束函数。 
 
* Referenced by a (U)nconditional or ©onditional Jump at Address: 
|:0043F7E8© 
| 
:0043F7F4 8B4DEC                  mov ecx, dword ptr [ebp-14]//读取武将战场属性地址 
:0043F7F7 E8643BFCFF              call 00403360 
:0043F7FC 50                      push eax 
:0043F7FD E88F61FFFF              call 00435991              //获得武将当前所在地形编号 
:0043F802 83C404                  add esp, 00000004          //压栈参数出栈 
:0043F805 25FF000000              and eax, 000000FF 
:0043F80A 8945F0                  mov dword ptr [ebp-10], eax//保存武将当前所在地形编号 
:0043F80D 50                      push eax 
:0043F80E 8B4DFC                  mov ecx, dword ptr [ebp-04]//读取武将职业 
:0043F811 6BC93C                  imul ecx, 0000003C 
:0043F814 81C1E0E44A00            add ecx, 004AE4E0 
:0043F81A E871380000              call 00443090              //获得该职业该地形的攻防加成 
:0043F81F 8845F4                  mov byte ptr [ebp-0C], al  //保存攻防加成 
:0043F822 8B4508                  mov eax, dword ptr [ebp+08]//读取参数,地形编号 
:0043F825 25FF000000              and eax, 000000FF 
:0043F82A 50                      push eax 
:0043F82B E840380000              call 00443070              //获得该职业该地形的行动力消耗 
:0043F830 8845F8                  mov byte ptr [ebp-08], al  //保存行动力消耗 
:0043F833 6A22                    push 00000022              //恶路移动(凌波微步)的特殊效果编号 
:0043F835 8B55EC                  mov edx, dword ptr [ebp-14] 
:0043F838 8B0A                    mov ecx, dword ptr [edx]   //获得该武将data编号 
:0043F83A 6BC948                  imul ecx, 00000048 
:0043F83D 81C1681B4A00            add ecx, 004A1B68          //计算武将基本属性地址 
:0043F843 E8C181FCFF              call 00407A09              //检测武将是否装备特殊效果编号为0x22的道具(返回值于eax,1是0否) 
:0043F848 85C0                    test eax, eax 
:0043F84A 742E                    je 0043F87A                //没有装备,则结束函数 
:0043F84C 8B4508                  mov eax, dword ptr [ebp+08]//读取参数,地形编号 
:0043F84F 3C09                    cmp al, 09                 //浅滩 
:0043F851 7408                    je 0043F85B 
:0043F853 3C0A                    cmp al, 0A                 //沼泽 
:0043F855 7404                    je 0043F85B 
:0043F857 3C0D                    cmp al, 0D                 //大河 
:0043F859 7505                    jne 0043F860 
 
* Referenced by a (U)nconditional or ©onditional Jump at Addresses: 
|:0043F851©, :0043F855© 
| 
:0043F85B B001                    mov al, 01                 //行动力消耗为1 
:0043F85D 8945F8                  mov dword ptr [ebp-08], eax//保存行动力消耗 
 
* Referenced by a (U)nconditional or ©onditional Jump at Address: 
|:0043F859© 
| 
:0043F860 8B45F0                  mov eax, dword ptr [ebp-10]//读取当前所在地形编号 
:0043F863 3C09                    cmp al, 09                 //浅滩 
:0043F865 7504                    jne 0043F86B 
:0043F867 B00B                    mov al, 0B 
:0043F869 EB0C                    jmp 0043F877 
 
* Referenced by a (U)nconditional or ©onditional Jump at Address: 
|:0043F865© 
| 
:0043F86B 3C0A                    cmp al, 0A                 //沼泽 
:0043F86D 7502                    jne 0043F871 
:0043F86F EB06                    jmp 0043F877 
 
* Referenced by a (U)nconditional or ©onditional Jump at Address: 
|:0043F86D© 
| 
:0043F871 3C0D                    cmp al, 0D                 //大河 
:0043F873 7505                    jne 0043F87A 
:0043F875 B00C                    mov al, 0C 
 
* Referenced by a (U)nconditional or ©onditional Jump at Addresses: 
|:0043F869(U), :0043F86F(U) 
| 
:0043F877 8945F4                  mov dword ptr [ebp-0C], eax//保存攻防加成 
 
* Referenced by a (U)nconditional or ©onditional Jump at Addresses: 
|:0043F84A©, :0043F873© 
| 
:0043F87A 8B45F8                  mov eax, dword ptr [ebp-08]//将移动力消耗放在eax,只有低8位有效 
:0043F87D 8B55F4                  mov edx, dword ptr [ebp-0C]//将攻防加成放在edx,只有低8位有效 
 
* Referenced by a (U)nconditional or ©onditional Jump at Address: 
|:0043F7EF(U) 
| 
:0043F880 8BE5                    mov esp, ebp               //函数结束,恢复入口的ebp和esp值 
:0043F882 5D                      pop ebp 
:0043F883 C20400                  ret 0004                   //返回并使参数出栈 
 
因为此函数的合并,调用部分也需要做相应修改。 
原本调用:0043F7CF的地方,由于入口、出口均未发生变化,故无需修改。 
原本调用:0043F84D的地方,调用函数地址、返回值发生变化,需要修改。这种情况共六处: 
:004381DD   , :0043A4FE   , :0043A510   , :0043BC9C   , :0043BCA7   , :00440E13 
原调用方法: 
:004381DD E86B760000              call 0043F84D 
:004381E2 25FF000000              and eax, 000000FF 
更改为: 
:004381DD E8ED750000              call 0043F7CF 
:004381E2 33C0                    xor eax, eax 
:004381E4 0AC2                    or al, dl 
:004381E6 90                      nop 
在有限的空间内辗转腾挪,不但把edx的数据传入eax,还把eax的高三字节清零。:0043A4FE,:0043A510,:00440E13的修改方法类似。 
 
原调用方法: 
:0043BC9C E8AC3B0000              call 0043F84D 
:0043BCA1 8845F4                  mov byte ptr [ebp-0C], al 
更改为: 
:0043BC9C E82E3B0000              call 0043F7CF 
:0043BCA1 8855F4                  mov byte ptr [ebp-0C], dl 
这个更改一目了然,不需解释。:0043BCA7的修改方法与之类似。 
 
这样便实现了破浪履的移动力和攻防加成功能,下面来看看绘图功能。 
去腿部分: 
:00451523 8B4D18                  mov ecx, dword ptr [ebp+18]//读取武将战场属性编号 
:00451526 81E1FF000000            and ecx, 000000FF 
:0045152C 6BC924                  imul ecx, 00000024 
:0045152F 81C1502C4B00            add ecx, 004B2C50          //计算武将战场属性地址 
:00451535 E8E6CDFEFF              call 0043E320              //获得武将的朝向 
更改为: 
:00451523 8B4D18                  mov ecx, dword ptr [ebp+18]//读取武将战场属性编号 
:00451526 E85BE3FEFF              call 0043F886              //自定义函数 
:0045152B 85C0                    test eax, eax              //检测是否装备破浪履 
:0045152D 0F85E8010000            jne 0045171B               //如装备则不执行去腿操作 
:00451533 90                      nop 
:00451534 90                      nop 
:00451535 E8E6CDFEFF              call 0043E320              //获得武将的朝向 
 
绘船部分与之类似: 
:0045174E 8B4D18                  mov ecx, dword ptr [ebp+18]//读取武将战场属性编号 
:00451751 81E1FF000000            and ecx, 000000FF 
:00451757 6BC924                  imul ecx, 00000024 
:0045175A 81C1502C4B00            add ecx, 004B2C50          //计算武将战场属性地址 
:00451760 E8BBCBFEFF              call 0043E320              //获得武将的朝向 
更改为: 
:0045174E 8B4D18                  mov ecx, dword ptr [ebp+18]//读取武将战场属性编号 
:00451751 E830E1FEFF              call 0043F886              //自定义函数 
:00451756 85C0                    test eax, eax              //检测是否装备破浪履 
:00451758 0F8590010000            jne 004518EE               //如装备则不执行绘船操作 
:0045175E 90                      nop 
:0045175F 90                      nop 
:00451760 E8BBCBFEFF              call 0043E320              //获得武将的朝向 
 
由这两处调用,可以定义出函数:0043F886的输入输出如下: 
  函数名          ecx            返回值 
:0043F886   武将战场属性编号   eax,是否装备破浪履(1是0否) 
                               ecx,武将战场属性地址(提供下面获得朝向的函数0043E320使用) 
 
实现如下: 
:0043F886 55                      push ebp 
:0043F887 8BEC                    mov ebp, esp 
:0043F889 51                      push ecx                   //等效于sub esp, 00000004 表示函数中可用内存为1个dword,地址ebp-04 
:0043F88A 81E1FF000000            and ecx, 000000FF 
:0043F890 6BC924                  imul ecx, 00000024 
:0043F893 81C1502C4B00            add ecx, 004B2C50          //计算武将战场属性地址 
:0043F899 8BD1                    mov edx, ecx 
:0043F89B 894DFC                  mov dword ptr [ebp-04], ecx//保存武将战场属性地址 
:0043F89E 6A22                    push 00000022              //恶路移动(凌波微步)的特殊效果编号 
:0043F8A0 8B0A                    mov ecx, dword ptr [edx]   //获得武将data编号 
:0043F8A2 6BC948                  imul ecx, 00000048 
:0043F8A5 81C1681B4A00            add ecx, 004A1B68          //计算武将基本属性地址 
:0043F8AB E85981FCFF              call 00407A09              //检测武将是否装备特殊效果编号为0x22的道具(返回值于eax,1是0否) 
:0043F8B0 8B4DFC                  mov ecx, dword ptr [ebp-04]//将武将战场属性地址放于ecx 
:0043F8B3 8BE5                    mov esp, ebp 
:0043F8B5 5D                      pop ebp 
:0043F8B6 C3                      ret 
 
最后,修改0x8AA98处的宝物效果说明,将“恶路移动”改为“凌波微步”。 
 |