草庐IT

小米开放平台逆向工程

JMCui 2023-04-16 原文

前言

最近在调研 小米开放平台 API 的能力,发现能力支持的实在有点少,没办法只能另辟蹊径去逆向 Consule UI 的能力。

逆向工程最重要解决的就是“认证”。有没有办法自动登录鉴权,或者使用一个长久可靠、可续期的 token,直接决定了该 Consule UI 是否可逆向。

逆向工程-认证

  1. 首先,抓到小米开放平台登录接口:/pass/serviceLoginAuth2
curl 'https://account.xiaomi.com/pass/serviceLoginAuth2' \
  -H 'Accept: application/json, text/plain, */*' \
  -H 'Accept-Language: zh-CN,zh;q=0.9' \
  -H 'Cache-Control: no-cache' \
  -H 'Connection: keep-alive' \
  -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
  -H 'Cookie: deviceId=wb_855aaa14-cb23-48ff-b828-708c627c48eb; pass_ua=web; pExpireTime=0; passInfo=login-end; JSESSIONID=aaa0jIoVQRTDN9uNTktqy; uLocale=zh_CN' \
  -H 'EUI: S6ApR6Vvom5JQTG2gxT3xfAuoMfXOpav/MdbTMcfQCVZVEqvzxSbBBCugod8JFANCLI0qafUfXANofq3TkjkUWu5xhbqrFOa/uwPi3jmmWEo3Kl7dbtQW2FyHaeOfypuAcyZpAhbPnxG9e4+sV9fQB/MvkQRIgn+7PUAWlf9rfU=.dXNlcg==' \
  -H 'Origin: https://account.xiaomi.com' \
  -H 'Pragma: no-cache' \
  -H 'Referer: https://account.xiaomi.com/fe/service/login/password?_locale=zh_CN&sid=mideveloper&qs=%253Fcallback%253Dhttps%25253A%25252F%25252Fdev.mi.com%25252Fsts%25253Fsign%25253DNUzuBPDqs94TS1jFRue%2525252BFtqq%2525252BrA%2525253D%252526followup%25253Dhttps%2525253A%2525252F%2525252Fdev.mi.com%2525252Fhome%2526sid%253Dmideveloper%2526_locale%253Dzh_CN&callback=https%3A%2F%2Fdev.mi.com%2Fsts%3Fsign%3DNUzuBPDqs94TS1jFRue%252BFtqq%252BrA%253D%26followup%3Dhttps%253A%252F%252Fdev.mi.com%252Fhome&_sign=5OL5w4GfqMJ2CWGnfv7yBBxpc7A%3D&serviceParam=%7B%22checkSafePhone%22%3Afalse%2C%22checkSafeAddress%22%3Afalse%2C%22lsrp_score%22%3A0.0%7D&showActiveX=false&theme=&needTheme=false&bizDeviceType=' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  --data-raw 'bizDeviceType=&needTheme=false&theme=&showActiveX=false&serviceParam=%7B%22checkSafePhone%22%3Afalse%2C%22checkSafeAddress%22%3Afalse%2C%22lsrp_score%22%3A0.0%7D&callback=https%3A%2F%2Fdev.mi.com%2Fsts%3Fsign%3DNUzuBPDqs94TS1jFRue%252BFtqq%252BrA%253D%26followup%3Dhttps%253A%252F%252Fdev.mi.com%252Fhome&qs=%253Fcallback%253Dhttps%25253A%25252F%25252Fdev.mi.com%25252Fsts%25253Fsign%25253DNUzuBPDqs94TS1jFRue%2525252BFtqq%2525252BrA%2525253D%252526followup%25253Dhttps%2525253A%2525252F%2525252Fdev.mi.com%2525252Fhome%2526sid%253Dmideveloper%2526_locale%253Dzh_CN&sid=mideveloper&_sign=5OL5w4GfqMJ2CWGnfv7yBBxpc7A%3D&user=xxxx&hash=xxxx&_json=true&policyName=miaccount&captCode=' \
  --compressed

把这个 cUrl 精简一下:

curl --location --request POST 'https://account.xiaomi.com/pass/serviceLoginAuth2?callback=https://dev.mi.com/sts?sign=NUzuBPDqs94TS1jFRue%2BFtqq%2BrA%3D&qs=%3Fcallback%3Dhttps%253A%252F%252Fdev.mi.com%252Fsts%253Fsign%253DNUzuBPDqs94TS1jFRue%25252BFtqq%25252BrA%25253D%2526followup%253Dhttps%25253A%25252F%25252Fdev.mi.com%25252Fhome%26sid%3Dmideveloper%26_locale%3Dzh_CN&sid=mideveloper&user=xxxx&cc=+86&hash=xxxx&_json=true&captCode=
' \
--header 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
--header 'EUI: YbSRNpc/gnpq1tgbE9y37EagHk+tgIrYnrJUap0FOYzCsUSBi6p1tbf9kT5G4DJUB7Vya+0q7dnFDTBVYRK8NNgGqt1JMAg6quLUNXLBlsK8KJDo9rGxFczOau8lLo/OH/jtDLLm51XbOWq42gdxVuKaJk9/FmgC+2qh+FOocio=.dXNlcg==' \
--header 'Origin: https://account.xiaomi.com' \

