小黑盒后端参数逆向 前言 最近闲来无事,想着逆向一下小黑盒的API接口,小黑盒因为有web端,所以不用在手机上抓包来看请求,直接在浏览器中用DevTools工具就可以看了,相比于知乎等其他后端,小黑盒的防护还算比较简答,小黑盒整个页面都是基于vue和vite搭建出来的。
思路 首先尝试在DevTools中搜索api,果不其然,直接找到了相应的api请求,也直接可以看到后端请求的地址,剩下的是不是直接访问就可以了吗,当然没这么简单。
我们肯定第一步就是先看看请求header,小黑盒的请求header倒没什么有效的信息,唯一可以说有效的,可能就是cookie了,这个登录以后,直接就可以复制进来用,其他的都是一些固定的参数,也没有加密什么之类的
然后自然就是请求链接了,我们先提取出一个链接来看看。
1 https://api.xiaoheihe.cn/account/data_report_web/?os_type=web&app=heybox&client_type=web&version=999.0.4&web_version=2.5&x_client_type=web&x_app=heybox_website&heybox_id&x_os_type=Windows&device_info=Chrome&device_id=2c2fef8385ccef915e3b3caf94e3aa06&hkey=3XX1P62&_time=1770529394&nonce=3D6891C5FEBD5A0A4C986784D2F60E81&type=104&time_=1770529394
不难发现,很多内容也都是固定的,没有什么含金量,但是最后的几个参数,就会发现有点不对劲了,那些time,hkey,nonce又是什么,怎么凭空出现这么多变化的参数,所以这一部分的内容,就是我们需要逆向的重点。
1 hkey=3XX1P62&_time=1770529394&nonce=3D6891C5FEBD5A0A4C986784D2F60E81&time_=1770529394
首先可以观察,time和_time一直是一样的,根据英文,应该可以知道,这个大概率是一个时间戳,经过验证,这个time就是当前美国时间的时间戳。
然后就是nonce和hkey了,这个非常没有头绪,nonce看着像md5,每次还不一样,其实nonce就是一串随机的md5,把二进制的哈希,转化为16进制的字符串,内容是无所谓的,这个参数的作用主要是配合time,防止重放攻击。
最后是hkey,这个也是整个逆向过程中,最难的一个步骤了。
首先在DevTools里面请求完后全局搜索hkey,但是会发现一无所获,所搜索到的一些js,里面都没有跟hkey相关的。
那应该怎么办呢。可以选择下断点,重新复现一下请求的过程,我们随便找一个api下断点,比如找feeds下XHR断点,就是一旦执行了包含feeds这个路由的访问时,就进入中断,果不其然,又有了新的发现。
这一次,我们进入了一个完全不一样的js文件,这个js文件非常大,这个文件就是vue/vite打包生成的一个文件,非常大,有1mb左右了,里面就包含了关于hkey的逻辑。
所以我选择把这个文件交给了gemini,结果很顺利,它经过了几次测试后,终于测试出了,生成hkey的方式。
算法逻辑 :
- 使用了三个输入:路径、时间戳、Nonce。
- 通过 `av` 和 `sv` 函数将这三个输入映射到字符集。
- 将映射后的字符串进行**交错混合** (Interleaving)。
- 对混合后的字符串取 **MD5**。
- 前缀取 MD5 前 5 位映射字符集,后缀取 MD5 后 6 位进行 Rijndael 变换(`Km` 函数)并计算校验和。
这是整个过程的主要逻辑,把整个过程,用js表达出来,就是这样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 import hashlib import time # --- 基础混淆函数--- def Vm(e): if e & 128: return (255 & ((e << 1) ^ 27)) else: return e << 1 def qm(e): return Vm(e) ^ e def dollar_m(e): return qm(Vm(e)) def Ym(e): return dollar_m(qm(Vm(e))) def Gm(e): return Ym(e) ^ dollar_m(e) ^ qm(e) def Km_full(e_arr): # 处理数组变换 e = e_arr[:] # 复制数组 t = [0, 0, 0, 0] t[0] = Gm(e[0]) ^ Ym(e[1]) ^ dollar_m(e[2]) ^ qm(e[3]) t[1] = qm(e[0]) ^ Gm(e[1]) ^ Ym(e[2]) ^ dollar_m(e[3]) t[2] = dollar_m(e[0]) ^ qm(e[1]) ^ Gm(e[2]) ^ Ym(e[3]) t[3] = Ym(e[0]) ^ dollar_m(e[1]) ^ qm(e[2]) ^ Gm(e[3]) # 更新前4位 e[0], e[1], e[2], e[3] = t[0], t[1], t[2], t[3] return e # --- 新版映射函数 --- def av(e, t, n): """ e: 输入字符串 t: 字符集 n: 切片长度 (负数表示切掉末尾) """ if n < 0: i = t[:n] else: i = t[:n] r = "" for char in e: idx = ord(char) % len(i) r += i[idx] return r def sv(e, t): """ e: 输入字符串 t: 字符集 """ n_str = "" for char in e: idx = ord(char) % len(t) n_str += t[idx] return n_str def get_hkey(url_path, timestamp, nonce): # 1. 字符集 (从文件中提取) charset = "AB45STUVWZEFGJ6CH01D237IXYPQRKLMN89" # 2. 路径标准化 parts = [p for p in url_path.split('/') if p] normalized_path = "/" + "/".join(parts) + "/" # 3. 生成三个分量 # 分量1: 处理时间戳 (使用字符集的前34位,即切掉后2位) comp1 = av(str(timestamp), charset, -2) # 分量2: 处理路径 (使用完整字符集) comp2 = sv(normalized_path, charset) # 分量3: 处理Nonce (使用完整字符集) comp3 = sv(nonce, charset) # 4. 字符串交错混合 (Interleave) # 逻辑: 取三个字符串的第0位拼接,然后第1位拼接...直到最大长度 comps = [comp1, comp2, comp3] max_len = max(len(c) for c in comps) interleaved = "" for k in range(max_len): for c in comps: if k < len(c): interleaved += c[k] # 截取前20位作为哈希输入 i_str = interleaved[:20] # 5. 计算 MD5 md5_hash = hashlib.md5(i_str.encode('utf-8')).hexdigest() # 6. 计算前缀 (使用 MD5 前5位映射,字符集切掉后4位) o_prefix = md5_hash[:5] hkey_prefix = av(o_prefix, charset, -4) # 7. 计算后缀校验和 (使用 MD5 后6位) suffix_part = md5_hash[-6:] suffix_input = [ord(c) for c in suffix_part] # 运行 Km 算法 km_output = Km_full(suffix_input) # 求和取余 checksum_val = sum(km_output) % 100 checksum_str = f"{checksum_val:02d}" return hkey_prefix + checksum_str # --- 验证你的数据 --- if __name__ == "__main__": # 输入数据 path = "/bbs/app/api/emojis/list" ts = 1770287253 nonce = "2B81EA33B45BA438DB1E4DFC5375B5D6" # 计算 hkey = get_hkey(path, ts, nonce) print(f"Path: {path}") print(f"Time: {ts}") print(f"Nonce: {nonce}") print(f"Calculated hkey: {hkey}")
其中path和ts都是可变的,nonce也是随意的。
成品 GitHub - luckylca/xhhBackCrack: 小黑盒后端请求逆向
这是应用方法,可以选择后可以直接运行,打开后的链接真实有效,在cookie正确的前提下,成功拿到了后端发过来的json