zoukankan      html  css  js  c++  java
  • Steam游戏《Northgard(北境之地)》修改器制作

    日期:2021.06.07

    博客期:181

    星期一

    温馨提示】:

      我现在把资源先放到开头,不想研究学习的就直接取用。如果修改器失效了,你们可以在博客园本页直接评论,也可以给我发邮件告诉我,就是不要到百度云上去说了,百度云我好久不登录一次的!大家给我发邮件的话,记得要注明是哪个游戏,内容当然是越详细越好啦!邮箱地址:nightskysxs@163.com

    资源下载表
    没有博客园账号的网友

    百度网盘下载链接https://pan.baidu.com/s/1ohVFp0vvE3nt-tEv9Xy5bQ

    提取码:nort

    有博客园账号的网友 版本 CT文件 修改器
     v2.5.3.21746  点我下载  点我下载

      

    博客防爬取部分:https://www.cnblogs.com/onepersonwholive/p/14858916.html


    前言

      现在是准备毕业,碰巧遇到了游戏我打不过,简单花时间开发一下。预计本次博客会不断完善,直到我本人满意为止,好吧!预期开发到各种指标的修改、个人组织成员无敌、建房速度啊、维修速度啊之类的。对于个人能力提升的方面,我没什么成见。或许这里面的内容并没有更多引起我注意的地方。基本是游戏修改初等的应用了。

    版本

      

    修改内容

      1、三项资源的修改(食物、木材、金钱)

      这三项资源类似,我们以 “食物” 一项为例,搜索 双浮点类型 (Double)的值,得到如下图所示的结果。其中我们需要的是最上方的有小数部分的那一个,因为实际上数据就应该是含小数部分的而不是给我们看的整数部分。

      

      我们查找是什么改写了这项代码,得到的结果是 —— “ 76CA9FC60A85  movsd [r10+48],xmm2 ” !得到区域代码:

    代码所在内存地址 操作码 伪代码 操作解释
    76CA9FC60A7F movsd xmm2,[rbp+18] xmm2 = [rbp+18] 将地址“rbp+18”所存储的 Double 类型值赋值给寄存器 xmm2
    76CA9FC60A85 movsd [r10+48],xmm2 [r10+48] = xmm2 将寄存器 xmm2所存储的 Double 类型值赋值给地址“r10+48”位置上

      

     

     

     

    这部分代码告诉我们上面讲 [rbp+18] 的值传给了 [r10+48] ,所以我们需要将 rbp+18 的值获取之前将它改掉。

      完成如下汇编:

      push ebx          // ebx 入栈
      mov ebx,C34F      //  ebx 获得 49999 的 4字节值
      cvtsi2sd xmm2,ebx    //  将 ebx 的值 转为 Double 类型 ,并赋值到 xmm2 寄存器中
      pop ebx         //  ebx 出栈
      movsd [rbp+18],xmm2  //  将 xmm2 的值 传给 [rbp+18] , 完成修改

      同理可以得到另外两项修改,所有汇编:(目前未采用 AOB 注入方式)

     1 [ENABLE]
     2 //code from here to '[DISABLE]' will be used to enable the cheat
     3 alloc(newmem,2048,76CA9FC60A7F) 
     4 label(returnhere)
     5 label(originalcode)
     6 label(exit)
     7 
     8 newmem: //this is allocated memory, you have read,write,execute access
     9 //place your code here
    10 
    11 originalcode:
    12 push ebx
    13 mov ebx,C34F //49999
    14 cvtsi2sd xmm2,ebx
    15 pop ebx
    16 movsd [rbp+18],xmm2
    17 
    18 
    19 exit:
    20 jmp returnhere
    21 
    22 76CA9FC60A7F:
    23 jmp newmem
    24 nop
    25 returnhere:
    26 
    27 
    28  
    29  
    30 [DISABLE]
    31 //code from here till the end of the code will be used to disable the cheat
    32 dealloc(newmem)
    33 76CA9FC60A7F:
    34 movsd xmm2,[rbp+18]
    35 //Alt: db F2 48 0F 10 55 18
    unlimited food
     1 [ENABLE]
     2 //code from here to '[DISABLE]' will be used to enable the cheat
     3 alloc(newmem,2048,76CA9FC60F02) 
     4 label(returnhere)
     5 label(originalcode)
     6 label(exit)
     7 
     8 newmem: //this is allocated memory, you have read,write,execute access
     9 //place your code here
    10 
    11 originalcode:
    12 push ebx
    13 mov ebx,C34F //49999
    14 cvtsi2sd xmm2,ebx
    15 pop ebx
    16 movsd [rbp+18],xmm2
    17 
    18 exit:
    19 jmp returnhere
    20 
    21 76CA9FC60F02:
    22 jmp newmem
    23 nop
    24 returnhere:
    25 
    26 
    27  
    28  
    29 [DISABLE]
    30 //code from here till the end of the code will be used to disable the cheat
    31 dealloc(newmem)
    32 76CA9FC60F02:
    33 movsd xmm2,[rbp+18]
    34 //Alt: db F2 48 0F 10 55 18
    unlimited wood 
     1 [ENABLE]
     2 //code from here to '[DISABLE]' will be used to enable the cheat
     3 alloc(newmem,2048,76CA9FC60CC2) 
     4 label(returnhere)
     5 label(originalcode)
     6 label(exit)
     7 
     8 newmem: //this is allocated memory, you have read,write,execute access
     9 //place your code here
    10 
    11 originalcode:
    12 push ebx
    13 mov ebx,C34F //49999
    14 cvtsi2sd xmm2,ebx
    15 pop ebx
    16 movsd [rbp+18],xmm2
    17 
    18 exit:
    19 jmp returnhere
    20 
    21 76CA9FC60CC2:
    22 jmp newmem
    23 nop
    24 returnhere:
    25 
    26 
    27  
    28  
    29 [DISABLE]
    30 //code from here till the end of the code will be used to disable the cheat
    31 dealloc(newmem)
    32 76CA9FC60CC2:
    33 movsd xmm2,[rbp+18]
    34 //Alt: db F2 48 0F 10 55 18
    unlimited money

      最终效果:

      

      2、快速获得村民

      这个想要实现的方式有很多,我目前发现的一种比较简单的是找到村民来到的百分数,如下图:

      

       如图,我们需要搜索这个 双浮点数值 (Double),数值和上面显示的一样,如果是 65% 就搜索 65 。有几点需要注意的地方——第一,需要在刚进入游戏对局的时候搜素,这个数值到后面就不是 65% 对应 65 的了;第二,搜素的时候也不要搜素 “65.0” 这样,因为数值是有小数部分的,这样搜是等于在搜纯整数的 Double 值;第三,搜索的时候一定要看清楚搜索时的数值是不是游戏当中的数值,实在不行配合 “变速齿轮”、“CE变速” 和 “搜索时游戏暂停” 等选项来搜索,别到时候游戏中的数值都变成 68 了,还在搜索 65 呢!还有这个值实在难以满足这三个条件的话,就直接去搜索 Double 值吧!暂停游戏时搜未变,增长搜增长的数值,新村民来了以后搜减少的数值,这样找。

      搜索 “哪里修改了此处代码”,得到的结果是 —— “ 76CA9FC731D4  movsd [rcx+60],xmm3 ” !得到区域代码:

    代码所在内存地址 操作码 伪代码 操作解释
    76CA9FC731CE movsd xmm3,[rbp+18] xmm3 = [rbp+18] 将地址“rbp+18”所存储的Double类型值赋值给寄存器 xmm3
    76CA9FC731D4 movsd [rcx+60],xmm3 [rcx+60] = xmm3 将寄存器 xmm3 所存储的Double类型值赋值给地址“rcx+60”位置上

     

     

     

     

      这部分代码告诉我们上面讲 [rbp+18] 的值传给了 [rcx+60] ,所以我们需要将传来的 xmm3 的值以更快的速度增长。

      完成如下汇编:

      push ebx         // ebx 入栈
      mov ebx,19       // ebx 获得 25 的 4字节值
      cvtsi2sd xmm0,ebx   // 将 ebx 的值 转为 Double 类型 ,并赋值到 xmm0 寄存器中 (因为后面 76CA9FC731DA 地址对应代码段 xmm3 值赋给了 xmm0 ,所以判定 xmm0的值是无用的)
      pop ebx        //  ebx 出栈
      addsd xmm3,xmm0     //  xmm3 = xmm3 + xmm0

      大致意思就是上述原赋值代码端每次运行会自动多增加 25 的值。汇编代码如下:(目前未采用 AOB 注入的方式)

     1 [ENABLE]
     2 //code from here to '[DISABLE]' will be used to enable the cheat
     3 alloc(newmem,2048,76CA9FC731D4) 
     4 label(returnhere)
     5 label(originalcode)
     6 label(exit)
     7 
     8 newmem: //this is allocated memory, you have read,write,execute access
     9 //place your code here
    10 
    11 originalcode:
    12 push ebx
    13 mov ebx,19 //25
    14 cvtsi2sd xmm0,ebx
    15 pop ebx
    16 addsd xmm3,xmm0
    17 
    18 exit:
    19 movsd [rcx+60],xmm3
    20 jmp returnhere
    21 
    22 76CA9FC731D4:
    23 jmp newmem
    24 nop
    25 returnhere:
    26 
    27 
    28  
    29  
    30 [DISABLE]
    31 //code from here till the end of the code will be used to disable the cheat
    32 dealloc(newmem)
    33 76CA9FC731D4:
    34 movsd [rcx+60],xmm3
    35 //Alt: db F2 48 0F 11 59 60
    quick abtain peple +25

      最终效果:

      

      3、个人单位 NPC 无敌 (基本确保战士无敌,其余未测试)

      每次看到己方小兵被敌方大兵骚扰,都气愤不已却又无能为力,现在吾将赐予汝等神力!己方血量不减,来,让我用村民完胜你的强化巨人战士!

      我们要搜索的值是 “收到伤害值” ,也就是说每次受到攻击我们要搜的值是增加的。一般最好在你有两名治疗师的情况下,去找一匹狼战斗!

      这样可以找到两个值,查找是什么代码段改写了这个值,得到的结果是 —— “ 76CA9F81F265  movsd [rdx+00000188],xmm3 ” !得到区域代码:

    代码所在内存地址 操作码 伪代码 操作解释
    76CA9F81F25F movsd xmm3,[rbp+18] xmm3 = [rbp+18] 将地址“rbp+18”所存储的 Double 类型值赋值给寄存器 xmm3
    76CA9F81F265 movsd [rdx+00000188],xmm3 [rdx+188] = xmm3 将寄存器 xmm3 所存储的 Double 类型值赋值给地址“rdx+188”位置上

     

     

            

                    

      这部分代码告诉我们上面讲 [rbp+18] 的值传给了 [rdx+188] ,所以我们需要将传来的 xmm3 的值改为 0,以保证血量收到伤害为 0 。

      所以,我就直接写入了将如下汇编代码嵌入到源代码中,它们的实际意义是 xmm3 = (Double) 0

      push ebx         // ebx 入栈

      mov ebx,0       // ebx 获得 25 的 4字节值
      cvtsi2sd xmm3,ebx   //  将 ebx 的值 转为 Double 类型 ,并赋值到 xmm3 寄存器中
      pop ebx        //  ebx 出栈

      结果您猜怎么着?系统直接弹出并自动关闭游戏进程,按我的历史经验来看这是报错了。我立马在 76CA9F81F265 处设置断点,发现除了给战斗中的双方赋值以外,还会带有其他未知的赋值,这可能是最接近 刚才报错原因 的原因了。之后,我按照做崩溃大陆的经验查看此处断点的堆栈情况:

      英雄被狼攻击时:

      

      狼被英雄攻击时:

      

      我左看看,右看看。这返回的地址都是变化的,而且没有一个可以用的。我们需要的是静态的能够标记出两边哪一方是敌人的。最后我发现返回值前面有一句 76CA9F92CB16 处的 call 76CA9F81F210 ,我一瞬间想到这可能就是我一直想要找的突破口了。我在前面加入标识符 tag_isHero 标记 代码是否是从这个地方调用一系列函数执行到这里的。

     1 [ENABLE]
     2 //code from here to '[DISABLE]' will be used to enable the cheat
     3 alloc(newmem,2048,76CA9F92CB16)
     4 alloc(tag_isHero,8)
     5 registersymbol(tag_isHero)
     6 label(returnhere)
     7 label(originalcode)
     8 label(exit)
     9 
    10 newmem: //this is allocated memory, you have read,write,execute access
    11 //place your code here
    12 
    13 originalcode:
    14 mov [tag_isHero],00000001
    15 call 76CA9F81F210
    16 mov [tag_isHero],00000000
    17 
    18 exit:
    19 jmp returnhere
    20 
    21 76CA9F92CB16:
    22 jmp newmem
    23 returnhere:
    24 
    25 
    26  
    27  
    28 [DISABLE]
    29 //code from here till the end of the code will be used to disable the cheat
    30 dealloc(newmem)
    31 dealloc(tag_isHero)
    32 unregistersymbol(tag_isHero)
    33 76CA9F92CB16:
    34 call 76CA9F81F210
    35 //Alt: db E8 F5 26 EF FF
    reset data

      之后在修改值的地方嵌入的代码又加上了如下判定:

      cmp [tag_isHero],00000001  // 比较 tag_isHero 的值代表地址的值是不是 1

      jne exit           // 不是的话跳转 exit 所指代的地址

      之后我发现程序不会报错了,但是双方都变得 “无敌” 了,谁也打不死谁。看来是需要找一找它们的结构区别了。(这一点类似于我在做《九张羊皮纸》的时候,处理共用代码端的方法)

      结构体对比图:

      

      经过长时间的对比,我们取 +44 处作为判定标准。敌人的 +40 处连带 +44处都是地址,而己方则是 0 值。

      之后在修改值的地方嵌入的代码又加上了如下判定:

      cmp [rdx+44],00000000      // 比较 rdx+44 的值代表地址的值是不是 0

      jne exit           // 不是的话跳转 exit 所指代的地址

      最后测试果然成功了,汇编代码如下:

     1 [ENABLE]
     2 //code from here to '[DISABLE]' will be used to enable the cheat
     3 alloc(newmem,2048,76CA9F81F25F)
     4 label(returnhere)
     5 label(originalcode)
     6 label(exit)
     7 
     8 newmem: //this is allocated memory, you have read,write,execute access
     9 //place your code here
    10 
    11 originalcode:
    12 cmp [tag_isHero],00000001
    13 jne exit
    14 cmp [rdx+44],00000000
    15 jne exit
    16 push ebx
    17 mov ebx,0 //0
    18 cvtsi2sd xmm3,ebx
    19 pop ebx
    20 mov [tag_isHero],00000000
    21 movsd [rbp+18],xmm3
    22 jmp returnhere
    23 
    24 // equals -> isHero -> damage = 0
    25 exit:
    26 movsd xmm3,[rbp+18]
    27 jmp returnhere
    28 
    29 76CA9F81F25F:
    30 jmp newmem
    31 nop
    32 returnhere:
    33 
    34 
    35  
    36  
    37 [DISABLE]
    38 //code from here till the end of the code will be used to disable the cheat
    39 dealloc(newmem)
    40 76CA9F81F25F:
    41 movsd xmm3,[rbp+18]
    42 //Alt: db F2 48 0F 10 5D 18
    isHero == 1 ? next : continue;[+44] == 0? damage = 0 : continue;

    测试结果

      

    修改器截图

      

     

  • 相关阅读:
    第二季-专题11-世界一下变大了-MMU
    第二季-专题10-C语言环境初始化
    第二季-专题9--代码搬移不可少
    第二季-专题8-不用内存怎么行
    第二季-专题6-点亮指路灯
    第二季-专题7-ARM跑快了---时钟初始化
    第二季-专题5-核心初始化
    第二季-专题4-我是bootloader设计师
    消除苹果系统对边框的优化
    css3
  • 原文地址:https://www.cnblogs.com/onepersonwholive/p/14858916.html
Copyright © 2011-2022 走看看