把自己以及朋友做进游戏mod里是一件很好玩的事

游戏mod作品介绍:

在游戏里可以升级自己为将军,然后率领军队作战:

 

原版游戏是没有西安的,我自己设计了喜欢的西安市地图:

可以二战剧本,也可以参与现代战争

2030年,中国三航母时代:

该游戏版本的mod有很多很多,这只是我做的比较喜欢的一个版本。

我给中国添加了航母并做了增强,众所周知,中国的火箭军也是非常强的,于是我给导弹火箭炮、解放军都做了相应的增强。

喜欢的话,APP下载链接:更多的版本等着你探索

https://pan.baidu.com/s/1-zHy74_SxU2e0X0gzGV5Ow 
提取码:3333

逆向教程:

1.so文件

so文件是一个用C++语言编写,编译得到的二进制库文件,修改so文件可以实现如下效果:

  1. 解除游戏引擎的某些限制,比如单位type,将军星星上限,将军技能上限,挂将上限
  2. 为游戏引擎添加更多功能,比如加入新将军技能,加入新兵种技能

一些概念

汇编语言:由简单的指令构成的编程语言,可以直接逐条翻译成计算机可以执行的二进制。

高级语言:接近人类语言,人类容易理解的编程语言,需要通过复杂的编译环节转化为汇编最终转化为二进制程序。
反汇编:通过软件将程序逆向转化成汇编语言,并进行修改。

IDA PRO 6.8

解压后应该长这个样子

找到Registry.reg没有,用记事本打开

这个文件是IDA PRO软件的注册机,我们需要正确设置路径才能破解成功。方法非常简单:

然后运行这个文件,如果弹出对话框点确认就好了。

解压后这个样子

进到lib下目录

把这两个文件夹删掉

安卓手机普遍使用ARM架构的处理器,该处理器使用的汇编语言指令集是ArmV7。要对so进行反汇编,我们需要掌握一些汇编语言方面的基础知识。

寄存器

寄存器是CPU的组成部分,它们可用来暂存指令、数据和地址,

程序中所有的数据操作都要经过寄存器。

每个寄存器有自己设计的用途,可供我们使用的寄存器主要是

R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11这12个寄存器。

每个寄存器都能存储4字节的数据。

R15寄存器,又称PC寄存器,用于记录CPU预读取的指令,
其存储的值为当前正在执行的指令位置+4。

此时PC寄存器值为0x00169F84

汇编指令

下面给出一些基础的汇编指令

MOV 指令 参数1:寄存器   参数2:寄存器或常数

将寄存器R6存的值装进寄存器R0里

将常数0x20装进寄存器R1里

(指令后加S不改变指令本身功能)

MOV指令完成了基础的数据操作。

ADD指令 参数1:寄存器  参数2:寄存器或常数

参数3: 寄存器或常数

将R3与0x3A相加的值存入R11
(在某条指令后面加.W是让这条指令占4个字节,不改变该指令本身的功能)

使R3存储的值+1

(ADD指令可以只写2个参数)

ADD指令是用于执行加法。

MUL指令,用法与ADD指令相同,功能是做乘法,不再赘述。

下面来介绍两个重要的指令

LDR,STR指令

介绍之前先科普一些知识

计算机中内存数据与内存地址都用二进制表示,

内存地址使用时一般采用原地址+偏移量。

比如0x00000080向后偏移0x10字节的地址就是0x00000090

LDR 参数1 寄存器   参数2 表达式

将指定内存地址的内存读取到指定寄存器

STR 参数1 寄存器   参数2 表达式

将指定寄存器数据写入到指定内存地址

汇编中的表达式与数学中有很多不同,它能表示的种类非常少。

这里介绍一种,样子是这样的:[寄存器,常数]

还记得寄存器可以表示地址吗?

[R4,0x54]就代表R4所存的内存地址向后偏移0x54的地址
这三句汇编用语言描述是这样的:
将[R4,0x54]内存地址的值取出到R3,这里取了4个字节的数据,可以用LDR指令的变种来取1,2个字节的数据。

用加法指令,使R3的值增加了1.

将R3的值放回[R4,0x54]内存地址,这里写了4个子节的数据,可以用STR指令的变种来写1,2个字节的数据。
也就是说,这三行汇编完成了使[R4,0x54]处数据增加1的效果。

CMP 比较一个寄存器与一个常数或寄存器的大小关系

