lzc090 发表于 2019-1-11 21:57

《魔法密码》详细分析

本帖最后由 lzc090 于 2019-5-2 08:23 编辑

前提:U3D游戏,请优先看懂这个贴子
U3D游戏《东方新世界》Il2Cpp破解详细教程
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一.货币修改
public uint get_money(); // 0xA9BA5C


text:00A9BA5C sub_A9BA5C ; CODE XREF: .text:00A44198↑p
.text:00A9BA5C0C 00 D0 E5               LDRB            R0,
.text:00A9BA601E FF 2F E1               BX            LR

修改成:

text:00A9BA5C             sub_A9BA5C                              
.text:00A9BA5C0F 02 E0 E3            MOV             R0, #0xFFFFFFF
.text:00A9BA601E FF 2F E1               BX                LR



--------------------------------------------------------------------------------------------------------------------------------------------------------
二.等级修改

public uint get_level(); // 0xA8D7D0

.text:00A8D7D0             sub_A8D7D0                           
.text:00A8D7D0 14 00 90 E5               LDR             R0,
.text:00A8D7D4 1E FF 2F E1               BX            LR

修改方式和货币一样,不过!!!!有个问题是,等级有了,但属性值可能没加上去,只是等级好看而已,没任何用处。因此我会介绍比较有用的经验修改

三.经验修改

经验修改1:
public uint get_exp(); // RVA: 0xA9BBE4 Offset: 0xA9BBE4

.text:00A9BBE4             sub_A9BBE4                        
.text:00A9BBE4 18 00 90 E5               LDR             R0,
.text:00A9BBE8 1E FF 2F E1               BX            LR

修改方式和金币一样,不过这个可能是获得的总经验

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

经验修改2:

public uint get_requiredExpToNextLevel(); // RVA: 0xA9BC1C-----------升级所需的必须经验



当看到
.text:00A9BC4C 14 10 94 E5               LDR             R1, ---假设:当前等级
.text:00A9BC50 01 20 A0 E3               MOV             R2, #1
.text:00A9BC54 63 30 A0 E3               MOV             R3, #99
.text:00A9BC58 00 50 8D E5               STR             R5,
.text:00A9BC5C 01 10 81 E2               ADD             R1, R1, #1
.text:00A9BC60 9A FE 01 EB               BL            sub_B1B6D0

我就联想起dump文件里面的下列2个函数

public const uint minLevel = 1; // 0x0

public const uint maxLevel = 99; // 0x0

那么将
.text:00A9BC4C 14 10 94 E5               LDR             R1,

修改成
.text:00A9BC4C 14 10 94 E5                MOV             R1,99      当前等级不就变成了99了?

经过修改后发现,这个函数其实是每个等级需要的经验数,那么我们将修改的99换成1,每一级升级只需要等级1的经验也是100左右,我现在29级,还是只需要100.


------------------------------------------------------------------------------------------------------------------------------------------------------------

经验值修改3:

public uint get_restExpToNextLevel(); // RVA: 0xA8EBE4-----------------------这个是剩余升级的经验,就是经验条灰色部分。

.text:00A8EBE4             sub_A8EBE4   
.text:00A8EBE4 10 4C 2D E9               STMFD         SP!, {R4,R10,R11,LR}
.text:00A8EBE8 08 B0 8D E2               ADD             R11, SP, #8
.text:00A8EBEC 00 40 A0 E1               MOV             R4, R0;
.text:00A8EBF0 09 34 00 EB               BL            sub_A9BC1C ;      
.text:00A8EBF4 18 10 94 E5               LDR             R1,        ------------获得的经验
.text:00A8EBF8 01 00 50 E0               SUBS            R0, R0, R1            需求的经验-获得的经验,
.text:00A8EBFC 00 00 A0 93               MOVLS         R0, #0                  结果≤0那么,结果就等于0   (result = 0;)
.text:00A8EC00 10 8C BD E8               LDMFD         SP!, {R4,R10,R11,PC}   如果是大于0,结果R0-R1(需求的经验-获得的经验)(result = v2 - v3;)==剩余升级经验(图片灰色部分)



伪代码:
unsigned int __fastcall sub_A8EBE4(int a1)
{
int v1; // r4
unsigned int v2; // r0
unsigned int v3; // r1
bool v4; // cf
unsigned int result; // r0
---------------------------------------------------------------------
v1 = a1;
v2 = sub_A9BC1C(a1);                               v1 = sub_A9BC1C(a1);
v3 = *(v1 + 24);
v4 = v2 >= v3;                         修改后       v2 = v1 >= v1 - 1;   
result = v2 - v3;                                       result = 1;
if ( result == 0 || !v4 )                              if ( !v2 )
    result = 0;                                             result = 0;
return result;                                             return result;
}

