今天来给大家揭秘一下XPE的完整修改流程。
从我怎么发现的这个问题,到我是如何分析这个问题的,最后再到我怎么解决这个问题。
接下来我将会详细给大家介绍Ex:Phiedit是如何一步一步变成它现在的样子的:
(相关资料图)
梦开始的地方:
经过漫长的等待,RPE的本体终于出现在了我们面前:
先把官方的补丁打上,的Bug就已经少了一半了。
之后我们进入Resources\Textures。
不难发现,这个文件夹中存放有大量未使用的按钮贴图,例如:
这个我不知道还有没有哪个骨灰级玩家认得它。
这个是远古时期PhiEditer的选歌界面中右上角那个添加歌曲的按钮!
Re:Phiedit中根本就没用过这张帖图!
最离谱的是,这张帖图居然一直跟着我们从到再到再到现在的从未被清理!!!
类似的还有,icon\,等等。
cmdysj从来就没清理过一次!
在Phigros自制谱的领域称霸天下了就开始放水。
那就让我来帮你吧。
只要删完没闪退或出现某个按钮因贴图缺失而消失不见的状况就全删。
每清理掉一个,我还将修改版RPE的界面与原版进行比对,反复确认没有按钮缺失。
全部弄完以后,整个文件夹大小减小了!
好,到此第一步就大功告成了!
除此之外还有很多大Bug从一直流传到一直不修!
比如这个下拉框超出屏幕边缘的Bug:
最后一个选项无法正常选取
这个也算是解决起来相对比较简单的,改一下就可以了。
我的修改方案是:
把密度和音符种类的位置互换,再把密度与曲线类型的位置互换。
原本我是想要把曲线类型的选项直接挪到最上面的,结果修改完发现音符种类的下拉框层级比曲线类型的下拉框要高,会有遮挡。
所以最后还是选择把它放到中间,音符种类摆最上面。
这样一来,下拉框中的最后一个选项Bounce就能正常选取了。
这一点我觉得cmdysj做的还是很友好的,所有组件的位置大小都能让你自己去DIY。
接下来我们来对RPE的界面做一下优化:
2004年前后流行的拟物化界面设计风格是真的帅到爆炸!
后来的扁平化全都是垃圾!
就这种界面设计也能叫设计???
我用Windows自带的画图都能给你画出来!
没有阴影,没有颜色渐变,没有光照。
几根简单的线条一勾勒就算完了。
Re:Phiedit的界面同样也是用的这个扁平化的设计风格,就是因为这样做起来简单,轻松!
甚至还会被一群对美术一窍不通的人夸奖很时髦!
好在cmdysj没有对软件的资源文件做任何的加密,也就意味着任何人都能够按照自己的喜好去DIY。
那正好,让我来帮你换个好看点的皮肤吧!
黑乐谱作者们最喜欢用的超高性能midi编辑器Domino的作者Takabo,除了开发Domino以外还制作了不少别的很好用的小工具。其中有一个就是AquaMaker。
这是我之前在Takabo的主页上随便瞎逛时发现的。
正好可以用来给RPE制作全新的按钮贴图!
Takabo制作的软件操作逻辑都非常直观,比苹果做的还要好,即使是对日文一窍不通的我也能连蒙带猜搞定。(不是广告!)
经过了反反复复的修改测试,我把RPE的界面成功修改成了如下图所示的模样:
虽然与我认为出色的界面设计相比还差了很大一段距离,但至少现在看上去已经比原版要好了很多了!
个人能力有限,如果你能设计出更好看的那么欢迎加入XPE项目。
现在,我们在不进行逆向的情况下可以做到的所有修改就已经结束了。
cmdysj的代码实在是写得太TM粪了,我受不了了我IDA动了。
做了一大堆花里胡哨的新功能,但每一个都坚决不把它做到最好。
这次的这个逆向工程真的是边搞边笑!哈哈哈!
各位准备好,正片开始!!!
我在前段时间搞Tan90时注意到了一个奇怪的现象:
当我拖动右上角的进度条时,整个拖动的过程都很流畅,然而偏偏在我松手的一瞬间卡死不动。等好几秒钟才能缓过来。
与此同时,我还注意到在中按Q,W,E,R放置音符的操作全部都是瞬间完成的。而在中则要卡上好一会。
这啥情况?
这明显不是RPE的图形渲染出了什么问题,一定还有什么别的东西在大大拖垮RPE的性能!
此时,我想到了一种可能的情况:谱面纠错!
为了右上角的两条线能够在对谱面做出修改后及时做出响应,cmdysj直接简单粗暴地在每一次对谱面做出任何修改动作时都自动调用一次谱面纠错函数!
好几十万音符的超大型塞炸谱Tan90如此频繁地要被检查纠错它能不卡吗?
于是,我打开了全网最强逆向工程神器:IDA。
尝试想要把这个恶毒的谱面纠错干掉。
然而,当我开始以后才发现,事情并没有我所想的这么简单。
由于cmdysj从版本开始就不再提供对应的PDB文件,所有的函数名称全部都是鸟语。
又臭又长的汇编代码完全看不懂。
一时完全不知从何下手。
但好在及以前的版本中都有PDB。
我们可以先从入手,找函数,之后再在中直接搜索代码或字符串就可以了。
打开版本的主程序以及其对应的PDB文件后,函数名称终于正常了。
搜索一下看看有没有什么和谱面纠错有关系的。
很快,我找到了这个:
可以看到,这里有检查谱面中各种不同类型错误的函数。
如xy绑定,音符重叠,事件,读谱时间等等。
随便打开一个,按下Ctrl + X快速查找出所有调用这个函数的语句:
就是你了!点OK进入。
好,罪魁祸首全部抓到。
把这几行语句全部替换成nop,意是就是啥都不做。
成果展示:
但这么一来,谱面纠错就完完全全彻底没法用了。
显然,这并不是我们想要的。
我们希望能够在我手动点击右上角的刷新按钮时进行一次纠错,其他时候就不要动了。
那接下来我们就需要去找有哪些语句调用了这个谱面纠错的主函数,把其他的全部删掉,只保留下刷新按钮。
向上滚动来到函数的开头,并按下Ctrl + X。
好家伙!这玩意居然在整个程序中被调用了50次!!!
用JitBit简简单单做一个脚本批量给这50个调用语句全部加上断点。
脚本大致内容为:
标签:Begin
Ctrl + X
下箭头
回车
F2
Esc
跳转到标签:Begin
运行程序,开始测试。
我滴个乖乖!这个纠错函数基本每点一下鼠标就要被调用一次啊!
不卡才怪!
此时点开主界面右下角的谱面纠错,点一下刷新。
回到IDA里,看看是这50次当中的哪一个。
按F2把它的断点删掉,其它地方不要动。
停止调试,回到IDA主界面。
按Ctrl + Alt + B打开断点列表,拖动它把它固定到IDA主界面右侧。
就像这样:
接下来用JitBit简单写个脚本把所有打了断点的语句全部替换成nop。
注意:由于指令长度不同,需要使用五个nop替换掉一个call语句。
脚本大致内容如下:
标签:Begin
双击打开右侧的第一个断点
Alt
E
P
A
输入文本:nop
回车
回车
循环4次
下箭头
回车
循环结束
按下F2
跳转到标签:Begin
很快,JitBit就完成了全部50次调用的修改。
测试一下,运行效率的确比以前提高了不是一点半点!
但是,我们的最终目标是要去修改,不是。
接下来就让我们来简单观察下这里面有没有什么我们可以利用的好东西:
按F5查看伪代码,可以减小代码阅读难度。
很快,我找到了这个:
出现字符串了!关键信息!
对我们在中找代码有很大帮助!
OK,找到你了!
点进去,向上翻,找到函数的开头。
把光标挪到那里然后按Ctrl + X。
成功定位到关键函数!
对比一下,一摸一样!
找到这个关键函数的开头,右键点这里给他重命名:
这样我们后面操作时就会容易一些。
之后对着它按Ctrl + X
惊了!整整60次调用!!!
里面才仅仅50次,里55次,居然给直接增加到了60次!
难怪这么卡!
按照之前搞的操作在里再搞一次。
好了,现在的这个简直比流畅!
不知道各位有没有注意到即兴演奏的一个大bug:
按下冒号和问好会把音符放置在同一个位置!
这个Bug我不知道各位受得了受不了,反正我是已经要疯了!
强迫症表示这玩意实在看不下去!!!
然而,接下来的难点在于我们无法通过去找对应的关键函数,因为这个功能是里才刚加入的。
这里我们可以去尝试找一下即兴演奏中用到的一些快捷键看能不能搜到:
确实可以!
第一个是的按键显示,第二个就是我们要找的了。
进来一看代码,给我气笑了!
怎么前面都写得好好的,9,10,11,到了12这边就莫名其妙写了个13?
只能感叹cmdysj的代码写地实在是太粗心啦!
仔细看一下,这不正是出问题的那个按键Semicolon嘛!
把它改成12,问题解决!
之后我便开始制作XPE的广告片。
结果,我居然在制作广告片的过程中意外间又发现了RPE的第二个性能杀手!!!
当我在制作这里/video/BV1aX4y1s71R?t=的性能优化演示时,我注意到了一个很奇怪的现象:
用Cheat Engine把XPE减速到倍速,再在软件里把播放速度调到。
理论上来说应该与之前播放的流畅程度没有区别,对吧?
然而,我却发现这样操作过以后播放的流畅程度却又了很大的提升!!!
这啥情况???
要知道,cheat engine减速是不会对软件代码的执行速度产生任何影响的。
只有跟计时有关的语句会因为cheat engine的介入而计算出错误的时间以达到增减速度的效果。
此时,我想到了一种可能的情况:计划任务。
让程序每隔一段时间就调用一次某个特定的函数。
用Cheat Engine减速会使单位时间内调用的次数减少。
而在软件内使用变速功能不会对这些计划任务产生任何影响。
计划任务是一种非常方便快捷的实现伪多线程的方式。
其原理在于将整个CPU分割成N多个时间片,在每个时间片中安排不同的任务。
由于几个时间片之间轮转的速度很快,从表面上看起来便是CPU同时在做多件事情。
我之前在AppInventor中做一个抢答器App的时候就是用的这个方法实现的多线程。(注:AppInventor不支持真多线程)
C++虽然可以做真多线程,但做起来比较繁琐,于是cmdysj就用计划任务偷了个懒。
但是用计划任务的方式实现伪多线程有一个大问题!
正常情况下,需要同时运行的几个函数是这样被调用的:
但如果需要处理的数据量过大的话就会出现接下来的场景:
前一个函数还没运行完,后一个就要被调用。
上图画的是安排,到了实际执行时就会变成如下的模样:
这样一来便会导致程序主循环被严重拖慢,软件运行的流畅程度严重下滑!
靠逆向工程把RPE改成真多线程几乎是不可能的。
我们只能通过修改代码增加这些计划任务执行的延迟,多分配一些处理时间。
这样便能使XPE的执行效率再一次得到质的飞跃!
要修改延迟,首先需要弄明白RPE是如何实现计划任务的。
我注意到左侧的函数列表中有不少跟一个叫cocos2d的东西有点关系:
于是随手上网去搜了一下这个玩意:
哦,原来就是个游戏引擎啊。
那来让我看看如何用cocos2d实现计划任务?
原来是用的Schedule。
于是我就去代码中搜了一下Schedule:
真的有,而且还不少!
点进去看一下代码:
按照我查到的schedule语句的用法,中间的是要调用的函数,最后一项应该就是用浮点数表示的时间。
拿这个hex to float转换器转换一下看看:/FloatConverter/
卧槽!这延迟就TM短的离谱!!!
每秒执行一次!!!
不卡才怪!
接下来我们要做的就是修改它们的延迟。
让这些函数在单位时间内少执行几次。
在转换器最上面的那个文本框中填入新的浮点数时间(单位为秒),并把下面转换出来的hex复制下来。
在IDA中选中scheduler的最后一个参数的数值,按Tab键跳转到在Disassembler视图中对应的位置。
依次点击Edit -> Patch Program -> Assemble把刚刚复制下来的数值贴进去修改就可以了。
吗?
又一个新的问题来了,IDA貌似还不支持修改这个指令。
能把这个指令从exe里反编译出来却无法编译修改后的指令真的令我很意外!
那看来我们只能用一些别的方式去修改了。
于是我便想到了进入hex视图看看能不能直接从机器语言下手把这行代码给改掉。
打开hex视图后先不着急改,回到Disassembler视图。
在空白处右键找到Synchronize with,勾选上Hex View-1。
接下来你就会发现你在Disassembler中把光标放在哪一行Hex里就会跟着高亮显示出那行代码所对应的hex。
经过一番分析,我发现了如下的规律:
以C7 04 24开头,之后接上以两个字母为单位倒序排列的浮点数时间的hex。
右键,然后点Edit,把这串数字修改掉。
再按右键,点Apply,刚刚做的修改就都成功地应用上了。
按照同样的方法把其它所有的scheduler全都改掉,依次点击Edit -> Patch Program -> Apply patches to input file把刚刚我们做的修改写入到可执行文件里。
之后只要再简单修改一些字符串,例如把 @cmdysj修改成Ex:Phiedit 等,这个XPE就可以算是完工了。
感谢各位的观看,我们下期再见。
标签:
X 关闭
X 关闭