首页
社区
课程
招聘
[原创]魔改chromium过无限debugger
发表于: 2025-6-5 19:16 2453

[原创]魔改chromium过无限debugger

2025-6-5 19:16
2453

将 debugger 关键字的 token 换成 null, 添加一个自己关键字

因为不是阅读 v8 代码的文章, 不在介绍怎么从头跟了, 直接看 v8/src/parsing/scanner-inl.h 中的 V8_INLINE Token::Value Scanner::ScanSingleToken 函数, 解释器的第一步, 将扫描文本生成 token 找到识别关键字的代码

向前跟两补到达 V8_INLINE Token::Value Scanner::ScanIdentifierOrKeywordInner 函数, 来看看这段代码:

阻碍我们添加关键字的第一道门槛是 CanBeKeyword(scan_flags) 预判断, 关键字经过它后才能进入 KeywordOrIdentifierToken 函数做一个完全判断。让我们看看 scan_flags 是怎么生成的, 关键地方是这里:

v8 在辨别是关键字还是变量的预判断中做了一个映射表, 即判断哪些标识符可能是关键字, 哪些标识符一看就不可能, 直接筛去一部分, 以提高运行效率。以 flags 的形式记录, 让我们看看 character_scan_flags 是怎么生成的:

总结来说就是将 0-127 输入 GetScanFlags 函数, 然后与结果做一个映射, 用 py 实现就是:

因为 char 实际上是一个 0-127 直接的数字, 所以可以直接使用。接下来重点放在 CanBeKeywordCharacter IsKeywordStart 函数, 先来看 CanBeKeywordCharacter:

利用了​​递归模板元编程​已经一些​宏的骚操作, 总的来说就是将所用的关键字全拼接起来形成一个长字符串, 像这样 "asyncawaitbreakcase..." 然后如果要检查的字符在这堆字符串中就返回 true, 如果遍历完了这段字符串也没找到就返回 false,

然后是 IsKeywordStart

简单来说就是检查开头, 如果首字符对不上就是 false, 对上了就认为可能是关键字。

好了, 现在我们可以通过 KeywordOrIdentifierToken 函数跟入 v8/src/parsing/keywords-gen.h 中的 PerfectKeywordHash::GetToken 函数了:

这是最小完美哈希的实现, 通过精心构造的哈希函数,确保​​所有关键字​​的哈希值在 [0, 127] 范围内​​互不冲突​​。每个关键字映射到唯一的桶(key), 有现成的算法可以生成完美哈希。

我们用 py 简单模拟一下:

这就是 v8 判断关键字的全部流程。

让我们从 v8/src/parsing/keywords-gen.h 开始。事实上官方提供了生成脚本 v8/tools/gen-keywords-gen-h.py 配合 v8/src/parsing/keywords.txt, 可以生成对应的 v8/src/parsing/keywords-gen.h, 因为我是在 windows 上开发的, 不太好使用 gperf 工具, 所以就不从自定义 keywords.txt 文件开始, 生成 keywords-gen.h 文件了

理想的情况是不改变 PerfectKeywordHash::Hash 函数中的 asso_values, 而是在 kPerfectKeywordHashTable 空闲的位置自定义一个关键字。好消息是有非常多的空闲位置, 如 u_debugger 对应的 hash 值为 111

这样只是做好了第一步, 还要往回看, 关键字的预判断

来到 v8/src/parsing/scanner-inl.h 文件的 #define KEYWORDS(KEYWORD_GROUP, KEYWORD), 增加:

这里 KEYWORD("debugger", Token::kDebugger) 中的 Token::kDebugger 可以不用修改, 因为没用到

两个 debugger 对比

代码提示

附件方法 3c4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6F1L8%4c8Z5K9h3&6Y4i4K6u0V1x3U0x3K6x3#2)9J5c8V1y4Z5M7X3!0E0K9i4g2E0e0h3!0V1

case Token::kIdentifier:
  return ScanIdentifierOrKeyword();
case Token::kIdentifier:
  return ScanIdentifierOrKeyword();
if (!CanBeKeyword(scan_flags)) return Token::kIdentifier;
// Could be a keyword or identifier.
base::Vector<const uint8_t> chars =
    next().literal_chars.one_byte_literal();
return KeywordOrIdentifierToken(chars.begin(), chars.length());
if (!CanBeKeyword(scan_flags)) return Token::kIdentifier;
// Could be a keyword or identifier.
base::Vector<const uint8_t> chars =
    next().literal_chars.one_byte_literal();