那么我们只需要将结果都改成1,

.text:00A8EBF4 18 10 94 E5               LDR             R1,

修改成:
.text:00A8EBF4 01 10 40 E2               SUB             R1, R0, #1 ;

说明下:
.text:00A8EBF0 09 34 00 EB               BL            sub_A9BC1C ;                  
.text:00A8EBF4 01 10 40 E2               SUB             R1, R0, #1 ;      ------------获得的经验=需求经验-1
.text:00A8EBF8 01 00 50 E0               SUBS            R0, R0, R1         ---------   需求的经验-获得的经验 =1 ,(v2 - v3)
.text:00A8EBFC 00 00 A0 93               MOVLS         R0, #0             ------   因为值=1不会<0,跳过
.text:00A8EC00 10 8C BD E8               LDMFD         SP!, {R4,R10,R11,PC}   值大于0,那么结果就是R0-R1的值(result = v2 - v3;)

比如需求经验100 ,(SUB      R1, R0, #1 ;)100-1=99, 获得的经验就是99,    result = v2(100) - v3(99);   代码就变成了这个   result = 1;

修改测试并没有任何变化,可能有其他原因限制,因此这个修改为理论!
-----------------------------------------------------------------------------------------------------------------------------------------------------------
三.HP修改
public uint get_maxHp(); // RVA: 0xA9BC78 Offset: 0xA9BC78       ----------本函数在IDA对应的是loc_A9BC78

这是不能F5,所以就需要慢慢去查看了

找到关键的跳转:



.text:00A9BD34 AA 1C 02 EA               B               loc_B22FE4

跳转后找到的关键点:



.text:00B230D4 00 10 A0 E1               MOV             R1, R0            ------------当前血量
.text:00B230D8 00 00 A0 E3               MOV             R0, #0
.text:00B230DC 01 20 A0 E3               MOV             R2, #1         --------------- MINHP
.text:00B230E0 0F 37 02 E3               MOV             R3, #9999 ;------------------MAXHP
.text:00B230E4 00 40 8D E5               STR             R4,

看到加粗的地方是不是又熟悉了,dump文件里面的函数

public const uint maxHp = 9999; // 0x0

只需要将

.text:00B230D4 00 10 A0 E1               MOV             R1, R0            ------------当前血量

修改成
.text:00B230D4 00 10 A0 E1               MOV             R1, 9999            ------------当前血量


----------------------------------------------------------------------------------------------------------------------------------------------------------

四.MP修改
看到MP和HP的汇编语言差不多因此尝试和HP一样的修改方式

public uint get_maxMp(); // RVA: 0xA9BD64 Offset: 0xA9BD64   ---------本函数在IDA对应的是loc_A9BD64
找到MP的相关代码



进入跳转.text:00A9BE20 FA 1C 02 EA               B               loc_B23210

找到关键位置



text:00B23318 0C 20 90 E5               LDR             R2,             -----------当前MP
.text:00B2331C 00 00 A0 E3               MOV             R0, #0
.text:00B23320 E7 13 00 E3               MOV             R1, #999
.text:00B23324 00 30 A0 E3               MOV             R3, #0
.text:00B23328 63 A7 F4 EB               BL            sub_84D0BC ;

看到这里是不是又熟悉了,dump文件里面的函数

public const uint maxMp = 999; // 0x0


text:00B23318 0C 20 90 E5               LDR             R2,             -----------当前MP

修改成
text:00B23318 0C 20 90 E5               MOV             R2, 999            -----------当前MP

发现没任何作用,那么函数就不是我们上面猜测的

我们分析下整体,找到了相关的点,所以就没吧所有的都贴出来了



.text:00B232E0             loc_B232E0                              ; CODE XREF: .text:00B232CC↑j
.text:00B232E0 00 30 90 E5               LDR             R3,
.text:00B232E4 08 10 A0 E1               MOV             R1, R8
.text:00B232E8 04 20 90 E5               LDR             R2,
.text:00B232EC 05 00 A0 E1               MOV             R0, R5
.text:00B232F0 33 FF 2F E1               BLX             R3
.text:00B232F4 00 10 A0 E1               MOV             R1, R0
.text:00B232F8 00 00 A0 E3               MOV             R0, #0
.text:00B232FC 00 20 A0 E3               MOV             R2, #0
.text:00B23300 00 60 A0 E3               MOV             R6, #0
.text:00B23304 06 9D FD EB               BL            sub_A8A724
.text:00B23308 00 50 A0 E1               MOV             R5, R0
.text:00B2330C 08 00 94 E5               LDR             R0,
.text:00B23310 00 00 50 E3               CMP             R0, #0
.text:00B23314 0C 00 00 0A               BEQ             loc_B2334C
.text:00B23318 0C 20 90 E5               LDR             R2, --我们之前改的是这个,但没用       unsigned int __fastcall sub_84D0BC {
.text:00B2331C 00 00 A0 E3               MOV             R0, #0                                                                      if ( a2 < a3 )   ----R2<999
.text:00B23320 E7 13 00 E3               MOV             R1, #999                                                                   a3 = a2;      
.text:00B23324 00 30 A0 E3               MOV             R3, #0                                                                      return a3;}
.text:00B23328 63 A7 F4 EB               BL            sub_84D0BC   --刚好是sub,我们看下代码            这代码是求MP ,设当前MP:72/80,求这个80,
.text:00B2332C 00 30 A0 E1               MOV             R3, R0       (R1, R0)               这就是上面的80也是MAXMP                                                
.text:00B23330 00 00 A0 E3               MOV             R0, #0       (R0, #0)                                                                        
.text:00B23334 05 10 A0 E1               MOV             R1, R5       (R2, #1)               当前MP                                                   
.text:00B23338 00 20 A0 E3               MOV             R2, #0       (R3, #9999)          MIXMP                                                            
.text:00B2333C 00 60 8D E5               STR             R6,                                                                                                                                                                      

有没发现蓝色这一段和上面HP的蓝色是同一个函数()里面的是HP的,不过位置变动了

位置调换一下
.text:00B23334 05 10 A0 E1               MOV             R1, R5      (R1, R0)
.text:00B23330 00 00 A0 E3               MOV             R0, #0       (R0, #0)
.text:00B23338 00 20 A0 E3               MOV             R2, #0       (R2, #1)
.text:00B2332C 00 30 A0 E1               MOV             R3, R0       (R3, #9999)

这样我们就知道要修改哪了


.text:00B23334 05 10 A0 E1               MOV             R1, R5      


修改成:
.text:00B23334 05 10 A0 E1               MOV             R1, 999



.text:00B2332C 00 30 A0 E1               MOV             R3, R0
      
修改成
.text:00B2332C 00 30 A0 E1               MOV             R3, 999



----------------------------------------------------------------------------------------------------------------------------------------------------
五.无限体力

游戏回复体力的方式看广告或者是等待时间回复

无限体力1(跳过广告):

public bool get_skipAds(); // RVA: 0xA9D88C Offset: 0xA9D88C   IDA对应的是loc_A9D88C,

同样无法看伪代码,不过查看过程中发现了这个关键点(代码很长就不全部贴出来了)



.text:00A9DB78             loc_A9DB78   
.text:00A9DB74 00 60 A0 E3               MOV             R6, #0
.text:00A9DB78
.text:00A9DB78             loc_A9DB78                           
.text:00A9DB78 06 00 A0 E1               MOV             R0, R6
.text:00A9DB7C F0 8B BD E8               LDMFD         SP!, {R4-R9,R11,PC}


.text:00A9DB78 06 00 A0 E1               MOV             R0, R6

修改成
.text:00A9DB78 06 00 A0 E1               MOV             R0, 1


同时抽取塔罗牌也是跳过广告的



修改体力2:

public uint get_motivation(); // RVA: 0xA8E98C Offset: 0xA8E98C

代码太长,提取关键地方


从伪代码可以开到,最后的结果是return (loc_A9C08C)(v1, HIDWORD(v7), v4, v3, v5, v6); 对应的就是loc_A9C08C,那么进去loc_A9C08C差看下

关键处:


前面的代码好像是计算时间的,不过我不确定就不在这里说了

.text:00A9C1B8 2F 69 DB EB               BL            j___udivsi3                  ---F5return a1 / a2       血力格式    R5/R0
.text:00A9C1BC 05 50 80 E0               ADD             R5, R0, R5                  ------- 当前体力         
.text:00A9C1C0 04 00 A0 E1               MOV             R0, R4
.text:00A9C1C4 70 FC FF EB               BL            loc_A9B38C                     -------这个是上限MAX体力,后面会分析到
.text:00A9C1C8 00 00 55 E1               CMP             R5, R0                                 ---判断当前体力是不是满               
.text:00A9C1CC 05 00 A0 91               MOVLS         R0, R5                        --   R5<=R0,体力不满,当前体力为R5
                                                                                                                                 当体力满时 ,当前体力=MAX体力 =R0
-------------------------------------------------------------------------------------------------------------------------------------------------------------------

关键MAX体力跳转

.text:00A9C1C4 70 FC FF EB               BL            loc_A9B38C



关键跳转
.text:00A9B448 66 20 02 EA               B               loc_B235E8

关键点:


看到是不是有是熟悉的感觉

.text:00B236E0 00 10 A0 E1               MOV             R1, R0;                        当前体力MAX
.text:00B236E4 00 00 A0 E3               MOV             R0, #0
.text:00B236E8 01 20 A0 E3               MOV             R2, #1                        体力限制MIN
.text:00B236EC E7 33 00 E3               MOV             R3, #999                     体力现在MAX
.text:00B236F0 00 40 8D E5               STR             R4,

.text:00B236E0 00 10 A0 E1               MOV             R1, R0

修改成
.text:00B236E0 E7 13 00 E3               MOV             R1, #999




六.跳过战斗画面

public bool get_skipBattle(); // RVA: 0xA9DBC8 Offset: 0xA9DBC8

同样的跳过战斗过程修改和去广告也是一样的修改方式





七.修改角色属性

1.敏捷/防御(其实是同一个东西)

public uint get_agility(); // RVA: 0xA9BF3C Offset: 0xA9BF3C-------IDA对应的是loc_A9BE50

public uint get_defence(); // RVA: 0xA9BE50 Offset: 0xA9BE50

关键代码



同样我们会再底部看到一个跳转

.text:2B 1D 02 EA               B               loc_B234AC ;

进去后看到一个关键的地方



是不是和HP的一样,敏捷取值范围1<=敏捷<=99

.text:00B23468 00 10 A0 E1               MOV             R1, R0

改成
.text:00B23468 00 10 A0 E1               MOV             R1, 99



-------------------------------------------------------------------------------------------------------------------------------------------------------------------

七.秒杀


秒杀修改方式有2种

1.修改主角本身的攻击力

2.修改怪物的血量为1

本游戏是主角挨打,伙伴攻击因此方式1的修改并不存在,我们修改方式2.

public uint get_hp(); // RVA: 0xB1141C Offset: 0xB1141C

.text:00B1141C             sub_B1141C                              
.text:00B1141C 1C 00 90 E5               LDR             R0,
.text:00B11420 1E FF 2F E1               BX            LR

修改为
.text:00B1141C             sub_B1141C                              
.text:00B1141C 1C 00 90 E5               mov            R0, 1
.text:00B11420 1E FF 2F E1               BX            LR

很多参数(暴击、闪避、无敌等)修改方式和上面介绍的差不多,多去看dump文件里面的参数就知道了,就不一一罗列出来了。
希望大家喜欢!




lzc090 发表于 2019-1-16 20:46

本帖最后由 lzc090 于 2019-1-16 20:51 编辑

878510 发表于 2019-1-16 20:25
..
在C之前是不是应该有更基础的东西
我啥都不懂呢
U3D打包模式有2种:
momo打包的游戏,源码是直接可以看到的,论坛也有很多入门的教程。
IL2是吧源码放到了so文件,反编译出来变成ARM语言的。需要再把ARM语言自己专为C#,所以难度会更大点,因此需要C#语言也需要ARM语言。
所以建议你从momo开始认识,这个帖子你就直接跳过,先去看MOMO的游戏教程

lzc090 发表于 2019-1-16 21:26

878510 发表于 2019-1-16 21:04

照着做都搞不定

去移动板块,查看那些无限金币帖子开始一步一步跟着做。
https://www.52pojie.cn/thread-846577-1-2.html
这个帖子就很适合入门学习,也写的非常清楚。如果看不懂,就需要多花点时间,记得是动手跟着做才有用。

吾爱支持 发表于 2019-1-11 23:00

支持原创……感谢楼主分享……。
最后一个小分分送上,请笑纳

fq645122 发表于 2019-1-11 23:01

看着可以哦

565266718 发表于 2019-1-11 23:06

支持了。。。。

飞天蜗牛 发表于 2019-1-11 23:24

好教程,感谢楼主分享,学习下

CrazyNut 发表于 2019-1-12 02:44

精华帖预定{:1_932:}

逐梦网络科技 发表于 2019-1-12 05:45

感谢楼主的分享。支持原创

wisoft 发表于 2019-1-12 10:01

膜拜,感谢分享

Dimi520 发表于 2019-1-13 00:53

好教程,楼主牛逼

Andy111618 发表于 2019-1-13 11:15

感谢楼主分享,学习下
页: [1] 2 3 4 5 6 7 8
查看完整版本: 《魔法密码》详细分析