某咖啡小程序逆向 (5月7日更新)
本文最后更新于 364 天前,其中的信息可能已经有所发展或是发生改变。

前言

本文章仅做安全学习交流用途,严禁作其他用途,如果侵犯您的权益请联系我删除。
所用工具: WeChatOpenDevTools

分析

搜索关键字如signcid无法定位到生成位置。通过分析堆栈一步一步向前确定sign生成位置,最终分析出生成逻辑。




目前AES加解密函数,sign生成函数均已实现,现在只看AES的key能否持久使用,如果不能,则需要探索其来源。

相关代码

//version 5.3.22

const crypto = require('crypto');

function t(r) {
    for (var t = function(r) {
        for (var e, t, n = [], a = 0; a < r.length; a++) {
            e = r.charCodeAt(a),
            t = [];
            do {
                t.push(255 & e),
                e >>= 8
            } while (e);
            n = n.concat(t.reverse())
        }
        return n
    }(r), n = new Array, a = e / 8, s = 0; s < a; s++)
        t.length > s ? n.push(t[s]) : n.push(0);
    return n
}
function stringToBytes(val) {
    const result = [];
    for (let i = 0; i < val.length; i++) {
    result.push(val.charCodeAt(i));
    }
    return result;
}
 function bytesToWords(t) {
    for (var n = [], r = 0, o = 0; r < t.length; r++,
    o += 8)
        n[o >>> 5] |= (255 & t[r]) << 24 - o % 32;
    return n
}
function wordsToBytes(t) {
    for (var n = [], r = 0; r < 32 * t.length; r += 8)
        n.push(t[r >>> 5] >>> 24 - r % 32 & 255);
    return n
}
function endianConversion(value) {
    if (typeof value === 'number') {
        // 32位整数字节交换
        return ((value & 0xFF) << 24) |
               ((value & 0xFF00) << 8) |
               ((value >> 8) & 0xFF00) |
               ((value >> 24) & 0xFF);
    }

    if (Array.isArray(value)) {
        return value.map(endianConversion);
    }

    return value;
}
function endian(t) {
    if (t.constructor == Number)
        return 16711935 & r.rotl(t, 8) | 4278255360 & r.rotl(t, 24);
    for (var n = 0; n < t.length; n++)
        t[n] = endianConversion(t[n]);
    return t
}
function de(e, n, a) {
    // 1. URL安全的Base64转换(如果a为true)
    if (a) {
      e = e.replace(/-/g, '+').replace(/_/g, '/');
    }

    // 2. Base64解码
    const encryptedData = Buffer.from(e, 'base64');

    // 3. 假设t(n)是密钥处理函数,这里简化为直接使用n作为密钥
    // 注意:实际实现中t(n)可能有特定处理,需要根据实际情况调整
    const key = Buffer.from(n, 'utf8'); 

    // 4. 创建解密器 - ECB模式通过不提供IV实现
    const decipher = crypto.createDecipheriv('aes-128-ecb', key, null);

    // 5. 设置PKCS7填充(Node.js默认就是PKCS7)
    decipher.setAutoPadding(true);

    // 6. 执行解密
    let decrypted = decipher.update(encryptedData);
    decrypted = Buffer.concat([decrypted, decipher.final()]);

    // 7. 返回解密后的字节数组
    return decrypted;
  }
const decrypted = de('密文', 'CJQjAc1hYieC4QYb', true);
console.log('解密结果:', decrypted.toString('utf8'));

