跑跑卡丁车kartriderrush.apk(跑跑卡丁车2008年韩文单机版)是nexon公司在2008年出品的手机单机版类似PC版的赛车游戏,可谓是那时的一代经典,曾经在iOS平台和我那800x480屏幕的小破安卓手机上完美运行。十年时间过去了,如今的手机屏幕分辨率已经达到1920x1080甚至2K、4K,高分屏的安卓手机上运行这个古老的apk,会出现游戏分辨率不能自适应的问题,触摸按钮位置和图标也出现漂移。原因自然是当时这个游戏只适配了800x480屏幕的手机。
经过3个多月不懈的努力,我利用unity3D游戏逆向的技术,终于成功让这个古老的游戏换发了生机,完美自适应适配各种屏幕的手机。同时顺便破解了付费跑道、人物和赛车。
最后总结一下,这三个月的经验与教训。
一、利用apktool或者androidkiller解包apk
assets文件夹,unity3d的东西基本都在里面
android文件夹,所有的跑道assetbundle在里面
bin->data文件夹,unity3d的所有关卡(场景)资源和序列化的资源(就是乱码的那些文件)都在里面,可以使用disunity来把资源解包成贴图和shade文件等。
bin->data->Managed文件夹,里面都是c#编写的dll动态链接库(或者说是assembly文件),核心文件是Assembly-CSharp.dll,我们主要修改这个文件
二、回编译一下apk文件,看有没有签名验证
结果游戏闪退,证明存在签名验证,估计在java代码里面,利用jd-gui查看java源码,搜索“sign”,发现在com\nexon\kartriderrush\android\olleh\KartRiderRushActivity.class类中存在判断代码
然后我们在smali文件中注释掉这个判断就可以了。
三、研究c#源码
打开Assembly-CSharp.dll,发现有500多个类,真是要命了~
我们主要修改GUI开头的类,下面我来分析一下
GUIAccomplishPopup.cs,跑完成弹出的一个什么东西,只要是带Popup都是关于弹出的窗口
GUIAtlas.cs这个atlas真没搞懂,好像是负责图片资源最初的加载的
GUIAtlasCreator.cs,顾名思义,atlas创建器
GUIAtlasManager.cs,atlas管理器
GUIBase.cs,gui基类
GUIBlackBar.cs,黑条,忘记了
GUIBlackBarPanel.cs,黑条面板
GUIBoosterGauge.cs,加速计
GUIButton.cs,按钮基类
GUIController.cs,控制器基类
GUIControllerIPad.cs,面板控制器基类
GUIControls.cs,管理在进行比赛过程中打开菜单选择gui操纵方式控件的,例如左右方向键和漂移按键,减速按键等
GUIFBLoginPopup.cs,facebook相关
GUIFontCalculator.cs,字体计算器
GUIFontCalculatorEx.cs,字体计算器增强版
GUIFontCalculatorEx2.cs,字体计算器增强版2
GUIFontCalculatorExParam.cs
GUIFontManager.cs字体管理器
GUIGarage.cs,车库
GUIGauge.cs,加速计
GUIImage.cs,图片基类
GUIInfo.cs,管理选完地图开始游戏的加载界面的小提示的
GUIInfoControllers.cs,也是管理选完地图开始游戏的加载界面的小提示的
GUIInterface.cs,接口基类
GUIIPad.cs,是在玩游戏时的左右漂移减速等操纵面板的类,很关键
GUIIPadItemSlot.cs,道具赛和氮气图标管理类
GUIIPadPlayerMark.cs,左上角玩家排名相关类
GUIIPadPlayerPanel.cs,左上角玩家排名相关类
GUIIPadPlayerRank.cs,左上角玩家排名相关类
GUIKartViewer.cs,不知道,3d查看器?
GUILastItem.cs,最后一个列表项目基类(可用于跑道,赛车、人物等)
GUIListCtrl.cs,列表控件基类
GUIListCtrlItem.cs,列表项目基类
GUILoading.cs,gui界面最初时“点击屏幕继续”的那个界面
GUILoadingPopup.cs
GUILoadingReplay.cs
GUIMain.cs,主界面,就是选竞速赛还是道具赛的那个界面
GUIMinimap.cs,跑车时右上角的小地图
GUIMinimapMark.cs,小地图标记
GUIMinimapPanel.cs,小地图面板
GUIMinimapPanelBehaviour.cs,小地图面板动态控制
GUIMode.cs,是控制最上方白条按钮栏的,不管在哪个GUI界面都控制
GUIMoreItemType.cs
GUINewRecord.cs,跑完新纪录产生弹出的那个2s的面板
GUIPackagePopup.cs
GUIPanel.cs,panel基类
GUIPanelBuilder.cs panel建造器
GUIPanelEx.cs panel扩展版
GUIPanelEx3Part.cs panel3部分扩展版(适用于中间那部分可随意伸长变宽)
GUIPanelEx3PartHorz.cs panel水平3部分,左中右
GUIPanelEx3PartVert.cs panel垂直3部分,上中下
GUIPanelExBuilder.cs panel扩展版建造器
GUIPanelFactory.cs 负责将贴图dds或tga等格式显示在屏幕上
GUIPanelLayout.cs 一个基类
GUIPanelManager.cs panel管理器
GUIPanelPlayerBuilderForIPad.cs
GUIPanelPlayerMarkBuilderForIPad.cs
GUIPanelPlayerRankBuilderForIPad.cs
GUIPatchSummaryPopup.cs 夏季补丁弹出
GUIPause.cs 管理暂停时的一些东西
GUIPlayerElem.cs 左上角玩家元素
GUIPosMoverWS.cs
GUIProgramVersion.cs 程序版本
GUIPurchaseConfirmPopup.cs购买确认弹出
GUIQuestPopup.cs请求弹出
GUIQuitPopup.cs 退出弹出
GUIRankingBgInSingle.cs
GUIRankingHeaderInSingle.cs
GUIRankingListInSingle.cs 这一块rankinglist大概是facebook的排名列表,反正我没看到过
GUIRankingListItem.cs
GUIRankingResetPopup.cs
GUIRestorePurchasesPopup.cs
GUIResult.cs 跑完到达终点后负责显示所有人排名和分数的计分板,带一点显示新纪录功能
GUIRoomSearchingPopup.cs 房间搜索弹出
GUIScrollBar.cs 滚动条基类
GUIScrollBarHorz.cs 水平滚动条
GUIScrollBarVert.cs 垂直滚动条
GUIScrollhelpItem.cs
GUIScrollImage.cs 滚动图片,在帮助面板里有可以滚动的图片(就是那些链接、物品介绍之类的)
GUIScrollImageEx.cs 扩展滚动图片
GUIShopList.cs 不是商店,store才是内购商店,这个是车库和人物选择库
GUIShopListItem.cs 车库和人物选择库的项目(车或人)
GUISingleMode.cs 顾名思义是单人模式,但是就是一个状态切换,没太大作用
GUISpeed.cs 速度计
GUISpeedArrow.cs 速度计箭头,我都没看到过这个箭头
GUISpeedArrowBuilder.cs
GUIStoreItemInfo.cs 内购商店项目(商品)信息
GUIStoreLeftBackground.cs商店左背景
GUIStoreList.cs 商店背景
GUIStoreListItem.cs 商店项目
GUIStoreListRestoreItem.cs以下都是商店的东西
GUIStoreListUnlockableItem.cs
GUIStoreListUnlockAllItem.cs
GUIStoreListUnlockOneItem.cs
GUIStorePurchaseButton.cs
GUIString.cs GUI形式的string(字符串)
GUITachometer.cs 按照翻译,还是速度计
GUITrackInfoInSingle.cs 单人竞速和道具模式下的跑道信息
GUITrackListInSingle.cs单人竞速和道具模式下的跑道列表
GUITrackListItem.cs单人竞速和道具模式下的跑道项目类
GUITrophyPopup.cs
GUITutorial.cs 教程(基本没用)
GUITutorial2.cs 教程2(也是没用的)
GUITutorialMulti.cs 教程多(都不是新手了)
GUIType.cs
GUIUpDownListItem.cs
GUIURLTouchRegion.cs 好像和帮助里的链接触控区域有关
GUIUtil.cs
GUIUVScrollImage.cs
GUIWaitingPlayersPopup.cs 等待玩家弹出窗口
GUIWifi.cs 其实是蓝牙模式,以下wifi开头的都是蓝牙模式
GUIWifiClient.cs
GUIWifiHost.cs
GUIWifiRoomList.cs
GUIWifiRoomListItem.cs
GUIWifiTrackList.cs
GUIWifiTrackListItem.cs
GUIWrongWay.cs 反方向跑时弹出的
四、使图片全屏显示
GUIPanelFactory.Instance.CreateByWindowSpace(type, f, tex, 5, GUIFontCalculator.DEFAULT_GAP);
注意到显示图片的地方就有这个函数,实际上这个函数就是将tex贴图中我们需要的那部分图片截取出来(缩放)并且显示在屏幕上的。
type:类型
f:float[6]或者float[8],如果长度为6则没有缩放,则f[0],f[1]为图片左上角在屏幕上显示的坐标(横屏以左上角为坐标系原点,水平右方向为x正方向,垂直向下为y正方向)。(f[2],f[3])-(f[4],f[5])为在贴图tex文件中截取的区域,就是左上角到右下角的对角线。用ps打开,用添加参考线的功能就可以看出实际截图区域。
Dds格式的贴图可使用ps-dds插件打开,2345看图王也可以查看,但是按照坐标截取查图片时要将dds格式的图片垂直翻转过来,否则一眼看出就是反的
Float[8]的情况就是增加了缩放,(float[0],float[1])-(float[2],float[3])是在手机屏幕上显示的区域的对角线,相对于float[6]增加了2位,可以实现放大缩小贴图。(float[4],float[5])-(float[6],float[7])同样是贴图截取位置
有人想既然这个方法是负责显示所有图片的,那么只要改一个方法 让其适应屏幕宽高,不就一劳永逸了吗?结果是悲观的,还存在很多地方有问题,例如在批量显示时,每个图片之间的高度和宽度,还有有些水平3部分或垂直3部分的控件图片,就比较复杂。所以还是得慢慢查看源码,慢慢改。
例如
Guiloading类是负责显示刚打开游戏那个界面的,这里它获取了mainTex,就是
这是改后的代码,原来的代码是长度为6数组,没有f[2]和f[3]。
例如
要是我们把未修改的屏幕位置标出来,
就是图上用白线圈出,用红笔标记出的位置,由于操纵方式有3中,所以这三个位置的按键功能是不固定的,所以就采取了先定位,在动态切换功能的方式。要使这5个位置缩放到全屏,只需改一下代码就可以了。
不过,这只是贴图的位置全屏了,触摸的位置还是没有变。
接下来我们来改触摸位置。
五、使触摸区域自适应屏幕
一般来说,触摸区域和贴图位置都是绑定的,只有很特殊的情况才需要专门分析修改。但是这个左右漂移减速按键是特殊的。它们的触控区域代码在:IOSControler类(设置漂移和方向按键触控区域的类)中的一个字段的get和set方法里(真。大神才敢这么写,活久见)
把这么关键的代码放在一个set方法里面,真的让我瑟瑟发抖,工程师厉害了!
判断操控方式type的值,有三种,对应三种操控方式,同样我给它加上了自动适应屏幕缩放。
六、破解付费跑道
这个是顺便做的,主要精力在适应高分屏上。
c#:GUITrackListInSingle类InitializeListctrl() : Void函数,this.visibleAssets_.Add(item);删除if判断是否是付费的跑道,结果跑道全部显示,但是要钱的跑道为阴影且无法选择
c#:GUITrackListInSingle类InitializeTrackList() : Void函数,
if (definition.Lock)
{
nONE = (GUITrackListItem.enItemLockType) definition.LockType;
直接改成了等于GUITrackListItem.enItemLockType.NONE
}
意思是在加载跑道列表时,不去判断是否跑道锁定或要钱,结果跑道没有阴影了但还是无法选择
到这一步,可以看见跑道,但是付费的就是无法选中,真的很急人。没事,让我们分析一下这个跑道类结构。
GUITrackListInSingle类是一个list类,list中的item类对应GUITrackListItem类,item被选中,最后发消息给list类,由list负责处理。
所以,关键验证核心代码在GUITrackListInSingle类的ReceiveMessage()方法中,注释掉就可以了。
付费的车辆和人物都是同样的list-item结构,破解的方法也是类似的,就不废话了。
七、拾遗
6、 GUITrackListInSingle类的方法
protected override Rect GetAvailableRegion()
{
return GUIBase.ConvertWSToUS(12f, 78f, 458f, 474f);将474f改为(float) Screen.height
}
7、 GUIControls类是管理在进行比赛过程中打开菜单选择gui操纵方式控件的,例如左右方向键和漂移按键,减速按键等
8、 对于CreateByWindowSpace(Int32, Single[], FiaTexture, Int32, Vector3) : GUIPanelEx
函数,在single数组为6的情况下,single[0] single[1]代表图片左上角在手机屏幕上的起始位置点坐标(以屏幕左上角为坐标系原点,确定),(single[2] ,single[3])和(single[4],single[5])代表在贴图资源上截图的矩形的对角线(似乎都要统一减2才准确,可能是系统偏移修正)。
在single数组长度为8的情况下,前四位数代表屏幕上显示的区域对角线两点的坐标(可以比图片实际大,会自动缩放填满),后四位仍然是贴图资源截取位置
12、 修改GUIIPad类的srtart()方法的this.panels_[24].SetTouchRegionByWindowPos((702f * Screen.width) / 800f, 0f, (float) Screen.width, (82f * Screen.height) / 480f);
使暂停触摸区域适应屏幕
13、修改数组layoutArray1[0-23]的前两个浮点数,使右上角计时面板位置自适应屏幕
14、GUIIPad类中的awake()方法给this.controlInfo赋值,这个this.controlInfo[5]就是屏幕下方最多5个按键的图片显示位置坐标,前4位是左上角和右下角的坐标,我修改成根据屏幕大小缩放图标
15、修改GUIIPad类的awake()和start()方法,使操纵按钮图标显示自适应屏幕缩放,修改iOSController类中的type字段的set_Type方法,使操纵按钮触摸位置自适应屏幕缩放。
16、class MinimapCameraControl类中修改小地图的位置
17、GUIMode类是控制最上方按钮栏的,不管在哪个GUI界面都控制
18、GameLoadingBack和GameLoadingStage类是管理选择跑道点击开始后的载入界面的。
最后的最后,想下载的:
链接:https://pan.baidu.com/s/1geWmnPT 密码:1ms1