浏览器研究-修改v8源码绕过无限debugger

js语言属于脚本语言,需要先解释再执行,v8作为js的执行引擎,肯定有词法分析、语法分析,按照这个思路,找到代码src\v8\src\parsing\parser-base.h,这个.h文件就是将js代码作为一个个statement或者block去解析,就是类似于AST里面那样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
AllowLabelledFunctionStatement allow_function) {
// Statement ::
// Block
// VariableStatement
// EmptyStatement
// ExpressionStatement
// IfStatement
// IterationStatement
// ContinueStatement
// BreakStatement
// ReturnStatement
// WithStatement
// LabelledStatement
// SwitchStatement
// ThrowStatement
// TryStatement
// DebuggerStatement

// {own_labels} is always a subset of {labels}.
DCHECK_IMPLIES(labels == nullptr, own_labels == nullptr);

// Note: Since labels can only be used by 'break' and 'continue'
// statements, which themselves are only valid within blocks,
// iterations or 'switch' statements (i.e., BreakableStatements),
// labels can be simply ignored in all other cases; except for
// trivial labeled break statements 'label: break label' which is
// parsed into an empty statement.
switch (peek()) {
case Token::LBRACE:
return ParseBlock(labels);
case Token::SEMICOLON:
Next();
return factory()->EmptyStatement();
case Token::IF:
return ParseIfStatement(labels);
case Token::DO:
return ParseDoWhileStatement(labels, own_labels);
case Token::WHILE:
return ParseWhileStatement(labels, own_labels);
case Token::FOR:
if (V8_UNLIKELY(is_await_allowed() && PeekAhead() == Token::AWAIT)) {
return ParseForAwaitStatement(labels, own_labels);
}
return ParseForStatement(labels, own_labels);
case Token::CONTINUE:
return ParseContinueStatement();
case Token::BREAK:
return ParseBreakStatement(labels);
case Token::RETURN:
return ParseReturnStatement();
case Token::THROW:
return ParseThrowStatement();
case Token::TRY: {
// It is somewhat complicated to have labels on try-statements.
// When breaking out of a try-finally statement, one must take
// great care not to treat it as a fall-through. It is much easier
// just to wrap the entire try-statement in a statement block and
// put the labels there.
if (labels == nullptr) return ParseTryStatement();
StatementListT statements(pointer_buffer());
BlockT result = factory()->NewBlock(false, true);
Target target(this, result, labels, nullptr,
Target::TARGET_FOR_NAMED_ONLY);
StatementT statement = ParseTryStatement();
statements.Add(statement);
result->InitializeStatements(statements, zone());
return result;
}
case Token::WITH:
return ParseWithStatement(labels);
case Token::SWITCH:
return ParseSwitchStatement(labels);
case Token::FUNCTION:
// FunctionDeclaration only allowed as a StatementListItem, not in
// an arbitrary Statement position. Exceptions such as
// ES#sec-functiondeclarations-in-ifstatement-statement-clauses
// are handled by calling ParseScopedStatement rather than
// ParseStatement directly.
impl()->ReportMessageAt(scanner()->peek_location(),
is_strict(language_mode())
? MessageTemplate::kStrictFunction
: MessageTemplate::kSloppyFunction);
return impl()->NullStatement();
case Token::DEBUGGER:
return ParseDebuggerStatement();
case Token::VAR:
return ParseVariableStatement(kStatement, nullptr);
case Token::ASYNC:
if (!impl()->HasCheckedSyntax() &&
!scanner()->HasLineTerminatorAfterNext() &&
PeekAhead() == Token::FUNCTION) {
impl()->ReportMessageAt(
scanner()->peek_location(),
MessageTemplate::kAsyncFunctionInSingleStatementContext);
return impl()->NullStatement();
}
V8_FALLTHROUGH;
default:
return ParseExpressionOrLabelledStatement(labels, own_labels,
allow_function);
}
}

这里要绕过也很简单,当执行到case Token::DEBUGGER的时候,直接让代码不去执行ParseDebuggerStatement,而是替换为空字符或者替换为分号(js中允许多个分号),都可以,不影响网页调试。

1
2
3
4
5
6
7
8
case Token::DEBUGGER:
//return ParseDebuggerStatement();
//jack
// 让代码正常往后执行
Next();
// 返回空语句
return factory()->EmptyStatement();
//jack end