记悠学派APP逆向及利用

  • 0×00 前言
  • 0×01 逆向部分
    • 抓包部分
      • 登录
    • APK逆向
      • sign鉴权算法
  • 0×02 功能实现
    • sign生成
    • 软件实现
  • 0×03 结论

0×00 前言


学校为促进学生们参加活动的积极性,通过学分制度来让学生们提高参加率,并通过该APP进行签到、记录学分,作为一个爱搞事情的好孩子,当然是对他进行一番嘿嘿嘿。
带着这样的想法,我们来进行分析

注:本文所提及到的内容,仅仅为技术讨论,切勿用到非法行为。

0×01 逆向部分

抓包部分

对于APP来说,一般都会通过HTTP协议来进行传输(当然也会有TCP、UDP协议传输的)。
那么第一步就是对APP进行抓包了,我用的抓包工具是Packet Capture,选择好要抓包的程序。从登录、获取我的活动、签到历史查询、签到、评价等几个操作进行抓包。
下面来分析上述所说的登录API的调用。

注:所有API都是通过POST方式进行请求。

登录

请求包

POST /wisdomprovider/router? HTTP/1.1
Content-Length: 267
Host: manage.cisau.com.cn:8080
Connection: Keep-Alive
Accept-Encoding: gzip
content-type: application/x-www-form-urlencoded;charset=utf8anonymousId=00000000-0000-0000-0000-000000000000&loginId=20*****0&method=wisdom.system.login&sign=D96DBA******0C50B4A&format=json&tenantCode=sxxyzhxy&deviceId=1*****c&password=2****2&v=1.0&appType=2&appKey=00000001&timestamp=1555600646//loginId为登录账号 password为登录密码 deviceId为设备ID sign为APP产生操作时的鉴权密钥

返回包

HTTP/1.1 200
Access-Control-Allow-Origin: *
Content-Type: text/html;charset=UTF-8
Content-Language: en-US
Content-Length: 799
Date: Thu, 18 Apr 2019 15:17:26 GMT{"code":"0","data":{"userId":"0*******-****-4***-***4-1*************3","userName":"*********2","studentNo":"2*****0","nickName":"**宇","realName":"**宇","mobile":"","email":"2********1@qq.com","qq":"","wechat":"","address":"北京市朝阳区***","batchCode":"00*","batchName":"201*年级","orgCode":"00*","orgName":"信息工程学院","specialtyName":"计算机科学与技术","remark":"","imageUrl":"http://smartclass.chinaedu.net:8000/sxxyzhxy/image/user/20*****2/f********1-****-****-***c-2b*******6.png","roleTypes":1,"checkinState":2,"userInfoConfirm":1,"checkinNoticeConfirm":1,"appDownloadUrl":"http://smartclass.chinaedu.net:8000/smartcampus/appdown/index.html","isBindCellphone":1},"detailCode":"0"}

注:此版本用的是老版本,该版本没有验证设备ID。

APK逆向

sign鉴权算法

由于开学的时候学过一些Java,我觉得用jadx将APK拖进去先把代码看个究竟。

看了一大圈也没找到啥有用的东西,还看的是一头汗水,我决定尝试最直接的办法就是直接搜索关键字sign。

经过长达20分钟的加载,心里一直想着等了这么久要是没搜到心态不得爆炸。但是事实并非我所料,竟然搜到了一个SignUtils.java

下面上代码,我们来具体分析下到底是怎么计算的这个Sign

public class SignUtils {public static String sign(Map<String, String> map, String str) {return sign(map, null, str); //递归}public static String sign(Map<String, String> map, List<String> list, String str) {  //重写方法try {StringBuilder stringBuilder = new StringBuilder();List<String> arrayList = new ArrayList(map.size());arrayList.addAll(map.keySet());if (list != null && list.size() > 0) {for (String remove : list) {arrayList.remove(remove);}}Collections.sort(arrayList);stringBuilder.append(str);for (String str2 : arrayList) {stringBuilder.append(str2);stringBuilder.append((String) map.get(str2));}stringBuilder.append(str); //通过map表排序的方法将未加密的信息存入stringBuilder中return byte2hex(getSHA1Digest(stringBuilder.toString())); //返回通过SHA-1加密后的全大写sign} catch (Throwable e) {throw new RuntimeException(e);}}.........}

通过观察登录时的代码,我们可以清楚的看到会在map表中添加所需的参数