具体的用处后面会提到

函数的实现

还记得之前讲的寄存器吗?

实现函数靠的就是寄存器。
传参数:计算机并不理解你的函数需要什么参数,你需要手动复制到你要用的寄存器中。

上图是一个调用函数生成随机数的例子

编写函数的人规定R0作为函数的唯一参数,函数生成0至R0-1间的随机数,并保存在R0寄存器。

使用这个函数想生成一个0-99的随机数,就要把参数100传入。
使用函数的本质

计算机执行程序的时候是一条一条指令执行的。
函数也是由一大堆指令构成的,很明显,我们不愿意写函数的话,可以把它的代码自己展开来。
但假如写成函数的话,它必然和主程序存放的位置不连续。
于是机智的指令设计者们设计了跳转类指令,这个指令跳转到某个地址,继续执行。当然,我们可以选择跳转到一个函数那里,实现调用函数,也可以在局部执行跳转。

常用的跳转指令

B指令 BL指令

首先要讲的是B指令
它可以按照指定偏移量跳转到某一地址。

偏移量计算是目标地址-PC,

实际计算方法是目标地址-调用地址-4
单纯的B指令几乎卵用没有,不过他的兄弟很强悍。
BEQ (B Equal)如果上次CMP相等执行跳转
BNE(B Not Equal) 如果上次CMP不等执行跳转。

BGT(B Greater Than)如果上次CMP大于执行跳转
还有几个大于等于,小于等于,小于就不赘述了

B指令可以用来实现条件判断,比如某种情况才执行某段代码

一些指令比如MOV STR LDR也可以加EQ NE GT之类的后缀,

实现条件执行。

BL 指令

这里要先讲另一个特殊寄存器
R14寄存器,又称LR寄存器,是一个很特别的寄存器。

BL指令与B指令用法完全相同,唯一不同是会把当前PC写进LR里。

函数的开始和结束

局部变量
大部分函数运行过程中需要使用一些临时数据变量。

它们的名字叫局部变量,顾名思义,这些变量只在这个函数里有效。

局部变量会使用一些寄存器,并改变它们的值,但需要注意的是,函数使用常常是一个函数套另一个函数的,寄存器又必须重复使用,还不能互相干扰,怎么办呢?
机智的科学家发明了栈,具体工作原理这里不介绍。他们设计了这样两条指令:

PUSH指令 将指定寄存器中数据按顺序放入栈

POP指令  将栈中数据按顺序放入指定寄存器

于是,我们可以在A函数中使用R4保存兵的类型,在A函数调用的B函数中用R4表示将军。只要在B函数开始时把R4放入栈中,对它动手动脚都没问题,只要结束时用保存好的恢复它的值就可以了,

也不会对A函数后续执行有任何影响。

有人可能会产生不好的联想:
如果我们把LR在函数开始保存下来呢?
再在函数结束把它的值给PC呢。
我们不就实现一个函数完整的使用了吗,并且使用完以后,我们又接着后面的执行了。

一个简单的完整函数:

这个函数是获取部队攻击下限,参数R0为部队数据地址,

获取到的结果保存在R0,计算部队的攻击下限需要用到部队的血量百分比和所属国家的科技。

这个函数用到了很多没有讲到的指令,但这不是重点。

我们首先看到,这个函数将用到的局部变量 R3-R5送入栈了,用到局部变量的函数都需要这样做。

用局部变量R5记录R0值,这是个常见的做法,因为R0经常作为各种函数的参数和保存结果的地方,所以经常被修改。

函数最后用栈中数据恢复用到的局部变量。

值得注意的是,图中BL指向的函数只是软件通过计算分析得出的,实际编写汇编代码时,必须手动计算偏移量。

1.打开IDA 6.8

菜单栏最左File

下拉选Open

选择解密版1.26下 lib\armeabi\libeasytech.so

稍后弹出此对话框

点最下面的OK即可
请耐心等待反汇编程序扫描SO文件,这个时候可以切到其他窗口做别的事情,读取过程中不要点IDA上任何东西。

状态栏扫描光标消失后,读取已经完成。

随意单击左侧Function name区域,点击菜单栏的Search
就能输入函数名字进行查找。
为了降低学习难度,我们直接去看GetSkillDamage函数。

这个函数的作用是计算伤害类技能的效果,

如各种半血技能,地形战,狼群战术,反装甲战,游击战。