return KeywordOrIdentifierToken(chars.begin(), chars.length());
AdvanceUntil([this, &scan_flags](base::uc32 c0) {
  // 非 ASCII 字符触发慢速路径
  if (V8_UNLIKELY(static_cast<uint32_t>(c0) > kMaxAscii)) {
    // A non-ascii character means we need to drop through to the slow
    // path.
    // TODO(leszeks): This would be most efficient as a goto to the slow
    // path, check codegen and maybe use a bool instead.
    scan_flags |=
        static_cast<uint8_t>(ScanFlags::kIdentifierNeedsSlowPath);
    return true;
  }
  uint8_t char_flags = character_scan_flags[c0];
  scan_flags |= char_flags; // 累积字符标志位
 
  // 遇到终止符(如引号、换行符)时停止扫描
  if (TerminatesLiteral(char_flags)) {
    return true;
  } else {
    AddLiteralChar(static_cast<char>(c0)); // 记录合法字符
    return false; // 继续扫描
  }
});
AdvanceUntil([this, &scan_flags](base::uc32 c0) {
  // 非 ASCII 字符触发慢速路径
  if (V8_UNLIKELY(static_cast<uint32_t>(c0) > kMaxAscii)) {
    // A non-ascii character means we need to drop through to the slow
    // path.
    // TODO(leszeks): This would be most efficient as a goto to the slow
    // path, check codegen and maybe use a bool instead.
    scan_flags |=
        static_cast<uint8_t>(ScanFlags::kIdentifierNeedsSlowPath);
    return true;
  }
  uint8_t char_flags = character_scan_flags[c0];
  scan_flags |= char_flags; // 累积字符标志位
 
  // 遇到终止符(如引号、换行符)时停止扫描
  if (TerminatesLiteral(char_flags)) {
    return true;
  } else {
    AddLiteralChar(static_cast<char>(c0)); // 记录合法字符
    return false; // 继续扫描
  }
});
// Table of precomputed scan flags for the 128 ASCII characters, for branchless
// flag calculation during the scan.
static constexpr const uint8_t character_scan_flags[128] = {
#define CALL_GET_SCAN_FLAGS(N) GetScanFlags(N),
    INT_0_TO_127_LIST(CALL_GET_SCAN_FLAGS)
#undef CALL_GET_SCAN_FLAGS
};
 
constexpr uint8_t GetScanFlags(char c) {
  return
      // Keywords are all lowercase and only contain letters.
      // Note that non-identifier characters do not set this flag, so
      // that it plays well with kTerminatesLiteral.
      (IsAsciiIdentifier(c) && !CanBeKeywordCharacter(c)
           ? static_cast<uint8_t>(ScanFlags::kCannotBeKeyword)
           : 0) |
      (IsKeywordStart(c)
           ? 0
           : static_cast<uint8_t>(ScanFlags::kCannotBeKeywordStart)) |
      // Anything that isn't an identifier character will terminate the
      // literal, or at least terminates the literal fast path processing
      // (like an escape).
      (!IsAsciiIdentifier(c)
           ? static_cast<uint8_t>(ScanFlags::kTerminatesLiteral)
           : 0) |
      // Possible string termination characters.
      ((c == '\'' || c == '"' || c == '\n' || c == '\r' || c == '\\')
           ? static_cast<uint8_t>(ScanFlags::kStringTerminator)
           : 0) |
      // Escapes are processed on the slow path.
      (c == '\\' ? static_cast<uint8_t>(ScanFlags::kIdentifierNeedsSlowPath)
                 : 0) |
      // Newlines and * are interesting characters for multiline comment
      // scanning.
      (c == '\n' || c == '\r' || c == '*'
           ? static_cast<uint8_t>(
                 ScanFlags::kMultilineCommentCharacterNeedsSlowPath)
           : 0);
}
 
