cd libprotobuf-mutator mkdir build cd build #编译动态库 cmake .. -GNinja -DCMAKE_C_COMPILER=clang-11 \ -DCMAKE_CXX_COMPILER=clang++-11 \ -DCMAKE_BUILD_TYPE=Debug \ -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON \ -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" ninja check # test, might took very long time ninja # just build, use this if you don't want to wait too long sudo ninja install # install
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 }
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; }
/** * Initialize this custom mutator * * @param[in] afl a pointer to the internal state object. Can be ignored for * now. * @param[in] seed A seed for this mutator - the same seed should always mutate * in the same way. * @return Pointer to the data object this custom mutator instance should use. * There may be multiple instances of this mutator in one afl-fuzz run! * Return NULL on error. */ extern"C"void *afl_custom_init(void *afl, unsignedint seed){ srand(seed); return afl; }
/** * Perform custom mutations on a given input * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] buf Pointer to input data to be mutated * @param[in] buf_size Size of input data * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on * error. * @param[in] add_buf Buffer containing the additional test case * @param[in] add_buf_size Size of the additional test case * @param[in] max_size Maximum size of the mutated output. The mutation must not * produce data larger than max_size. * @return Size of the mutated output. */ extern"C"size_tafl_custom_fuzz(void *data, // afl state 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 )
// Here we implement our own custom mutator static MyMutator mutator; TEST input; // mutate input.a ( integer ) int id = rand() % 305; input.set_a(id); // mutate input.b ( string ) std::string tmp = ""; std::string new_string = mutator.MutateString(tmp, 1000); // use the default protobuf mutator input.set_b(new_string); // convert input from TEST to raw data, and copy to mutated_out const TEST *p = &input; std::string s = ProtoToData(*p); // convert TEST to raw data // Copy the raw data to output buffer 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); *out_buf = mutated_out;
return mutated_size; }
/** * Deinitialize everything * * @param data The data ptr from afl_custom_init */ extern"C"voidafl_custom_deinit(void *data){ // Honestly I don't know what I'm gonna do with this... return; }
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; }
/** * Initialize this custom mutator * * @param[in] afl a pointer to the internal state object. Can be ignored for * now. * @param[in] seed A seed for this mutator - the same seed should always mutate * in the same way. * @return Pointer to the data object this custom mutator instance should use. * There may be multiple instances of this mutator in one afl-fuzz run! * Return NULL on error. */ extern"C"MyMutator *afl_custom_init(void *afl, unsignedint seed){ MyMutator *mutator = new MyMutator(); mutator->RegisterPostProcessor( TEST::descriptor(), [](google::protobuf::Message* message, unsignedint seed) { // libprotobuf-mutator's built-in mutator is kind of....crappy :P // Even a dumb fuzz like `TEST.a = rand();` is better in this case... Q_Q // We register a post processor to apply our dumb fuzz TEST *t = static_cast<TEST *>(message); t->set_a(rand()); });
srand(seed); return mutator; }
/** * Perform custom mutations on a given input * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] buf Pointer to input data to be mutated * @param[in] buf_size Size of input data * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on * error. * @param[in] add_buf Buffer containing the additional test case * @param[in] add_buf_size Size of the additional test case * @param[in] max_size Maximum size of the mutated output. The mutation must not * produce data larger than max_size. * @return Size of the mutated output. */ 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; }
/** * Deinitialize everything * * @param data The data ptr from afl_custom_init */ extern"C"voidafl_custom_deinit(void *data){ // Honestly I don't know what to do with this... return; }