PANDA for code coverage with IDA pro

Now that we have a working PANDA tracer with Operating System Introspection (OSI), we can use it to acquire program code coverage information using a plugin.

In the following, we will use this facility to obtain an coverage trace for a program, ch28, that has shown itself resilient against PIN, drcov and Frida.

The recording and playback memory size parameters have to match. For example, if the system for which the recording was was taken was launched using

$ ./panda-system-x86_64 --monitor stdio -m 4096 -cdrom 'ubuntu-18.04.4-desktop-amd64.iso'

then the -m 4096 parameter has to be carried over to the playback command:

$ ./panda-system-x86_64 -m 4096 -replay ch28_recording -os linux-64-ubuntu -panda osi -panda osi_linux:kconf_group=ubuntu:5.3.0-28-generic:64 -panda coverage:filename=ch28_coverage.csv,mode=process
PANDA[core]:os_familyno=2 bits=64 os_details=ubuntu
PANDA[osi_linux]:adding argument kconf_group=ubuntu:5.3.0-28-generic:64.
PANDA[coverage]:adding argument filename=ch28_coverage.csv.
PANDA[coverage]:adding argument mode=process.
PANDA[core]:initializing osi
PANDA[core]:loading required plugin osi_linux
PANDA[core]:initializing osi_linux
PANDA[osi_linux]:W> kernelinfo bytes [20-23] not read
PANDA[osi_linux]:W> kernelinfo bytes [124-127] not read
PANDA[core]:/home/ubuntu/panda/panda/scripts/panda/build/x86_64-softmmu/panda/plugins/panda_osi_linux.so already loaded
PANDA[core]:initializing coverage
PANDA[coverage]:output file name ch28_coverage.csv
PANDA[coverage]:file buffer_size 8192
PANDA[coverage]:log all records DISABLED
PANDA[coverage]:mode process
PANDA[core]:loading required plugin osi
PANDA[core]:/home/ubuntu/panda/panda/scripts/panda/build/x86_64-softmmu/panda/plugins/panda_osi.so already loaded
PANDA[coverage]:start disabled DISABLED
loading snapshot
... done.
opening nondet log for read :  ./ch28_recording-rr-nondet.log
./ch28_recording-rr-nondet.log:   991951943 instrs total.
ch28_recording:     9919528 (  1.00%) instrs.    1.22 sec.  4.04 GB ram.
ch28_recording:    19839042 (  2.00%) instrs.    2.29 sec.  4.06 GB ram.

[ ... ]

ch28_recording:   972112912 ( 98.00%) instrs.   70.00 sec.  4.17 GB ram.
ch28_recording:   982032431 ( 99.00%) instrs.   70.88 sec.  4.17 GB ram.
./ch28_recording-rr-nondet.log:  log is empty.
./ch28_recording-rr-nondet.log:  log is empty.
Time taken was: 72 seconds.
Stats:
RR_INPUT_1 number = 0, size = 0 bytes
RR_INPUT_2 number = 0, size = 0 bytes
RR_INPUT_4 number = 7084, size = 99176 bytes
RR_INPUT_8 number = 103402, size = 1861236 bytes
RR_INTERRUPT_REQUEST number = 13809, size = 193326 bytes
RR_EXIT_REQUEST number = 0, size = 0 bytes
RR_SKIPPED_CALL number = 11, size = 625 bytes
RR_END_OF_LOG number = 1, size = 10 bytes
RR_PENDING_INTERRUPTS number = 0, size = 0 bytes
RR_EXCEPTION number = 0, size = 0 bytes
max_queue_len = 498
Checksum of guest memory: 0x275bbf7d
Replay completed successfully
Exiting cpu_handle_execption loop

We now have a file, ch28_coverage.csv, which contains the code coverage information. We can import this file into IDA by using the coverage.py script that comes with the PANDA coverage plugin. Simply go to File->Script file... and select ch28_coverage.csv

A selection window will open with all the processes that were recorded. Here, we can see that ch28 has forked.

After selecting one of the two processes, IDA has the coverage information color coded and annotated. Note the sequence number and thread ID in the comments.

After selecting both processes, all of the code paths are colored. Here the fork() that separates the processes

A useful trick is to change the colors in the script file between executions to have better color coding

Now we have accurate coverage information in IDA for this pesky executable.