实现词缀的自定义
它是按大神573650245分享的脚本上调整而来,大家记住,最核心的部分是573650245大佬完成且无偿无私分享出来,文章的开关应该向之致敬。这是极破坏游戏的修改,但也极有借鉴学习意义,无论是为了拯救动不动就脆求词缀存档者,还是为了让某些野心家少赚点不当收入,还是分享吧。
下图是整个脚本的构造:

实现的功能是:
将无词缀装备扔到地面上,会增加自定义词缀,并自动完成鉴定(可选)
脚本因使用全局定义,所以大家按顺序复制并依次建立相应的脚本吧,不然可能出错。
1, 定义全局变量, 多脚本调用此变量,所以这个脚本必须放最前面, "置顶"使用.
[ENABLE]
globalalloc(CT1,256)
// 存储自定义数据
// +0 byte 为词缀孔洞顺序, +1 byte 为调整的技能等级或上下限的孔洞序号
// +4 为启用词缀修改
// +10 起存储修改的词缀原数据,为还原之用,否则因词缀被破坏,游戏无法再打出正常词缀
[DISABLE]
2, 给地面物品附加词缀时,调整其装备等级,否则可能生成词缀数量不足5洞
如果要给不能生成5洞的部件附加5洞,应该还要调整装备类型改为戒指或手镯等等
这一点,也是本注入地址的函数之中,请自行下断分析后调整.
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)
newmem:
mov eax,[eax+74]
originalcode:
cmp [CT1+4],1
jne exit //不是扔背包装备时,不予以调整等级,使用原数值
mov eax,7
exit:
mov [ebp-1C],eax
jmp returnhere
"gamesvr.exe"+60C4E:
jmp newmem
nop
returnhere:
[DISABLE]
dealloc(newmem)
"gamesvr.exe"+60C4E:
mov eax,[eax+74]
mov [ebp-1C],eax
//Alt: db 8B 40 74 89 45 E4
3, 丢弃装备时,给它附加词缀;
代码注入点是判断有无词缀之处,如果想附加全部装备,需要更改注入在跳转之后的语句处。
注意,不要随便更改注入地址,有词缀的装备需要先清除原词缀数据,否则保存游戏重登录时可能会引起词缀错乱。
[ENABLE]
alloc(newmem,2048)
label(returnhere)
newmem:
jne returnhere
mov [CT1],0 // 每次必清计数器,这样就能保证从第1洞开始修改
mov [CT1+4],1 // 启用词缀修改标志, 修改的调整才不影响到杀怪爆的词缀
lea ecx,[ebp-000000AC] // 地面物品数据地址
push 5 // 参数2 生成词缀的总孔洞数量
push ecx // 参数1 地面物品 不能是背包物品,因为数据长度不一样
call gamesvr.exe+60B90
xor ecx,ecx
mov eax,CT1
mov [eax+4],ecx // 关闭词缀修改标志
_loop: // 以下是还原记录到的词缀数据,如果有记录的话
inc ecx
cmp ecx,6
jnl _end_loop // 最多有6条记录
lea eax,[eax+10]
mov edx,[eax] // 读出原词缀的地址
test edx,edx
je _loop // 无记录
push ecx // 临时征用ecx寄存器来中转数据
mov ecx,[eax+4]
mov [edx],ecx // 还原词缀编号
mov ecx,[eax+8]
mov [edx+C],ecx // 还原词缀技能数据
mov [eax],0 // 清0,以示已处理
pop ecx // 还原计数器的循环次数
jmp _loop
_end_loop:
jmp gamesvr.exe+983AB
"gamesvr.exe"+9830F:
jmp newmem
nop
returnhere:
[DISABLE]
dealloc(newmem)
"gamesvr.exe"+9830F:
je gamesvr.exe+983AB
//Alt: db 0F 84 96 00 00 00
4, 自定义词缀的类型,并记录原数据
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)
newmem:
cmp [CT1+4],1
jne originalcode // 非丢弃装备时,不启用词缀调整
inc byte ptr [CT1] // 词缀孔洞序号 +1, 每次都是从第1洞开始处理
//记录词缀原始数据
movzx edx,byte ptr [CT1]
imul edx,10
lea ecx,[CT1+edx]
mov eax,[edi+1C]
mov [ecx],eax
mov edx,[eax]
mov [ecx+4],edx
mov edx,[eax+C]
mov [ecx+8],edx
movzx edx,byte ptr [CT1]
//读出孔洞序号后,比较. 判断的默认值是第1洞,即不是2~5,其它数字全则看作是1
cmp dl,2
je JN2
cmp dl,3
je JN3
cmp dl,4
je JN4
cmp dl,5
je JN5
mov [eax],09 //词缀1的编号, 09 为烈火
// 注大佬群中,也有群友整理出全部词缀编号等数据,请加群获取.
mov [eax+C],000F0001 //烈火技能的词缀数据,须跟09编号配套使用
jmp originalcode
JN2:
mov [eax],12 //词缀2的编号
mov [eax+C],001A0001
jmp originalcode
JN3:
mov [eax],13 //词缀3的编号
mov [eax+C],001B0001
jmp originalcode
JN4:
mov [eax],2B //词缀4的编号
mov [eax+C],00311000
jmp originalcode
JN5:
mov [eax],2C //词缀5的编号
mov [eax+C],00321000
originalcode: //游戏原代码
mov eax,[edi+1C]
mov eax,[eax]
exit:
jmp returnhere
"gamesvr.exe"+102CD:
jmp newmem
returnhere:
[DISABLE]
dealloc(newmem)
"gamesvr.exe"+102CD:
mov eax,[edi+1C]
mov eax,[eax]
//Alt: db 8B 47 1C 8B 00
5, 调整范围类词缀的上下限
// 与大佬直接修改上下限数值不同,这里是直接调整后续调用函数的参数值
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)
newmem:
// ebx == 最小值 + 最大值 00 XX 00 YY
// FF FF == 最大值 65535
cmp [CT1+4],1 // 非丢弃装备时,不启用调整
jne originalcode
inc byte ptr[CT1+1] // 孔洞计数器
cmp byte ptr [CT1+1],1
je _lv1
cmp byte ptr [CT1+1],2
je _lv2
cmp byte ptr [CT1+1],3
je _lv3
cmp byte ptr [CT1+1],4
je _lv4
// 这里是默认的第5孔洞的数据
mov ebx, 00020008
jmp originalcode
_lv1:
mov ebx, 000A000B
jmp originalcode
_lv2:
mov ebx, 000B000C
jmp originalcode
_lv3:
mov ebx, 000C000D
jmp originalcode
_lv4:
mov ebx, 00030007
jmp originalcode
originalcode:
movzx eax,word ptr [ecx+0E]
mov ecx,[ebp-04]
exit:
jmp returnhere
"gamesvr.exe"+10376:
jmp newmem
nop 2
returnhere:
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"gamesvr.exe"+10376:
movzx eax,word ptr [ecx+0E]
mov ecx,[ebp-04]
//Alt: db 0F B7 41 0E 8B 4D FC
6, 设置加成是非范围的词缀的增益值(幸运,技能等级,掉落等等)
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(exit)
newmem:
cmp [CT1+4],1 // 非丢弃装备时,不启用调整
jne exit
inc byte ptr[CT1+1] // 孔洞计数器
cmp byte ptr [CT1+1],1
je _lv1
cmp byte ptr [CT1+1],2
je _lv2
cmp byte ptr [CT1+1],3
je _lv3
cmp byte ptr [CT1+1],4
je _lv4
// 默认孔洞也是第5孔
mov edx,5
jmp returnhere
_lv1:
mov edx,4
jmp returnhere
_lv2:
mov edx,2
jmp returnhere
_lv3:
mov edx,1
jmp returnhere
_lv4:
mov edx,4
jmp returnhere
exit:
inc ecx
idiv ecx
add edx,esi
jmp returnhere
"gamesvr.exe"+103D2:
jmp newmem
returnhere:
[DISABLE]
dealloc(newmem)
"gamesvr.exe"+103D2:
inc ecx
idiv ecx
add edx,esi
//Alt: db 41 F7 F9 03 D6
7, 捡起地面物品时,自动完成鉴定.
有缺陷,词缀名称不显示,所以只适合用来调试.
这里演示了如何自定义一个功能函数.
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)
newmem:
call gamesvr.exe+402F0 // 游戏原代码, 捡物品向C端发回物品数据
push edi // 背包物品地址, 注意不是地面物品地址
mov ecx,esi // 人物地址
call JD_cizui // 实现全鉴定的自定义自定义函数
originalcode:
exit:
jmp returnhere
JD_cizui:
//注意看自定义函数代码的放置位置
// 放在注入的自定义代码的后面,且在游戏注入地址的前面
// +8 参数1 == 背包物品地址
push ebp
mov ebp,esp
sub esp,20
push ebx
push esi
push edi
mov edi,[ebp+8]
mov [ebp-4],ecx
mov dl,[edi+56]
and dl,01
je _get_item_type
mov edx,[edi+4C]
mov ecx,[gamesvr.exe+1CEA1C]
call gamesvr.exe+D4240 // 解密读取词缀存储的编号
mov esi,eax
movzx edx,byte ptr [edi+24]
movzx ecx,byte ptr [gamesvr.exe+1CEA13]
call gamesvr.exe+D4240 // 解密读取物品的类型
jmp _is_eqt_not
_get_item_type:
movzx eax, byte ptr[edi+24]
mov esi,[edi+4C]
mov ecx,eax
_is_eqt_not:
call gamesvr.exe+6A8C0 // 是否是装备
test al,al
je __end__JD_cizui // 非装备,跳
movzx eax,si
test eax,eax
je __end__JD_cizui // 无词缀,跳
xor esi,esi
inc esi
//取出词缀序号后
push eax //序号
mov ecx,[ebp-4] // chr
call gamesvr.exe+8DEB0 //取出词缀数据
mov [ebp-14],eax
test eax,eax
je __end__JD_cizui
//核心函数
push 6 //设置已鉴定的词缀数目,最多是6洞
push 15 // 固定数值
mov ecx,[ebp-14] // 词缀 ptr
call gamesvr.exe+104A0 // 设置鉴定状态
push [ebp-14]
mov ecx,[ebp-4] // 人物地址
call gamesvr.exe+8DEF0 // 让C端同步词缀鉴定状态
//函数尾
__end__JD_cizui:
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret 4
gamesvr.exe+91470:
jmp newmem
returnhere:
[DISABLE]
dealloc(newmem)
gamesvr.exe+91470:
call gamesvr.exe+402F0
再次感谢573650245的分享!也祝愿所有爱学习单机修改的朋友,学有所成!
记得到希望BM上分享你们的学习成果,传播BM火种!