返回

文章详情

我不小心将 LLM 内存变成了程序分析

Hacker News2026年8月28日 23:27

在过去的几个月里,我一直在相当积极地玩转 LLM 代理,特别是用于漏洞研究。它们在浏览大型代码库、解释不熟悉的子系统以及帮助探索潜在攻击面方面变得出奇的优秀。然而,一旦调查开始进行几小时,我就不断遇到同样的问题:模型会慢慢失去我们实际上已经建立的东西。它可能建议一种我们已经排除的方法,忘记一个假设结果是错误的,或者自信地继续基于一个不再有效的观察进行推理。显然,告诉 LLM 某些事情是错误的并不一定意味着它会停止相信所有依赖于它的东西 :) 我最初开始研究内存系统是因为我想让 LLM 在复杂漏洞研究中更有用,并减少这种类型的幻觉。当然,已经有很多解决方案可以为 LLM 提供内存。通常,这涉及将旧的对话或观察存储在某个地方,进行嵌入,然后在模型需要时检索最相关的部分。这基本上运行得还不错,但其中有些东西让我感到困扰。在漏洞研究时,我不仅希望模型记住我们说过的内容。我希望它保持我们当前的知识。想象一下,在调查中我们确定以下内容:攻击者控制 object_a,object_a 指向 object_b,object_b 是内核对象。基于这一点,我们可以得出结论:攻击者可以控制一个内核对象。一个普通的记忆系统可以存储所有这些观察,并在我们询问这个漏洞的可利用性时再次检索它们。然后 LLM 计算出相同的结论。太好了!但假设两个小时后,我们在 LLDB 中发现 object_a 实际上并不指向 object_b,而我们之前的观察是基于错误的假设。在那时,我们的记忆可能包含类似以下内容:object_a 指向 object_b,攻击者可以控制 object_b,object_a 实际上并不指向 object_b。现在我们检索这些记忆的某个子集,并希望 LLM 正确判断哪些结论仍然有效。这开始让我感到有些熟悉。这看起来像程序分析。我通常做的很多工作涉及程序分析。在分析一个程序时,我们通常有一堆关于程序的事实和一些规则,从中可以推导出其他事实。例如,假设我们知道:calls(foo, bar), calls(bar, baz)。我们可以定义一个规则,表明如果一个函数调用另一个函数,而该函数本身可以达到第三个函数,那么第一个函数也可以达到第三个函数。最终,我们计算出一个固定点,包含我们可以从程序中推导出的所有内容。更重要的是,如果我们的输入事实之一发生变化,有很多技术可以仅更新受影响的结果,而不是从头开始重新运行所有内容。这也正是我在进行漏洞研究时希望 LLM 实现的。如果一个观察发生变化,我不希望模型从记录中重新构建整个调查,并希望注意到所有的后果。我希望受影响的结论自动变为无效。从这个角度看待问题时,我开始想知道为什么我们让 LLM 一次又一次地重建其整个状态。如果我们只是保持它呢?这就是我不知怎么的最终写了一个供 LLM 使用的 Datalog 引擎 :) Datalog 在继续之前,简单介绍一下 Datalog 实际上是什么可能是有用的。Datalog 是一种声明式逻辑编程语言。我们不是编写描述如何计算某物的指令,而是描述事实和规则,从中可以推导出新事实。例如,我们可以存储以下事实:controls(attacker, object_a),points_to(object_a, object_b),kernel_object(object_b)。然后我们可以定义以下规则:controls_kernel_object(Attacker) :- controls(Attacker, ObjectA), points_to(ObjectA, ObjectB), kernel_object(ObjectB)。因此,从我们现有的事实出发,引擎可以推导出:controls_kernel_object(attacker)。尚无特别令人兴奋的内容。然而,假设我们稍后发现:points_to(object_a, object_b) 是不正确的。如果 controls_kernel_object(attacker) 是从该事实中推导出来的,我们准确知道哪个结论依赖于刚刚发生变化的观察,并且可以自动使其无效。这明显优于将所有旧信息放入提示中,并希望 LLM 能够注意到相同的事情。Lemmalog 最终这演变为 Lemmalog。基本的想法是,LLM 不一定应该负责维护自己的知识。相反,我将问题拆分为两个部分。LLM 处理模糊的部分:"LLDB 显示被释放的对象是 L"

赞助内容

NordVPN Next-gen Antivirus

本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。

请我喝杯咖啡