如何遍历AST树
How to traverse AST tree
我正在尝试为 Groovy 创建静态分析。作为我上级的 POC,我只是尝试解析简单代码并检测 SQL 注入,这是最容易发现的一种。我在 Python 上成功做到了,这是我的主要语言,但我的公司主要使用 Grails(在 Groovy 上)。
这是我目前拥有的:
import org.codehaus.groovy.ast.expr.*;
import org.codehaus.groovy.ast.stmt.*;
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.ast.CodeVisitorSupport
import org.codehaus.groovy.ast.builder.AstBuilder
public class SecurityCheck extends CodeVisitorSupport {
void visitBlockStatement(BlockStatement statement) {
println "NEW BLOCK STATEMENT:"
println statement.getText();
//keep walking...
statement.getStatements().each { ASTNode child ->
println "CHILD FOUND: "
println child.getText();
child.visit(this)
}
}
}
def code = new File('groovy_source.groovy').text // get the code from the source file
def AstBuilder astBuilder = new AstBuilder() // build an instance of the ast builder
def ast = astBuilder.buildFromString(CompilePhase.CONVERSION, code) // build from string when the compiler converts from tokens to AST
def SecurityCheck securityCheck = new SecurityCheck() // create an instance of our security check class
println ast
println ast[0]
ast[0].visit(securityCheck)
groovy_source.groovy 文件非常简单,只包含一个极小的文件,其中有一个非常容易发现的漏洞:
def post(id) {
query = "SELECT * FROM table WHERE id = " + id;
result = sql.execute query
return result;
}
据我了解,因为我继承自 CodeVisitorSupport,所以这只会访问 BlockStatement,然后对于该语句中的每个语句,它会使用 supper class 中的方法来访问它.
尽管如此,当我从 BlockStatement 打印文本时,它是一个空字符串,并且 for each 方法甚至从未被调用(我认为这一定意味着 AST 没有找到我的块语句的子项,即使函数中肯定有语句。
[org.codehaus.groovy.ast.stmt.BlockStatement@363a52f[]] // println ast
org.codehaus.groovy.ast.stmt.BlockStatement@363a52f[] // println ast[0]
NEW BLOCK STATEMENT:
{ } // println statement.getText()
如有任何帮助,我们将不胜感激。谢谢!
我找到了答案。最后我并没有那么难,但是糟糕的文档并没有让它变得容易。如果你要遍历树,你需要给构造函数一个 false 布尔值作为第二个参数,像这样:
def ast = astBuilder.buildFromString(CompilePhase.CONVERSION, false, code)
然后您就可以按预期使用 visit* 方法了。
我正在尝试为 Groovy 创建静态分析。作为我上级的 POC,我只是尝试解析简单代码并检测 SQL 注入,这是最容易发现的一种。我在 Python 上成功做到了,这是我的主要语言,但我的公司主要使用 Grails(在 Groovy 上)。
这是我目前拥有的:
import org.codehaus.groovy.ast.expr.*;
import org.codehaus.groovy.ast.stmt.*;
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.ast.CodeVisitorSupport
import org.codehaus.groovy.ast.builder.AstBuilder
public class SecurityCheck extends CodeVisitorSupport {
void visitBlockStatement(BlockStatement statement) {
println "NEW BLOCK STATEMENT:"
println statement.getText();
//keep walking...
statement.getStatements().each { ASTNode child ->
println "CHILD FOUND: "
println child.getText();
child.visit(this)
}
}
}
def code = new File('groovy_source.groovy').text // get the code from the source file
def AstBuilder astBuilder = new AstBuilder() // build an instance of the ast builder
def ast = astBuilder.buildFromString(CompilePhase.CONVERSION, code) // build from string when the compiler converts from tokens to AST
def SecurityCheck securityCheck = new SecurityCheck() // create an instance of our security check class
println ast
println ast[0]
ast[0].visit(securityCheck)
groovy_source.groovy 文件非常简单,只包含一个极小的文件,其中有一个非常容易发现的漏洞:
def post(id) {
query = "SELECT * FROM table WHERE id = " + id;
result = sql.execute query
return result;
}
据我了解,因为我继承自 CodeVisitorSupport,所以这只会访问 BlockStatement,然后对于该语句中的每个语句,它会使用 supper class 中的方法来访问它.
尽管如此,当我从 BlockStatement 打印文本时,它是一个空字符串,并且 for each 方法甚至从未被调用(我认为这一定意味着 AST 没有找到我的块语句的子项,即使函数中肯定有语句。
[org.codehaus.groovy.ast.stmt.BlockStatement@363a52f[]] // println ast
org.codehaus.groovy.ast.stmt.BlockStatement@363a52f[] // println ast[0]
NEW BLOCK STATEMENT:
{ } // println statement.getText()
如有任何帮助,我们将不胜感激。谢谢!
我找到了答案。最后我并没有那么难,但是糟糕的文档并没有让它变得容易。如果你要遍历树,你需要给构造函数一个 false 布尔值作为第二个参数,像这样:
def ast = astBuilder.buildFromString(CompilePhase.CONVERSION, false, code)
然后您就可以按预期使用 visit* 方法了。