然后发现我们需要解决的问题有 user、hash、captCode、EUI。

  • user:用户名,密文,需要弄清除怎么加密的;
  • hash:密码,密文,需要弄清楚怎么加密的;
  • captCode:验证码,触发时机未知;
  • EUI:Request Header

然后,就去翻小米 js 中加密这些的逻辑,在这个 JS 里面。核心代码是下面这段(有些变量被我重命名了):

        function Pt(ttttt) {
            var e, r;
            ttttt = ttttt || {};
            // 16 位固定字符随机字符串
            var iiii = function (t) {
                for (var e = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*", r = "", i = 0; i < t; i++) {
                    var n = Math.floor(Math.random() * e.length);
                    r += e.substring(n, n + 1)
                }
                return r
            }(16), s = new Ct({});
            s.setPublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYEVrK/4Mahiv0pUJgTybx4J9P5dUT/Y0PuwMbk+gMU+jrZnBiXGv6/hCH1avIhoBcE535F8nJQQN3UavZdFkYidsoXuEnat3+eVTp3FslyhRwIBDF09v4vDhRtxFOT+R7uH7h/mzmyA2/+lfIMWGIrffXprYizbV76+YQKhoqFQIDAQAB");
            var h = s.encrypt(window.btoa(iiii)), u = l.a.parse("0102030405060708"), f = l.a.parse(iiii),
                p = window.btoa(a()(ttttt).join(",")), gggg = {};
            return o()(e = a()(ttttt)).call(e, (function (e) {
                var r = ttttt[e], i = c.a.encrypt(r, f, {iv: u, padding: d.a});
                i = i.toString(), gggg[e] = i
            })), {EUI: n()(r = "".concat(h, ".")).call(r, p), encryptedParams: gggg}
        }

直接说结论,随机生成 16 位字符串作为密钥,先 Base64 后,再 RSA 加密,publicKey 就是这串:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYEVrK/4Mahiv0pUJgTybx4J9P5dUT/Y0PuwMbk+gMU+jrZnBiXGv6/hCH1avIhoBcE535F8nJQQN3UavZdFkYidsoXuEnat3+eVTp3FslyhRwIBDF09v4vDhRtxFOT+R7uH7h/mzmyA2/+lfIMWGIrffXprYizbV76+YQKhoqFQIDAQAB

加密出来的信息和 "user" 字符串的 Base64 拼接就是 EUI,并传递给服务端;
user 是用 AES 加密的,密钥就是随机生成的 16 位字符串,iv 向量是固定的 0102030405060708 , padding 方式是 AES/CBC/PKCS5Padding ;
hash 是密码简单 MD5,没有加 salt 操作;
captCode 触发时机无法知晓。

逆向工程-鉴权

有了以上信息后,我们就能直接通过 username + password 的方式登录小米开放平台了,返回信息如下:

&&&START&&&{
    "qs": "?callback=https%3A%2F%2Fdev.mi.com%2Fsts%3Fsign%3DNUzuBPDqs94TS1jFRue%252BFtqq%252BrA%253D%26followup%3Dhttps%253A%252F%252Fdev.mi.com%252Fhome&sid=mideveloper&_locale=zh_CN",
    "ssecurity": "MEQ+3bDLm2toC7OuIPia1g==",
    "code": 0,
    "passToken": "xxx",
    "description": "成功",
    "securityStatus": 0,
    "nonce": 6417736210287713280,
    "userId": xxx,
    "cUserId": "xxx",
    "result": "ok",
    "psecurity": "69f4VnfI6mcnMwLl990Aaw==",
    "captchaUrl": null,
    "location": "https://dev.mi.com/sts?sign=xxx%20Ftqq%20rA%3D&d=wb_7a366d72-c639-4390-a584-6e4122f1543f&ticket=0&pwd=1&p_ts=1667104077000&fid=0&p_lm=1&auth=kqQrNRt4ljohm2qZoQgkBnh06dJS4UD7yYgG7QXOdXBHP1x9d5WfqCE2q18jd2rGoLLgpuSKEw60oGsYHIpHqzIGxESRIInKhS8DGDfN9bwsYXpLCctCK8D%2BHk7Gb399N1houCp9gqcaZEeDfsWMu1%2BBgs8iPsQcQ8DpL8Peay8%3D&m=1&_group=DEFAULT&tsl=0&p_ca=0&p_ur=CN&p_idc=China&nonce=EzbXp8ocSecBp%2Fdr&_ssign=RP2a7pLwZ%2BygW9aoH%2BK6uvKWf54%3D",
    "pwd": 1,
    "child": 0,
    "desc": "成功"
}

