afl的llvm模式插桩改一个小需求

有人用过llvm的pass吗?afl里面有一个llvm的插桩模块,是通过一个pass实现的,它可以对一个C代码进程插桩操作。执行afl-clang-fast test.c -o test指令时,可以在test.c这个c代码里,在每一个基本块的第一条指令处插一个随机数,然后下一个基本块也插一个随机数,然后把这两个随机数异或一下得到一个值作为这条边的编号存在一个共享内存里。然后我想让他实现一个功能就是,修改pass的代码,对test进行插随机数的地方,插进去一句把这个随机数输出到一个外部文件的话。然后这个插桩后的可执行文件test,每次执行它的时候,就可以把实际执行的路径中的随机数给输出出来,这样我就知道test中哪条路径走过了。 但是这个pass应该怎么改,有人用过llvm的pass嘛?我感觉如果llvm用的好的话可能这就是一个小需求,但是我llvm pass学的不好,这周要做出来,有没有人帮帮忙呀(大哭)

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答由chatgpt基于相关博客总结生成:

    解决方案:

    要修改afl的llvm模式插桩,以便将随机数输出到外部文件,需要对afl-llvm-pass.so文件进行修改。以下是解决该问题的步骤:

    步骤1: 下载afl插件源码

    首先,你需要下载afl插件源码。你可以在https://github.com/mirrorer/afl上找到源码。将源码下载到你的本地目录中。

    步骤2: 编译afl插件源码

    进入源码目录,并编译插件源码。运行以下命令:

    cd afl
    make clean all
    

    这将会编译插件并生成afl-llvm-pass.so文件。

    步骤3: 打开afl插件源码

    使用文本编辑器打开afl-llvm-pass.c文件,该文件位于afl/llvm_mode目录下。这是afl的llvm插件源码文件。

    步骤4: 查找插入随机数的位置

    afl-llvm-pass.c文件中,你需要找到基本块被插入随机数的位置。在该位置后面,你需要添加代码将随机数输出到外部文件中。

    afl在InstrumentBasicBlock函数中插入了随机数。你可以使用以下代码找到插入随机数的位置:

    static void InstrumentBasicBlock(BasicBlock &BB, const Module *M) {
      ...
    }
    

    步骤5: 添加代码将随机数输出到外部文件

    在找到插入随机数的位置后,你需要添加代码将随机数输出到外部文件中。可以通过以下步骤实现:

    5.1: 添加头文件

    在文件开头添加以下头文件:

    #include <fstream>
    

    5.2: 打开文件

    InstrumentBasicBlock函数中,找到插入随机数的位置后,添加以下代码来打开一个文件:

    std::ofstream outfile;
    outfile.open("random_numbers.txt", std::ios::app);
    

    这将会打开一个名为random_numbers.txt的文件,并以附加方式打开。

    5.3: 写入随机数

    在插入随机数的位置之后,添加以下代码来将随机数写入文件:

    outfile << random_number << std::endl;
    

    这将会将random_number写入random_numbers.txt文件中,并在每个随机数后添加一个换行符。

    5.4: 关闭文件

    InstrumentBasicBlock函数结束的位置,添加以下代码来关闭文件:

    outfile.close();
    

    这将会关闭random_numbers.txt文件。

    步骤6: 保存修改并重新编译插件

    保存修改后,重新编译插件源码。运行以下命令:

    make
    

    这将会重新编译插件并生成新的afl-llvm-pass.so文件。

    步骤7: 使用新的插件对C代码进行插桩

    使用新生成的afl-llvm-pass.so插件对C代码进行插桩。运行以下命令:

    afl-clang-fast test.c -o test -Xclang -load -Xclang /path/to/afl-llvm-pass.so
    

    确保将/path/to/afl-llvm-pass.so替换为新生成的afl-llvm-pass.so的路径。

    完成以上步骤后,每次执行插桩后的可执行文件test时,会将实际执行的路径中的随机数输出到random_numbers.txt文件中。你可以根据需要修改文件名和路径。

    希望以上解决方案对你有所帮助!如果你有任何其他问题,请随时提问。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

