作者 | 孙景卫

责编 | 郭   芮

如何在短时间内成为Python工程师?

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

最近流行玩《魔卡幻想》,作为一名手游测试人员,于是申请了一个号码,取名“大头包子”。闯关、打塔,打了一个多月,只有一张五星黑龙,很是悲催。于是花了40两银子在某宝上买了一个天使开局,附送了一个凤凰号。

所谓天使、凤凰,就是其中两张比较厉害的五星卡牌,如下图所示:

左:天使,我的最爱;右:凤凰

所以,我现在就有了三个号码:一个开局号,一个天使号,一个凤凰号。虽然说,手游本身不太花费时间,但三个号一起玩,就很费时间了,而且和其他手游一样,魔卡也有一个很“变态”的设置,就是有些行动,你必须间隔10分钟或者1个消失才能执行一次,每天中午事儿点和晚上十点还有“魔神入侵”的活动,然后在魔神被打死前,你需要每隔3分钟打一次魔神,才能获得足够的金币奖励,这样你就不能花五分钟玩完游戏,然后放手去做其他事情。也就是说,你必须每隔一段时间上去看看,很是神伤。

另外,魔卡高级卡牌的获取有三种方式,一种是魔卡碎片换取,一种是晶钻兑换,一种是刷塔(反复的对指定的关卡进行通关)。不管你是不是RMB玩家,不管你是大R还是小R,或者是如我之辈的非酋玩家,换取高级卡牌都是很考验人品的,有人说洗漱好之后获得五星卡牌几率高,有人说,晚上六点到六点十分几率高,有人说贴吧爆照第二天会出五星,所以,十分的纠结,魔卡的五星卡牌发放到底是什么样的规则呢?

总结一下,问题有二:

  • 费时间:玩多个号、每天刷塔,耗费时间,而且需要你一直惦记着;

  • 运行机制搞不清楚:高级卡牌靠人品,不免想起,魔卡到底是怎么工作的呢?

遭遇困境,尝试反编译

想搞清楚魔卡到底是怎么工作的,第一个,很自然的想法就是反编译。对Android程序更熟悉,所以,试着反编译Android版本的apk。

我们知道android的安装文件.apk实际上是一个压缩包,所以将你下载下来的魔卡幻想的apk文件后缀改为zip并解压(我放置在D:\works\mokahuanxiang\下面),得到如下文件:

先看第一个文件夹,assets下面有两个文件夹,一个是卡牌的底图,一个是符文的底图,如下:

apk解压后的卡片底图,可以看到天使也在其中

apk解压后的符文图片

其他几个文件对我们用处不大,我们关注的代码都放置在classes.dex里面,游戏逻辑应该都写在里面了,不过classes.dex是经过Google制定的一种可以在android dalvik虚拟机上运行的格式,要查看里面的内容,先用dex2jar转换一下格式,命令行模式下运行:

dex2jar classes.dex

会生成classes_dex2jar.jar,这个jar包就可以利用jdgui来反编译。进入jdgui文件夹双击jd-gui.exe,打开上面生成的jar包classes_dex2jar.jar,即可看到源代码了,代码如下图:

反编译后的Java代码

至此,大功告成!但深入去看的时候,找遍了所有的代码,发现竟然完全没有逻辑代码,比如卡牌强化是如何强化的?魔神是如何的?盗贼是什么情况下出现的?......纠结呀,那么逻辑代码都是写在哪里的呢?

反编AIR,柳暗又花明

可以看到,dex2jar的文件夹下面有一个shanks.flash.ane的类,ane即Adobe AIR Native Extension,因为Adobe AIR是跨平台的,Mac、Windows、Android、iOS都能运行,但也有其局限性,比如在Android上面,AIR就无法调用Android系统级别的API,比如摄像头、系统通知等。

如果想做类似的事情,就需要先用Android写一段本地代码,让AIR和这段代码通信,进而完成类似的工作,这也就是魔卡游戏的总体工作机制。

如下图所示:

魔卡游戏架构图

