《Android逆向学习》-- 某庄园手游登录协议分析
0x00 前言
最近学习安卓逆向,刚好发现有个小时候玩过的页游,现在最近一段时间出了手游,拿来练练手也挺好。写的不是很好,请各位看官看个热闹就好。
0x01 使用工具
Fiddler 任意版本 、jadx、IDA
雷电模拟器
代理工具 Postern
任意一款编程工具
0x02 教程内容
0x20 首先配置好 Fiddler 这里就不赘述了,论坛里有很多相关教程,模拟器里设置好VPN
![](https://i-blog.csdnimg.cn/blog_migrate/aa6eda09ccd4fb99a5153c862a61daf6.png)
0x21 打开游戏,随便登录个账号密码抓个登录包。
可以发现返回内容是没经过加密,然后需要的参数 这里就列举几个比较重要的参数
表单名称 | 值 | 说明 |
---|---|---|
channelNo | 110001 | 登录渠道,如IOS渠道为 210009 |
key | 1881c326106056afee3da488560d75b9 | 经过 username与pwd计算得出的md5 |
username | 123123123 | 游戏账号 |
userpwd | 13038c34b00c2645f1cf4e5f087c1681 | 密码 DES_ECB |
versionName | 0.13.21082101S | 安装包的版本号 |
返回关键信息
表单名称 | 值 | 说明 |
---|---|---|
sid | eaps7chp | 游戏ID |
token | 5779c00f1e0a8cd6393b66f6f8930b0c | 登录令牌 |
登录成功后 二次令牌登录游戏
![](https://i-blog.csdnimg.cn/blog_migrate/005f239aba0b4679cd0762d70507edf9.png)
提交格式为 JSON 需要的关键数据为 sid 和 token
提交地址已匿。可以通过自行复现找到,接下来可以分析dex了。
0x22 寻找加密过程
将APK丢入 Apktool Box 先查个壳
![查壳结果](https://i-blog.csdnimg.cn/blog_migrate/9761d2cb6d8b32dd5f421d74866e6df6.png)
然后丢入 jadx 直接载入apk 这里采用最简单的方式,全局搜索提交地址的部分信息 < mobile!sdkLogin.action > 试着找出关键登录函数
![搜索结果](https://i-blog.csdnimg.cn/blog_migrate/49a0c5a5e1619292dae26bc738dc957a.png)
继续跟进搜索 xxx_LOGIN 被谁调用了
![搜索-2](https://i-blog.csdnimg.cn/blog_migrate/d78c8b89a3a438093ac831e137cf876e.png)
可以看到有个调用函数 getLoginUrl 提交的时候肯定也有地方引用了这个函数
可以看到 他有个
XXXSDKUser
直接在这里面找就大概率能找到登录封装过程了。
这里有SDK登录函数,然后我们仔细分析
public void doSdkLogin(String str, String str2) {
UserBean userBean = new UserBean();// new一个 用户数据
userBean.setUsername(str.trim());//可以看出 str 为用户名 去掉字符串前面和后面的空格.
str = DesUtil.encrypt(str2.trim());// 将密码进行加密 可以深入查一下
if (TextUtils.isEmpty(str) != null) {
loginFailNotify(String.valueOf(-3), ResUtil.getString(this.mActivity, "lt_encrypt_fail_msg"), false);
return;
}
userBean.setUserpwd(str);//设置密码 也可以看出 str2 为明文密码
doSdkLogin(userBean, false);
}
public void doSdkLogin(final UserBean userBean, final boolean z) {
if (SdkConfigManager.getInstanse().getLoginUrl() == null) {
this.mHandler.postDelayed(new Runnable() {
public void run() {
LeitingSdkUser.this.doSdkLogin(userBean, z);
}
}, 1000);
} else {
handleLogin(setUserBean(userBean, z), z, 0);//先设置其他用户信息后再进行发送登录
}
}
public UserBean setUserBean(UserBean userBean, boolean z) {
userBean.setGame(SdkConfigManager.getInstanse().getGame());//设置游戏名
userBean.setChannelNo(SdkConfigManager.getInstanse().getChannelNo());//登录渠道
userBean.setVersionCode(ApkUtil.getVersionCode(this.mActivity));//设置版本编号
userBean.setVersionName(ApkUtil.getVersionName(this.mActivity));//设置版本名
String str = "1";
userBean.setCheckAuth(str);//检查验证
userBean.setOs(str);//
userBean.setMmid(LeitingUserManager.getInstance().getMimiId(this.mActivity, userBean.getUsername()));//设置米米号
if (z) {
//是否开启验证
userBean.setKey(CookieUtil.encryptMobileCookie(userBean.getSid(), BaseConstantUtil.G_1));//设置Key
z = new StringBuilder();
z.append(SdkConfigManager.getInstanse().getLoginUrl());//添加登录地址
z.append(SdkConfigManager.getInstanse().getUrlApi(LeitingConstant.CHECK_LOGIN_API));//添加检验API
userBean.setUrl(z.toString());//设置提交网址
} else