In AFL-fuzzer, Afl-gcc is used to compile the C program to instrument it for AFL-fuzzing.
How is this instrumentation done?
For a start, the source code for afl-gcc.c is here:
https://github.com/mirrorer/afl/blob/master/afl-gcc.c
To answer this question, start using afl-gcc for compilation and look at the process created:
root 28938 17612 0 03:58 pts/2 00:00:00 gcc server.c -B /usr/local/lib/afl -g -O3 -funroll-loops -D__AFL_COMPILER=1 -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1
root 28940 28938 0 03:58 pts/2 00:00:00 /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -quiet -imultilib . -imultiarch x86_64-linux-gnu -D __AFL_COMPILER=1 -D FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1 server.c -quiet -dumpbase server.c -mtune=generic -march=x86-64 -auxbase server -g -O3 -funroll-loops -fstack-protector -o /tmp/ccgRShVr.s
root 28982 28938 0 03:58 pts/2 00:00:00 /usr/lib/gcc/x86_64-linux-gnu/4.6/collect2 –sysroot=/ –build-id –no-add-needed –as-needed –eh-frame-hdr -m elf_x86_64 –hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/local/lib/afl -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. /tmp/ccERGpVK.o -lgcc –as-needed -lgcc_s –no-as-needed -lc -lgcc –as-needed -lgcc_s –no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
root 28983 28982 0 03:58 pts/2 00:00:00 /usr/bin/ld –sysroot=/ –build-id –no-add-needed –as-needed –eh-frame-hdr -m elf_x86_64 –hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/local/lib/afl -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. /tmp/ccERGpVK.o -lgcc –as-needed -lgcc_s –no-as-needed -lc -lgcc –as-needed -lgcc_s –no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
For another snapshot:
root 32068 17612 0 04:03 pts/2 00:00:00 gcc server.c -B /usr/local/lib/afl -g -O3 -funroll-loops -D__AFL_COMPILER=1 -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1
root 32071 32068 0 04:03 pts/2 00:00:00 /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -quiet -imultilib . -imultiarch x86_64-linux-gnu -D __AFL_COMPILER=1 -D FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1 server.c -quiet -dumpbase server.c -mtune=generic -march=x86-64 -auxbase server -g -O3 -funroll-loops -fstack-protector -o /tmp/ccHGsB6v.s
root 32102 32068 0 04:03 pts/2 00:00:00 /usr/local/lib/afl/as –64 -o /tmp/ccRIBVNJ.o /tmp/ccHGsB6v.s
root 32103 32102 0 04:03 pts/2 00:00:00 as –64 -o /tmp/ccRIBVNJ.o /tmp/.afl-32102-1614398589.s
root 32110 32068 0 04:03 pts/2 00:00:00 /usr/lib/gcc/x86_64-linux-gnu/4.6/collect2 –sysroot=/ –build-id –no-add-needed –as-needed –eh-frame-hdr -m elf_x86_64 –hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/local/lib/afl -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. /tmp/ccRIBVNJ.o -lgcc –as-needed -lgcc_s –no-as-needed -lc -lgcc –as-needed -lgcc_s –no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
root 32112 32110 0 04:03 pts/2 00:00:00 /usr/bin/ld –sysroot=/ –build-id –no-add-needed –as-needed –eh-frame-hdr -m elf_x86_64 –hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/local/lib/afl -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. /tmp/ccRIBVNJ.o -lgcc –as-needed -lgcc_s –no-as-needed -lc -lgcc –as-needed -lgcc_s –no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
Now look at how a normal C program is compiled:
First GCC is used for compilation:
root 44966 17612 0 04:03 pts/2 00:00:00 gcc server.c -B /usr/local/lib/afl -g -O3 -funroll-loops -D__AFL_COMPILER=1 -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1
Then GCC will initiate cc1 to generate the assembly files:
root 44969 44966 0 04:03 pts/2 00:00:00 /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -quiet -imultilib . -imultiarch x86_64-linux-gnu -D __AFL_COMPILER=1 -D FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1 server.c -quiet -dumpbase server.c -mtune=generic -march=x86-64 -auxbase server -g -O3 -funroll-loops -fstack-protector -o /tmp/ccAac4Vm.s
Then this is where “afl-as” (re-softlinked as “as” during AFL-Fuzzer installation) is used to instrument the assembly program into another assembly program.
root 44996 44966 0 04:03 pts/2 00:00:00 /usr/local/lib/afl/as –64 -o /tmp/ccymy8Ck.o /tmp/ccAac4Vm.s
The the OS’s assembler “as” will be used to compile the assembly into object files:
root 44997 44996 0 04:03 pts/2 00:00:00 as –64 -o /tmp/ccymy8Ck.o /tmp/.afl-44996-1614398600.s
Then GCC will call “collect2” as part of compilation (https://gcc.gnu.org/onlinedocs/gccint/Collect2.html#:~:text=GCC%20uses%20a%20utility%20called,indicating%20they%20are%20constructor%20functions.):
root 45004 44966 0 04:03 pts/2 00:00:00 /usr/lib/gcc/x86_64-linux-gnu/4.6/collect2 –sysroot=/ –build-id –no-add-needed –as-needed –eh-frame-hdr -m elf_x86_64 –hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/local/lib/afl -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. /tmp/ccymy8Ck.o -lgcc –as-needed -lgcc_s –no-as-needed -lc -lgcc –as-needed -lgcc_s –no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
Then GCC will initiate ld to relink all the object files:
root 45005 45004 0 04:03 pts/2 00:00:00 /usr/bin/ld –sysroot=/ –build-id –no-add-needed –as-needed –eh-frame-hdr -m elf_x86_64 –hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/local/lib/afl -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. /tmp/ccymy8Ck.o -lgcc –as-needed -lgcc_s –no-as-needed -lc -lgcc –as-needed -lgcc_s –no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
We can conclude the following sequence of event happing:
1. GCC is called by AFL-GCC to compile the C program.
2. An assembly program listing is generated during compilation.
3. This assembly program is then modified by AFL-GCC to include all coverage information collection – mainly at the start of all functions, and for all conditional branching. The assembly statement to be instrumented is in afl-as.h, and substitution is done by afl-as.c.
4. Then the assembler is called by “afl-as.c” to assemble the instrumented assembly program into object codes, and later on combined by linker.
References:
https://gcc.gnu.org/onlinedocs/gccint/index.html#toc-Link-Time-Optimization
You must be logged in to post a comment.