所以,大胆猜测,大部分游戏逻辑是写在Adobe AIR层的。据百度百科,AIR是针对网络与桌面应用的结合所开发出来的技术,可以不必经由浏览器而对网络上的云端程式做控制,这样的优势,就是跨平台,主要的逻辑代码无论在Android上还是在IOS上,甚至在Windows Phone上都是一致的。在每个平台上,只要实现对应的系统API即可,这也是为什么,魔卡的账号体系在iOS上和Android上是统一的,不像某掌门游戏。

既然确定,游戏逻辑写在AIR层,于是开始找对应的实现文件,终于发现了:

找到逻辑代码所在处

得到了Cardmain.swf文件,在浏览器下直接打开看看,没有任何反应,只是白屏,怎么办呢?再来反编译,使用业界出名的硕思闪客精灵进行反编译试试,安装了一个企业版,打开这个swf文件,经过“漫长”的等待,终于,结果出来了。可以看到,游戏界面主要的形状、图像、音频、视频以及关键的动作脚本都是在这个swf文件里面的。

反编译后的Cardmain.swf文件

点开对应的额动作复选框,查看对应的脚本代码。其中有几个关键的文件和目录,其中一个是URLconfig文件,是记录的所有的客户端命令所对应的服务器指令地址,比如:

这个card.php?do=GetAllCard就是用来获的指定用户的所有的卡片的信息的,后面还有很多:

反编译的UrlConfig文件

核心逻辑代码写在这里:

魔卡核心逻辑代码

以卡牌/符文强化为例,每张卡牌都对应着一定的升级金币和经验点数,每张符文也有对应的经验点数,这是每张卡牌固有的属性。当你升级的时候,是将被升级卡牌的金币和经验乘以一个系数进行累加,然后再计算被升级卡牌、符文的升级情况的。

具体代码片段如下:

可以看到,一星卡牌的升级系数是0.6,二星卡牌是0.7,以此类推,也就是说,如果你吃三星卡牌,那么你将损失20%的经验,如果你吃五星卡牌的话,那么经验点将完全不会损失哦。不过又有几个非大R玩家能富裕到舍得吃五星呢......

当然,里面还有很多其他秘密,待你去发掘。

90%的程序员学Python这么认为:

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

协议分析,自动打迷宫

到目前为止,我们了解了魔卡的架构,还有一些底层的实现。我们知道,主题的逻辑是通过AIR来和服务器进行交互,所以,大部分命令都是server端完成的,那么,很自然想到分析一下协议,使用大名鼎鼎的wireshark软件抓包。但是,魔卡幻想是个手机游戏,想要抓手机给服务器端发包,怎么做呢?可以用模拟器来做。

大家知道BlueStacks本身就是一个Android模拟器,这个模拟器运行在我的Windows操作系统之上,那么,我在BlueStacks上玩魔卡幻想的时候,所有的命令包都会通过我操作系统的网卡发送出去。所以,利用wireshark抓取Windows上的数据包,也就能够抓取到魔卡幻想给其服务器端的数据包了。

我们先看一下,打一个迷宫大致的数据流如何。我现在在末日之塔,也就是7塔,第四层的最后一个怪,先在BlueStacks上进入这个状态,然后打开wireshark开始抓包,打怪,结束后停止录制,查看wireshark上的信息。

记录的网络通信包如下图所示。因为wireshark记录了所有的网络交互,所以,我使用一个Filter来过滤我们所关注的数据包,filter为:

http && (ip.dst == 116.90.81.139) || (ip.src==116.90.81.139)

这句话的意思是,过滤掉HTTP协议的中目标地址为116.90.81.139或者源地址为116.90.81.139的协议包,其中116.90.81.139为魔卡幻想的web server。可以看到,其实每次打一个怪,相当于给服务器发送了一个POST命令!而POST的数据内容为“manual=1&MapStageId=7&Layer=4&ItemIndex=13”——这句话什么意思呢?Manual=1,代表自动战斗,MapStageID=7,代表我打的是第7个塔,也就是末日之塔,ItemIndex=13是什么意思呢?为什么是13呢?暂时搞不清楚。

再刷几个怪对比一下数据。我们发现,每进入一个楼层的时候,服务器端会返回一个本楼层的一个基本信息。末日之塔第四层的信息如下:

{"status":1,"data":{"Name":"\u672b\u65e5\u4e4b\u5854\u7b2c4\u5c42","BoxNum":2,"MonsterNum":2,"RemainBoxNum":2,"RemainMonsterNum":1,"Layer":4,"TotalLayer":5,"Map":{"IsFinish":false,"WallRows":[0,0,0,1,0,0,0,0,1,1,1,1,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0],"WallCols":[0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,0],"Items":[1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,3,1,1,1,1,6,1,4,6,1,1,6,1,1,1]}},"version":{"http":"201302090","stop":"","appversion":"version_1","appurl":"ios:\/\/xxx"}}

其中Name字段是unicode编码,然后用gb2312编码打印出来,"\u672b\u65e5\u4e4b\u5854\u7b2c4\u5c42" 就是“末日之塔第4层”,后面的字段顾名思义,重点说一下Items字段。

我们发现,"Items" : [1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,3,1, 1,1,1, 6, 1 , 4, 6, 1,1,6,1,1,1 ] 共28位,我们调整一下格式:

[1,1,1,1,1,1,1,5,
1,1,1,1,1,1,1,1,
1,3,1,1,1,1,6,1,
4,6,1,1,6,1,1,1]

再和下图对比一下:

你会发现,这个Items字段中,1代表普通方块,5代表是向上的楼梯,4代表向下的楼梯,6代表已经被打掉的宝箱或者怪物,同理可以分析,2代表宝箱,3代表怪物,然后indexitem就是方块的索引!

这样,我们自动打塔的思路就确定了:

先获得每一层的信息,然后分析一下这一层的怪物和宝箱的情况,得到对应的indexitem,然后再POST给对应的server就可以完成了,上代码:

其中maze_info返回的是一个指定地图和楼层的json格式的信息,我使用exec将其转化为一个dict对象,然后获得其中的Items字段,如果这个字段是2或者3的话,我就去打,最后再打去楼上的楼梯口,很简单吧。

具体如何打的呢?请看maze_battle函数:

关键是我们的PostMessage函数,最终都是通过这个函数组成特定的魔卡服务器能识别的HTTP协议包,利用Post命令发送出去。

发送的HTTP协议包的内容为:

POST /maze.php?do=Info&v=9945&phpp=ANDROID&phpl=ZH_CN&pvc=1.2.0&pvb=2013-04-16%209%3A18%3A23 HTTP/1.1
Host: s9.mysticalcard.com
Accept-Encoding: identity
Content-Length: 20
Accept: text/xml, application/xml, application/xhtml+xml, text/html;q=0.9, text/plain;q=0.8, text/css, image/png, image/jpeg, image/gif;q=0.8, application/x-shockwave-flash, video/mp4;q=0.9, flv-application/octet-stream;q=0.8, video/x-flv;q=0.7, audio/mp4, application/futuresplash, */*;q=0.5
User-Agent: Mozilla/5.0 (Android; U; zh-CN) AppleWebKit/533.19.4 (KHTML, like Gecko) AdobeAIR/3.6
Connection: Keep-Alive
Cookie: _sid=qjl7qn8js501756f57lrevet55
Cache-control: no-cache
Content-Type: application/x-www-form-urlencoded
Refer: app:/assets/CardMain.swfLayer=2&MapStageId=5

使用Python的urllib库来进行HTTP协议发送,另外,由于server端可能返回gzip格式的数据内容,所以需要利用Python的gzip库对gzip格式的返回数据进行解码。

这样,刷塔的程序就大致成型了。

最终,你只需要两行代码就能完成刷塔工作了:

这两句话的意思是,我新建一个魔卡幻想的对象,然后刷第五塔的一二三四层!搞定。

再举一个简单的例子,就是对某个地图进行探索,返回信息。下图为我进行一次探索的运行截图,我对编号为44的关卡进行探索,获得了740点经验,1280个金币,以及一个8号魔幻碎片。

探索地图协议流

探索地图获得奖励

除了自动打地图、自动探索外,你可以利用协议做更多的事情,比如每隔10分钟获取一次盗贼,如果有盗贼,则挑选级别最高的打。再比如每天中午12点魔神入侵的时候,你每隔3分钟打一次魔神,这样会累积比较高的积分,也不用你总是惦记着打魔神这回事了。

登陆破解,大江已东去

上文中,利用HTTP协议进行自动打塔,有一个关键的地方没有说明,就是登陆。魔卡幻想本身具有自动登陆的功能,其实现的原理就是利用Cookie信息,如果你发送HTTP请求的时候,HTTP头携带了Cookie字段,而且Cookie字段和你最近登录一次的设备匹配的话,那么就不需要重新登录,而可以直接进行一些对应操作了。

魔卡对Cookie信息的处理流程大致是,如果你发送过来的Cookie信息在我的server端有记录,而且最近登录设备匹配的话,那么我就返回给你所有你需要的信息。这样,如果你有一个账号,只在一台设备上登录的话,那么你可以一直用这个Cookie,但是如果你有多个账号的话,则需要一个手动登录账号的过程,非常麻烦,能否进行自动登陆呢?

那么我们就来看一下魔卡的登陆是怎么做的吧。

继续抓取登陆的时候的协议,如下图所示,即给login.php?do=PassportLogin发送一个POST命令,POST的消息体内容为Devicetoken=&time=1371305578867&key=7a370df34c5fddd1f1c6ee9d6279d7da&Origin=TTGW&Udid=3D%3ABF%3A4A%3A6A%3AC0%3A7D&UserName=qqqaaagsr&Password=1000616820。其中Devicetoken为空,time为自Epoc以来的秒数,key这个东西,猜测是用来做验证的,比如验证cookie,uid等是否是一致的。Udid是设备的唯一标示信息。UserName是我的账号名,password=1000616820,这个是经过加密之后的密码。

试着直接将UserName改成我另外一个好的用户名,发送POST信息,得到一个错误“passport\u7b7e\u540d\u9a8c\u8bc1\u5931\u8d25!”,意思是:“passport签名验证失败!”。猜测玄机在key上,其应该是用来验证Udid、UserName和Password的一致性的。

魔卡登陆协议包抓取

但是,这个key是怎么生成的呢?猜测是在登陆页面生成的,同样利用反编译,找到其登陆界面的网址:http://pp.fantasytoyou.com/pp/start.do?udid=3D:BF:4A:6A:C0:7D&locale=CHS&gameName=CARD-ANDROID-CHS&client=flash,这样就可以在Chrome中打开了:

在Chrome中打开登陆界面

邮件查看源码,发现其主要的登陆逻辑都是写在“http://d.muhecdn.com/pp/V20130528/js/startHttp.js”这个JS脚本里面的。时间关系,这个登陆的破解暂时还没有搞定,服务器端总是提示Passport验证错误。

经过一段时间探索,自动登陆终于搞定了。魔卡的服务器主要有两个,第一个是业务服务器,host为s9.mysticalcard.com,绝大多数的业务操作、日常事务都是和这个服务器交互完成的,还有一个是登陆验证服务器,host是pp.fantasytoyou.com,是专门进行用户登陆的验证的。

所以,登陆共分为三步:

第一步,先给业务服务器发送一个GET请求,进入登陆界面。包主题内容为:

GET /pp/start.do?udid=3D:BF:4A:6A:C0:7D&locale=CHS&gameName=CARD-ANDROID-CHS&client=flash

返回的即是登陆界面。

第二步,将用户名、密码、设备标识信息发送给验证服务器,获得密钥。包主体内容为POST  /pp/httpService.do,POST的内容为:

{"serviceName":"login","callPara":{"userName":"qqqaaagsr","userPassword":"password1","gameName":"CARD-ANDROID-CHS","udid":"3D:BF:4A:6A:C0:7D","clientType":"flash","releaseChannel":"","locale":"chs"}}

返回的信息(密钥)如下:

{"returnCode":"0","returnMsg":"No error.","returnObjs":{"GS_NAME":"server9","GS_IP":"http://s9.mysticalcard.com/","friendCode":"null","GS_PORT":"80","timestamp":"1372814484134","GS_CHAT_PORT":"8000","source":"qqqaaagsr","userName":"qqqaaagsr","GS_DESC":"","U_ID":"1000616820","key":"b1ddb0dd6c2ab73ff1b5cb84b2c9d465","G_TYPE":"1","GS_CHAT_IP":"116.90.81.139"}}

第三步,利用上述返回的信息进行登陆,在业务服务器上的login.php进行登陆,包主体内容为:

POST /login.php?do=PassportLogin&v=3539&phpp=ANDROID&phpl=ZH_CN&pvc=1.2.0&pvb=2013-04-16%2012%3A46%3A54

POST的消息体为:

Devicetoken=&time=1372814484134&key=b1ddb0dd6c2ab73ff1b5cb84b2c9d465&Origin=TTGW&Udid=3D%3ABF%3A4A%3A6A%3AC0%3A7D&UserName=qqqaaagsr&Password=1000616820

登陆成功。

其中,登陆能否成功,上述的三个蓝色字段是关键字段,其中timestamp是个时间戳,验证的时间戳必须和登陆的时间戳为同一时间,key是验证服务器生成的一个类似MD5的数值,要伪造不太可能,只能通过截取转发的方式来记录,而U_ID字段,则是在登陆的时候作为Password这个参数的值传递给server的。

最终的效果为:

这段代码既可完成对我三个账号的第8塔的1~5层进行刷塔。

作者:孙景卫,运营个人公众号老铁开花,IT行业资深从业者,拥有十余年技术实战经历,之前任职于百度、网易等多家上市公司。具备管理大型项目经验,管理上百人团队,目前就职于某互金公司,担任高级技术总监。

声明:本文为CSDN原创投稿,未经允许请勿转载。欢迎通过以下方式联系投稿。


 热 文 推 荐  

淘宝、飞猪、闲鱼都挂了,阿里云却正常?!

☞ 阿里布局物联网!开源操作系统 AliOS Things 喜提 1 亿芯片出货量

☞ 阿里战微信!20 亿元扶持小程序开发者

☞程序员版的《小王子》,过于真实!

前阿里 P9 级员工称离婚是模拟测试,已回滚复婚!

要钱还是要命? 比特币正悄悄杀死你...

没有新芯片,没有大核弹,黄教主这次给大家带来了个PRADA

刚刚,数学界“诺奖”Abel Prize迎来首位女性得主

曝光!月薪 5 万的程序员面试题:73% 人都做错,你敢试吗?

System.out.println("点个在看吧!");
console.log("点个在看吧!");
print("点个在看吧!");
printf("点个在看吧!\n");
cout << "点个在看吧!" << endl;
Console.WriteLine("点个在看吧!");
Response.Write("点个在看吧!");
alert("点个在看吧!")
echo "点个在看吧!"

点击阅读原文,输入关键词,即可搜索您想要的 CSDN 文章。

喜欢就点击“在看”吧!

国家认证的Python工程师有哪些能力要求?

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

程序员如何从技术上“开挂”魔卡手游? | 技术头条相关推荐

  1. 从程序员小仙飞升上神,java技术开发要如何实现?

    新霸哥是一个专业从事java开发的,近期,新霸哥发现很多的朋友在问,从程序员小仙飞升上神难吗?在此新霸哥将为你详细的介绍,下面新霸哥将从新手入门和老司机进阶多方面详细的为大家介绍一下. 说起java首 ...

  2. 好程序员分享大势所趋 HTML5成Web开发者最关心的技术

    为什么80%的码农都做不了架构师?>>>    好程序员分享大势所趋 HTML5成Web开发者最关心的技术,最近,在Stack Exchange上出现了一个比较热门的问题:Web开发 ...

  3. 有人晒出程序员聚餐照片,网友:根据头发量能看出技术水平高低!

    有人晒出程序员聚餐照片,网友:根据头发量能看出技术水平高低! 关于程序员的头发一直是网友们爱调侃的一个话题,说什么程序员容易秃顶,这样的话题被大家聊得很热,甚至有人还拿出一组程序员工作一年,三年,五年 ...

  4. 跳出打工圈!程序员要如何走上创业逆袭路,获得百万、千万?

    作者 | 闫辉           责编 | 屠敏 出品 | CSDN(ID:CSDNnews) 程序员的尽头是什么? 有人说,程序员尽头就是不做程序员. 那么,不做程序员又能做什么? 每当打开网络上 ...

  5. 程序员要如何走上创业逆袭路,获得百万、千万?

    程序员的尽头是什么? 有人说,程序员尽头就是不做程序员. 那么,不做程序员又能做什么? 每当打开网络上发布的十大高薪职业排行榜时,不出所料,总是会有一个身影映入眼帘,那就是--程序员.然而,在创富这条 ...

  6. 程序员岗位介绍,我爬取了拉勾网所有技术岗位工资数据,算法工程师平均薪资高达2W

    点击观看视频 ↓↓↓ 程序员岗位介绍,我爬取了拉勾网所有技术岗位工资数据,算法工程师平均薪资高达2W 文字版 大家好,我是宁一,一个多月没有更新视频了,这一个多月我都在准备一个店铺商城的云开发小程序项 ...

  7. 浏览器崩溃_字节跳动程序员28岁身价上亿,财务自由宣布退休;微软最新系统再迎“喜报”:更多用户的浏览器开始崩溃...

    新闻1:字节跳动程序员28岁身价上亿,财务自由宣布退休 最近字节跳动前员工郭宇火了. 原因是他在今年二月份发了一条微博.大概是说他在28岁的年纪实现了财务自由,然后选择了退休. 郭宇本来是字节跳动的一 ...

  8. 一个程序员如何做到结构上胸有成竹

     我们做网站一直都是小开发,没什么复杂度可言,那么如果做大项目,会遇到什么问题?纵向剖析,做到结构上胸有成竹. 理清"接口--测试--伪代码--GTD编程"这样(或与之相近的) ...

  9. [推荐] 一个 Node.js 技术选型案例:使用 CARMEN 作为卡牌手游技术栈

    作者 @超人张宝胜 ,原文地址:https://zhuanlan.zhihu.com/p/103724412,如需转载请联系作者授权. 前言 本文介绍了在资金.人员.时间上全面告急.云服务提供商不确定 ...

最新文章

  1. 深度学习之输入通道个数、卷积核通道个数,卷积核个数、输出通道个数的关系
  2. 公平与精确同样重要!CMU提出学习公平表征方法,实现算法公平
  3. 简单理解:同步、异步、阻塞、非阻塞
  4. 使用etcd的proto文件生成编译etcd client v3的c++客户端代码
  5. 诺奖技术和高通量筛选双双找到新冠病毒的脉门
  6. jemter的竞品分析
  7. 深度学习笔记(37) 交并比
  8. 女生长胖是一种什么样的体验?
  9. [LibTorch] C++ 调用 PyTorch 导出的模型
  10. Android studio 升级指定dradle
  11. 计算机的组成 —— 磁盘阵列(RAID)
  12. 人工智能机器学习笔记 10月10日
  13. SublimeText集成印象笔记插件简略步骤
  14. 一木.溪桥---Python之简介、环境搭建、PyCharm配置
  15. Android中屏蔽返回键,HOME键以及模拟HOME键返回效果的方法
  16. vue3 script setup写法
  17. 计算机网络网卡作用是什么,什么是网卡?它的作用是什么?
  18. git一直输入用户名和密码的解决方法remote: HTTP Basic: Access denied fatal: Authentication failed for
  19. Adversarial Semantic Alignment for Improved Image Captions
  20. CF 1646C Factorials and Powers of Two

热门文章

  1. linux 查看端口战役,漫画 :Apache Nginx80 端口争夺战
  2. mysql 5.5主从同步_MySQL 5.5主从同步
  3. redis笔记5 stream消息队列
  4. 中国速度袋行业市场供需与战略研究报告
  5. 2021年中国一次性弹性泵市场趋势报告、技术动态创新及2027年市场预测
  6. 传感器贴片行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  7. Spring Boot Serverless 实战系列“架构篇”首发 | 光速入门函数计算
  8. android dialog 点击遮罩 关闭_如何用构建者模式打造自己dialog
  9. 清华硕士分享思维导图:机器学习所需的数学基础
  10. 还在 Bug 不断?不妨试试这 2 个装X技巧