Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.
这段是 Google 官方网站给出的介绍,protobuf 可以自动化生成代码,用于读入或者写入结构化数据。一个简单的 protobuf 文件可以是这样的:
1 2 3 4 5
message Person { requiredstring name = 1; requiredint32 id = 2; optionalstring email = 3; }
#define DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, Proto) \ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { \ using protobuf_mutator::libfuzzer::LoadProtoInput; \ Proto input; \ if (LoadProtoInput(use_binary, data, size, &input)) \ TestOneProtoInput(input); \ return 0; \ }
// Defines custom mutator, crossover and test functions using default // serialization format. Default is text. #define DEFINE_PROTO_FUZZER(arg) DEFINE_TEXT_PROTO_FUZZER(arg) // Defines custom mutator, crossover and test functions using text // serialization. This format is more convenient to read. #define DEFINE_TEXT_PROTO_FUZZER(arg) DEFINE_PROTO_FUZZER_IMPL(false, arg) // Defines custom mutator, crossover and test functions using binary // serialization. This makes mutations faster. However often test function is // significantly slower than mutator, so fuzzing rate may stay unchanged. #define DEFINE_BINARY_PROTO_FUZZER(arg) DEFINE_PROTO_FUZZER_IMPL(true, arg)
执行 make 后报错 ./test.pb.h:17:2: error: This file was generated by an older version of protoc which is,因为我们在编译的时候使用了 -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON 下载了新版本的 protobuf,所以出了这个错误。只好使用下载的 protoc 重新生成 test.pb.cc 和 test.pb.h
std::string res = all.str(); if (bb.size() != 0 && res.size() != 0) { // set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf if (constchar *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { std::ofstream of(dump_path); of.write(res.data(), res.size()); } } return res; }
extern"C"intFuzzTEST(constuint8_t* data, size_t size); // our customized fuzzing function
DEFINE_PROTO_FUZZER(const TEST &test_proto) { auto s = ProtoToData(test_proto); // convert protobuf to raw data FuzzTEST((constuint8_t*)s.data(), s.size()); // fuzz the function }
# for testing libprotobuf + libfuzzer # compile harness first # then link lpm_libfuzz with harness.o & static libraries harness.o: harness.cc $(CXX)$(CXXFLAGS) -c $(DFUZZ)$<
$(TARGET): harness.o $(TARGET).cc $(CXX)$(CXXFLAGS) -o $@$^$(PB_SRC)$(LPM_LIB)$(PROTOBUF_LIB)$(INC)# $(LPM_LIB) must be placed before $(PROTOBUF_LIB)
.PHONY: clean clean: rm $(TARGET) *.o
make 后报错,找不到头文件
1 2 3 4
/home/henices/code/AFL+/external/libprotobuf-mutator/include/libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h:24:10: fatal error: 'port/protobuf.h' file not found #include"port/protobuf.h" ^~~~~~~~~~~~~~~~~ 1error generated.
# for testing libprotobuf + libfuzzer # compile harness first # then link lpm_libfuzz with harness.o & static libraries harness.o: harness.cc $(CXX)$(CXXFLAGS) -c $(DFUZZ)$<
$(TARGET): harness.o $(TARGET).cc $(CXX)$(CXXFLAGS) -o $@$^$(PB_SRC)$(LPM_LIB)$(PROTOBUF_LIB)$(INC)# $(LPM_LIB) must be placed before $(PROTOBUF_LIB)
extern"C"size_tafl_custom_fuzz(MyMutator *mutator, // return value from afl_custom_init uint8_t *buf, size_t buf_size, // input data to be mutated uint8_t **out_buf, // output buffer uint8_t *add_buf, size_t add_buf_size, // add_buf can be NULL size_t max_size){ // This function can be named either "afl_custom_fuzz" or "afl_custom_mutator" // A simple test shows that "buf" will be the content of the current test case // "add_buf" will be the next test case ( from AFL++'s input queue )
TEST input; // parse input data to TEST // Notice that input data should be a serialized protobuf data // Check ./in/ii and test_protobuf_serializer for more detail bool parse_ok = input.ParseFromArray(buf, buf_size); if(!parse_ok) { // Invalid serialize protobuf data. Don't mutate. // Return a dummy buffer. Also mutated_size = 0 staticuint8_t *dummy = newuint8_t[10]; // dummy buffer with no data *out_buf = dummy; return0; } // mutate the protobuf mutator->Mutate(&input, max_size);
// Convert protobuf to raw data const TEST *p = &input; std::string s = ProtoToData(*p); // Copy to a new buffer ( mutated_out ) size_t mutated_size = s.size() <= max_size ? s.size() : max_size; // check if raw data's size is larger than max_size uint8_t *mutated_out = newuint8_t[mutated_size+1]; memcpy(mutated_out, s.c_str(), mutated_size); // copy the mutated data // Assign the mutated data and return mutated_size *out_buf = mutated_out; return mutated_size; }