| 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处的宝物效果说明,将“恶路移动”改为“凌波微步”。
 |