 private void login() {if (this.mLoginTenantEntity == null) {Toast.makeText(this, getString(R.string.login_check_tenant_tip), 0).show();} else if (StringUtil.isEmpty(this.mobile) || StringUtil.isEmpty(this.pwd)) {Toast.makeText(this, getString(R.string.username_pwd_not_null), 0).show();} else {this.preference.save("username", this.mobile);CommonTenant commonTenant = (CommonTenant) TenantManager.getInstance().getCurrentTenant();commonTenant.setTenantRealCode(this.mLoginTenantEntity.getCode());CommonUrl commonUrl = (CommonUrl) commonTenant.getCurrentHttpRoot();commonUrl.setAppRootHttpUrl(this.mLoginTenantEntity.getAppUrl());commonUrl.setUploadHttpUrl(this.mLoginTenantEntity.getAppUploadUrl());commonUrl.setUmengShareHttpUrl(this.mLoginTenantEntity.getAppUmengShareUrl());if (!StringUtil.isEmpty(WisdomHttpUtil.getAppRootUrl())) {LoadingProgressDialog.showLoadingProgressDialog(this);Map hashMap = new HashMap();hashMap.put("loginId", this.mobile); //参数loginIdhashMap.put(PreferenceService.KEY_USER_PWD, this.pwd); //参数passwordhashMap.put("appType", String.valueOf(AppTypeEnum.Android.getValue())); //参数appTypehashMap.put("deviceBindingId", BindkeyUtil.getBindKey(this)); //参数deviceIdWisdomHttpUtil.sendAsyncPostRequest(Urls.LOGIN_URI, InterfaceVersionConfig.VERSION_2, hashMap, this.handler, (int) Vars.LOGIN_REQUEST, new TypeToken<User>() {});}}}

在继续跟踪POST请求这个方法的时候,还发现了method、timestamp等等。

public static String SECRET_KEY = "52c203760cf28798a44f6ac4"; //这个是在生成sign时必要的KEY

生成sign时,要注意必要的KEY以及参数的完整性。

0×02 功能实现

sign生成

package lanqiao;import java.io.IOException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class SignUtils {public static void main(String[] args) {SignUtils s = new SignUtils();Map<String, String> map = new HashMap<String, String>();Map<String, String> hashMap = new HashMap<String, String>();hashMap.put("loginId", "[loginid]");hashMap.put("password", "[password]");hashMap.put("appType", "2");hashMap.put("appKey", "00000001");hashMap.put("method", "wisdom.system.login");hashMap.put("format", "json");hashMap.put("v", "1.0");hashMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));//String.valueOf(System.currentTimeMillis() / 1000)hashMap.put("sign", SignUtils.sign(hashMap, "52c203760cf28798a44f6ac4"));}public static String sign(Map<String, String> map, String str) {return sign(map, null, str);}public static String sign(Map<String, String> map, List<String> list, String str) {try {StringBuilder stringBuilder = new StringBuilder();List<String> arrayList = new ArrayList(map.size());arrayList.addAll(map.keySet());if (list != null && list.size() > 0) {for (String remove : list) {arrayList.remove(remove);}}Collections.sort(arrayList);stringBuilder.append(str);for (String str2 : arrayList) {stringBuilder.append(str2);stringBuilder.append((String) map.get(str2));}stringBuilder.append(str);System.out.println(stringBuilder.toString());System.out.println(byte2hex(getSHA1Digest(stringBuilder.toString())));return byte2hex(getSHA1Digest(stringBuilder.toString()));} catch (Throwable e) {throw new RuntimeException(e);}}public static String utf8Encoding(String str, String str2) {try {return new String(str.getBytes(str2), "UTF8");} catch (Throwable e) {throw new IllegalArgumentException(e);}}private static byte[] getSHA1Digest(String str) throws IOException {try {return MessageDigest.getInstance("SHA-1").digest(str.getBytes("UTF8"));} catch (Throwable e) {throw new IOException(e);}}private static byte[] getMD5Digest(String str) throws IOException {try {return MessageDigest.getInstance("MD5").digest(str.getBytes("UTF8"));} catch (Throwable e) {throw new IOException(e);}}private static String byte2hex(byte[] bArr) {StringBuilder stringBuilder = new StringBuilder();for (byte b : bArr) {String toHexString = Integer.toHexString(b & 255);if (toHexString.length() == 1) {stringBuilder.append("0");}stringBuilder.append(toHexString.toUpperCase());}return stringBuilder.toString();}
}

这里我直接复制原包中的代码加以修改后直接利用。
为了方便在易语言中方便使用,我直接生成里stringBuilder中的字符,然后通过直接替换字符来快捷使用。

软件实现

.版本 2
.支持库 iext.子程序 登陆账号
.局部变量 未加密数据, 文本型
.局部变量 提交数据, 文本型
.局部变量 sign, 文本型
.局部变量 i, 整数型
.局部变量 返回文本, 文本型
.局部变量 username, 文本型
.局部变量 password, 文本型
.局部变量 deviceid, 文本型
.局部变量 timestamp, 文本型.计次循环首 (账号列表框.取表项数 (), i)username = 账号列表框.取标题 (i - 1, 1)password = 账号列表框.取标题 (i - 1, 2)deviceid = 账号列表框.取标题 (i - 1, 3)timestamp = 时间_取现行时间戳 (真)提交数据 = “anonymousId=00000000-0000-0000-0000-000000000000&loginId=[loginid]&method=wisdom.system.login&sign=[sign]&format=json&tenantCode=sxxyzhxy&deviceId=[deviceid]&password=[password]&v=1.0&appType=2&appKey=00000001&timestamp=[timestamp]”未加密数据 = “52c203760cf28798a44f6ac4anonymousId00000000-0000-0000-0000-000000000000appKey00000001appType2deviceId[deviceid]formatjsonloginId[loginid]methodwisdom.system.loginpassword[password]tenantCodesxxyzhxytimestamp[timestamp]v1.052c203760cf28798a44f6ac4”提交数据 = 子文本替换 (提交数据, “[loginid]”, username, , , 真)提交数据 = 子文本替换 (提交数据, “[password]”, password, , , 真)提交数据 = 子文本替换 (提交数据, “[deviceid]”, deviceid, , , 真)提交数据 = 子文本替换 (提交数据, “[timestamp]”, timestamp, , , 真)未加密数据 = 子文本替换 (未加密数据, “[loginid]”, username, , , 真)未加密数据 = 子文本替换 (未加密数据, “[password]”, password, , , 真)未加密数据 = 子文本替换 (未加密数据, “[deviceid]”, deviceid, , , 真)未加密数据 = 子文本替换 (未加密数据, “[timestamp]”, timestamp, , , 真)sign = 到大写 (校验_取sha1 (到字节集 (未加密数据)))提交数据 = 子文本替换 (提交数据, “[sign]”, sign, , , 真)' “application/x-www-form-urlencoded;charset=utf8”返回文本 = 编码_utf8到gb2312 (到文本 (网页_访问_对象 (“http://manage.cisau.com.cn:8080/wisdomprovider/router”, 1, 提交数据, , , , , , , , )))程序_写日志 (“[” + 时间_格式化 (取现行时间 (), “yy-MM-dd ”, “hh:mm:ss”, 真) + “]  登陆返回信息:” + 返回文本, 取运行目录 () + “\log\return.txt”)json.解析 (返回文本).如果 (json.取通用属性 (“data.userId”) ≠ “”)' 登陆成功账号列表框.置标题 (i - 1, 4, json.取通用属性 (“data.userId”))编辑框1.加入文本 (“[” + 时间_格式化 (取现行时间 (), “yy-MM-dd ”, “hh:mm:ss”, 真) + “] ” + username + “登陆成功...” + #换行符).否则' 登陆失败json.取通用属性 (“msg”)编辑框1.加入文本 (“[” + 时间_格式化 (取现行时间 (), “yy-MM-dd ”, “hh:mm:ss”, 真) + “] ” + username + “登陆失败:” + json.取通用属性 (“msg”) + #换行符).如果结束.计次循环尾 ()

为了防止白嫖党,我把签到、评价的代码删除咯,欢迎大家自己来编写代码。
由于技术太渣就不给大家提供其他语言的代码了,这里就用易语言做示例了。
我的代码就随缘写法,如果有可以改进的地方,联系我。

0×03 结论


通过对APP逆向后,提取接口后,实现自动登录、报名、签到、评价等等功能……
同样可以做一个通知机器人来通知你有什么新活动可以参加。

*如果有写的有问题的地方,欢迎留言告知
*本文原创作者:WeiShaos,未经许可禁止转载

记悠学派APP逆向及利用相关推荐

  1. 知物由学 | 干货!一文了解安卓APP逆向分析与保护机制

    "知物由学"是网易云易盾打造的一个品牌栏目,词语出自汉·王充<论衡·实知>.人,能力有高下之分,学习才知道事物的道理,而后才有智慧,不去求问就不会知道."知物 ...

  2. 《APP逆向学习》课程介绍和什么是安卓app逆向?

    来源[小肩膀 零基础一站式安卓app逆向安全(2021版)]:aHR0cHM6Ly93d3cuYmlsaWJpbGkuY29tL3ZpZGVvL0JWMUFWNDExSjd6aw== 1.课程介绍 安 ...

  3. 某直播APP逆向TCP协议分析

    概述 一枚小菜鸟终于完成对炫舞梦工厂APP的分析.该直播APP采用TCP协议,TCP连接建立之后,首先进行基础连接认证,认证通过之后,进行帐号认证,完成即可进行获取角色信息.进入房间等各类操作.发送数 ...

  4. 逆向工程--苹果移动端app逆向分析技术(一)

    0x01 基础准备 关于iphone移动端app逆向程序相关初级基础大家可以自己提前学习.本 文主要给大家分享关于脱壳加密app程序的技术.学习之前大家先搭建系 统环境,准备相应的工具,参考链接教程自 ...

  5. 【APP逆向-入门级】某直播APP逆向过程

    原文章逆向思路 重点:先向CSDN审核客服声明一下:本文仅仅是用于技术交流,甚至可以都算不上APP逆向,文章提到的截图已经全部打码.也没有提及是什么APP,希望审核人员可以通过本文章,谢谢. 这是一篇 ...

  6. Progressive Web App是一个利用现代浏览器的能力来达到类似APP的用户体验的技术——不就是chrome OS吗?...

    什么是Progressive Web App? Progressive Web App是一个利用现代浏览器的能力来达到类似APP的用户体验的技术,由Google实现,让浏览器打开的网址像APP一样运行 ...

  7. App逆向 Frida - 夜神模拟器安装配置 基本使用

    App逆向 Frida - 夜神模拟器安装配置 基本使用 文章目录 App逆向 Frida - 夜神模拟器安装配置 基本使用 前言 一.Frida简单介绍? 1.Frida是什么 2.Frida原理( ...

  8. App逆向案例 X嘟牛 - Frida监听 WT-JS工具还原(一)

    App逆向案例 X嘟牛 - Frida监听 & WT-JS工具还原(一) 提示:文章仅供参考,禁止用于非法途径: 文章目录 App逆向案例 X嘟牛 - Frida监听 & WT-JS工 ...

  9. H5的APP逆向方法

    注:小肩膀新课程<安卓逆向百例>,讲解一百个APP的实战,1999¥. 现在的app开发有很多框架,不再是单纯的Java和so了.不同框架开发的app,有不同的逆向方法. 1. 常见的Ja ...

最新文章

  1. egg.js连接mysql数据库遇到的问题
  2. ASP数据库插马小议
  3. SAP CRM里Interaction Object是个什么东东
  4. HDU 6061 RXD and functions(NTT)
  5. LeetCode 547. 朋友圈(图的遍历BFS DFS)
  6. 简单参数让谷歌Chrome浏览器单进程运行
  7. spring mvc 传中文 到controller层乱码的 解决方法
  8. java----Servlet的生命周期
  9. python装饰器详解-python中的装饰器详解
  10. jQuery -- 光阴似箭(三):jQuery 操作 HTML 元素和属性
  11. 用python逆序输出字符串中的所有元素_Python中逆序输出字符串的六种方法
  12. 毕设题目:Matlab瑕疵检测
  13. idea结合git教程(拉取项目,提交代码,合代码等等)
  14. Python Apex 武器自动识别与压枪 全过程记录
  15. 寒假学习之stm32(15)----DMA(direct memory access)
  16. python避障小车_[TPYBoard - Micropython之会python就能做硬件 8] 学习使用超声波模块制作避障小车...
  17. JAVA / JS 中关于this和that
  18. 解决树莓派开机黑屏不显示桌面问题
  19. ctf夏季集训结训赛-简单题writeup
  20. 乐2 乐视X621_官方线刷包_救砖包_解账户锁

热门文章

  1. Java SE第0节课  程序设计学习七宗罪
  2. 高性能计算(HPC)和智能计算理解
  3. 我的世界java版刷雪球机,我的世界自动刷雪球机制作方法,自动刷雪球机怎么做?...
  4. 该怎么用设计测试用例测网上银行转账?
  5. 洛谷-P1010 幂次方
  6. 2021年未来最赚钱的六个方向
  7. python手机代码识别数字_利用python构建神经网络识别手写数字(附源代码)
  8. 命令行查看、设置和取消git或终端代理
  9. 乐视网php工资,乐视今天发工资了吗?没有
  10. 阿里云被工信部暂停合作,惹事的Log4j2漏洞该如何解决?