首页
社区
课程
招聘
[原创]OLLVM控制流平坦化源码分析+魔改
2023-7-30 19:21 9995

[原创]OLLVM控制流平坦化源码分析+魔改

2023-7-30 19:21
9995
目录

前置知识

Module是指模块,Function模块下的函数,BasicBlock函数下的基本块,Instruction 基本块下的IR指令

Flattening::flatten(Function *f)

1
2
3
4
5
6
7
8
9
for (Function::iterator i = f->begin(); i != f->end(); ++i) {
   BasicBlock *tmp = &*i;
   origBB.push_back(tmp);
 
   BasicBlock *bb = &*i;
   if (isa<InvokeInst>(bb->getTerminator())) {
     return false;
   }
 }

把函数分成很多个基本块,并且push到vector类型的 origBB中。
判断里面基本块是否大于1,不大于1的话就没有意义去进行混淆:

1
2
3
if (origBB.size() <= 1) {
   return false;
 }

需要把vertor里面的第一个基本块即入口基本块单独拿出来进行处理:对入口基本块进行判断,如果是无条件跳转则不进行任何处理,否则需要找到最后一条指令,将整个if结构给split,split之后两个块之间会自动添加跳转指令,然后就可以把原来的split后的if结构给它扔进要处理的基本块列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
origBB.erase(origBB.begin());
 
// Get a pointer on the first BB
Function::iterator tmp = f->begin(); //++tmp;
BasicBlock *insert = &*tmp;
 
// If main begin with an if
BranchInst *br = NULL;
if (isa<BranchInst>(insert->getTerminator())) {
  br = cast<BranchInst>(insert->getTerminator());
}
 
if ((br != NULL && br->isConditional()) ||
    insert->getTerminator()->getNumSuccessors() > 1) {
  BasicBlock::iterator i = insert->end();
  --i;
 
  if (insert->size() > 1) {
    --i;
  }
 
  BasicBlock *tmpBB = insert->splitBasicBlock(i, "first");
  origBB.insert(origBB.begin(), tmpBB);
}

如果是条件跳转的话这里是把上面自动添加那个跳转指令给删除,如果不是的话,那么也是需要把它删除,因为跳转点目标还不能确定:

1
2
// Remove jump
  insert->getTerminator()->eraseFromParent();

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
%retval = alloca i32, align 4
 %argc.addr = alloca i32, align 4
 %argv.addr = alloca i8**, align 8
 %a = alloca i32, align 4
 store i32 0, i32* %retval, align 4
 store i32 %argc, i32* %argc.addr, align 4
 store i8** %argv, i8*** %argv.addr, align 8
 %0 = load i8**, i8*** %argv.addr, align 8
 %arrayidx = getelementptr inbounds i8*, i8** %0, i64 1
 %1 = load i8*, i8** %arrayidx, align 8
 %call = call i32 @atoi(i8* %1) #3
 store i32 %call, i32* %a, align 4
 %2 = load i32, i32* %a, align 4
 br label %NodeBlock8

目前代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
entry:
  %.reg2mem = alloca i32
  %retval = alloca i32, align 4
  %argc.addr = alloca i32, align 4
  %argv.addr = alloca i8**, align 8
  %a = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  store i32 %argc, i32* %argc.addr, align 4
  store i8** %argv, i8*** %argv.addr, align 8
  %0 = load i8**, i8*** %argv.addr, align 8
  %arrayidx = getelementptr inbounds i8*, i8** %0, i64 1
  %1 = load i8*, i8** %arrayidx, align 8
  %call = call i32 @atoi(i8* %1) #3
  store i32 %call, i32* %a, align 4
  %2 = load i32, i32* %a, align 4
  store i32 %2, i32* %.reg2mem
  %switchVar = alloca i32

创建一个switchvar变量,然后去获取一个随机整数创建store指令塞给switchvar中

1
2
3
4
5
6
switchVar =
     new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar", insert);
 new StoreInst(
     ConstantInt::get(Type::getInt32Ty(f->getContext()),
                      llvm::cryptoutils->scramble32(0, scrambling_key)),
     switchVar, insert);

也就是在switchvar添了如下这一行:

1
store i32 157301900, i32* %switchVar

创建switch

创建两个block,其它的基本块插入它们之间

1
2
loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert);
loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert);

如下:

1
2
3
loopEntry:                                     
  
loopEnd:                                         

目标基本块里面啥内容也没有。

在loopEntry里面新建一个load指令,并且把switchVar:

1
load = new LoadInst(switchVar, "switchVar", loopEntry);

