一切始于我的女友向我挥舞着手机,然后大声喊道“瞧瞧我对这件事的看法”。 “ THIS” == 2048,是一款益智游戏,一年半以前就非常有名。

因此,我拿起自己的Macbook并开始玩,确保我要去拥有她。 所以我惨败了:’(现在,我只想操心这场比赛并获得最高分。
记忆编辑
我想到的第一件事是,分数位于游戏记忆的某个位置,也许我可以覆盖它。 做一些研究(搜索周围的东西)时,我偶然发现了一个非常出色的开源软件:Bit Slicer。 正是我所需要的,它自己作为“ macOS通用游戏培训师”出售。

您要做的就是搜索所需类型的值,在我的情况下为Int32。 当时我的分数是216:

找到1702个内存地址,其中包含216个值。 太多了,您需要缩小搜索范围,而这样做需要稍微改变一下演奏的乐谱的值,并在第一个1702个地址中搜索哪个乐谱更改为您的新乐谱。 就我而言,我的新分数是240。
现在它只显示2个地址,也许是您在问为什么两个而不是一个,这可能是因为有些冗余,一个用于将数字保存为Integer,另一个用于保存String的值,诸如此类。 现在,我只需要将这两个编辑为1337。

游戏并未更改其值,但是如果您在其中进行了某些操作,它将更新该值。

是的,我的BEST真的很棒
不错! 我给我的女朋友看,她就像“你刚刚编辑记忆对吗? 卷起眼睛 ”。 但这太简单了:/
编辑保存
之后,我意识到游戏在关闭时会保存最后一个状态,这使我尝试找到保存状态的位置并进行编辑。 另一轮Google向我展示了所有程序的支持文件都在~/Library/Application Support/
目录中。 不幸的是,该游戏不存在,也没有该软件的bundleId( com.codinn.2048
在该应用的Info.plist
中找到。 更多的Google告诉我,某些Apps使用“容器”,这是OS X应用的某种沙盒,位于~/Library/Containers/
。
在那里,我找到了一个带有游戏的bundleId的目录,以及一个包含游戏状态的plist: ~/Library/Containers/com.codinn.2048/Data/Library/Preferences/com.codinn.2048.plist
。 在Xcode中打开:

“ gameState”的值是:
{"grid":{"size":4,"cells":[[{"position":{"x":0,"y":0},"value":4},{"position":{"x":0,"y":1},"value":8},{"position":{"x":0,"y":2},"value":32},{"position":{"x":0,"y":3},"value":8}],[{"position":{"x":1,"y":0},"value":8},{"position":{"x":1,"y":1},"value":16},{"position":{"x":1,"y":2},"value":2},{"position":{"x":1,"y":3},"value":4}],[{"position":{"x":2,"y":0},"value":2},{"position":{"x":2,"y":1},"value":8},null,{"position":{"x":2,"y":3},"value":2}],[{"position":{"x":3,"y":0},"value":4},{"position":{"x":3,"y":1},"value":2},null,{"position":{"x":3,"y":3},"value":2}]]},"score":1337,"over":false,"won":false,"keepPlaying":false}
它不过是带有图块的值和位置的json。 所以我只编辑此内容,瞧,对吧? 否:/由于某些原因,可能是因为该应用程序是沙盒的,即使我编辑了它,gameState也不会改变。 我确信这一定是绕过和编辑此方法的方式,我会在将来尝试。
反转和编辑游戏
所以现在怎么办 ? Errrrrr,我可以编辑游戏的二进制文件以取得更多分,依此类推。 让我们开始吧!
首先,让我们在Radar2上打开它-不,我不是想炫耀不使用GUI工具,r2是免费和开源的,而且我只是一个没有钱购买IDA Pro或Hopper的学生。
$ sudo r2 -w /Applications/2048+.app/Contents/MacOS/2048+ Password: arw 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020160000010000000000000000000000000000000000000000000000000000000000000000000000 -- You see it, you fix it! [0x100001620]>
-w
用于编写。 您要做的第一件事是aaa
然后分析所有功能和名称。 r2有一种非常酷的方式来命名命令,它只是描述的前几个字母,第一个a
表示“ analyse”,第二个表示“ all”,第三个表示“ autoname”。 r2还有一个非常有用的帮助(双关语不是故意的)界面,只需在命令后加上问号,它就会显示所有相邻项,例如:

因此,在运行aaa
,您要列出所有功能。 只需运行afl
,它将显示大量功能,如果在命令后加上~
,它将对其进行grep。 我想搜索二进制文件的开头,所以我做了afl~main
; afl~entrypoint
; afl~begin
afl~start
,什么也没有(请注意,这是区分大小写的)。
我回到了基础知识,并在二进制文件中添加了strings
,这真的使我“ WTF”吗? :它显示了很多webView
字符串。 所以,是的,那只是一个Web应用程序-‘
糟糕的实现之后,我只是在应用程序中打开“ Resources”目录,这真是该应用程序的所有html / js / css,实在令人沮丧。
$ ls
CONTRIBUTING.md README.md index.html sound LICENSE.txt fontello js style
这真的很容易编辑。
在文件Resources/2048/js/game_manager.js
的第188行中,当两个图块合并时,游戏在其中计算新值,只需将前一个值乘以2。
var merged = new Tile(positions.next, tile.value * 2);
因此,只需将2更改为9999即可。 这就是美丽。

一切顺利,一切都很好。 但是真的很有趣。 现在我是全球排名第一的^^

比光速快
FTL是一款类似胭脂的独立游戏,具有太空飞船和不折不扣的战斗。 很多的乐趣,但是真的很努力(我从未击败过最后一个老板)。 因此,让我们摆脱困境。
记忆力不佳
我从与2048+相同的内存编辑开始。 您确实可以编辑所有变量,您的生活,敌人的生活,金钱等。 相同的程序,相同的结果,令人讨厌。

注意那些数字不适合盒子
编辑保存
但是游戏更加复杂,因此您必须不断编辑自己的生活,不能编辑伤害(因为您不知道要搜索什么),这很无聊。
我尝试的第一件事是编辑保存游戏,因为我在上一个游戏中失败了。 保存游戏位于~/Library/Application Support/fasterthanlight
,不在Containers
,因此没有沙箱,不错。 文件 :
$ ls
ae_prof.sav continue.sav prof.sav settings.ini
settings.ini
只是一个包含游戏,声音,全屏等配置的txt文件。.sav文件是保存/统计/成就。 那么,wtf是吗?
$ file continue.sav
continue.sav: data
$ xxd continue.sav 0000000: 0900 0000 0000 0000 0100 0000 0100 0000 ................ 0000010: 0400 0000 1600 0000 0300 0000 0b00 0000 ................ 0000020: 5468 6520 4b65 7374 7265 6c10 0000 0050 The Kestrel....P 0000030: 4c41 5945 525f 5348 4950 5f48 4152 4401 LAYER_SHIP_HARD. 0000040: 0000 0000 0000 0003 0000 000a 0000 0066 ...............f 0000050: 6972 6564 5f73 686f 7405 0000 0006 0000 ired_shot....... 0000060: 0068 6967 686f 3201 0000 000c 0000 0075 .higho2........u 0000070: 7365 645f 6d69 7373 696c 6502 0000 0010 sed_missile..... 0000080: 0000 0050 4c41 5945 525f 5348 4950 5f48 ...PLAYER_SHIP_H 0000090: 4152 440b 0000 0054 6865 204b 6573 7472 ARD....The Kestr 00000a0: 656c 0700 0000 6b65 7374 7261 6c03 0000 el....kestral... 00000b0: 0005 0000 0068 756d 616e 0700 0000 4359 .....human....CY 00000c0: 2048 656e 6705 0000 0068 756d 616e 0600 Heng....human.. 00000d0: 0000 4772 6163 6965 0500 0000 6875 6d61 ..Gracie....huma 00000e0: 6e06 0000 0041 7472 6579 7501 0000 00c2 n....Atreyu..... ... ETC
那是专有的文件格式,所以我必须尝试了解我要编辑的值在哪里。 我使用了HexFiend应用程序,它是Mac的十六进制编辑器,也是开放源代码,实际上Bit Slicer使用了部分代码。
首先,我要编辑我有多少废品(这是游戏的钱)。 如果我使用BitSlicer进行此操作,则必须能够更改该值以缩小研究范围。
当时我的钱是10,在hexa中是0xa
,所以只需搜索:

0xa
是一个很糟糕的值,因为它看起来很多,而不是内存中的很多,而是很多。 在文件的开头,它具有一些与我的船相匹配的信息,例如名称,船员,因此我认为第一个0A
是金钱(是的,我是个猜测的骑士)。 只需将第一个外观编辑为FFFF
(65535),保存它,然后砰!

哦! 另一个猜测是文件continue.sav
,其他文件具有游戏的其他状态,得分,成就。 我可以对二进制进行反向操作以找到更多的值,并且更加精确,但这将需要几天的时间。
反转二进制
我想做的另一件事是变得无敌,而无需一直手动编辑内存。 r2时间!
游戏的二进制文件位于/Library/Application Support/Steam/steamapps/common/FTL Faster Than Light/FTL.app/Contents/MacOS/FTL
因为它在Steam上。 首先,我检查了它是否是WebApp,但不是:’(
在r2上运行并分析所有功能需要花费一些时间,然后我开始查看带有“损坏”功能的功能。
[0x1000f9959]> afl~Damage 0x100018382 1 8 sym.Collideable::DamageBeam 0x10001838a 1 8 sym.Collideable::DamageArea 0x100018392 1 8 sym.Collideable::DamageShield 0x1000183bc 1 6 sym.Targetable::DamageTarget 0x1000184f2 1 60 sym.Projectile::SetDamage 0x10001a9b8 3 168 sym.IonDrone::GetRoomDamage 0x10001b778 3 35 sym.CrewDrone::ShipDamage 0x10001cb80 1 14 sym.CrewMember::GetDamageMultiplier 0x10001cbe2 1 83 sym.CrewMember::GetRoomDamage 0x10001ce52 1 14 sym.BoarderDrone::GetDamageMultiplier ... ETC ... ETC
在分析了几个小时的功能之后,它们全部还是真的没什么特别的,或者由于一些非常奇怪的说明而无法进行编辑,例如:

确实,我不知道这些指令的作用,并且我已经搜索过,因为它是带有double / float类型的。
所以我有一个主意,该船能够躲避导弹和新芽,它必须具有计算该功能的功能。
[0x1000f8104]> afl~Dodge 0x10001839a 1 8 sym.Collideable::GetDodged 0x1000f8828 19 340 sym.ShipManager::GetDodgeFactor 0x1000f9906 1 47 sym.ShipManager::GetNetDodgeFactor 0x1000f9935 1 18 sym.non_virtualthunktoShipManager::GetDodged__ 0x1000f9948 20 396 sym.ShipManager::GetDodged 0x100112c18 2 27 sym.ShipSystem::GetEngineDodgeFactor 0x1001137d0 8 159 -> 105 sym.EngineSystem::GetDodgeFactor
并查看sym.ShipManager::GetDodged
:
[0x1000f8104]> s sym.ShipManager::GetDodged [0x1000f9948]> VV
s
表示“搜索”,而VV
表示进入可视模式。 p
在可视模式下更改可视化的类型。

功能开始

功能结束
最后(第二次打印),在0x1000f9ac6
它只是将寄存器bl
移到了eax
并返回了它,因此bl
必须是持有该寄存器的寄存器,以防船舶能够躲避。 然后在0x1000f995b
(第一次打印) 0x1000f995b
1移动到bl
并跳转到函数的末尾。 现在,第一个跳转0x1000f9959
是一个jne
(不相等跳转),它检查最后一个cmp 0x1000f995
是否成功,是否成功跳转到0x1000f9962
,否则不只是继续执行。 好吧,导致0x1000f9962
的执行链确实令人困惑,它进行了很多比较和检查,以确定它将bl
0x1000f9962
1还是0,所以我只想函数返回1并始终闪避。 编辑0x1000f9959
并0x1000f9959
一个nop
(什么都不做的指令)代替jne
,它将导致函数始终将mov 1移至bl
,将jmp
移至最后。 让我们这样做:
[0x1000f9948]> s 0x1000f9959 [0x1000f9959]> wa nop Written 1 bytes (nop) = wx 90
导致 :

现在,如果您查看0x1000f995a
,它将显示“ invalid”,因为作为nop
十六进制表示形式的90
不会覆盖所有jne
hexa 7507
。 让我们只剩下一点,这一切都很好,也许有更好的方法可以做,但是操吧。
[0x1000f995b]> s 0x1000f995a [0x1000f995a]> wa nop

现在它总会躲闪东西,很好! 超级忍者模式(:SUPER NINJA MODE(:您可以编辑游戏中想要的任何内容,但这是我发现变得无敌的最简单方法)。
脚本编写
击败游戏的另一种方法是处理大量伤害,但是编辑装配很难,而编辑内存则不然。 但是如何使事情变得容易呢? 好吧,BitSlicer有一个可用于脚本编写的Python Python库,yaaaaay!
第一件事是找到敌人生命的记忆地址。 进行相同的搜索,找到地址后,右键单击它并单击“ Watch Write Accesses”,现在每次在该地址中写入一些指令时,我们都会看到。 取消暂停游戏并攻击您的敌人,然后再次暂停以查看在该敌人的生活地址中写了两条指令,将这两条指令添加到列表中。 一条指令进行了数百次写入,而另一条指令受到了您的攻击,请在调试器上以较少的写入次数打开一条指令,然后查看Symbol指向Ship::ProjectileStrike(int,float)
的功能,该函数确实会损坏。
现在分析程序集: mov [rdi+0x70], eax
。 [rdi+0x70]
是保存敌人生命的寄存器,我们要对其进行编辑的寄存器存储在0xD642
,该值不变,因此我制作了该脚本:
全部评论,将其添加到BitSlicer中,对敌人造成一些伤害以获得他的生命地址,并使用cntrl+a
杀死它ˆ-ˆ
总结了在离线游戏中作弊的所有方法,我正在对在线游戏进行一些研究并逆转其协议,但这需要时间。
ty!