|
92| 0
|
[Android 原创] Interlink Network APK 逆向工程笔记 |
其他扫描出的 API / 第三方域名
2. APK 文件结构 & 关键资产
3. Hermes Bundle 反编译步骤(hermes-dec)3.1 安装
落到
3.2 三步反编译
3.3 输出特点 & 阅读技巧
3.4 高效检索套路
4. RN Android APK 逆向通用知识4.1 工具链 & 选择
4.2 常见混淆手法 & 应对
4.3 17 dex 反汇编命令模板(内存受限环境)
5.
|
| # | 问题 | 证据 | 影响 |
|---|---|---|---|
| 1 | POST body \= undefined |
r0 = undefined; r2.bind(r3)(r1, r0) |
axios 不带 Content-Type、空 body → 服务端期待 JSON 时 400/422 |
| 2 | 客户端收集了点击坐标但没上传 | onPress 里 _closure5_slot0..3 = nativeEvent.{locationX,locationY,pageX,pageY},下游 mutate({}) 没带 |
强烈疑似反作弊"真人坐标"校验,客户端漏传 |
| 3 | 没带 captcha token | app 集成 captcha.interlinklabs.ai,但 mutationFn 不接收任何参数 |
服务端开启 captcha → 403 |
| 4 | 没带幂等 key / 风控字段 | 同时存在 /token/number-user-duplicate-claim-airdrop 重复检测端点,本接口请求体空 |
防刷字段缺失 |
| 5 | 前置 UI 锁 | isEmailConfirmed=false → not_defined_email 模态;isClaimable=false → 倒计时 |
条件不满足按钮根本不发请求 |
| 6 | 错误吞噬 | onError 只记 CLAIM_INDIVIDUAL_ERROR,前端通用错误 modal |
服务端真实报错被埋点淹没 |
curl -X POST 'https://prod.interlinklabs.ai/api/v1/token/claim-airdrop' \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-H "version: 5.0.1" \
-H "x-platform: android" \
-H "x-bundle-id: org.ai.interlinklabs.interlinkId" \
-H "x-system-name: Android" \
-H "x-brand: google" \
-H "x-model: Pixel 4" \
-H "x-device-id: 3732b0aac88b56ab" \
-H "x-unique-id: 3732b0aac88b56ab" \
-H "x-date: $(node -e 'console.log(Date.now())')" \
-H "x-signature: <见 §6 算法>" \
-d '{}'
x-signature 查找过程 & 生成算法| 阶段 | 动作 | 结果 |
|---|---|---|
| 1 | grep 'x-signature' over JS 伪代码 |
1 处命中(mini-app submitScore),全局机制无 |
| 2 | strings over 17 dex |
无字面量(被 RN-Keys 加密) |
| 3 | strings over 所有 .so |
无字面量 |
| 4 | 找 OkHttp Interceptor 实现 + HmacSHA256 | 候选都是第三方 SDK,业务自有拦截器不存在 |
| 5 | 反查 react-native-keys 模块 |
命中 KeysModule.getSecureFor / 加密载荷 PrivateKey.privatekey / JNI libreact-native-keys.so |
| 6 | 在 JS 伪代码里找 secureFor 调用 |
命中 HMAC_CONSTANTS 完整 key 表 + generateHmacHeaders 函数 |
结论:签名在 JS 层完成,密钥与所有 header 名通过 secureFor() 在运行时解密注入。
secureFor 取的)HMAC_HASH_SECRET // HMAC 主密钥(值未知,需 Frida)
HMAC_SIGNATURE_HEADER_NAME // = "x-signature"
REQUEST_DATE_HEADER_NAME // = "x-date"
REQUEST_CONTENT_HASH_HEADER_NAME // 请求体 hash 头名(仅 JSON body 时附)
MAX_REQUEST_MINUTES_ALLOW // 服务端 x-date 容忍窗(分钟)
REQUEST_UNIQUE_ID // = "x-unique-id"
REQUEST_MODEL // = "x-model"
REQUEST_BRAND // = "x-brand"
REQUEST_SYSTEM_NAME // = "x-system-name"
REQUEST_DEVICE_ID // = "x-device-id"
REQUEST_BUNDLE_ID // = "x-bundle-id"
axios 实例创建时还固定带:
{ 'Content-Type': 'application/json', 'Accept': '*/*', 'version': '5.0.1', 'x-platform': 'android' }
generateHmacHeaders 还原import CryptoJS from 'crypto-js';
function generateHmacHeaders({ method, url, baseURL, params, body, contentType }) {
const SECRET = HMAC_CONSTANTS.HMAC_HASH_SECRET; // 由 RNKeys 解出
if (!SECRET) return {};
const M = method.toUpperCase(); // GET / POST / ...
const date = String(Date.now()); // 毫秒时间戳字符串
// 1) 拼完整 URL(如有 params 则 ?qs.stringify(params))
let full = (baseURL || '') + url;
if (params && Object.keys(params).length > 0) {
const qs = qsStringify(params);
if (qs) full += '?' + qs;
}
// 2) URL 解析(host + pathname+search)
const u = new URL(full);
const host = u.host; // e.g. prod.interlinklabs.ai
const path = u.pathname + u.search; // e.g. /api/v1/token/claim-airdrop
// 3) body 摘要:仅当 Content-Type 含 application/json
let bodyHash = '';
if (body && typeof contentType === 'string' && contentType.includes('application/json')) {
bodyHash = CryptoJS.SHA256(JSON.stringify(body))
.toString(CryptoJS.enc.Base64);
}
// 4) message = 用 ";" 拼
const parts = [M, path, date, host];
if (bodyHash) parts.push(bodyHash);
const message = parts.join(';');
// 例: "POST;/api/v1/token/claim-airdrop;1778543721362;prod.interlinklabs.ai"
// 5) HMAC-SHA256 → Base64
const signature = CryptoJS.HmacSHA256(message, SECRET)
.toString(CryptoJS.enc.Base64);
const headers = {
[HMAC_CONSTANTS.REQUEST_DATE_HEADER_NAME]: date, // x-date
[HMAC_CONSTANTS.HMAC_SIGNATURE_HEADER_NAME]: signature, // x-signature
};
if (bodyHash && HMAC_CONSTANTS.REQUEST_CONTENT_HASH_HEADER_NAME) {
headers[HMAC_CONSTANTS.REQUEST_CONTENT_HASH_HEADER_NAME] = bodyHash;
}
return headers;
}
message = METHOD ";" PATH+SEARCH ";" DATE_MS ";" HOST [ ";" SHA256_BASE64(JSON.stringify(body)) ]
x-signature = base64( HMAC-SHA256( message, HMAC_HASH_SECRET ) )
x-date = String(Date.now())
服务端会校验
|now - x-date| < MAX_REQUEST_MINUTES_ALLOW * 60_000,超时就 401。
x-unique-id / x-device-id / x-model / x-brand / x-system-name / x-bundle-id 头名由 secureFor() 解出;值由 react-native-device-info 在运行时取,对应:
x-bundle-id ← getBundleId() ≡ org.ai.interlinklabs.interlinkIdx-system-name ← getSystemName() ≡ Androidx-brand ← getBrand() ≡ googlex-model ← getModel() ≡ 设备型号(e.g. Pixel 4)x-unique-id / x-device-id ← getUniqueId() / getAndroidId(),均为 16 字符 hexpip install frida-tools + 设备端 frida-server 启动adb install app.apkdump_rn_secure_keys.js// frida -U -f org.ai.interlinklabs.interlinkId -l dump_rn_secure_keys.js
Java.perform(function () {
const KM = Java.use('com.reactnativekeysjsi.KeysModule');
const keys = [
'HMAC_HASH_SECRET',
'HMAC_SIGNATURE_HEADER_NAME',
'REQUEST_DATE_HEADER_NAME',
'REQUEST_CONTENT_HASH_HEADER_NAME',
'MAX_REQUEST_MINUTES_ALLOW',
'REQUEST_UNIQUE_ID', 'REQUEST_MODEL', 'REQUEST_BRAND',
'REQUEST_SYSTEM_NAME', 'REQUEST_DEVICE_ID', 'REQUEST_BUNDLE_ID',
];
// 等 RN bridge / native lib 起来再调
setTimeout(() => {
keys.forEach(k => {
try { console.log(k, '=', KM.getSecureFor(k)); }
catch (e) { console.log(k, 'ERR', e); }
});
}, 3000);
});
# 1) 拉 frida-server 到设备(按 CPU 架构选)
adb push frida-server-arm64 /data/local/tmp/fs && adb shell "su -c 'chmod 755 /data/local/tmp/fs && /data/local/tmp/fs &'"
# 2) 启动 + hook
frida -U -f org.ai.interlinklabs.interlinkId -l dump_secrets.js --no-pause
预期输出(值是占位):
HMAC_HASH_SECRET = <随机字符串/十六进制>
HMAC_SIGNATURE_HEADER_NAME = x-signature
REQUEST_DATE_HEADER_NAME = x-date
REQUEST_CONTENT_HASH_HEADER_NAME = x-content-hash
MAX_REQUEST_MINUTES_ALLOW = 5
REQUEST_UNIQUE_ID = x-unique-id
REQUEST_MODEL = x-model
REQUEST_BRAND = x-brand
REQUEST_SYSTEM_NAME = x-system-name
REQUEST_DEVICE_ID = x-device-id
REQUEST_BUNDLE_ID = x-bundle-id
如果你只想验证算法对不对、或绕过密钥提取:
// hook axios 包装层,直接 dump 已签名请求
Java.perform(function () {
const NetworkingModule = Java.use('com.facebook.react.modules.network.NetworkingModule');
NetworkingModule.sendRequestInternal.implementation = function (method, url, requestId, headers, data, responseType, useIncrementalUpdates, timeout, withCredentials) {
console.log('[REQ]', method, url);
const it = headers.iterator();
while (it.hasNext()) console.log(' ', it.next().toString());
if (data) console.log(' body:', data.toString());
return this.sendRequestInternal.apply(this, arguments);
};
});
把 HMAC_HASH_SECRET 填到 §6.3 的 generateHmacHeaders,配合一个 Node 项目就能离线复现整套签名 → curl/axios 直接打通 claim-airdrop 等所有 prod.interlinklabs.ai 接口。
HMAC_HASH_SECRET 公开到 GitHub / 公网;它一旦泄露足以伪造任意请求。tools/rn-rev/
├── in/
│ ├── app.apk # 197 MB
│ └── bundle.hbc # 22 MB Hermes 字节码
├── apk_extracted/ # unzip app.apk 直出
├── smali_out/c0..c17/ # 全部 dex 反汇编
├── out/
│ ├── header.txt # bundle 元信息
│ ├── bundle.hasm (.gz) # 字节码反汇编
│ └── bundle.pseudo.js (.gz) # 类 JS 伪代码(4.2M 行)
├── bin/ # jadx + baksmali
└── docs/interlink-reverse.md # 本文档发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。
RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )
GMT+8, 2026-5-16 04:01
Powered by Discuz!
Copyright © 2001-2020, Tencent Cloud.