// clang-format off
#define INT_0_TO_127_LIST(V)                                          \
V(0)   V(1)   V(2)   V(3)   V(4)   V(5)   V(6)   V(7)   V(8)   V(9)   \
V(10)  V(11)  V(12)  V(13)  V(14)  V(15)  V(16)  V(17)  V(18)  V(19)  \
V(20)  V(21)  V(22)  V(23)  V(24)  V(25)  V(26)  V(27)  V(28)  V(29)  \
V(30)  V(31)  V(32)  V(33)  V(34)  V(35)  V(36)  V(37)  V(38)  V(39)  \
V(40)  V(41)  V(42)  V(43)  V(44)  V(45)  V(46)  V(47)  V(48)  V(49)  \
V(50)  V(51)  V(52)  V(53)  V(54)  V(55)  V(56)  V(57)  V(58)  V(59)  \
V(60)  V(61)  V(62)  V(63)  V(64)  V(65)  V(66)  V(67)  V(68)  V(69)  \
V(70)  V(71)  V(72)  V(73)  V(74)  V(75)  V(76)  V(77)  V(78)  V(79)  \
V(80)  V(81)  V(82)  V(83)  V(84)  V(85)  V(86)  V(87)  V(88)  V(89)  \
V(90)  V(91)  V(92)  V(93)  V(94)  V(95)  V(96)  V(97)  V(98)  V(99)  \
V(100) V(101) V(102) V(103) V(104) V(105) V(106) V(107) V(108) V(109) \
V(110) V(111) V(112) V(113) V(114) V(115) V(116) V(117) V(118) V(119) \
V(120) V(121) V(122) V(123) V(124) V(125) V(126) V(127)
// clang-format on
// Table of precomputed scan flags for the 128 ASCII characters, for branchless
// flag calculation during the scan.
static constexpr const uint8_t character_scan_flags[128] = {
#define CALL_GET_SCAN_FLAGS(N) GetScanFlags(N),
    INT_0_TO_127_LIST(CALL_GET_SCAN_FLAGS)
#undef CALL_GET_SCAN_FLAGS
};
 
constexpr uint8_t GetScanFlags(char c) {
  return
      // Keywords are all lowercase and only contain letters.
      // Note that non-identifier characters do not set this flag, so
      // that it plays well with kTerminatesLiteral.
      (IsAsciiIdentifier(c) && !CanBeKeywordCharacter(c)
           ? static_cast<uint8_t>(ScanFlags::kCannotBeKeyword)
           : 0) |
      (IsKeywordStart(c)
           ? 0
           : static_cast<uint8_t>(ScanFlags::kCannotBeKeywordStart)) |
      // Anything that isn't an identifier character will terminate the
      // literal, or at least terminates the literal fast path processing
      // (like an escape).
      (!IsAsciiIdentifier(c)
           ? static_cast<uint8_t>(ScanFlags::kTerminatesLiteral)
           : 0) |
      // Possible string termination characters.
      ((c == '\'' || c == '"' || c == '\n' || c == '\r' || c == '\\')
           ? static_cast<uint8_t>(ScanFlags::kStringTerminator)
           : 0) |
      // Escapes are processed on the slow path.
      (c == '\\' ? static_cast<uint8_t>(ScanFlags::kIdentifierNeedsSlowPath)
                 : 0) |
      // Newlines and * are interesting characters for multiline comment
      // scanning.
      (c == '\n' || c == '\r' || c == '*'
           ? static_cast<uint8_t>(
                 ScanFlags::kMultilineCommentCharacterNeedsSlowPath)
           : 0);
}
 
// clang-format off
#define INT_0_TO_127_LIST(V)                                          \
V(0)   V(1)   V(2)   V(3)   V(4)   V(5)   V(6)   V(7)   V(8)   V(9)   \
V(10)  V(11)  V(12)  V(13)  V(14)  V(15)  V(16)  V(17)  V(18)  V(19)  \
V(20)  V(21)  V(22)  V(23)  V(24)  V(25)  V(26)  V(27)  V(28)  V(29)  \
V(30)  V(31)  V(32)  V(33)  V(34)  V(35)  V(36)  V(37)  V(38)  V(39)  \
V(40)  V(41)  V(42)  V(43)  V(44)  V(45)  V(46)  V(47)  V(48)  V(49)  \
V(50)  V(51)  V(52)  V(53)  V(54)  V(55)  V(56)  V(57)  V(58)  V(59)  \
V(60)  V(61)  V(62)  V(63)  V(64)  V(65)  V(66)  V(67)  V(68)  V(69)  \
V(70)  V(71)  V(72)  V(73)  V(74)  V(75)  V(76)  V(77)  V(78)  V(79)  \
V(80)  V(81)  V(82)  V(83)  V(84)  V(85)  V(86)  V(87)  V(88)  V(89)  \
V(90)  V(91)  V(92)  V(93)  V(94)  V(95)  V(96)  V(97)  V(98)  V(99)  \
V(100) V(101) V(102) V(103) V(104) V(105) V(106) V(107) V(108) V(109) \
V(110) V(111) V(112) V(113) V(114) V(115) V(116) V(117) V(118) V(119) \
V(120) V(121) V(122) V(123) V(124) V(125) V(126) V(127)
// clang-format on
character_scan_flags = []
for i in range(0, 127):
    character_scan_flags.append(GetScanFlags(i))