继承pass类来实现自定义的pass

afl-clang-fast插桩代码解析第一部分:afl-llvm-pass.so.cc
可以参考下


AFL源码阅读笔记(二)—— llvm_mode 和 pass 源码_afl llvm_mode_CSU_DEZ_THU的博客-CSDN博客 afl源码阅读,llvm模式插桩,包括llvm相关概念和pass的理解。_afl llvm_mode https://blog.csdn.net/weixin_45651194/article/details/128331312

在原来的代码上,修改随机数代码,然后重新编译

找到随机数的代码位置,增加一个数据输出

虽然我无法了解每个用户的具体经历,但我可以告诉您如何实现您所描述的功能。首先,您需要修改AFL中的LLVM插桩模块,以在每个基本块的第一条指令处插入输出随机数的代码。接着,编译被插桩的C代码,使其包含您的修改后的插桩Pass。然后,您可以执行被插桩的测试程序,并查看输出文件,以了解测试过程中每个路径所使用的随机数。

下面是大致的步骤:

1.找到AFL中实现LLVM插桩的代码。这通常位于llvm_mode文件夹中。

2.找到LLVM的插桩Pass,负责在每个基本块的第一条指令处插入随机数。可能是一个类似AFLCoverage.cpp的文件。

3.在Pass中添加输出随机数的功能。您可以使用LLVM提供的日志函数或自定义的输出方式。例如,在Pass中添加代码,以在每个基本块插入类似以下的指令:

errs() << "Random number: " << random_value << "\n";


1.构建您修改后的AFL插桩工具。

2.然后,使用您的AFL插桩工具来编译测试代码,将插桩后的可执行文件生成。

3.执行被插桩的测试程序。您会看到随机数输出到屏幕上,但如果您希望将其保存到文件,可以将输出重定向到文件中:

./test > output.txt


现在,您可以查看output.txt文件,其中包含测试过程中每个路径使用的随机数信息。
请注意,AFL的代码可能会随着时间不断更新,所以根据您使用的AFL版本,有关插桩模块的代码可能会有所不同。确保在正确的代码版本上进行修改。

采用chatgpt:
要实现在 AFL 的 LLVM 模式 pass 检测期间将随机数输出到外部文件的功能,您可以对 pass 代码进行以下修改。 我将提供所需更改的高级概述。

定义输出文件名:决定要输出随机数的文件的名称。 对于此示例,我们使用“random_numbers.txt”。

包含必要的标头:包含文件处理和输出所需的标头。

生成和输出随机数:修改通道以生成随机数并将其输出到适当位置的外部文件(例如,基本块检测)。

以下是修改后的通道在 LLVM 中的外观概要:

// Add necessary includes
#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include <fstream>

using namespace llvm;

namespace {
  struct AFLInstrumentationPass : public FunctionPass {
    static char ID;

    AFLInstrumentationPass() : FunctionPass(ID) {}

    // Function to generate random numbers
    int getRandomNumber() {
      // Implement your random number generation logic here.
      // You can use C++ standard library random functions or any other method.
      // For this example, let's assume you have a function that generates a random number.
      return generateRandomNumber();
    }

    bool runOnFunction(Function &F) override {
      // Open the output file for appending
      std::ofstream outFile("random_numbers.txt", std::ios_base::app);

      for (auto &BB : F) {
        // Generate a random number
        int randomNum = getRandomNumber();

        // Output the random number to the external file
        outFile << randomNum << "\n";

        // Insert instrumentation before the first instruction of the basic block
        IRBuilder<> Builder(&*BB.getFirstInsertionPt());
        Builder.CreateCall(...); // Add code to insert the random number into the shared memory as you have done before
      }

      // Close the output file
      outFile.close();

      return true;
    }
  };
}

char AFLInstrumentationPass::ID = 0;

static RegisterPass<AFLInstrumentationPass> X("afl-instrumentation", "AFL Instrumentation Pass");

