Skip to content

Commit 6c244cc

Browse files
author
exploit
committed
Update the function CFGBuilder in CFGGenerator.php
Then added some new function in the same file such as: -addLoopVariable used to handle the loop statement in php. -getEndLine used to get the last line number in the set of AST nodes. Actually, I think there were some bugs in CFGBuilder, so fix them when it happens.
1 parent 31fca52 commit 6c244cc

File tree

7 files changed

+162
-62
lines changed

7 files changed

+162
-62
lines changed

CFGBuilder.php

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
class CFGBuilder{
4+
5+
}
6+
7+
8+
?>

CFGEdge.php

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<?php
2-
require "./CFGNode.php" ;
32

43
class CFGEdge{
54
private $source ; //边的来源

CFGGenerator.php

+137-57
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
require_once './vendor/autoload.php' ;
44
ini_set('xdebug.max_nesting_level', 2000);
5+
require_once './BasicBlock.php';
56

6-
@define("JUMP_STATEMENT", array('Stmt_If','Stmt_Switch','Stmt_TryCatch','Expr_Ternary','Expr_BinaryOp_LogicalOr')) ;
7-
@define("LOOP_STATEMENT",array('Stmt_For','Stmt_While','Stmt_Foreach','Stmt_Do')) ;
8-
@define("STOP_STATEMENT",array('Stmt_Throw','Stmt_Break','Stmt_Continue')) ;
9-
@define("RETURN_STATEMENT",array('Stmt_Return')) ;
7+
8+
$JUMP_STATEMENT = array('Stmt_If','Stmt_Switch','Stmt_TryCatch','Expr_Ternary','Expr_BinaryOp_LogicalOr') ;
9+
$LOOP_STATEMENT = array('Stmt_For','Stmt_While','Stmt_Foreach','Stmt_Do') ;
10+
$STOP_STATEMENT = array('Stmt_Throw','Stmt_Break','Stmt_Continue') ;
11+
$RETURN_STATEMENT = array('Stmt_Return') ;
1012

1113
use PhpParser\Node ;
1214

@@ -35,15 +37,18 @@ public function getBranches($node){
3537

3638
//处理elseifs,elseifs为索引数组,由cond和stmts构成
3739
$elseifs = $node->elseifs ;
38-
foreach($elseifs as $if){
39-
$if_branch = new Branch($if->cond, $if->stmts) ;
40-
array_push($branches,$if_branch) ;
40+
if($elseifs){
41+
foreach($elseifs as $if){
42+
$if_branch = new Branch($if->cond, $if->stmts) ;
43+
array_push($branches,$if_branch) ;
44+
}
4145
}
4246

4347
//处理else分支,由stmts组成,没有cond,这里的cond填为"else"
44-
$if_branch = new Branch('else', $node->stmts) ;
45-
array_push($branches,$if_branch) ;
46-
48+
if($node->else){
49+
$if_branch = new Branch('else', $node->else) ;
50+
array_push($branches,$if_branch) ;
51+
}
4752
break ;
4853

4954
case 'Stmt_Switch':
@@ -95,54 +100,139 @@ public function getBranches($node){
95100
return $branches ;
96101
}
97102

103+
/**
104+
* 处理循环结构,将循环变量添加到基本块
105+
* @param unknown $node AST Node
106+
* @param unknown $block BasicBlock
107+
*/
108+
public function addLoopVariable($node,$block){
109+
switch ($node->getType()){
110+
case 'Stmt_For': //for(i=0;i<3;i++) ===> extract var i
111+
$block->loop_var = $node->init[0] ;
112+
break ;
113+
case 'Stmt_While': //while(cond) ====> extract cond
114+
$block->loop_var = $node->cond ;
115+
break ;
116+
case 'Stmt_Foreach': //foreach($nodes as $node) ======> extract $nodes
117+
$block->loop_var = $node->expr ;
118+
break ;
119+
case 'Stmt_Do': //do{}while(cond); =====> extract cond
120+
$block->loop_var = $node->cond ;
121+
break ;
122+
}
123+
}
124+
125+
/**
126+
* 给定AST Nodes集合,返回结束的行号
127+
* @param unknown $nodes
128+
*/
129+
public function getEndLine($nodes){
130+
return end($nodes)->getAttribute('endLine') ;
131+
}
132+
133+
98134

99135
/**
100136
* 由AST节点创建相应的CFG,用于后续分析
101137
*
102-
* @param unknown $nodes 传入的PHP file的所有nodes
103-
* @param unknown $condition 构建CFGNode时的跳转信息
104-
* @param unknown $pEntryBlock 入口基本块
105-
* @param unknown $pNextBlock 下一个基本块
138+
* @param $nodes 传入的PHP file的所有nodes
139+
* @param $condition 构建CFGNode时的跳转信息
140+
* @param $pEntryBlock 入口基本块
141+
* @param $pNextBlock 下一个基本块
106142
*/
107-
public function CFGBuilder($nodes,$condition,$pEntryBlock,$pNextBlock){
143+
public function CFGBuilder($nodes,$condition,$pEntryBlock,$pNextBlock,$endLine=0){
144+
echo "<pre>" ;
145+
global $JUMP_STATEMENT,$LOOP_STATEMENT,$STOP_STATEMENT,$RETURN_STATEMENT ;
108146
$currBlock = new BasicBlock() ;
109147

110148
//创建一个CFG节点的边
111149
if($pEntryBlock){
112-
$block_edge = new CFGEdge($pEntryBlock, $pNextBlock,$condition) ;
150+
$block_edge = new CFGEdge($pEntryBlock, $currBlock,$condition) ;
151+
$pEntryBlock->addOutEdge($block_edge) ;
152+
$currBlock->addInEdge($block_edge) ;
113153
}
114-
154+
115155
//迭代每个AST node
116156
foreach($nodes as $node){
117-
if(in_array($node->getType(), JUMP_STATEMENT)){
157+
if(!is_object($node))continue ;
158+
//判断node是否是结束node
159+
if($node->getAttribute('endLine') == 9){
160+
$currBlock->is_exit = true ;
161+
}
162+
163+
//如果节点是跳转类型的语句
164+
if(in_array($node->getType(), $JUMP_STATEMENT)){
165+
//生成基本块的摘要
166+
//simulate(currBlock) ;
118167
$nextBlock = new BasicBlock() ;
119168
//对每个分支,建立相应的基本块
169+
$branches = $this->getBranches($node) ;
170+
foreach ($branches as $b){
171+
$this->CFGBuilder($b->nodes, $b->condition, $currBlock, $nextBlock) ;
172+
}
173+
//var_dump($nextBlock) ;
174+
$currBlock = $nextBlock ;
175+
176+
}elseif(in_array($node->getType(), $LOOP_STATEMENT)){ //如果节点是循环语句
177+
$this->addLoopVariable($node, $currBlock) ; //加入循环条件
178+
//simulate($currBlock) ;
179+
$currBlock->nodes = $node->stmts ;
180+
$nextBlock = new BasicBlock() ;
181+
$this->CFGBuilder($node->stmts, NULL, $currBlock, $nextBlock) ;
182+
$currBlock = $nextBlock ;
120183

184+
}elseif(in_array($node->getType(), $STOP_STATEMENT)){
185+
$currBlock->is_exit = true ;
186+
break ;
187+
}elseif(in_array($node->getType(),$RETURN_STATEMENT)){
188+
$currBlock->addNode($node) ;
189+
//simulate($currBlock) ;
190+
return ;
191+
}else{
192+
$currBlock->addNode($node);
121193
}
122194
}
123195

196+
197+
198+
//simulate(currBlock) ;
199+
print_r($currBlock) ;
200+
if($pNextBlock && !$currBlock->is_exit){
201+
$block_edge = new CFGEdge($currBlock, $pNextBlock) ;
202+
$currBlock->addOutEdge($block_edge) ;
203+
$pNextBlock->addInEdge($block_edge) ;
204+
}
205+
206+
//print_r($currBlock) ;
207+
124208
}
125209

126210
}
127211

128212

213+
129214
/**
130215
* 跳转语句的分支结构类
131216
* @author Administrator
132217
*
133218
*/
134219
class Branch{
135-
private $condition ;
136-
private $nodes = array() ;
220+
public $condition ;
221+
public $nodes ;
137222

138223
/**
139224
* 构造函数
140225
* @param $cond 跳转的条件
141226
* @param $nodes 分支中携带的所有nodes
142227
*/
143228
public function __construct($cond,$nodes){
144-
$this->condition = $cond ;
145-
$this->nodes = $nodes ;
229+
$this->condition = array($cond) ;
230+
if(is_array($nodes)){
231+
$this->nodes = $nodes ;
232+
}else{
233+
$this->nodes = array($nodes) ;
234+
}
235+
146236

147237
//将跳转的条件也加入至nodes中
148238
if(is_array($this->condition)){
@@ -154,34 +244,18 @@ public function __construct($cond,$nodes){
154244
}
155245
}
156246

157-
/**
158-
* getter for $condition
159-
*/
160-
public function getCondition(){
161-
return $this->condition ;
162-
}
163-
164-
/**
165-
* getter for $nodes
166-
* @return multitype:
167-
*/
168-
public function getNodes(){
169-
return $this->nodes ;
170-
}
171-
172-
173247
}
174248

175-
249+
/**
250+
* 获取PHP File中所有的AST节点的访问者
251+
* @author Administrator
252+
*
253+
*/
176254
class MyVisitor extends PhpParser\NodeVisitorAbstract{
177255
private $nodes = array();
178256

179-
public function leaveNode(Node $node) {
180-
$this->addNode($node) ;
181-
}
182-
183-
public function addNode($node){
184-
array_push($this->nodes, $node) ;
257+
public function beforeTraverse(array $nodes){
258+
$this->nodes = $nodes ;
185259
}
186260

187261
public function getNodes(){
@@ -229,19 +303,25 @@ public function leaveNode(Node $node) {
229303
$traverser->addVisitor($visitor) ;
230304
$traverser->traverse($stmts) ;
231305
$nodes = $visitor->getNodes() ;
232-
$branches = NULL ;
233-
foreach ($nodes as $node){
234-
if($node instanceof PhpParser\Node\Stmt\If_ ){
235-
$branches = $cfg->getBranches($node) ;
236-
}elseif($node instanceof PhpParser\Node\Stmt\Switch_ ){
237-
$branches = $cfg->getBranches($node) ;
238-
}else{
239-
$branches = $cfg->getBranches($node) ;
240-
}
241-
}
306+
// $branches = NULL ;
307+
// foreach ($nodes as $node){
308+
// if($node instanceof PhpParser\Node\Stmt\If_ ){
309+
// $branches = $cfg->getBranches($node) ;
310+
// }elseif($node instanceof PhpParser\Node\Stmt\Switch_ ){
311+
// $branches = $cfg->getBranches($node) ;
312+
// }else{
313+
// $branches = $cfg->getBranches($node) ;
314+
// }
315+
// }
316+
// echo "<pre>" ;
317+
// print_r($branches) ;
318+
319+
$pEntryBlock = new BasicBlock() ;
320+
$pEntryBlock->is_entry = true ;
321+
$endLine = $cfg->getEndLine($nodes);
322+
$ret = $cfg->CFGBuilder($nodes, NULL, NULL, NULL,$endLine) ;
242323
echo "<pre>" ;
243-
print_r($branches) ;
244-
324+
//print_r($pEntryBlock) ;
245325
?>
246326

247327

CFGNode.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
<?php
22

3+
require_once './CFGEdge.php';
4+
35
class CFGNode{
6+
public $is_entry = false ;
7+
public $is_exit = false ;
8+
public $loop_var = NULL;
49
//CFG节点的进入边
510
private $inEdges = array() ;
611
//CFG节点的出边
7-
private $outEdges ;
12+
private $outEdges = array() ;
813

914

1015
/**

parser.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function afterTraverse(array $nodes){}
9090

9191
$stmts = $parser->parse($code) ;
9292
echo "<pre>" ;
93-
//print_r($stmts) ;
93+
print_r($stmts) ;
9494

9595
$traverser->addVisitor(new MyVisitor) ;
9696
$traverser->traverse($stmts) ;

test.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
<?php
22

3-
is_array() ;
3+
function test($a=3){
4+
echo $a ;
5+
}
6+
7+
test(5) ;
48

59
?>

test/simple_demo.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
<?php
22

3-
in_array($a,'1') or is_array($a) or die('xx') or is_bool($a) ;
3+
$a = 2;
4+
while($a){
5+
$b = 4 ;
6+
}
7+
echo 3 ;
48
?>

0 commit comments

Comments
 (0)