然后直接访问返回的 location 地址,在 reponse 的 header 的 set-cookie 信息里面就能找到 serviceToken 的信息,这个就是开放平台的鉴权信息,Consule UI 所有的接口都能用 serviceToken 来访问。

curl 'https://dev.mi.com/uiueapi/myitems/undefined/0' \
  -H 'authority: dev.mi.com' \
  -H 'cookie: serviceToken=Xv5lATucFWfMVEEue0csFBgx7IPAbtamENHgyJjhFU4qOMuwbpOLB3TX0oDJTmKguEgDrYw2qar0xiEQK1rQvIq3OZ0k7JCF/DXCnMRAr727GzINrcV2qRC6JGxScmMA835wenAdpBRixjxFdTKyPT/zwlUTT4h42NxxxxxWwYJ5d1DeWmvDwIq+so7dsE/ibzDcnPJRhhatIefbBbgyHpsBzTMa7Vgw057finoamZs7hc2q7E/mt+xmavAsLollWm0H7QC7qhsTqvUOSYDJXD2Df7bnadM8I0PM97ME=; userId=xxx' \
  -H 'referer: https://dev.mi.com/distribute' \
  --compressed

有关小米开放平台逆向工程的更多相关文章

  1. NFT交易平台开发 创建NFT数字藏品平台 - 2

    为什么需要NFT市场?NFTMarketplace允许用户购买、出售、交易、查看或创建自己的NFT,就像他们需要一个市场来购买物理或数字世界中的大多数产品一样。几乎每个人都可以进入NFT市场,但要做到这一点,用户必须满足以下要求:一个NFT市场用户账户,允许您在给定平台上购买NFT。你需要一个与区块链兼容的加密钱包来购买NFT。NFTMarketplace非常重要,因为它连接了买卖双方,并为用户提供了多种工具来快速创建自己的NFT。艺术家可以在市场上列出要出售的NFT,买家可以通过投标过程探索市场并购买物品。NFT市场开发过程解释创建NFT市场是一个耗时的过程,需要编程知识和理解。那么搭建NF

  2. Ruby跨平台EOF符号的写法 - 2

    在Ruby中是否有一种平台无关的方式将EOF符号写入字符串。在*nix中,我认为符号是^D,但在Windows中是^Z,这就是我问的原因。 最佳答案 EOF不是一个字符,它是一个状态。终端使用控制字符来表示此状态(C-d)。没有这样的事情是“读一个EOF字符”,写一个也是一样的。如果您正在写入文件,请在完成后将其关闭。看这个mailinglistpost:ItsoundslikeyouarethinkingofEOFasanin-bandbutspecialcharactervaluethatmarkstheendoffile.It

  3. 华为认证的网络工程师证好考吗,含金量高吗 ? - 2

    华为认证分等级的,相当于初中高三个等级,当然高级是比较难考的,也是含金量最高的。我就慢慢给你介绍一下。1.了解华为认证华为认证网络工程师是由华为公司认证与采购部推出的独立认证体系,与之前的华为认证不同,简称HCIA。同时华为认证是华为技术有限公司凭借多年信息通信技术人才培养经验,以及对行业发展的理解,以层次化的职业技术认证为指引,推出的覆盖IP、IT、CT以及ICT融合技术领域的认证体系,是ICT全技术领域认证体系。​2.怎么考取华为认证网络工程师?要考取华为认证网络工程师必须选择最近的Prometric授权考试中心APTC报名并参加GB0-190的考试,考试通过后,以获得由华为统一签发的“华

  4. 打通源码,高效定位代码问题|云效工程师指北 - 2

    大家好,我叫胡飞虎,花名虎仔,目前负责云效旗下产品Codeup代码托管的设计与开发。代码作为企业最核心的数据资产,除了被构建、部署之外还有更大的价值。为了帮助企业和团队挖掘更多源代码价值以赋能日常代码研发、运维等工作,云效代码团队在大数据和智能化方向进行了一系列的探索和实践(例如代码搜索与推荐),本文主要介绍我们如何通过直接打通源代码来提高研发与运维效率。随着微服务架构的流行,一个业务流程需要多个微服务共同完成。一旦出现问题,运维人员在面对数量多、调用链路复杂的情况下,很难快速锁定导致问题发生的罪魁祸首:代码。为了提高排查效率,目前常见的解决方案是:链路跟踪+日志分析工具相结合。即通过链路跟踪

  5. 软件工程毕业设计课题(81)微信小程序毕业设计PHP校园跑腿小程序系统设计与实现 - 2

        项目背景和意义 目的:本课题主要目标是设计并能够实现一个基于微信校园跑腿小程序系统,前台用户使用小程序发布跑腿任何和接跑腿任务,后台管理使用基于PHP+MySql的B/S架构;通过后台管理跑腿的用户、查看跑腿信息和对应订单。意义:手机网络时代,大学生通过手机网购日常用品、外卖外卖、代取快递等已不再是稀奇的事情。此外,不少高校还流行着校园有偿工作,校园跑腿就成了大学生创业服务项目。        因为你在校园里,所以不会有进入的限制。并不是所有的外卖平台都可以随意进入校园,比如小黄和小蓝的双打外卖平台。许多大学禁止送餐进入学校,更不用说送餐进入宿舍了。这一措施使得校园服务市场的竞争相对不

  6. 视频融合技术解决方案,三维全景拼接赋能平台 - 2

    近年来,随着信息化时代的到来,三维全景拼接以视频监控领域为代表的智能硬件公司迅速崛起,随后全国各地在视频监控领域进行了大量的建设。但随着摄像头数量的增加,视频监控画面离散、庞杂、关联性差等诸多问题日渐凸显。如何优化现有视频技术,助力管理者或使用者有效、直观、准确地掌控现场实时动态,成为我国信息化前行路上面临的新课题。视频融合技术平台解决方案北京智汇云舟科技有限公司成立于2012年,专注于创新性的“视频孪生(实时实景数字孪生)”技术研发与应用。公司依托自研三维地理信息引擎(3DGIS),融合建筑信息模型(BIM)、视频监控(Video)、人工智能(AI)及物联网(IOT)等多种技术,并在此基础上

  7. ruby - 从我的胰岛素泵 Controller 逆向工程统计数据文件 - 2

    这可能是也可能不是灰色地带主题,尽管我的意图肯定不是,所以我的意图不是激起关于逆向工程主题的道德辩论。我是1型糖尿病患者,目前正在接受泵治疗。我是OmniPod用户,这是一个一次性胶囊,可以粘在我的身上并分配胰岛素3天。它由个人糖尿病管理器[PDM](见下文)控制,该管理器控制进餐期间分配的胰岛素量、血糖读数,并且包含一个用于计算碳水化合物的食物指数。(来源:myomnipod.com)新的PDM有一个用于下载数据的USB端口。该软件对Windows用户免费(名为CoPilot的软件包),但不支持Mac。将PDM插入我的Mac后,它像任何其他USB设备一样安装,并为我提供了一个可读卷,

  8. ruby - 如何指定 gem 仅是 JRuby 平台? - 2

    我正在开发一个只适用于JRuby平台的gem。如何在我的.gemspec中指定它? 最佳答案 你可以简单地输入gemspecspec.platform='java'表示它仅适用于JRuby。具体设置平台可以看一下:RubygemSpecificationReference 关于ruby-如何指定gem仅是JRuby平台?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/189366

  9. ruby-on-rails - 选择 Ruby on Rails 作为基于浏览器的在线游戏平台 - 2

    对于类似Travian的在线策略游戏,我有一些(我认为)非常棒的想法。有些内容我还没有想通,还有一些我还不知道的挑战。这是一个相当大的项目,对于(还)不是熟练的Web开发人员的人来说可能太重了。我还是想试一试,但我在选择平台时遇到了麻烦。世界上的“规模”最近被抛得一团糟,我看到RubyonRails因规模不佳而受到抨击,所以我来这里是为了得到一些答案。我喜欢RubyonRails,无论是Ruby还是Rails。我当然不是这方面的专家,但我喜欢使用它。我之前也使用过Python+Django,也使用过PHP(我不喜欢它。)理想情况下,假设每个服务器有7000名玩家,大概每秒要处理大量数据

  10. ruby-on-rails - 有谁知道 Ruby On Rails 的任何跨平台 GUI 日志查看器? - 2

    我厌倦了使用:tail-fdevelopment.log跟踪我的Rails日志。相反,我想要在网格中显示信息并允许我对每个日志消息进行排序、过滤和查看堆栈跟踪的东西。有谁知道用于显示Rails日志的GUI工具。理想情况下,我想要一个独立的应用程序(不是Netbeans或Eclipse中的东西) 最佳答案 Splunk,有一个免费版本,限制为500mb,但具有与完整版本相同的所有功能。 关于ruby-on-rails-有谁知道RubyOnRails的任何跨平台GUI日志查看器?,我们在St

随机推荐