character_scan_flags = []
for i in range(0, 127):
    character_scan_flags.append(GetScanFlags(i))
// Recursive constexpr template magic to check if a character is in a given
// string.
template <int N>
constexpr bool IsInString(const char (&s)[N], char c, size_t i = 0) {
  return i >= N ? false : s[i] == c ? true : IsInString(s, c, i + 1);
}
 
inline constexpr bool CanBeKeywordCharacter(char c) {
  return IsInString(
#define KEYWORD_GROUP_CASE(ch)  // Nothing
#define KEYWORD(keyword, token) keyword
      // Use C string literal concatenation ("a" "b" becomes "ab") to build one
      // giant string containing all the keywords.
      KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
#undef KEYWORD
#undef KEYWORD_GROUP_CASE
          ,
      c);
}
 
// Keyword Matcher
#define KEYWORDS(KEYWORD_GROUP, KEYWORD)                  \
  KEYWORD_GROUP('a')                                      \
  KEYWORD("async", Token::kAsync)                         \
  KEYWORD("await", Token::kAwait)                         \
  KEYWORD_GROUP('b')                                      \
  KEYWORD("break", Token::kBreak)                         \
  KEYWORD_GROUP('c')                                      \
  KEYWORD("case", Token::kCase)                           \
  KEYWORD("catch", Token::kCatch)                         \
  KEYWORD("class", Token::kClass)                         \
  KEYWORD("const", Token::kConst)                         \
  KEYWORD("continue", Token::kContinue)                   \
  KEYWORD_GROUP('d')                                      \
  KEYWORD("debugger", Token::kDebugger)                   \
  KEYWORD("default", Token::kDefault)                     \
  KEYWORD("delete", Token::kDelete)                       \
  KEYWORD("do", Token::kDo)                               \
  KEYWORD_GROUP('e')                                      \
  KEYWORD("else", Token::kElse)                           \
  // ... 太多了没列全
// Recursive constexpr template magic to check if a character is in a given
// string.
template <int N>
constexpr bool IsInString(const char (&s)[N], char c, size_t i = 0) {
  return i >= N ? false : s[i] == c ? true : IsInString(s, c, i + 1);
}
 
inline constexpr bool CanBeKeywordCharacter(char c) {
  return IsInString(
#define KEYWORD_GROUP_CASE(ch)  // Nothing
#define KEYWORD(keyword, token) keyword
      // Use C string literal concatenation ("a" "b" becomes "ab") to build one
      // giant string containing all the keywords.
      KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
#undef KEYWORD
#undef KEYWORD_GROUP_CASE
          ,
      c);
}
 
// Keyword Matcher
#define KEYWORDS(KEYWORD_GROUP, KEYWORD)                  \

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2025-6-5 19:38 被nothing233编辑 ,原因:
上传的附件:
收藏
免费 22
支持
分享
魔改chromium (多选)
魔改chromium (0 票,0%)
最新回复 (14)
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2025-6-6 09:14
0
雪    币: 293
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
6666
2025-6-9 00:30
0
雪    币: 217
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2025-7-16 23:53
0
雪    币: 73
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
赞赞赞
2025-9-13 02:58
0
雪    币: 41
活跃值: (1205)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2025-9-13 08:31
0
雪    币: 2693
活跃值: (2820)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
6666666
2025-9-13 10:47
0
雪    币: 230
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
感谢分享0000000000000000
2025-10-10 01:16
0
雪    币: 100
活跃值: (135)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
666
2025-10-10 14:11
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
11
2025-11-10 17:12
0
雪    币: 237
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
大佬有实力
2025-11-14 13:27
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
666
2025-11-19 20:49
0
雪    币: 736
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
感谢分享
2025-11-20 16:29
0
雪    币: 562
活跃值: (2641)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
555
2025-11-21 10:40
0
雪    币: 5050
活跃值: (2615)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
感谢分享
3天前
0
游客
登录 | 注册 方可回帖
返回