搜索GetSkillDamage我们直接定位到了这里。

双击这个函数

可以看到右侧区域变成了这样:

拿到一个陌生的函数,我们不能首先去研究每个寄存器什么意思,而应该从大局出发,先扫一遍这个函数。

看到了一些我们认识的指令,由前面所学,我们可以推测
R8表示第一次调用这个函数的结果,R4表示第二次调用这个函数的结果。这个函数的功能呢,由英文名字推测,

是获取一个地块/位置之类的东西。

这是一个条件判断结构,我们将经常遇到。
其大意是:

若R8为0,将结果R0置为0,结束函数,否则继续。

这个片段告诉我们大量的信息
执行到这里的时候,R8一定非0

将R8作为GetArmy的参数,

这个函数我们可以猜到是获取部队,结果存在R7
将R4作为GetShieldCityDefence的参数,

结果存在R5,我们可以猜到是获取城防
在R7为0时跳到0x169f44,注意,这个地址在上面出现过,跳转到这里意思是结果为0并退出
如果GetShieldCityDefence结果为0,也要退出。

R6为R7地址偏移0x10位,我们现在还不能确定R6的意义。

这两句出现在IsDefence后,若R0不为0,跳转到0x16A0B6

我们使用菜单中的Jump,下拉选Jump to address

我们看到一个函数FindSkillSetting,两个参数R0,R1
将R6,0x12两个参数带进去

这个函数,由名字我们推测是获取技能数据
目前我们已知的是:

  1. R6与一方的部队有关
  2. 城防存在
  3. 神秘的数字0x12
    (4)如果这个函数结果非0

R4为R0地址向后偏移0x10的值

如果这个函数结果为0

R4赋值为0

把技能伤害  城防  联系起来

大胆作出猜测吧

我们会想到爆破

0x12,10进制下的18,是爆破的type

我们知道了,FindSkillSetting的第二个参数应该填技能的type

那么第一个参数呢?

它跟部队有关,但又不是部队,它跟技能会联系起来

它是什么呢?

我们将用一个简单的例子作为修改SO文件的入门。

  1. 打开IDA软件,并打开SO文件,转到GetSkillDamage处。
  1. 回忆上一讲提到的内容,FindSkillSetting的第二个参数,

含义是要获取技能的type。我们这次想修改反装甲战技能,

把它变成反步兵战。

(3)

查阅json文件,可知反装甲战的type为40。
我们要找实现反装甲战的代码,

  • 明确的线索就是第二个参数也就是R1被设置为40。
  • 一条往下翻,我们找到了。
    由这段代码,我们可以验证上次的结论,

R4记录的是所有技能的伤害之和。

R5是敌方的兵种信息。
我们看到了一个不认识的函数IsArmor。

由上下文可知,它只有一个参数R0,结果存在R0。
由它的英文名我们推测它的作用是判断兵种是否为装甲部队。

我们的修改思路出来了:

把这个函数调用改成调用判断是否为步兵的函数。

经验告诉我们功能相似的函数位置相近。
我们搜索一下抓获了一窝判断兵种类型的函数。
IsInfantry就是判断步兵啦。

好,可以开始改了。

我们需要写出汇编代码
在00169FC2写 BL  IsInfantry
IsInfantry的地址是

还记得以前讲的,汇编里是没有函数名字这种东西的
BL的参数是偏移量,也就是PC到要调用函数的位移

当前PC是00169FC6  
用下windows计算器

我们在汇编里需要写BL 0xffff3880
我们需要把这行汇编代码转化为16进制写进so文件里
我们需要用到一个网站
打开http://armconverter.com/

把下拉框设置成Armv7 Converter

在上面输入好代码点击Convert,要换行请用快捷键Ctrl+Enter。

把网页往下拖:


Thumb2-Hex里的16进制,就是我们要往so文件里写的内容。

先点击一个地址,然后点击Hex View

右键选Edit,就可以修改了。

改好啦,再右键选Apply Changes。

看起来是成功了。

但是,我们只是在IDA内部修改了,并没有输出到so文件。

点击菜单

 

选择Edit-Patch program-Apply patches to input file

点OK,就输出到so里了。

接下来是一些小测试技巧展示。

在将军数据里修改迈尔的价格,行军(方便测试),

把攻击星星都写为0

锁定坦克攻击上下限,为了方便各个等级的坦克都设成25

这样坦克打平原上0级部队的伤害不考虑技能稳定为25