// The rest of your pass registration and other boilerplate code
// ...

getRandomNumber() 的实际实现以及如何将随机数插入共享内存可能取决于您的具体用例。 另外,请确保正确处理文件 I/O 错误。 上面的代码是让您了解如何修改通行证的起点。

进行这些更改并重建 LLVM 通道和 AFL 后,您应该能够像以前一样执行 afl-clang-fast test.c -o 测试。 运行检测的测试二进制文件时,它会将随机数输出到“random_numbers.txt”,因为它在执行过程中采用不同的路径通过代码。

AFL是一款基于边界值分析(Fuzzing)的自动化工具,用于发现软件中的漏洞。它能够将输入数据随机性生成,并将结果与程序的行为比较,从而找到程序中的缺陷。

LLVM是一款开源编译器架构,用于编译C、C++以及其他编程语言。在AFL中使用LLVM模式插桩,可以自动化地将程序的二进制文件进行修改,从而使AFL能够对程序进行边界值分析。

在这里,我们将讨论如何将一个小需求内容插入AFL的LLVM模式插桩中。

首先,我们需要安装AFL和LLVM。安装步骤网上有很多教程,此处不再赘述。

接下来,我们需要为程序编写一个简单的插件。一个插件是一个LLVM Pass,它将在程序解析期间被AFL的LLVM模式插桩所调用。Pass是一种内置于LLVM中的模块,用于在编译期间对程序进行修改。

我们将为程序编写一个Pass,以将一个简单的需求内容插入程序中。假设我们要在程序中添加一个日志记录功能,用于记录程序的执行过程。为此,我们需要修改程序的源代码,在关键位置处添加日志输出。

下面是一个简单的Pass代码:

#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {
  struct MyPass : public FunctionPass {
    static char ID;
    MyPass() : FunctionPass(ID) {}

    bool runOnFunction(Function &F) override {
      errs() << "Function " << F.getName() << "\n";
      for (auto &B : F) {
        for (auto &I : B) {
          if (auto *op = dyn_cast<BinaryOperator>(&I)) {
            errs() << "Found a binary operator: " << op << "\n";
          }
        }
      }
      return false;
    }
  };
}

char MyPass::ID = 0;
static RegisterPass<MyPass> X("mypass", "My custom LLVM Pass");

该Pass会在程序解析期间遍历程序中的所有函数,并查找其中的二元运算符。如果找到了二元运算符,它将在标准错误输出流中打印一条消息。

我们接下来需要将这个Pass和程序进行链接。为此,我们需要使用LLVM的工具链编译程序和Pass,并使用链接器将它们链接在一起。

假设我们将程序命名为“test.c”,编写的Pass命名为“mypass”,则可以使用以下命令来编译程序和Pass:

clang -c test.c -o test.o
clang++ -c mypass.cpp -o mypass.o `llvm-config --cxxflags`

接下来,我们可以使用以下命令将程序和Pass链接在一起:

clang++ test.o mypass.o `llvm-config --ldflags --libs` -o test

这个命令将生成一个名为“test”的可执行文件,其中包含了我们编写的Pass。

最后,我们需要使用AFL的LLVM模式插桩来对程序进行边界值分析。为此,我们可以使用以下命令:

afl-clang-fast -mllvm -afl -mllvm -no-cmplog -mllvm -passname=mypass test.c -o test

这个命令将生成一个名为“test”的可执行文件,它已经被AFL的LLVM模式插桩修改过了。现在,我们可以使用AFL来对程序进行边界值分析了。

在执行边界值分析之前,我们还需要创建一个输入文件夹和一个输出文件夹,以存储AFL生成的输入和输出数据。为此,我们可以使用以下命令:

mkdir in_dir
mkdir out_dir

最后,我们可以使用以下命令来启动AFL进行边界值分析:

afl-fuzz -i in_dir/ -o out_dir/ ./test

这个命令将启动AFL进行边界值分析,并将生成的输入数据存储在“in_dir”文件夹中,将输出数据存储在“out_dir”文件夹中。

