因为顽石吴刚的推荐而最近大火的Android手游“小小帝国”,我也下载下来玩了几个小时,并且瞬间就在里面消费了50元人民币。游戏整体感觉还是不错的,当然作为技术人员,对于一个新东西除了欣赏它的表面之外,更感兴趣的还是它背后的实现。
需要说明的是,这里只有对这个游戏实现方法的分析,作为自己开发的借鉴,不涉及破解内容。同样是一名游戏开发者,深知游戏开发的艰辛,也不希望看到游戏破解的存在,更希望这个市场能够更美好。
首先想看看这款手机网游的网络部分,在Android上抓包分析也还是挺方便的,使用的工具是Shark,如果想在手机上浏览数据包还可以再装上Shark Reader,不过因为手机屏幕与操作的问题,最终还是在Windows平台上使用的Analyzer,一款开源的抓包及分析工具。注意在使用Analyzer的时候需要先安装WinPcap,这个软件就不用多介绍了,Windows平台下做数据包分析的必备。
通过几次简单的进入退出与操作的sniffer,对这个游戏与服务器交互的大致流程有了个了解。
1. 服务器部署在amzon aws上,本地先请求解析dns 179.87.32.176.in-addr.arpa,返回ec2-176-32-87-179.ap-northeast- 1.computer.amazonaws.com,之后再解析这个地址,这台服务器提供玩家数据服务,监听在80端口. 另外一台游戏服务器为ec2-46-51-239-9.ap-northeast-1.computer.amazonaws.com,提供游戏逻辑处理 服务,监听在8200端口。
2. 服务器使用ngix 0.8.54,http server,使用JSON数据格式,部分客户端发往服务器的数据经过了加密,服务器下发的数据全部都是明文,且未压缩。
3. 游戏的地理位置信息使用maps.google.com的服务来实现,每次进入游戏后会主动获取一次当前位置信息并向google查询该位置的详细信息。 之后如果要攻击其他玩家,会根据两个人的实际距离来计算需要等待的时间,这也仅仅只是游戏介绍里的LBS所具有的唯一功能,有点小失望。
4. 目前只看到六个api: login, account, building,visit, attack和friend,分别在进入游戏、发送本地帐号数据、操作建筑单位、访问其他人的城市、攻击其他玩家和获取好友列表信息时使用。之前在购买道 具的时候没有sniffer,后来也没打算为了sniffer再花一次人民币。login api实现在176.32.87.179服务器上,其他api实现在46.51.239.9服务器上。
5. 目前游戏的消息或者叫api设计稍微有些不合理。游戏一开始的时候使用login api从服务器上获取所有的数据,包括自己的信息,已经添加过好友(包括对方还没有通过的玩家)的所有信息,大概有50多个1488字节的数据包,共计 70多K。当操作建筑单位的时候,也会把整个完整信息发一次,同样的,攻击、访问好友列表等操作都是,消息设计的太冗余。很多信息可以在使用到的时候再请 求,还有一些消息可以拆分成多个,不需要每次都发完整的大包。
6. 从目前抓包的情况下看,登录时的验证过程很简单,并且看起来是透明的,是否存在被恶意攻击的情况。
登录时客户端发送两个明文包之后,服务器就会回应完整的游戏信息,即那50多个1488字节的数据包,也是明文。这两个请求包内容为:
/api/login?s_s=0&v=1.5.1&s_url=http://176.32.87.179/api/&a=q
{“model”:”Nexus One”,”lang_c”:”zh”,”devi_id”:”35495703168***”,”vt”:”1″,”cou_c”:”CN”,”finger_p”:1330579205583,”cv”:”26″,”password”:”****”,”key”:”3066***”}
我把其中的devi_id、password和key做了一下隐藏。因为没有实际尝试,所以不是很清楚是否存在这样的可能性:某个恶意玩家或者竞争 对方就只需要不断伪造这两个POST数据包发到服务器,服务器的带宽很有可能会被占尽,或者至少需要为此支付很大一笔带宽费。当然这可以在防火墙上做一些 策略来避免,或者程序内部限制login频率。
7. 目前看起来account api是用来向服务器提交本地数据用以验证。在每次进入游戏后客户端都会请求一次account api,在之后的游戏过程中偶尔也会有。因为上传的数据进行了加密,不清楚具体内容,但是返回的数据是明文,比如某次返回的可能是这样:
{“user_account”:{“icon”:0,”lon”:121.3929507,”status”:0,”addr”:”Minhang, Shanghai, China”,”sign”:”gggggg”,”level”:6,”email”:”[email protected]”,”token”:”371a5453-0b47-4d25- b593-d8b841a41f09″,”reg_f”:true,”name”:”白云哥 哥”,”cou_c”:”CN”,”la_log_t”:1330525373242,”key”:”3066***”,”lat”:31.170099,”tut_f”:true},”success”:true}
其中的token在后面调用其他api时都要提供,估计相当于鉴权用的令牌。有的时候在success之后还会带上p_rew信 息:cr_left:90, g_left:900, m_left:300。这些数值对应着当前的水晶数、金币数和魔豆数。也就是说有可能在account验证之后服务器认为客户端本地的数据不正确或者不合 理,返回一个服务器端的正确数据。
因为在游戏过程中,本地可以获取一些金币等资源,这些都是客户端计算,而且并没有向服务器验证。如果上面的猜测正确的话,那这里必须有一个服务器容忍度的问题,也就是说客户端上报的数据可以大一些,即有作弊的可能性。
8. 关于客户端上报数据的加密,在android手机sdcard/.camelgames/.fantasy/目录下有以用户key为文件名的配置文件,里 面记录的一段数据疑似RSA公钥。有可能服务器采用的是RSA加密,客户端保存的是公钥,而且在每台设备上都有这个公钥,所以服务器下发的数据即使加密, 其他人也能够用自己手上的公钥将其解密,所以不如不加密。另外服务器下发的数据量都比较大,RSA加密算法太过于复杂,解密需要花费较长时间。
然后是客户端部分。
解开apk文件,里面比较干净,只有一个libfantasy.so,从里面的导出函数里没有见到一些广为人知的开源3D引擎的名字,应该是自己写 的。res/raw里的.jet文件是3D模型,打开看了下,文件头MS3D表明这应该是MilkShape 3D的文件格式,下载了MilkShape 3D程序安装后,将.jet后缀改为.ms3d果然能够直接打开。
最大的模型文件是城市的大地形:
从游戏中摆放建筑物时的操作也能看出来,实际游戏还是以2D方式实现:
中间的摆放区域以tile块的方式呈现,从服务器发下来的数据也能大致了解到,每个建筑物所占的tile块坐标等信息。
战斗场景就是完全的2D表现,包括地形与角色:
角色使用类似植物大战僵尸那样的拼接方式生成,类似于中国古代的皮影戏。从资源文件里能够看到:
然后是模型贴图部分,做的比较好,所有的模型加在一起只使用了一张1024*1024的jpg贴图,这对于渲染优化是非常有利的。另外还有一张512的png贴图,应该是带alpha通道的。
总体来说,这个游戏的制作还是不错的,除了个人认为服务器部分的技术应该还要加强一些,目前最大的问题是带宽占用太大,不开wifi基本不敢玩。另 外从游戏内容上来说,玩家间的互动也可以再加强,当然这受限于平台的操作便利性,不一定能做的像PC平台上那么好,但至少不应该像现在这样,只是吵了个 LBS的名字,实际上与地理位置信息并没有太大的关联性。