这极其有利于我们测试伤害。

重新打包签名,开始测试。

分别攻击坦克,步兵,大炮,得出我们修改成功的结论。

单纯修改函数很难满足我们的需求。我们可能需要自己编写函数。

添加函数的限制

任何技术都是有局限性的,作为技术的使用者,不能迷信技术。

MOD的核心是创意而非技术,不要为了展示技术画蛇添足。

SO文件是一个结构非常严谨,内容非常复杂的文件。要了解SO文件的结构,要学习的知识和需要的储备知识非常多,要添加函数需要的技术水平非常高,因此现阶段我们可以认为SO文件是不能真正添加函数的。

替换函数

不过幸运的是,so中有不少没有实际作用的函数。

我们可以把它们替换成我们编写的函数,实现增加函数。

下面用一个例子来实际说明如何做,起到抛砖引玉的效果

这次我们的目标是制作一个加钱的技能,效果是这个将军所在城市金钱收入按数值增加。由于我们使用的普通解密版,无法增加新Type技能,我们决定使用工事的type 16作为该技能的type。

转到函数 FindSkillSetting,右键选Proximity browser

我们可以看到一个树状图,这个图是IDA软件得出的函数调用关系图,

我们可以很方便的知道哪些函数调用了FindSkillSetting,

要退回汇编视图,右键选TextView即可。
我们可以在关系图内找到

从函数的英文名字我们可以推测它的用途:

获取每回合金钱加成百分比。

又跟将军技能有关,那一定是经济专家技能了。

有了之前的基础,我们不难通过分析读懂这个函数。
R0在调用时被填进了将军的地址,这个函数获取该将军经济专家的能力数值,放在R0作为结果。

我们今天要自己编写的函数,将和这个函数非常相似。

修改so,常常需要模仿已有的汇编代码。

用刚才的方法,打开GetMoney函数,我们很容易推测这个函数获取的是某地块的金钱收入。正和我们的意思是不是?

先介绍一个函数,ARM是没有除法指令的

要做除法需要调用一个函数_divsi3。

这个函数两个参数R0,R1,分别是被除数,除数。

调用后,计算得到的商存在R0里。

GetMoney这个函数也不长,这里就简单分析一下。

用R4作为存储结果的局部变量。
先计算建筑带来的收入。

获取地块上的将军,获取将军的加成百分比。

将建筑收入先乘以百分比再除以100,加到R4里。

最后把R0取走R4保存的结果,函数结束。

替换函数的方法

我们需要找到一个没用的函数,将它改造成我们的。

如果不小心替换了有用的函数,游戏就会闪退,而且新函数长度不能比被替换的长,所以我们要很谨慎的挑选一个。

这里只简述挑选函数的过程,multiplayer::开头的函数都是与多人游戏的有关,这部分基本无用,可以经过简单测试决定是否可以替换。

我们选择了ClearPlayer函数,地址是0013125A,最后一条指令地址是0013128A。

这里介绍一条新指令NOP,16进制代码00BF,

这是空指令,CPU遇到这条指令会无视这条指令。

把整个函数用NOP指令填充,这相当于我们有了一张白纸。

全局规划

不要急着想汇编代码具体怎么写,我们要先考虑我们要做什么。
我们需要在GetMoney函数里把私货掺进去,而不影响原来的。

我们需要这个技能也需要用到将军。
于是一个不错的想法就出现了,我们写一个函数代替GetIncreaseMoneyPercent。

这个函数要完成以下工作:

  1. 把新技能带来的金钱收入加到R4里
  2. 把将军经济专家的数值存到R0

我们在调用这个函数以前,R0里放了将军,这给我们提供了方便。

要完成第二个目标,我们可以调用GetIncreaseMoneyPercent。

编写思路

我们要先仿照GetIncreaseMoneyPercent得到新技能的效果数值加到R4里,再调用GetIncreaseMoneyPercent。

建议读者独立思考编写这个函数的汇编代码,可以写在纸上,

也可以上机实现。

伪代码(不能直接使用的代码,方便人理解)
1.函数开始,使用R5局部变量保存将军

  1. 将R1修改为16,调用FindSkillSetting。
  2. 获取效果数值,加到R4里。
  3. 将R0修改为将军,调用GetIncreaseMoneyPercent。
  4. 函数结束,恢复局部变量

参考代码