function encryptAesEcb(e, n, a) {
  // 将密钥处理为16/24/32字节长度(AES-128/192/256)
  const key = Buffer.from(n, 'utf8');

  // 创建加密器 (ECB模式在Node.js中通过不提供IV来实现)
  const cipher = crypto.createCipheriv('aes-128-ecb', key, null);

  // 设置自动PKCS7填充
  cipher.setAutoPadding(true);

  // 加密数据
  let encrypted = cipher.update(e, 'utf8', 'base64');
  encrypted += cipher.final('base64');

  // 如果需要URL安全的Base64
  if (a) {
    encrypted = encrypted
      .replace(/\+/g, '-')
      .replace(/\//g, '_'); // 移除末尾的等号
  }

  return encrypted;
}

// 使用示例
const plaintext = '{"deptId":325525,"supportTakeout":0,"miniversion":"5347"}';
const key = 'CJQjAc1hYieC4QYb'; // AES-256需要32字节密钥

// 标准Base64输出
const encrypted1 = encryptAesEcb(plaintext, key, false);
console.log('标准Base64:', encrypted1);

// URL安全Base64输出
const encrypted2 = encryptAesEcb(plaintext, key, true);
console.log('URL安全Base64:', encrypted2);

function _md5(r) {
    r.constructor == String && (r = stringToBytes(r));
    for (var n = bytesToWords(r), i = 8 * r.length, s = 1732584193, u = -271733879, a = -1732584194, f = 271733878, c = 0; c < n.length; c++)
        n[c] = 16711935 & (n[c] << 8 | n[c] >>> 24) | 4278255360 & (n[c] << 24 | n[c] >>> 8);
    n[i >>> 5] |= 128 << i % 32,
    n[14 + (i + 64 >>> 9 << 4)] = i;
    var g = function(r, t, n, e, i, o, s) {
        var u = r + (t & n | ~t & e) + (i >>> 0) + s;
        return (u << o | u >>> 32 - o) + t
    }
      , _ = function(r, t, n, e, i, o, s) {
        var u = r + (t & e | n & ~e) + (i >>> 0) + s;
        return (u << o | u >>> 32 - o) + t
    }
      , y = function(r, t, n, e, i, o, s) {
        var u = r + (t ^ n ^ e) + (i >>> 0) + s;
        return (u << o | u >>> 32 - o) + t
    }
      , d = function(r, t, n, e, i, o, s) {
        var u = r + (n ^ (t | ~e)) + (i >>> 0) + s;
        return (u << o | u >>> 32 - o) + t
    };
    for (c = 0; c < n.length; c += 16) {
        var v = s
          , h = u
          , T = a
          , l = f;
        s = g(s, u, a, f, n[c + 0], 7, -680876936),
        f = g(f, s, u, a, n[c + 1], 12, -389564586),
        a = g(a, f, s, u, n[c + 2], 17, 606105819),
        u = g(u, a, f, s, n[c + 3], 22, -1044525330),
        s = g(s, u, a, f, n[c + 4], 7, -176418897),
        f = g(f, s, u, a, n[c + 5], 12, 1200080426),
        a = g(a, f, s, u, n[c + 6], 17, -1473231341),
        u = g(u, a, f, s, n[c + 7], 22, -45705983),
        s = g(s, u, a, f, n[c + 8], 7, 1770035416),
        f = g(f, s, u, a, n[c + 9], 12, -1958414417),
        a = g(a, f, s, u, n[c + 10], 17, -42063),
        u = g(u, a, f, s, n[c + 11], 22, -1990404162),
        s = g(s, u, a, f, n[c + 12], 7, 1804603682),
        f = g(f, s, u, a, n[c + 13], 12, -40341101),
        a = g(a, f, s, u, n[c + 14], 17, -1502002290),
        s = _(s, u = g(u, a, f, s, n[c + 15], 22, 1236535329), a, f, n[c + 1], 5, -165796510),
        f = _(f, s, u, a, n[c + 6], 9, -1069501632),
        a = _(a, f, s, u, n[c + 11], 14, 643717713),
        u = _(u, a, f, s, n[c + 0], 20, -373897302),
        s = _(s, u, a, f, n[c + 5], 5, -701558691),
        f = _(f, s, u, a, n[c + 10], 9, 38016083),
        a = _(a, f, s, u, n[c + 15], 14, -660478335),
        u = _(u, a, f, s, n[c + 4], 20, -405537848),
        s = _(s, u, a, f, n[c + 9], 5, 568446438),
        f = _(f, s, u, a, n[c + 14], 9, -1019803690),
        a = _(a, f, s, u, n[c + 3], 14, -187363961),
        u = _(u, a, f, s, n[c + 8], 20, 1163531501),
        s = _(s, u, a, f, n[c + 13], 5, -1444681467),
        f = _(f, s, u, a, n[c + 2], 9, -51403784),
        a = _(a, f, s, u, n[c + 7], 14, 1735328473),
        s = y(s, u = _(u, a, f, s, n[c + 12], 20, -1926607734), a, f, n[c + 5], 4, -378558),
        f = y(f, s, u, a, n[c + 8], 11, -2022574463),
        a = y(a, f, s, u, n[c + 11], 16, 1839030562),
        u = y(u, a, f, s, n[c + 14], 23, -35309556),
        s = y(s, u, a, f, n[c + 1], 4, -1530992060),
        f = y(f, s, u, a, n[c + 4], 11, 1272893353),
        a = y(a, f, s, u, n[c + 7], 16, -155497632),
        u = y(u, a, f, s, n[c + 10], 23, -1094730640),
        s = y(s, u, a, f, n[c + 13], 4, 681279174),
        f = y(f, s, u, a, n[c + 0], 11, -358537222),
        a = y(a, f, s, u, n[c + 3], 16, -722521979),
        u = y(u, a, f, s, n[c + 6], 23, 76029189),
        s = y(s, u, a, f, n[c + 9], 4, -640364487),
        f = y(f, s, u, a, n[c + 12], 11, -421815835),
        a = y(a, f, s, u, n[c + 15], 16, 530742520),
        s = d(s, u = y(u, a, f, s, n[c + 2], 23, -995338651), a, f, n[c + 0], 6, -198630844),
        f = d(f, s, u, a, n[c + 7], 10, 1126891415),
        a = d(a, f, s, u, n[c + 14], 15, -1416354905),
        u = d(u, a, f, s, n[c + 5], 21, -57434055),
        s = d(s, u, a, f, n[c + 12], 6, 1700485571),
        f = d(f, s, u, a, n[c + 3], 10, -1894986606),
        a = d(a, f, s, u, n[c + 10], 15, -1051523),
        u = d(u, a, f, s, n[c + 1], 21, -2054922799),
        s = d(s, u, a, f, n[c + 8], 6, 1873313359),
        f = d(f, s, u, a, n[c + 15], 10, -30611744),
        a = d(a, f, s, u, n[c + 6], 15, -1560198380),
        u = d(u, a, f, s, n[c + 13], 21, 1309151649),
        s = d(s, u, a, f, n[c + 4], 6, -145523070),
        f = d(f, s, u, a, n[c + 11], 10, -1120210379),
        a = d(a, f, s, u, n[c + 2], 15, 718787259),
        u = d(u, a, f, s, n[c + 9], 21, -343485551),
        s = s + v >>> 0,
        u = u + h >>> 0,
        a = a + T >>> 0,
        f = f + l >>> 0
    }
    return endian([s, u, a, f])
}

//uid就是cookie+key,那么key从哪来?
var t =wordsToBytes(_md5('cid=230101;dk=1;q=加密后密文+cookie'))

function n(r, e) {
    return (255 & r[e]) << 24 | (255 & r[e + 1]) << 16 | (255 & r[e + 2]) << 8 | 255 & r[e + 3]
}
var a = Math.abs(n(t, 0))
, s = Math.abs(n(t, 4))
, o = Math.abs(n(t, 8))
, c = Math.abs(n(t, 12));
var final_sign = a.toString() + s.toString() + o.toString() + c.toString()
console.log('final_sign => ',final_sign);

2025.5.7发现更新了算法

依旧跟栈找到sign出现位置


进入后来到这里

步进然后扣出关键代码,在本地实现即可

具体实现代码这里就不贴了,有需要的可以私我

5.8优化算法

如果已知utf8编码的明文,则可以使用 CryptoJS.enc.Utf8.parse 方法生成 WordArray 对象。

const CryptoJS = require("crypto-js");

// 生成 WordArray 对象
const keyWordArray = CryptoJS.enc.Utf8.parse("wm0!@w-s#ll1flo(");
console.log(keyWordArray);


转载请注明:
作者:syy,出处:https://www.94i.top/index.php/2025/05/01/某咖啡小程序逆向/
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