总之,通过以上步骤,我们可以将一个小需求内容插入到AFL的LLVM模式插桩中,并使用AFL对程序进行边界值分析。这只是一个简单的例子,实际上,我们可以根据自己的需求编写更加复杂的Pass,并将它们应用于各种程序中。

AFL(American Fuzzy Lop)是一个针对二进制文件的模糊测试工具,可以在软件测试中发现未处理的漏洞,其中LLVM模式是其最新版本的插桩技术,可以对代码进行更加深入的分析和测试。现在,我们需要针对AFL的LLVM模式进行一个小的需求改动,需要修改的内容如下:

将插桩输出的文件格式从默认的二进制格式修改为文本格式。

这个需求的背景是,二进制格式虽然可以更加高效地进行处理,但是在查看和分析时会有一定的困难,因此需要将其转换为文本格式,方便分析人员查看和处理。

要实现这一需求,我们需要进行以下几个步骤:

  1. 确定输出文件格式:由于我们需要将输出文件格式修改为文本格式,因此需要选择一种适合的文本格式作为输出格式。在选择时,需要考虑到可读性、易处理性和存储空间大小等因素。常见的文本格式包括XML、JSON、YAML等,我们可以根据实际情况进行选择。

  2. 修改插桩代码:AFL的插桩代码是使用LLVM的Pass来实现的,因此我们需要对AFL的LLVM Pass代码进行修改,将输出文件格式从二进制格式改为文本格式。具体来说,我们需要在插桩代码中对输出进行重定向,并将输出转换为指定的文本格式。这里我们以JSON格式为例,将插桩输出转换为JSON格式的字符串,并写入文件中。

  3. 测试验证:修改完成后,需要进行测试验证,确保修改后的插桩代码能够正确地输出指定格式的文本文件,并能够进行正确的分析和处理。我们可以编写一些简单的测试用例,用于验证修改后的代码是否能够正确运行。

  4. 集成部署:修改完成后,需要将修改后的代码集成到AFL的LLVM模式中,并进行部署。在部署时需要确保修改后的代码与原有代码的兼容性,不影响原有的功能和性能。

总体来说,对AFL的LLVM模式进行插桩输出文件格式的修改是一项比较简单的需求,但是需要对插桩代码进行适当的修改,以保证修改后的代码能够正确地输出指定格式的文本文件。同时,我们还需要进行测试验证和集成部署,以保证修改后的代码能够正常运行,并能够对软件进行有效的测试。

可以通过修改LLVM的pass来实现。以下是大致步骤:
找到LLVM的源代码,并编译出LLVM的二进制工具(如clang)。
在LLVM的源代码中,找到与插桩相关的的地方,这可能涉及到一些LLVM的内部结构。AFL的插桩模块位于lib/Transforms/Instrumentation目录下,你可以在此处找到相关的文件。
在插桩模块的代码中,找到输出随机数的位置,并修改代码,使其输出随机数的同时,将随机数写入到外部文件中。
编译修改后的LLVM二进制工具,并使用它来编译你的测试程序

参考gpt

  1. 首先,您需要了解LLVM的基本原理和编译器的工作流程。这将有助于您理解如何使用LLVM的pass来修改代码。

  2. 接下来,您可以使用LLVM提供的API来编写自定义的pass。您可以参考LLVM的官方文档和示例代码来了解如何编写和注册一个pass。

  3. 在您的pass中,您可以通过遍历基本块(BasicBlock)来定位插桩的位置。在每个基本块的第一条指令处,您可以插入一段代码来生成随机数,并将其输出到外部文件。

  4. 在生成随机数并输出到外部文件的代码中,您可以使用LLVM提供的API来创建文件输出流,并将随机数写入文件中。请注意,您可能需要在pass的构造函数中添加一些额外的参数来指定输出文件的路径。

  5. 最后,您需要将修改后的pass编译为LLVM插件,并将其与AFL一起使用,以便在编译过程中应用该pass。您可以使用clang命令行工具来编译带有插件的可执行文件。