别忘记在原来调用GetIncreaseMoneyPercentPerRound的地方调用这个函数哦。

测试部分不赘述。

指令的限制

在修改中我们会发现,很多指令如果使用的常数参数太大,

是不合法的,不能在网站上转换为16进制。

以MOV指令为例,它不能给一个数赋值超过4096。

ARM公司设计指令时,每条指令有固定的长度。

占4个字节的MOV指令,一共32个二进制位。

有些位是让CPU识别这是MOV指令,就跟人的名字一样。

有些位是特殊用途,比如存储执行条件。有些位是记录寄存器。

最终留给常数参数的位置,只有12位。

而12位的二进制数,能表示的最大的数就是2^12-1=4095。

我们写汇编时一定要注意指令的限制。

字符与字符串

计算机本身是不理解人类语言的,也没办法存储任何文字。

科学家们将文字表示成数据,比如大写字母A在内存中是65。

字母,数字,半角标点符号被存储为1个字节,它们被称为字符。

汉字至少要用2个字节才能表达。

字符串就是一串字符,本质上是一片连续的内存。

怎么知道字符串的长度呢?

如果一个字符串中某个字节值是0,那么字符串就在这里结尾。注意,这里的0不是字符0,是内存中的数据0。

所以,要存储长度为10的字符串,就需要11字节的空间。

SO里的数据

有了以0结尾这个规定,我们把字符串数据存储在so的某个位置后,只需要字符串第一个字节的地址,就可以调用这个字符串。

比如这张图,就是 升级播放音乐 的名字。

这里介绍软件的一个功能

右键点一个地址,选Jump to Xref to operand

软件就会分析列出so中涉及此地址的代码。

选中第一处,OK试试。

我们就跳到用到这个字符串的地方了。

第一行的LDR 跟我们以前见到的很不一样。

选中第一行,看看他的16进制代码。

这么短,怎么回事呢。

打开下面的网页,这个网页可以帮我们把16进制转换成汇编指令。

armconverter

下面的下拉框选ARMV7 THUMB

上面的输入框输入16进制

中间的输入框输入地址

点击最下面的Convert按钮

底下的转换框里出现如下内容:

我们得分析下了。

当前地址是0x15e564,当前的PC就是0x15e568。

PC偏移0x18字节,地址就是0x15e580。

我们去看看这里存了什么内容。

看来LDR把这个读到R1里了。

这就是LDR伪指令:

格式:LDR 寄存器 , = 地址(常数)

作用是将地址(常数)送入寄存器。

这条指令与LDR的区别在于,

这条指令是给寄存器赋值,LDR指令从内存中读取值。

我们可以用这条指令代替MOV给寄存器赋值常数,因为LDR伪指令能赋值的常数比MOV大得多。

这里是so中的一个常见结构DCD,常数被存储在这里。

我们可以用LDR读取这里的存储的常数,这样读取的常数可以用

4个字节也就是32位二进制表示,上限大约20亿。

有人可能会困惑,那条LDR伪指令本来是LDR指令啊,

为什么软件解析成LDR伪指令。

这是软件为了使用者读汇编代码更容易理解,做的展开,

我们要学会透过现象看本质,不能被表象所欺骗。

浮点数

BTL中出现过浮点数这个概念,不记得的温习下BTL知识。

浮点数就是计算机表示小数的实现方法:

用二进制小数去近似表示。

思考一下这个结论,这里不证明:

计算机是基于二进制的,所以无法精确表示10进制小数。

表示一个浮点数使用的字节数越多,它的精度显然越高。

由于浮点数的性质,它可以存在寄存器里,

整数也很容易转化成浮点数。

ARM CPU提供了一些特殊的寄存器存储浮点数,

也设计了浮点数寄存器的操作指令。

R5是某军团首地址。

程序里税率的地址是军团首地址偏移0x54,不用纠结与BTL不同。

这段代码就是把R4保存的税收乘以税率。

下面讲解一下这里出现的浮点数操作。

S14,S15都是浮点寄存器,浮点寄存器S14-S20都可以用。

VLDR 类似LDR 但是将内存中的值读取到浮点寄存器中。

注意,现在浮点寄存器中的值还是以整数形式保存,

没有转化成浮点数。

VCVT  CVT就是Convert的缩写 这个指令完成的是数据格式转换

可以将整数转化为浮点数,也可以将浮点数转化为整数。

VCVT.F32.S32作用是把S32(32位整数)转化成F32(32位浮点数)