目前loopentry指令如下:

1
2
loopEntry:                                        ; preds = %entry, %loopEnd
  %switchVar10 = load i32, i32* %switchVar

把insert插入到loopEntry之前,这里的insert就是entry基本块,再创建两个跳转指令,从insert(即第一个基本块)跳转到loopEntry;从loopend跳转到loopEntry:

1
2
3
4
5
// Move first BB on top
insert->moveBefore(loopEntry);
BranchInst::Create(loopEntry, insert);
// loopEnd jump to loopEntry
BranchInst::Create(loopEntry, loopEnd);

这里结束后,entry模块就完整了,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
entry:
  %.reg2mem = alloca i32
  %retval = alloca i32, align 4
  %argc.addr = alloca i32, align 4
  %argv.addr = alloca i8**, align 8
  %a = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  store i32 %argc, i32* %argc.addr, align 4
  store i8** %argv, i8*** %argv.addr, align 8
  %0 = load i8**, i8*** %argv.addr, align 8
  %arrayidx = getelementptr inbounds i8*, i8** %0, i64 1
  %1 = load i8*, i8** %arrayidx, align 8
  %call = call i32 @atoi(i8* %1) #3
  store i32 %call, i32* %a, align 4
  %2 = load i32, i32* %a, align 4
  store i32 %2, i32* %.reg2mem
  %switchVar = alloca i32
  store i32 157301900, i32* %switchVar
  br label %loopEntry

而loopend模块也有了一条指令(其实也是完整了):

1
2
loopEnd:                                       
br label %loopEntry

紧接着创建一个基本块,然后在基本块里面创建一个跳转指令,从switchDefault跳转到loopend中:

1
2
3
BasicBlock *swDefault =
     BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd);
 BranchInst::Create(loopEnd, swDefault);

多了一个switchDefault基本块,指令如下:

1
2
switchDefault:                                    ; preds = %loopEntry
  br label %loopEnd

创建一个switch指令,位置是在loopentry基本块下,且创建了0个case,然后设置了条件为load,就上面的load。

1
2
switchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry);
 switchI->setCondition(load);

把entry最后一行跳转指令删除后再创建了一个跳转指令,从entry跳转到loopentry:

1
2
f->begin()->getTerminator()->eraseFromParent();
  BranchInst::Create(loopEntry, &*f->begin());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (std::vector<BasicBlock *>::iterator b = origBB.begin();
     b != origBB.end(); ++b) {
  BasicBlock *i = *b;
  ConstantInt *numCase = NULL;
 
  // Move the BB inside the switch (only visual, no code logic)
  i->moveBefore(loopEnd);
 
  // Add case to switch
  numCase = cast<ConstantInt>(ConstantInt::get(
      switchI->getCondition()->getType(),
      llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key)));
  switchI->addCase(numCase, i);
}

目前代码:

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
entry:
  %.reg2mem = alloca i32
  %retval = alloca i32, align 4
  %argc.addr = alloca i32, align 4
  %argv.addr = alloca i8**, align 8
  %a = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  store i32 %argc, i32* %argc.addr, align 4
  store i8** %argv, i8*** %argv.addr, align 8
  %0 = load i8**, i8*** %argv.addr, align 8
  %arrayidx = getelementptr inbounds i8*, i8** %0, i64 1
  %1 = load i8*, i8** %arrayidx, align 8
  %call = call i32 @atoi(i8* %1) #3
  store i32 %call, i32* %a, align 4
  %2 = load i32, i32* %a, align 4
  store i32 %2, i32* %.reg2mem
  %switchVar = alloca i32
  store i32 157301900, i32* %switchVar
  br label %loopEntry
 
loopEntry:    
%switchVar10 = load i32, i32* %switchVar
  switch i32 %switchVar10, label %switchDefault [
  ]
 
switchDefault:                                    ; preds = %loopEntry
  br label %loopEnd
 
loopEnd:                                       
br label %loopEntry

创建case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (std::vector<BasicBlock *>::iterator b = origBB.begin();
     b != origBB.end(); ++b) {
  BasicBlock *i = *b;
  ConstantInt *numCase = NULL;
 
  // Move the BB inside the switch (only visual, no code logic)
  i->moveBefore(loopEnd);
 
  // Add case to switch
  numCase = cast<ConstantInt>(ConstantInt::get(
      switchI->getCondition()->getType(),
      llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key)));
  switchI->addCase(numCase, i);
}

这里的i就是指剩下的那些case分支代码基本块,i->moveBefore(loopEnd),把某个代码基本块置于loopend之前。比如某个基本块是这样:

1
2
3
NodeBlock8:                                       ; preds = %entry
  %Pivot9 = icmp slt i32 %2, 2
  br i1 %Pivot9, label %LeafBlock, label %NodeBlock

然后下面的这些代码就是创建一个numcase,就是case分支里面的case值,这个值它是随机生成的,种子的话是Entry.cpp里面的那个AesSeed值,如果确定AesSeed的话,那么这里随机生成的case每次都是固定的。
switchI->addCase(numCase, i);紧接着在switch里面增加一个case值,跳转到NodeBlock8里面。
目前switch执行完一次后,loopentry基本bolck块如下:

1
2
3
4
5
loopEntry:    
%switchVar10 = load i32, i32* %switchVar
  switch i32 %switchVar10, label %switchDefault [
   i32 157301900, label %NodeBlock8
  ]

当循环执行结束后:

目前代码

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
entry:
  %retval = alloca i32, align 4
  %argc.addr = alloca i32, align 4
  %argv.addr = alloca i8**, align 8
  %a = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  store i32 %argc, i32* %argc.addr, align 4
  store i8** %argv, i8*** %argv.addr, align 8
  %0 = load i8**, i8*** %argv.addr, align 8
  %arrayidx = getelementptr inbounds i8*, i8** %0, i64 1
  %1 = load i8*, i8** %arrayidx, align 8
  %call = call i32 @atoi(i8* %1) #3
  store i32 %call, i32* %a, align 4
  %2 = load i32, i32* %a, align 4
  br label %NodeBlock8
 
NodeBlock8:                                       ; preds = %entry
  %Pivot9 = icmp slt i32 %2, 2
  br i1 %Pivot9, label %LeafBlock, label %NodeBlock
 
NodeBlock:                                        ; preds = %NodeBlock8
  %Pivot = icmp slt i32 %2, 3
  br i1 %Pivot, label %sw.bb2, label %LeafBlock6
 
LeafBlock6:                                       ; preds = %NodeBlock
  %SwitchLeaf7 = icmp eq i32 %2, 3
  br i1 %SwitchLeaf7, label %sw.bb4, label %NewDefault
 
LeafBlock:                                        ; preds = %NodeBlock8
  %SwitchLeaf = icmp eq i32 %2, 1
  br i1 %SwitchLeaf, label %sw.bb, label %NewDefault
 
sw.bb:                                            ; preds = %LeafBlock
  %call1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
  br label %sw.epilog
 
sw.bb2:                                           ; preds = %NodeBlock
  %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0))
  br label %sw.epilog
 
sw.bb4:                                           ; preds = %LeafBlock6
  %call5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i64 0, i64 0))
  br label %sw.epilog
 
NewDefault:                                       ; preds = %LeafBlock6, %LeafBlock
  br label %sw.default
 
sw.default:                                       ; preds = %NewDefault
  br label %sw.epilog
 
sw.epilog:                                        ; preds = %sw.default, %sw.bb4, %sw.bb2, %sw.bb
  %3 = load i32, i32* %a, align 4
  %cmp = icmp eq i32 %3, 0
  br i1 %cmp, label %if.then, label %if.else
 
if.then:                                          ; preds = %sw.epilog
  store i32 1, i32* %retval, align 4
  br label %return
 
if.else:                                          ; preds = %sw.epilog
  store i32 10, i32* %retval, align 4
  br label %return
 
return:                                           ; preds = %if.else, %if.then
  %4 = load i32, i32* %retval, align 4
  ret i32 %4
   
loopEnd:                                          ; preds = %if.else, %if.then, %sw.epilog, %sw.default, %NewDefault, %sw.bb4, %sw.bb2, %sw.bb, %LeafBlock, %LeafBlock6, %NodeBlock, %NodeBlock8, %switchDefault
  br label %loopEntry
 
}

枚举更改各个case block块

return block

1
2
3
4
// Ret BB
   if (i->getTerminator()->getNumSuccessors() == 0) {
     continue;
   }

getNumSuccessors是获取后续BB的个数,Ret BB后继BB为0个(判断分支),直接continue

非条件跳转block

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// If it's a non-conditional jump
   if (i->getTerminator()->getNumSuccessors() == 1) {
     // Get successor and delete terminator
     BasicBlock *succ = i->getTerminator()->getSuccessor(0);
     i->getTerminator()->eraseFromParent();
 
     // Get next case
     numCase = switchI->findCaseDest(succ);
 
     // If next case == default case (switchDefault)
     if (numCase == NULL) {
       numCase = cast<ConstantInt>(
           ConstantInt::get(switchI->getCondition()->getType(),
                            llvm::cryptoutils->scramble32(
                                switchI->getNumCases() - 1, scrambling_key)));
     }
 
     // Update switchVar and jump to the end of loop
     new StoreInst(numCase, load->getPointerOperand(), i);
     BranchInst::Create(loopEnd, i);
     continue;
   }

