威化饼的一隅 2019-05-25 21:11 采纳率: 0%
浏览 406

如何使用LLVM在基本块的入口和出口插入代码?

  In my recent work, I need insert the instrumentation code at the entry and exit of basic blocks to get value of varibles and so I can check them based on a DFA of the source code. Another task is when the executable file is executed according to the instrumentation code, an exception will be triggered before function call and system call or an access of an variable or after an update of an variable.

  I've read LLVM manual about how to write a pass. However, it doesn't tell me how can I get the latest value of variables.

  Someone provide a link contains basic usage of LLVM pass but it's too simple -----------
https://github.com/SumedhArani/LLVM
https://www.cs.cornell.edu/~asampson/blog/llvm.html

A simple program that can be exploited to launch DOP attacks:

#include <stdio.h>
int main(){
    int old_valud,new_value;
    int *p=&old_value,*q=&new_value;
    int connect_limit=100;
    char buf[64];

    while(connect_limit--){
        read(0,buf);
        *p=*q;
    }
    return 0;
}

LLVM IR

    define i32 @main() #0 {
      %1 = alloca i32, align 4
      %old_value = alloca i32, align 4
      %new_value = alloca i32, align 4
      %p = alloca i32*, align 8
      %q = alloca i32*, align 8
      %connect_limit = alloca i32, align 4
      %buf = alloca [64 x i8], align 16
      store i32 0, i32* %1
      store i32* %old_value, i32** %p, align 8
      store i32* %new_value, i32** %q, align 8
      store i32 100, i32* %connect_limit, align 4
      br label %2

    ; <label>:2                                       ; preds = %6, %0
      %3 = load i32, i32* %connect_limit, align 4
      %4 = add nsw i32 %3, -1
      store i32 %4, i32* %connect_limit, align 4
      %5 = icmp ne i32 %3, 0
      br i1 %5, label %6, label %12

    ; <label>:6                                       ; preds = %2
      %7 = getelementptr inbounds [64 x i8], [64 x i8]* %buf, i32 0, i32 0
      %8 = call i32 (i8*, ...) @__isoc99_scanf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8* %7)
      %9 = load i32*, i32** %q, align 8
      %10 = load i32, i32* %9, align 4
      %11 = load i32*, i32** %p, align 8
      store i32 %10, i32* %11, align 4
      br label %2

    ; <label>:12                                      ; preds = %2
      ret i32 0
    }









** CFG **


CFG of is


Can someone provide some relevant source code and guidance?

  • 写回答

1条回答 默认 最新

  • 你知我知皆知 2024-08-09 20:18
    关注

    以下回答参考 皆我百晓生券券喵儿 等免费微信小程序相关内容作答,并由本人整理回复。

    要使用LLVM在基本块的入口和出口插入代码,你需要创建一个Module对象,并将你的函数定义为这个模块中的一个函数。然后你可以通过调用addPassesToModule()方法来添加你的编译器变换。

    以下是一个示例:

    #include <llvm/IR/Module.h>
    #include <llvm/IR/DerivedTypes.h>
    #include <llvm/Support/raw_ostream.h>
    
    // 函数定义
    void insertInstrumentation(Module &M);
    
    // 编写一个简单的测试函数
    void testInsertion() {
        // 创建一个新的模块
        Module M("test");
        
        // 添加我们的编译器变换到模块中
        insertInstrumentation(M);
        
        // 打印模块信息
        raw_string_ostream OS;
        M.print(OS, nullptr, llvm::raw_ostream::OstreamPrinters::prettyprint());
        std::cout << "Module Info:\n" << OS.str();
    }
    
    int main() {
        testInsertion();
        return 0;
    }
    

    在这个例子中,我们首先创建了一个新的模块test。然后,我们在模块中添加了我们的编译器变换。最后,我们打印出模块的信息以查看它是否正确地被添加到了模块中。

    请注意,这只是一个非常基础的例子,实际应用中你可能需要根据你的具体需求进行更多的调整和优化。例如,你可能需要处理更复杂的语法结构、变量类型以及异常处理等。

    评论

报告相同问题?