VCVT.S32.F32作用是把F32(32位浮点数)转化成S32(32位整数)

VMUL.F32 与MUL指令相似,完成一次浮点数乘法

VMOV 将浮点寄存器中的值以整数格式送入普通寄存器,一定要在转换好数据格式之后再做,不然后果自负。

使用浮点指令一定要注意浮点寄存器中的值目前的数据格式。

VLDR伪指令当然也是存在的,这条指令一般用来做小数赋值。

看看他的本质是什么

原来是读取这个

这就是0.8的浮点数表示

最后教大家在IDA里写小数

右键如图点选。

然后右键Edit  改完Apply Changes就好了

如果想切回普通16进制视图,就在Data Format选 1-byte Integer就好了

面对一个我们了解很少的问题,唯一的办法是顺藤摸瓜。
我们在游戏中唯一能看到击杀数的地方就是将领界面,

我们去layout找找线索。

这个lbl_cmdKill就是显示击杀个数的文本

他的layout中的Text明显没有意义,一定在so中被设置了。

我们需要在so里查找字符串lbl_cmdKill

我这里用的是WinHex 用Ultra-Edit当然没问题

搜索文本

找到了一处   地址 0x00359e48 记下来

打开IDA,跳转到这个地址

看哪些语句引用了此字符串,这里一定有线索

就一处我们就过去看看

信息量不怎么够,我们上下多看几行

这次我们能知道不少东西了。
发现了奇怪的FindElement函数,判断可知R0,R1参数,R0保存结果

从函数的英文名字,我们可以猜测他的作用是获取一个layout中一个组件(按钮、文本、图片等)的数据地址。
调用后,将结果保存在R4偏移0x180的地址,我们可以猜测作用是把对应地址和组件,通过R4偏移0x180可以访问该文本。

再看看上下文,有助于获取更多信息。

我们发现军衔体力数字那个文本保存在R4偏移0x178

这段代码存在的函数:

我们去看看跟他开头相同的函数:这种函数一般都有联系


有两个SetContent函数,猜测是设置组件内容,应该是我们看的重点。

第二个函数比较短,在最后调用了第一个,我们看第一个。

这个函数非常的长,通读它费时又没有意义。

我们猜测这个函数要设置军衔文本组件和击杀数文本组件的文本,

所以可以采用寻找关键字的方法,浏览一下找找0x178和0x180。

这绝不是不严谨的方法,不要陷入误区,猜测是研究so中非常常用的技巧。在信息量很有限的情况下,我们只能少量的已知不断推理

得到更多有用的结论。

我们发现了两处可疑线索

这两处代码有不少相似的地方。

第一个获取了将军军衔对应增加的生命。

第二个则是获取了将军的某个信息(偏移0x24字节得到)

我们可以推测击杀数存储在将军地址偏移0x24字节

共同调用的第一个函数StrUtilConvertInt名字好像很难懂,

但其实就是缩写连着String Utility Convert Integer 可以猜测功能是把整数转换成内存中的一片字符串,保存其地址。

LabelSetString意思就很明显了,功能是给文本组件设置字符串。

到了这里,我们终于明白怎么获取将军杀敌数了,

可我们对实现回血依然没有头绪。

还记得17号技能补给吗,我们可以试着看看这个技能的实现代码。

找到老朋友FindSkillSetting ,哪个技能它能不掺和呢?

看看谁调用了它。

本图最左CUnitCommander::GetSupplyPerRound函数

我们可以猜测,这个函数作用是获取将军每回合的回血,进去看看吧。

看看,多么标准的调用FindSkillSetting,R0已经提前代入将军地址了。

我们的目标既然是实现与击杀数有关回血,一个很合理的思路就是

把FindSkillSetting换成我们自己写的一个函数。第七讲讲解这种套路比较完整,这里就只简要分析下。

我们需要把17号补给技能效果和击杀数加在一块放在R0,

是不是不难呢。

然后放心大胆的修改游戏为自己想要的样子就行了。

不知不觉居然一万多字了,可是还是没有写完,更多的逆向和游戏修改教程以后再说,感谢观看。

