本帖最后由 puluter 于 2017-2-9 15:03 编辑
第一次发帖就得到这么多朋友的认同 感谢各位啦qwq
php代码部分写的比较乱 变量名随手设置的,想要仔细分析的私聊我下吧
-------------------------------------------------------------前两天下了个游戏,名字叫做“咚嗒嗒部落”。
感觉还挺好玩,然后就忍不住尝试去破解一下。
解压游戏的安装包,用Android Killer分析了一下,发现这是个Unity写的游戏。
Unity的游戏肯定要找找Assmbly-Csharp.dll啊,于是把它丢进refelector。
开发者不用心啊,代码都不混淆,于是试着找点有用的东西。
这期间试着把关卡冷却时间调成0,本地上成功了,但是服务器端还有另一层冷却验证,冷却时间只能不了了之。
又更改了英雄的攻击,结果一进入战斗页面就闪退= =
可能是我改得不好,反正通过改dll我得不到什么好玩的东西。
想了想,干脆做个挂机的软件吧。
于是用fiddler抓了包,进行了相关的分析。
抓包的过程不详细写了,就把分析的结果贴上来吧。
这个游戏在登录时会向121.199.54.144:101发包,结构如下:
[PHP] 纯文本查看 复制代码 121.199.54.144:101 /default.ashx?
MsgId=2
Sid=
Uid=0
St=
actionId=1004
Handler=Login
MobileType=1
PassportId=puluter
Password=密码屏蔽下qwq
DeviceID=android-0fa7fe268b41e6082c4489537992e698
RetailID=0000
RetailUser=
sign=251b5ed2598d668a876ee812c83c0935
然后服务器会返回一个token和一个UserID,结构如下。
[PHP] 纯文本查看 复制代码 {
"StateCode":0,
"StateDescription":"",
"Vesion":"1.0",
"Handler":"Login",
"Data":
{
"Token":"04cfe4f03****7b4a42f38475cda862f",
"PassportId":"puluter",
"UserId":114364,
"UserType":0,
"IsGuest":false
}
}
这个部分主要是获取UserID。
然后会向主服务器(121.199.54.144:81)索取其他服务器的名称和IP地址。
[PHP] 纯文本查看 复制代码 121.199.54.144:81/Service.aspx?d=MsgId%3d4%26Sid%3d%26Uid%3d114364%26St%3d%26actionId%3d1001%26GameID%3d1%26Pid%3dpuluter%26sign%3d80f97b67d3a4c0d15456baf3f03092e3
分析↑这个包,我们会发现,其实这个包信息部分是“d=”后面的那一块,一眼看出这是Urlencode,我们解码来看一下。
解码后的结构如下:
[PHP] 纯文本查看 复制代码 MsgId=4
&Sid=
&Uid=114364
&St=
&actionId=1001
&GameID=1
&Pid=puluter
&sign=80f97b67d3a4c0d15456baf3f03092e3
MsgId我在一开始还以为要严格保证递增= =实际上MsgId是多少无所谓。
Uid是上面获取到的UserId。
然后比较麻烦的就是这个sign了。
可以发现这个sign是一个MD5,经过一些尝试发现这个MD5和前面的请求有关,那它到底是怎么加密的呢?
这个时候我突然想起来还有个dll没有分析呢,发包加密方式肯定在那个dll里。
先搜索一下MD5,然后再analyze一下这个函数被怎么调用,发现如下代码:
关键部分是:
[C#] 纯文本查看 复制代码 s_strPostData = s_strUserData + "&sign=" + getMd5String(s_strUserData + s_md5Key);
sign的值是md5(前面的那些请求+s_md5Key).
这个s_md5key是什么东西?
再搜一搜,最后在netwriter类里找到了它。
所以我们现在得出,sign=md5(request+"123");
有了sign,接下来的事情就很简单了。
在得出sign之后,我们还需要Sid这个东西。它来自于与服务器的第一次交互:
[PHP] 纯文本查看 复制代码 /default.ashx?d=MsgId%3d27%26Sid%3d%26Uid%3d114364%26St%3d%26actionId%3d1007%26MobileType%3d1%26Token%3d461bd5efee****52914e5b73ebcfd504%26DeviceID%3dandroid-bd19f5ede3358bdff8ff0eadc425d524%26RetailID%3d0000%26sign%3d069d0b7c6af822fd903f5773713d867c
MsgId=27
&Sid=
&Uid=114364
&St=
&actionId=1007
&MobileType=1
&Token=461ed5ef*****552914p5b73ebcfd504
&DeviceID=android-bd19f5ede3358bdff8ff0eadc425d524
&RetailID=0000
&sign=1381204e9b30736fc3c45fcb7717a0dd
这个包的返回response里会含有Sid,我通过正则表达式获取它。
然后进入这篇文章的正题:刷关。
分析包得出,某个小关卡胜利前后,游戏会发送两个极为重要的包,分别是:
[PHP] 纯文本查看 复制代码 MsgId=36&Sid={$sid}&Uid=114364&St=&actionId=1068&BigLevel={$big}&SmallLevel={$small}&Difficulty={$dif}
[PHP] 纯文本查看 复制代码 MsgId=57&Sid={$sid}&Uid=114364&St=&actionId=1069
之前反编译的时候,其实还反编译出了一份action表:
[C#] 纯文本查看 复制代码
public const int AddCharacteristic = 0x44b;
public const int AddFish = 0x7d3;
public const int AddFriend = 0x3fe;
public const int AddGoldAndDiamond = 0x7d1;
public const int AddHero = 0x3f1;
public const int AddItem = 0x7d5;
public const int AddOrChangeHeroTotem = 0x3f4;
public const int AddOrChnageOrClearGod = 0x3f8;
public const int AddResources = 0x7d4;
public const int AddTotem = 0x7d2;
public const int BindPhone = 0x271d;
public const int BindVerificationCode = 0x271b;
public const int BuyComfirmedShop = 0x40c;
public const int BuyDiamond = 0x40b;
public const int BuySundryItem = 0x40e;
public const int BuyVip = 0x4b0;
public const int ChangeHeroFightQueue = 0x3f0;
public const int ChangeHeroName = 0x3f5;
public const int ChangePwd = 0x3ee;
public const int ChangePwdByCode = 0x271c;
public const int ChangePWDVerificationCode = 0x271f;
public const int ChangeRoleHeadImg = 0x3f9;
public const int CheckBaiDuPayment = 0x459;
public const int CheckPhoneBind = 0x271e;
public const int CheckUCOrder = 0x45a;
public const int CheckXiaoMiPayment = 0x452;
public const int ClickFriendSeed = 0x441;
public const int ComposeTotem = 0x3fc;
public const int CreateRote = 0x3ed;
public const int DeleteFriend = 0x400;
public const int DeleteMail = 0x41c;
public const int Diamond10Fishing = 0x418;
public const int DiamondFishing = 0x417;
public const int DiamondRefreashPVPTargets = 0x430;
public const int DirServer = 0x3e9;
public const int DismisseHero = 0x427;
public const int EatFish = 0x420;
public const int FreashSundryShop = 0x43c;
public const int FreeRefreashPVPTargets = 0x42f;
public const int GetAiBeIOrder = 0x456;
public const int GetAllInfos = 0x468;
public const int GetAnnouncements = 0x457;
public const int GetBossDoubleReward = 0x453;
public const int GetDailyTaskInfo = 0x437;
public const int GetDiamondShop = 0x40a;
public const int GetEventSysInfoDta = 0x432;
public const int GetFaith = 0x43f;
public const int GetFightEventSysInfoDta = 0x435;
public const int GetFishBag = 0x410;
public const int GetFishingInfoData = 0x416;
public const int GetForeverTaskInfo = 0x439;
public const int GetFriendRequests = 0x445;
public const int GetFriends = 0x3ff;
public const int GetGameInfo = 0x271a;
public const int GetGodChangeFaithData = 0x41a;
public const int GetHeapReward = 0x461;
public const int GetItemBag = 0x411;
public const int GetLands = 0x405;
public const int GetLoginIn7DaysInfo = 0x45b;
public const int GetMailBag = 0x41b;
public const int GetNotice = 0x450;
public const int GetOffLineReward = 0x428;
public const int GetPVPInfoData = 0x424;
public const int GetPVPTargets = 0x423;
public const int GetRecommendFriends = 0x442;
public const int GetResourcesBag = 0x40f;
public const int GetRewardInfos = 0x460;
public const int GetRiverGodTask = 0x412;
public const int GetRiverGodTaskExtReward = 0x414;
public const int GetRiverGodTaskReward = 0x413;
public const int GetRoleLandsInfos = 0x434;
public const int GetRolePVPQueue = 0x431;
public const int GetSignInfo = 0x409;
public const int GetSingleRechargeReward = 0x462;
public const int GetStrikeInfo = 0x42b;
public const int GetSundryShop = 0x40d;
public const int GetTotemDatas = 0x3fa;
public const int GetVIPInfo = 0x45d;
public const int GetVivoPayInfo = 0x455;
public const int GetWinpointRanking = 0x421;
public const int GodAddFaith = 0x27a7;
public const int GoldChangeFaith = 0x419;
public const int GoldFishing = 0x415;
public const int Harvest = 0x404;
public const int LifeCardUserDailyReward = 0x45f;
public const int LoginAccountServer = 0x3ec;
public const int LoginGameServer = 0x3ef;
public const int MiLoginServer = 0x2720;
public const int MonthCardUserDailyReward = 0x45e;
public const int OpenLand = 0x402;
public const int Passport = 0x3ea;
public const int PVPReward = 0x422;
public const int QQOrder = 0x458;
public const int ReceiveFriendRequest = 0x443;
public const int ReceiveMailReward = 0x41d;
public const int RefuseFriendRequest = 0x444;
public const int Regist = 0x3eb;
public const int RequestActiveCode = 0x463;
public const int RequestADDiamond = 0x465;
public const int RequestADGetFish = 0x467;
public const int RequestAdReward = 0x464;
public const int RequestADSeedOK = 0x466;
public const int RequestBossFight = 0x42c;
public const int RequestBossFightReward = 0x42d;
public const int RequestFight = 0x41e;
public const int RequestFightReward = 0x41f;
public const int RequestPVPFight = 0x425;
public const int ResourcesExchangeFaith = 0x429;
public const int RewardDailyTask = 0x438;
public const int RewardEventSysInfo = 0x433;
public const int RewardFightEventSysInfo = 0x436;
public const int RewardForeverlTask = 0x43b;
public const int RewardLevelTask = 0x43a;
public const int RewardLoginIn7Days = 0x45c;
public const int SaleResource = 0x3f6;
public const int SaleTotem = 0x3fb;
public const int SearchFriend = 0x3fd;
public const int SearchFriendPVE = 0x401;
public const int Seeding = 0x403;
public const int SeedSpeedUp = 0x440;
public const int SellFish = 0x451;
public const int SendTutoralOk = 0x42e;
public const int SignIn = 0x408;
public const int StrikeReward = 0x42a;
public const int SubmitPics = 0x454;
public const int TransferHero = 0x3f3;
public const int TribeLevelUpdate = 0x407;
public const int TribeUpdate = 0x406;
public const int UpgradeGod = 0x3f7;
public const int UpgradeHero = 0x3f2;
public const int UpgradeheroSkill = 0x426;
public const int UseChangeCharacteristic = 0x44a;
public const int UseDoubleRewardItem = 0x449;
public const int UseExpItem = 0x446;
public const int UseFishEatCount = 0x44d;
public const int UseFreashCD = 0x44c;
public const int UseGoldItem = 0x447;
public const int UseHeroTransform = 0x44e;
public const int UseSkillPointItem = 0x448;
public const int VerifyAppStoreOrderInfo = 0x44f;
进行对照得出,第一个包是告诉服务器:‘我要开始打这一关了!’,第二个包是“这一关我打完了,快告诉我有什么奖励!”
结合这两个包就能达到成功刷关的目的了。
值得注意的是,刷关最好是对零cd的关卡使用。
最后附上刷关部分的代码:
密码各位自己抓包找吧,找完对这段代码进行简单的修改就能用了~
[PHP] 纯文本查看 复制代码 <?php
/**
* Created by PhpStorm.
* User: puluter
* Date: 2017/2/9
* Time: 8:34
*/
require_once ("./include.php");
//phpinfo();
$cookie = dirname(__FILE__) . '/cookie.txt';
$a=login("121.199.54.144:101/default.ashx?MsgId=1&Sid=&Uid=114364&St=&actionId=1004&Handler=Login&MobileType=1&PassportId=puluter&Password=密码不能看qwq&DeviceID=android-bd19f5ede3358bdff8ff0eadc425d524&RetailID=0000&RetailUser=&sign=e6e2c90fdaf3f59d22bf87586c9f983d",$cookie);
var_dump($a);
ret();
$b=login("121.199.54.144:81/Service.aspx?d=MsgId%3d4%26Sid%3d%26Uid%3d114364%26St%3d%26actionId%3d1001%26GameID%3d1%26Pid%3dpuluter%26sign%3d80f97b67d3a4c0d15456baf3f03092e3",$cookie);
var_dump($b);
$ip="120.27.196.105:104";
ret();
$c=get($ip."/default.ashx?d=MsgId%3d27%26Sid%3d%26Uid%3d114364%26St%3d%26actionId%3d1007%26MobileType%3d1%26Token%3d461bd5efeee*****14e5b73ebcfd504%26DeviceID%3dandroid-bd19f5ede3358bdff8ff0eadc425d524%26RetailID%3d0000%26sign%3d069d0b7c6af822fd903f5773713d867c",$cookie);
ret();
$f=preg_match("/s_(.*?)\|1\|3/",$c,$g);
$g=$g[0];
ret();
var_dump($g);
$sid=$g;
$big=6;$small=1;$dif=1;$cnt=0;
while(true){$cnt++;
$packet="MsgId=36&Sid={$sid}&Uid=114364&St=&actionId=1068&BigLevel={$big}&SmallLevel={$small}&Difficulty={$dif}";
$md55=md5($packet."123");
$packet=$packet."&sign=".$md55;
$packet=urlencode($packet);
$app=get($ip."/default.ashx?d=".$packet,$cookie);
//var_dump($app);
//ret();
$ans=preg_match("/请求/",$app);
// if($ans!=0){
// $small=1;$big++;
// continue;
// }
$packet="MsgId=57&Sid={$sid}&Uid=114364&St=&actionId=1069";
$md55=md5($packet."123");
$packet=$packet."&sign=".$md55;
$packet=urlencode($packet);
$app=get($ip."/default.ashx?d=".$packet,$cookie);
var_dump($app);
//ret();
$ans=preg_match("/请求/",$app);
// if($ans==0){
// $ans=preg_match("/需要/",$app);
//// if($ans==0){
// $small++;
//// }
// }
// else {
// $small++;
// }
var_dump($big);var_dump($small);var_dump($cnt);//ret();
sleep(0.5);
}
[PHP] 纯文本查看 复制代码 <?php
/**
* Created by PhpStorm.
* User: yuzhu
* Date: 2017/2/9
* Time: 8:35
*/
function ret(){echo "<br/>";}
function login($url,$cookie){
$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_HEADER, "User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.1.1; MI 5 Build/NMF26V)");
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie); //设置Cookie信息保存在指定的文件中
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
function get($url,$cookie=""){
$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_HEADER, "User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.1.1; MI 5 Build/NMF26V)");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie); //读取cookie
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
function post($url,$params,$cookie=""){
//$post_data = array ("username" => "bob","key" => "12345");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, "User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.1.1; MI 5 Build/NMF26V)");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie); //读取cookie
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
对了,多说一句,这个php最好在cmd中运行,如果想在浏览器里用,那就得改不少代码了。
(其实这个游戏还有其他的一些小的逻辑bug,比如刷供奉值,今天先不写了) |