Search code examples
assemblymeasure

How to measure number of executed assembler instructions?


I want to somehow get the "number of executed assembler instructions" from a binary. Consider the following piece of code:

if(password[0] == 'p') {
 if(password[1] == 'a') {
   ......
     printf("Correct Password\n");
 }
}

Then if I would start the program with e.g. "abc" it would not take the first branch, thus it would execute less instructions. If I put in "pbc" it would take the first branch, thus it would execute a little bit more (about 4-5) instructions. (This is some Research for CTF (Capture The Flag) files). So my idea is instead of reversing a binary and trying to understand the algorithm, I use the faster approach in counting the number of executed assembler instructions for different setups (like different characters or password lengths and so on to see if I can take another branch using another input thus creating more assembler instructions).

My basic idea would be to write a simple debugger just placing a int3 after the current Instruction, increment there a counter, disassembler the next instruction and place a int3 right after this instruction (strong simplified version of my idea).

Is there any program/library/... which already done that stuff? (Because I see some problemens when the program deals with signals, ...)

(I already tried using high precises timers to measure the time, but that was a complete fail because of the difference are just 4-5 instructions)


Solution

  • The Linux "perf" tool can use hardware performance counters to give you precise numbers for lots of things including instructions executed.

    $ perf stat true
    
     Performance counter stats for 'true':
    
              0.183734 task-clock                #    0.314 CPUs utilized          
                     0 context-switches          #    0.000 M/sec                  
                     0 CPU-migrations            #    0.000 M/sec                  
                   118 page-faults               #    0.642 M/sec                  
               627,313 cycles                    #    3.414 GHz                    
               396,604 stalled-cycles-frontend   #   63.22% frontend cycles idle   
               268,222 stalled-cycles-backend    #   42.76% backend  cycles idle   
               404,935 instructions              #    0.65  insns per cycle        
                                                 #    0.98  stalled cycles per insn
                75,949 branches                  #  413.364 M/sec                  
                 3,602 branch-misses             #    4.74% of all branches        
    
           0.000584503 seconds time elapsed
    

    To get only user-mode instructions:

    $ perf stat -e instructions:u true
    
     Performance counter stats for 'true':
    
                92,687 instructions:u            #    0.00  insns per cycle        
    
           0.000520925 seconds time elapsed
    

    I see a little bit of variance in this though, like 5-6 instructions. Not sure if that's real or just a measurement artifact. To get more reliable results, I think of turning to a simulator like Valgrind. I had some luck getting stable instruction counts that only vary by 1 instruction from these two commands:

    $ valgrind --tool=callgrind true
    $ valgrind --tool=exp-bbv true