如果后面只有一个分支的话,那么先判断分支是否能够找到,不为null后先去根据原来条件去创建一个store指令,然后创建一个跳转指令跳转到loopend,再把原来跳转指令抹去。
原来:

1
2
3
sw.bb:                                            ; preds = %LeafBlock
  %call1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
  br label %sw.epilog

改变后:

1
2
3
4
sw.bb:                                            ; preds = %LeafBlock
  %call1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
  store i32 387774014, i32* %switchVar
  br label %loopEnd

条件跳转 block

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
if (i->getTerminator()->getNumSuccessors() == 2) {
    // Get next cases
    ConstantInt *numCaseTrue =
        switchI->findCaseDest(i->getTerminator()->getSuccessor(0));
    ConstantInt *numCaseFalse =
        switchI->findCaseDest(i->getTerminator()->getSuccessor(1));
 
    // Check if next case == default case (switchDefault)
    if (numCaseTrue == NULL) {
      numCaseTrue = cast<ConstantInt>(
          ConstantInt::get(switchI->getCondition()->getType(),
                           llvm::cryptoutils->scramble32(
                               switchI->getNumCases() - 1, scrambling_key)));
    }
 
    if (numCaseFalse == NULL) {
      numCaseFalse = cast<ConstantInt>(
          ConstantInt::get(switchI->getCondition()->getType(),
                           llvm::cryptoutils->scramble32(
                               switchI->getNumCases() - 1, scrambling_key)));
    }
 
    // Create a SelectInst
    BranchInst *br = cast<BranchInst>(i->getTerminator());
    SelectInst *sel =
        SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "",
                           i->getTerminator());
 
    // Erase terminator
    i->getTerminator()->eraseFromParent();
 
    // Update switchVar and jump to the end of loop
    new StoreInst(sel, load->getPointerOperand(), i);
    BranchInst::Create(loopEnd, i);
    continue;
  }

首先会把两个跳转分支都取出来,先判断两个分支是否都能够找到,如果都不为null 的话,那么取出原来的跳转指令,根据br的两个分支条件,去创建一个SelectInst然后再删除原来指令,创建一个store指令,再去创建一个跳转指令跳转到loopend。
原来:

1
2
3
NodeBlock8:                                       ; preds = %entry
  %Pivot9 = icmp slt i32 %2, 2
  br i1 %Pivot9, label %LeafBlock, label %NodeBlock

改变后:

1
2
3
4
5
NodeBlock8:                                       ; preds = %entry
  %Pivot9 = icmp slt i32 %2, 2
  %3 = select i1 %Pivot9, i32 -1519555718, i32 241816174
  store i32 %3, i32* %switchVar
  br label %loopEnd

目前代码

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
106
107
108
109
110
111
define dso_local i32 @main(i32 %argc, i8** %argv) #0 {
entry:
  %.reg2mem = alloca i32
  %retval = alloca i32, align 4
  %argc.addr = alloca i32, align 4
  %argv.addr = alloca i8**, align 8
  %a = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  store i32 %argc, i32* %argc.addr, align 4
  store i8** %argv, i8*** %argv.addr, align 8
  %0 = load i8**, i8*** %argv.addr, align 8
  %arrayidx = getelementptr inbounds i8*, i8** %0, i64 1
  %1 = load i8*, i8** %arrayidx, align 8
  %call = call i32 @atoi(i8* %1) #3
  store i32 %call, i32* %a, align 4
  %2 = load i32, i32* %a, align 4
  store i32 %2, i32* %.reg2mem
  %switchVar = alloca i32
  store i32 157301900, i32* %switchVar
  br label %loopEntry
 
loopEntry:                                        ; preds = %entry, %loopEnd
  %switchVar10 = load i32, i32* %switchVar
  switch i32 %switchVar10, label %switchDefault [
    i32 157301900, label %NodeBlock8
    i32 241816174, label %NodeBlock
    i32 1003739776, label %LeafBlock6
    i32 -1519555718, label %LeafBlock
    i32 -749093422, label %sw.bb
    i32 1599617141, label %sw.bb2
    i32 1815329037, label %sw.bb4
    i32 1738940479, label %NewDefault
    i32 -282945350, label %sw.default
    i32 387774014, label %sw.epilog
    i32 1681741611, label %if.then
    i32 347219667, label %if.else
    i32 -618048859, label %return
  ]
 
