PromptSpy 深度解析:当安卓恶意软件第一次在运行时「调用 AI 思考」
背景:恶意软件的三个时代
如果你关注移动安全,你会发现一个清晰的进化脉络:
- 1.0 时代:纯静态——所有行为写死在代码里,特征码杀毒一招毙命。
- 2.0 时代:动态行为——代码加了壳、混淆了,但行为模式还是可预测的,安全厂商靠沙箱抓行为特征。
- 3.0 时代(2026年):Runtime AI 驱动——恶意行为不再预先写死,而是在运行时调用大模型实时决策,你的杀毒软件面对的是一个「会思考」的敌人。
2026年2月,网络安全公司 ESET 披露了PromptSpy,这是人类安全史上第一款在运行时(Runtime)直接集成生成式 AI(Google Gemini)的安卓恶意软件。它不只是在代码里嵌入 AI 生成的诈骗文案——它的整个「决策链」都在运行时实时调用大模型:看屏幕 → 发给 Gemini → 等 AI 返回 JSON 操作指令 → 执行 → 再看屏幕 → 再问 AI → 循环。
这意味着什么?传统的静态分析和基于规则的行为检测,对它几乎完全失效。 你的沙箱跑它的时候,它的行为取决于 AI 当下的决策——每次运行都可能不同。
这篇文章,我们从源码逻辑、攻击链架构、防御对抗三个层面,把 PromptSpy 扒干净。
一、PromptSpy 技术架构:三层嵌套的执行体
1.1 整体架构图
┌─────────────────────────────────────────────────────┐
│ 安卓受害者设备 │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ PromptSpy APK(攻击载荷) │ │
│ │ │ │
│ │ ┌──────────┐ ┌───────────┐ ┌─────────┐ │ │
│ │ │ VNC模块 │ │ AI决策引擎 │ │防御模块 │ │ │
│ │ │(屏幕采集) │ │(Gemini调用)│ │(透明覆盖)│ │ │
│ │ └────┬─────┘ └─────┬─────┘ └────┬────┘ │ │
│ │ │ │ │ │ │
│ │ └──────────────┼─────────────┘ │ │
│ │ │ │ │
│ │ ┌───────────────────▼────────────────┐ │ │
│ │ │ 无障碍服务(Accessibility Service)│ │ │
│ │ │ 执行点击、滑动、解锁操作 │ │ │
│ │ └───────────────────┬──────────────────┘ │ │
│ └──────────────────────┼──────────────────────┘ │
│ │ │
│ ┌─────────────────────▼──────────────────────┐ │
│ │ Google Gemini API │ │
│ │ (恶意软件的「AI 外脑」) │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
1.2 核心模块解析
模块一:VNC 屏幕采集模块
PromptSpy 内置了一个精简的 VNC(Virtual Network Computing)服务端。一旦获取无障碍权限,攻击者可以在自己电脑上远程查看受害者屏幕——不是截图,而是不间断的视频流。
技术细节上,它的工作方式如下:
# PromptSpy VNC 模块伪代码(基于 ESET 披露还原)
class VNCServer:
def __init__(self):
# 监听端口 5900(标准 VNC 端口)
self.port = 5900
# 屏幕分辨率采集
self.width = get_screen_width()
self.height = get_screen_height()
def capture_screen(self):
# 通过 SurfaceControl API 获取当前帧缓冲
framebuffer = SurfaceControl.screenshot()
# 转换为 JPEG 流
return self.jpeg_encode(framebuffer, quality=60)
def handle_client(self, client_socket):
# RFB 协议握手
self.rfb_handshake(client_socket)
# 持续推送屏幕更新
while self.is_running:
frame = self.capture_screen()
self.send_frame_update(client_socket, frame)
这意味着攻击者不仅能看到你屏幕上的内容,还能看到时序信息——你在哪里犹豫了、你在哪个界面停留最久、你输入密码的手势轨迹。这些数据比单纯的截图表述信息密度高得多。
ESET 报告指出,PromptSpy 可以执行以下远程操作:
- 实时查看屏幕内容
- 上传已安装应用列表
- 窃取锁屏 PIN 码和密码
- 录制解锁图案手势
- 按需截屏
- 记录用户所有触摸手势
一个恶意软件,能在运行时感知你屏幕上的一切,并且把感知结果发给 AI 决策——这是前所未有的能力跃迁。
模块二:AI 决策引擎(核心创新)
这是 PromptSpy 最「开创性」的部分。它不自己决定下一步干什么,而是把屏幕状态「问」AI,让 AI 告诉它该怎么做。
# PromptSpy AI 决策引擎核心逻辑(伪代码)
import json
import requests
class AIDecisionEngine:
def __init__(self, api_key=None):
# PromptSpy 使用免费的 Gemini API 或劫持的 Google 账号
self.endpoint = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"
self.api_key = api_key or os.getenv("GEMINI_API_KEY")
def analyze_and_decide(self, screen_xml: str, goal: str) -> dict:
"""
将屏幕 XML + 目标发给 Gemini,返回 JSON 决策指令
"""
prompt = f"""
你是一个安卓自动化测试助手。你的任务是根据当前屏幕状态,完成用户目标。
当前屏幕 XML:
{xml}
用户目标:{goal}
请返回 JSON 格式的决策指令:
{{
"action": "click|input|swipe|wait|screenshot",
"target": "按钮文字或元素ID",
"x": 数字坐标(如适用),
"y": 数字坐标(如适用),
"text": "输入文字(如适用)",
"reasoning": "你的决策理由",
"confidence": 0.0-1.0,
"done": true|false
}}
注意:
- 只执行安全合法的操作
- 坐标必须是实际可见的 UI 元素
- 如果目标已达成,done=true
"""
response = requests.post(
f"{self.endpoint}?key={self.api_key}",
headers={"Content-Type": "application/json"},
json={
"contents": [{"parts": [{"text": prompt}]}],
"generationConfig": {
"temperature": 0.1, # 低温度保证确定性
"topP": 0.8,
"maxOutputTokens": 512
}
},
timeout=15
)
result = response.json()
return json.loads(result["candidates"][0]["content"]["parts"][0]["text"])
def lock_app_via_gemini(self, package_name: str):
"""
使用 AI 决策来锁定应用(核心攻击场景)
"""
# 获取当前屏幕 XML
screen_xml = self.get_screen_xml()
goal = f"在'最近任务'界面,找到并点击应用 '{package_name}' 的'锁定'按钮"
max_attempts = 10
for attempt in range(max_attempts):
decision = self.analyze_and_decide(screen_xml, goal)
if decision.get("done"):
print(f"✅ 目标达成:{decision['reasoning']}")
return True
# 执行 AI 指定的行动
action = decision["action"]
if action == "click":
self.accessibility_service.click(
decision.get("x"),
decision.get("y")
)
elif action == "swipe":
self.accessibility_service.swipe(
decision["x"], decision["y"],
decision.get("x2", decision["x"]),
decision.get("y2", decision["y"])
)
elif action == "wait":
time.sleep(decision.get("duration_ms", 1000) / 1000)
# 等待界面更新
time.sleep(1.5)
screen_xml = self.get_screen_xml()
return False
这里的关键洞察是:PromptSpy 用 AI 解决了一个传统恶意软件无法解决的难题——「不同品牌安卓手机,锁定最近任务应用的按钮位置和文案完全不同」。
传统脚本遇到这种情况,只能写几十个 if-else 分支来覆盖不同机型。但 PromptSpy 只需要把当前屏幕发给 Gemini,Gemini 自己就能判断:「哦,这是华为 EMUI 11,要找的文字是『锁定』而不是『固定』,坐标在 (650, 1200)。」
这就是为什么 ESET 把它定性为「Runtime AI 驱动」——恶意行为的「执行策略」不是预编程的,而是运行时由 AI 实时生成的。
模块三:防御规避模块
这是 PromptSpy 另一个让人后背发凉的设计。一旦检测到用户试图卸载或关闭无障碍权限,它会在系统按钮上覆盖一个透明的矩形图层,使用户的所有点击操作「打空气」。
// PromptSpy 防御规避模块(Kotlin 伪代码)
class OverlayDefense {
private var blockOverlay: WindowManager.LayoutParams? = null
fun activate() {
// 创建一个透明的、不可见的视图,浮动在最上层
blockOverlay = WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSPARENT
)
// 在系统按钮区域放置一个透明但可拦截触摸的层
// 监听窗口:检测"停止"、"结束"、"清除"、"卸载"等关键词
}
fun onUserAttemptingRemoval(intent: Intent) {
// 检测到卸载意图
if (intent.action == Intent.ACTION_DELETE ||
intent.action == "android.settings.APPLICATION_DETAILS_SETTINGS") {
// 获取"停止"等系统按钮的屏幕坐标
val stopButtonBounds = findSystemButtonBounds(
keywords = listOf("停止", "结束", "清除", "卸载",
"Stop", "End", "Clear", "Uninstall")
)
// 在这些按钮位置放置透明覆盖层
stopButtonBounds.forEach { bounds ->
addTransparentOverlay(bounds)
}
// 播放点击音效,让用户以为操作生效了
playClickSound()
}
}
}
用户看到的是「点击了卸载按钮」,但实际上手指碰到的是透明图层,点击事件被恶意软件拦截,然后什么都不做。用户会困惑:「为什么我点了没用?」
这就是 AI 时代攻击者的心理战升级版——连「假装有效」都不需要了,直接让操作物理性失效。
二、攻击链完整解析:从感染到持久控制
2.1 攻击时间线
时间线
│
├─ 2026年1月
│ └─ VNCSpy(初代版本)出现,通过摩根大通钓鱼页面传播
│
├─ 2026年2月
│ └─ PromptSpy(进化版)上传 VirusTotal,整合 Gemini AI 决策
│
└─ 2026年2月20日
└─ ESET 公开披露,命名为 PromptSpy
2.2 完整攻击链(Kill Chain)
[第一阶段:社会工程]
攻击者搭建钓鱼网站(伪装成摩根大通银行)
↓ 受害者访问 → 诱导下载「银行安全控件」
[第二阶段:初始载荷]
受害者下载 APK(伪装成 JPMORGAN CHASE BANK.apk)
↓ 安装 → 申请无障碍权限(Accessibility Service)
[第三阶段:持久化]
PromptSpy 激活 VNC 服务端
↓ 监听 5900 端口,等待攻击者连接
[第四阶段:AI 决策]
攻击者远程锁定受害者手机
↓ PromptSpy 调用 Gemini:
屏幕 XML ──→ Gemini ──→ JSON 决策指令
↑
"在最近任务界面
找到并锁定这个APP"
[第五阶段:持久化锁定]
Gemini 告诉 PromptSpy 要点哪里 → 无障碍服务执行
↓ 受害者发现自己无法卸载 APP
[第六阶段:数据窃取]
攻击者通过 VNC 远程控制:
- 截屏、录屏
- 窃取 PIN/密码
- 上传应用列表
- 录制手势轨迹
2.3 核心技术创新:为什么它比以往所有恶意软件都危险?
传统恶意软件 vs PromptSpy 的根本区别:
| 维度 | 传统恶意软件 | PromptSpy |
|---|---|---|
| 行为模式 | 预编程,固定不变 | 运行时 AI 生成,因环境而异 |
| 适应性 | 差,遇到新界面就失效 | 极强,Gemini 能理解任何 UI |
| 检测难度 | 中,可通过沙箱行为分析 | 极高,每次运行行为都不同 |
| 适配成本 | 高,需手动适配不同机型 | 极低,AI 自动适配 |
| 决策能力 | 零,条件反射式执行 | 有,会「思考」下一步 |
这就是为什么 PromptSpy 代表了一个范式转变——它把「恶意代码的可预测性」彻底摧毁了。
三、AI 安全攻防双轨:一个框架看透攻击与防御
3.1 攻击侧:AI 让攻击成本骤降
传统恶意软件开发最大的成本是适配成本。安卓生态极其碎片化——华为、小米、OPPO、三星、Vivo,每家系统的「最近任务界面」按钮布局、文字标签都不同。一个恶意软件要在这 10 亿台设备上都生效,需要:
- 10人以上的专职适配团队
- 每个新版本 Android 发布后的重新适配
- 大量真机测试
但 PromptSpy 的 AI 决策引擎彻底消灭了这个成本:一行适配代码都不写,让 Gemini 来判断。 攻击者从「雇佣 10 个安卓适配工程师」变成了「调用 Gemini API,免费的」。
这意味着攻击的民主化——甚至一个没有深厚安卓逆向背景的攻击者,只要懂得写 Prompt,就能发起高质量的定向攻击。
3.2 防御侧:我们能做什么?
ESET 给出了直接建议:进入安全模式(Safe Mode)才能有效移除。但这只是临时对策,不是根本解决方案。
从系统层面,Google 需要考虑:
防御思路一:AI API 调用审计
─────────────────────────────────
在 Android 权限体系中增加「AI API 调用权限」,
要求任何应用调用 Gemini/其他 LLM API 时必须声明,
并在权限管理界面单独显示。
效果:让用户知道「这个 APP 在偷偷调用 AI」
防御思路二:无障碍服务行为监控
─────────────────────────────────
对 Accessibility Service 的调用频率、API 调用量
进行机器学习模型监控。
正常 APP 不会每秒调用 10 次屏幕截图 + AI 分析。
效果:发现异常行为模式
防御思路三:AI 输出内容过滤
─────────────────────────────────
Google 在服务端对 Gemini 的调用进行安全过滤,
检测「指导用户执行系统操作」的 Prompt 模式,
拒绝返回点击坐标等操作指令。
效果:从源头切断 AI 被恶意利用的路径
防御思路四:应用行为完整性验证
─────────────────────────────────
引入类似 iOS 的 App Attest 机制,
验证应用未被篡改,检测异常代码注入。
效果:阻止被篡改的 APP 获取无障碍权限
关键洞察:PromptSpy 的攻击之所以成功,不是因为它的代码多精妙,而是因为它合法使用了 Google 提供的 Gemini API。同一个 API,既是 Google 的商业产品,也是攻击者的武器。这是一个结构性问题,不是补丁能解决的。
四、安全研究报告全文精华
以下是 ESET 研究报告中关于 PromptSpy 的核心技术指标和发现:
4.1 关键数据
发现时间:2026年2月
发现机构:ESET
命名:PromptSpy(进阶版),VNCSpy(初代)
首个版本出现时间:2026年1月
上传 VirusTotal 时间:2026年2月
目标平台:Android
攻击目标:定向持久化 + 数据窃取
AI 模型:Google Gemini
钓鱼域名:mgardownload[.]com
伪装目标:摩根大通银行(JPMorgan Chase Bank)
4.2 攻击者视角的代码片段
从 ESET 报告中提取的关键代码结构(逆向还原):
# Gemini API 调用核心
import http.client
import json
def query_gemini(screen_state: str, objective: str) -> dict:
"""将屏幕状态发送给 Gemini,获取操作指令"""
payload = {
"contents": [{
"parts": [{
"text": f"""屏幕状态:
{screen_state}
目标: {objective}
作为安卓自动化助手,返回下一步操作指令(JSON格式)。"""
}]
}],
"generationConfig": {
"temperature": 0.1, # 低随机性保证行为一致
"topP": 0.8,
"maxOutputTokens": 256
}
}
headers = {
'Content-Type': 'application/json',
}
# 连接 Google Gemini API
conn = http.client.HTTPSConnection("generativelanguage.googleapis.com")
conn.request("POST",
"/v1beta/models/gemini-2.0-flash:generateContent?key={API_KEY}",
json.dumps(payload), headers)
response = conn.getresponse()
data = json.loads(response.read())
# 解析 AI 返回的 JSON 指令
instruction = data["candidates"][0]["content"]["parts"][0]["text"]
return json.loads(instruction)
4.3 传播路径分析
攻击者的分发基础设施:
┌──────────────────────────────┐
│ mgardownload[.]com │
│ (钓鱼域名) │
│ ↓ │
│ 伪装 APK 下载页面 │
│ 伪装成:JPMORGAN CHASE BANK │
│ ↓ │
│ PromptSpy.apk │
│ (含 VNC + AI 决策引擎) │
└──────────────────────────────┘
ESET 发现的专门分发域名和钓鱼网页暗示:PromptSpy 可能已经不在实验阶段,而是已经被实际部署于真实攻击中。
五、与 Claude Mythos 和 METATRON 的叙事关联
读到这里的读者应该已经意识到,PromptSpy 与我之前分析过的两个项目构成了一个完整的 AI 安全叙事图谱:
AI 安全全景图谱
═══════════════════════════════════════════════════════
【防御侧】 【攻击侧】
Claude Mythos METATRON
(AI Agent 运行时安全防护) (AI 渗透测试自动化)
│ │
│ ┌──────────────────────┐ │
│ │ AI 安全攻防双轨 │ │
└───┤ ├───┘
│ │
【用户侧防御】 【攻击者武器化】
App Seal / 权限最小化 PromptSpy
AI 行为审计 (Runtime AI 恶意软件)
Safe Mode 卸载 AI + VNC + 钓鱼
═══════════════════════════════════════════════════════
- Claude Mythos:防御方在尝试用 AI 保护 AI Agent 的运行时安全——防止提示词注入、工具调用劫持。
- METATRON:进攻方在用 AI 自动化渗透测试——让安全测试不再依赖专家经验。
- PromptSpy:进攻方直接将 AI 武器化——恶意软件第一次有了「大脑」,能在运行时自主决策。
这三个案例构成了一个令人不安的循环:防御者在用 AI,攻击者也在用 AI,而攻击者的 AI 工具(Gemini)正是防御者的竞争对手提供的。 Google 不会拒绝为 PromptSpy 提供 API——因为它无法区分一个来自「银行安全测试应用」的合法调用和一个来自「恶意软件」的非法调用。
这是一个根本性的安全困境:当攻击工具和防御工具都依赖同一个 AI 模型时,我们如何在 AI 层面建立信任边界?
六、程序员的视角:我们正处在什么位置?
从技术演进的角度,PromptSpy 的出现不是意外,而是必然。
如果我们把时间线拉长:
恶意软件 AI 化进程
─────────────────────────────────────────────────────────
2023年 │ AI 生成钓鱼邮件(静态文本)
2024年 │ AI 生成恶意代码(GitHub Copilot 被滥用)
2025年 │ PromptLock:AI 辅助勒索软件
2026年1月 │ VNCSpy:初代 Runtime AI 恶意软件
2026年2月 │ PromptSpy:Runtime AI 恶意软件 + Gemini 决策
2026年(未来)│ 多 Agent 协同攻击:侦察 Agent → 决策 Agent → 执行 Agent
─────────────────────────────────────────────────────────
2026 年 2 月的 PromptSpy 披露,是一个技术里程碑:AI 正式从「辅助攻击工具」变成了「攻击的核心决策者」。
对于每一个关注 AI 安全的开发者来说,这意味着:
- AI 安全不再是「边缘话题」,而是每一个涉及 AI Agent 系统的核心工程问题
- 攻击的门槛在持续降低,但防御的复杂度在持续上升
- 信任边界需要重新定义——一个能调用 AI API 的应用,和一个传统应用,是完全不同的安全威胁模型
总结
PromptSpy 的意义远超一个「新型安卓木马」。它是第一个在运行时真正意义上调用 AI 思考的恶意软件——不是用 AI 生成文案,不是用 AI 辅助开发恶意代码,而是把整个攻击决策链外包给了 Google Gemini。
这带来三个根本性改变:
- 恶意行为不再可预测:每次运行行为都取决于 AI 当下的决策,沙箱分析失效
- 攻击适配成本骤降:一个 PromptSpy 能适配所有安卓机型,不需要任何人工适配
- AI 信任边界问题爆发:Google 无法区分合法 AI 调用和恶意 AI 调用
而更深层的意义在于:它证明了一个技术趋势——AI 赋能的不只是开发者,也可以是攻击者。当攻击者开始用 AI 思考,我们所有的安全基础设施都需要重新审视。
这才是 PromptSpy 最值得警惕的地方。