From 91120ae00aeb72b40b8993429307e9124d45a195 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 25 Aug 2026 15:02:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(memhub):=20detection=20=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=20-=20free=20=E5=90=8E=E7=94=A8=E6=88=B7=E5=8C=BA=E5=A1=AB=200?= =?UTF-8?q?xCD=20+=20=E8=AE=B0=E5=BD=95=E4=BF=9D=E7=95=99=E5=B9=B6?= =?UTF-8?q?=E7=BD=AE=20free=20=E6=A0=87=E5=BF=97=EF=BC=8C=E6=8E=A2?= =?UTF-8?q?=E6=B5=8B=E6=97=B6=E5=AF=B9=E4=BB=8D=20free=20=E7=9A=84?= =?UTF-8?q?=E5=9D=97=E9=AA=8C=E8=AF=81=200xCD=20=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=EF=BC=88=E9=A6=96=E6=9C=AB=208=20=E5=AD=97=E8=8A=82=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E8=A2=AB=E5=86=99=E7=A9=BF=E5=8D=B3=20[DET]=20UAF=20?= =?UTF-8?q?=E5=86=99=E5=85=A5=20=E6=8A=A5=E8=AD=A6=E7=BB=88=E6=AD=A2=20-?= =?UTF-8?q?=20=E6=8B=A6=E6=88=AA=20use-after-free=20=E5=86=99=E5=85=A5?= =?UTF-8?q?=EF=BC=88=E5=A6=82=20SlotsBugTest=20KwEntry=20cargs=20=E5=9D=97?= =?UTF-8?q?=20free=20=E5=90=8E=E8=A2=AB=E9=83=A8=E5=88=86=E8=A6=86?= =?UTF-8?q?=E7=9B=96=EF=BC=89=EF=BC=8C=E4=B8=8E=E5=90=8E=E6=A0=87=E8=AE=B0?= =?UTF-8?q?=E8=B6=8A=E7=95=8C=E5=86=99=E6=A3=80=E6=B5=8B=E4=BA=92=E8=A1=A5?= =?UTF-8?q?=EF=BC=9B=E5=9D=97=E8=A2=AB=E9=87=8D=E6=96=B0=20alloc=20?= =?UTF-8?q?=E5=90=8E=E5=9D=97=E5=A4=B4=E5=8F=98=E5=A5=87=E6=95=B0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=B7=B3=E8=BF=87=E6=97=A7=20free=20=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E9=98=B2=E8=AF=AF=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/memhub.vp | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/includes/memhub.vp b/includes/memhub.vp index 46c8ece..f64d733 100644 --- a/includes/memhub.vp +++ b/includes/memhub.vp @@ -729,13 +729,18 @@ class MemBuddy(MemManager): if self.detection != 0: # [DET] 返回指针比实际用户区靠后 2 字节,回收时向前偏移 2 p_eff = t.CVoid(t.CUInt64T(ptr) - 2, t.CPtr) - # 从记录表移除该条(置 size=0):块复用后旧后标记位置 - # 会被新数据覆盖,若不移除会导致 _det_probe 误报 + # 从记录表取本条真实 size,free 后把用户区填 0xCD(UAF 写入 + # 检测:free 后块被写穿 → 探测时 0xCD 被破坏 → 报警);记录 + # 保留并置 free 标志(探测时对仍 free 的块验证 0xCD 完整)。 if self._det_records is not None: ri: t.CSizeT = 0 while ri < self._det_count: - if self._det_records[ri * 2] == t.CUInt64T(ptr): - self._det_records[ri * 2 + 1] = 0 + rp: t.CUInt64T = self._det_records[ri * 2] + rs: t.CUInt64T = self._det_records[ri * 2 + 1] + if rp == t.CUInt64T(ptr) and (rs & (t.CUInt64T(1) << 63)) == 0: + if rs > 0: + string.memset(ptr, MEMBUDDY_FILL_PATTERN, rs) + self._det_records[ri * 2 + 1] = rs | (t.CUInt64T(1) << 63) break ri += 1 if self._is_valid_ptr(p_eff) != 0: @@ -821,13 +826,33 @@ class MemBuddy(MemManager): def _det_probe(self): if self._det_records is None: return + free_flag: t.CUInt64T = t.CUInt64T(1) << 63 + cd_word: t.CUInt64T = (t.CUInt64T(0xCDCDCDCD) << 32) | t.CUInt64T(0xCDCDCDCD) i: t.CSizeT = 0 while i < self._det_count: p: t.CUInt64T = self._det_records[i * 2] s: t.CUInt64T = self._det_records[i * 2 + 1] + if (s & free_flag) != 0: + # free 记录:块头仍为 0(未被重新 alloc)则验证用户区 0xCD + # 完整——被写穿 = use-after-free 写入(free 后块被某代码覆盖) + real_s: t.CUInt64T = s & (free_flag - 1) + if real_s > 0: + blk_h: t.CUInt64T = p - 2 - MEMBUDDY_HEADER_SIZE + hdr_v: t.CUInt64T = t.CUInt64T(c.Deref(t.CUInt64T(blk_h, t.CPtr))) + if (hdr_v & 1) == 0: + w0: t.CUInt64T = t.CUInt64T(c.Deref(t.CUInt64T(p, t.CPtr))) + w1: t.CUInt64T = w0 + if real_s >= 8: + w1 = t.CUInt64T(c.Deref(t.CUInt64T(p + real_s - 8, t.CPtr))) + if w0 != cd_word or w1 != cd_word: + stdio.printf("[DET] UAF 写入: ptr=%llu size=%llu(free 后块被写,首=0x%llX 末=0x%llX)\n", + p, real_s, w0, w1) + stdlib.exit(1) + i += 1 + continue if s == 0: i += 1 - continue # 该条已被 free(记录移除) + continue # 无 size 记录(理论不发生,防御) m16: t.CUInt16T | t.CPtr = (t.CUInt16T | t.CPtr)(t.CVoid(p + s, t.CPtr)) mv: t.CUInt16T = m16[0] if mv != t.CUInt16T(MEMBUDDY_DET_MARKER):