switchDefault:                                    ; preds = %loopEntry
  br label %loopEnd
 
NodeBlock8:                                       ; preds = %entry
  %Pivot9 = icmp slt i32 %2, 2
  %3 = select i1 %Pivot9, i32 -1519555718, i32 241816174
  store i32 %3, i32* %switchVar
  br label %loopEnd
 
NodeBlock:                                        ; preds = %NodeBlock8
  %Pivot = icmp slt i32 %2, 3
  %4 = select i1 %Pivot, i32 1599617141, i32 1003739776
  store i32 %4, i32* %switchVar
  br label %loopEnd
 
LeafBlock6:                                       ; preds = %NodeBlock
  %SwitchLeaf7 = icmp eq i32 %2, 3
  %5 = select i1 %SwitchLeaf7, i32 1815329037, i32 1738940479
  store i32 %5, i32* %switchVar
  br label %loopEnd
 
LeafBlock:                                        ; preds = %NodeBlock8
  %SwitchLeaf = icmp eq i32 %2, 1
  %6 = select i1 %SwitchLeaf, i32 -749093422, i32 1738940479
  store i32 %6, i32* %switchVar
  br label %loopEnd
 
sw.bb:                                            ; preds = %LeafBlock
  %call1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
  store i32 387774014, i32* %switchVar
  br label %loopEnd
 
sw.bb2:                                           ; preds = %NodeBlock
  %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0))
  br label %sw.epilog
 
sw.bb4:                                           ; preds = %LeafBlock6
  %call5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i64 0, i64 0))
  store i32 387774014, i32* %switchVar
  br label %loopEnd
 
NewDefault:                                       ; preds = %LeafBlock6, %LeafBlock
  br label %sw.default
 
sw.default:                                       ; preds = %NewDefault
  store i32 387774014, i32* %switchVar
  br label %loopEnd
 
sw.epilog:                                        ; preds = %sw.default, %sw.bb4, %sw.bb2, %sw.bb
  %3 = load i32, i32* %a, align 4
  %cmp = icmp eq i32 %3, 0
  %8 = select i1 %cmp, i32 1681741611, i32 347219667
  store i32 %8, i32* %switchVar
  br label %loopEnd
 
if.then:                                          ; preds = %sw.epilog
  store i32 1, i32* %retval, align 4
  store i32 -618048859, i32* %switchVar
  br label %loopEnd
 
if.else:                                          ; preds = %sw.epilog
  store i32 10, i32* %retval, align 4
  store i32 -618048859, i32* %switchVar
  br label %loopEnd
 
return:                                           ; preds = %if.else, %if.then
  %4 = load i32, i32* %retval, align 4
  ret i32 %4
 
loopEnd:                                          ; preds = %if.else, %if.then, %sw.epilog, %sw.default, %NewDefault, %sw.bb4, %sw.bb2, %sw.bb, %LeafBlock, %LeafBlock6, %NodeBlock, %NodeBlock8, %switchDefault
  br label %loopEntry
}

附带一句,进行控制流平坦化之前刚开始会把switch语句给它全部进行改为if else目的主要是为了进行多次平坦化做准备(进行平坦化时里面是可以填次数)

魔改平坦化

正常流程就是首先进入entry,entry会给一个case常量值,然后进入loopentry,loopentry根据这个常量值进行switch分跳转到case常量对应的基本块,基本块执行完又会赋值一个case常量值,跳转到loopend,loopend又会跳转到loopentry进行下一次分发。(感觉特征点的话就是entry和loopend都会跳转到loopentry)。

大部分的方法都是基于定位loopend基本块,这种简单的IR结构编译成汇编代码也是这个样子,很容易定位到loopend基本块。在这里,我们的魔改方法就直接在loopend基本块后面加一个新的switchInst,然后跳转到基本块,相当于从开始的switch转移到后面来了。即抹除原来的跳转,插入loadInst加载swichvar,再用于swichInst跳转。

尾声

网上很多很多现成资料,我这个也是自己看了再总结的,如果哪里不对的话,还请多多指教。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2023-7-30 19:21 被寻梦之璐编辑 ,原因:
收藏
点赞11
打赏
分享
最新回复 (2)
雪    币: 19410
活跃值: (29069)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-7-30 21:07
2
1
感谢分享
雪    币: 519
活跃值: (3752)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
龙飞雪 2023-9-1 22:58
3
0
谢谢分享
游客
登录 | 注册 方可回帖
返回