记录一次逆向并自己编写游戏mod相关推荐

  1. 逆向攻击破解安卓游戏

    ** 主要使用三个工具 ** 1.Il2CppDumper软件 2.IDA_Pro_v7.0软件 3.AndroidKiller软件 使用Il2CppDumper对关键函数的偏移进行分析,也就是找到相 ...

  2. 用scratch编写游戏2048(印章法)

    用印章法编写游戏2048,是以克隆法编写游戏2048为基础,修改部分脚本而完成的.如果读者未看过我的上一篇博文:用scratch编写游戏2048(克隆法),请先读一读.印章法和克隆法,在处理数据的思路 ...

  3. Python编写游戏——拼图游戏

    Python编写游戏需要用到pgzrun模块.但不能用pip install pgzrun进行安装,正确的库名是pgzero,pip install pgzero. 一.开发工具 Python版本:P ...

  4. 如何下载c语言游戏,如何用C语言编写游戏.doc

    <如何用C语言编写游戏.doc>由会员分享,可在线阅读,更多相关<如何用C语言编写游戏.doc(71页珍藏版)>请在皮匠网上搜索. 1.如何用C语言编写游戏网络游戏是常谈的话题 ...

  5. 手把手教你编写游戏模拟器 - Chip8篇(1)

    转自 http://www.cnblogs.com/YiranXie/p/3439934.html 手把手教你编写游戏模拟器 - Chip8篇(1) 手把手教你编写游戏模拟器 - Chip8篇 翻译整 ...

  6. 使用Managed DirectX编写游戏

    转自  http://dev.gameres.com/Program/Visual/DirectX/ManagedDirectX9Game_01.htm http://dev.gameres.com/ ...

  7. 为什么我选择用 C 编写游戏?

    "古老"的C++,仍然是当前编写游戏时最常用的语言,但是 C 为什么才是最适合的? 作者 | Jonathan Whiting 译者 | 弯月,责编 | 郭芮 出品 | CSDN( ...

  8. 通过编写游戏程序的视角去编写字符驱动--设备树-百问imx6ull-pro

    本文基于imx6ull-pro百问网开发板进行驱动开发设计 编写驱动就好比是创建一个游戏并注册一个角色,每一步都是有意义的 对于这个游戏本身,我们也是管理者.首先先把游戏的初始化.退出框架搭好,然后提 ...

  9. python编写游戏测试机器人客户端(一)

    系列文章目录 python编写游戏测试机器人客户端(一) python编写游戏测试机器人客户端(二) python编写游戏测试机器人客户端(三) python编写游戏测试机器人客户端(四) pytho ...

最新文章

  1. ONAP — Overview
  2. int.TryParse的使用
  3. Istio 中的 Sidecar 注入及透明流量劫持过程详解
  4. 分布式事务解决方案以及 .Net Core 下的实现(上)
  5. Oracle11.2.0.4 RAC安装文档
  6. php怎么修改div自带属性吗,修改html 属性,css样式。
  7. linux 网络端口全连接扫描,端口全连接扫描程序(Linux, socket):TCP的connect方式...
  8. [置顶] EasyUI提交表单
  9. iOS关键代码遭泄露;Google正式抛弃HTTP;微博网页版出故障 | 一周业界事
  10. 11月热门下载资源TOP100强力推荐!
  11. 微软最近宣布了一项政策更新,将限制在Office 365中使用Flash,Shockwave和Sil
  12. 首都机场t2长期停车收费,首都机场t2停车场过夜价格表
  13. Win10 + Ubuntu 双系统完美避坑删除 Ubuntu 教程
  14. 传统项目管理和敏捷项目管理的区别是什么?
  15. 利用强化学习设计具有目标有效杨氏模量的复合材料
  16. Abstraction Functions and Rep Invariants
  17. 聊天程序设计实验报告——java
  18. id在python中是什么意思_Python中的id函数是什么意思
  19. 什么是php微信开发,php微信公众号开发模式详解
  20. 为什么学习Vue框架??

热门文章

  1. 密钥、证书原理与创建
  2. SC钢管人防套管如何选型
  3. 算法导论 — 思考题15-10 投资策略规划
  4. vim下使用 寄存器 剪切板
  5. 二值线形图像 识别 matlab,用MATLAB检测二值图像中的线间隙
  6. C语言实现扫雷游戏(完整版)
  7. Thinkphp全新UI黑白模式微信影视小程序源码(支持多开)
  8. 详细解释下小波分解去噪的原理
  9. VNC Linux 远程桌面控制软件
  10. Windows PC、 Linux、 Android、 iOS多平台支持H5无插件播放RTSP摄像机解决方案