2016-04-26 16 views
6

Provo ad analizzare tutte le chiamate e i rets da un eseguibile con ptrace. Conforme allo x64opcode, ho trovato codici opzionali per Chiamate: 0xe8 e per Reti: 0xc3, 0xc2, 0xca, 0xcb.Parsing Call e Ret con ptrace.

Da quando li ho analizzati ho trovato più Reti che Chiamate.

C'è il programma che traccia:

void func()                      
{                        
    write(1, "i", 1);                    
}                        

int main(int ac)                    
{                        
    func();                      
    return(0);                     
} 

c'è la mia tracciante:

int      tracer(t_info *info)             
{                        
    int     status;                 
    long     ptr;                 
    int     ret = 0;                     
    int     call = 0;                     


    waitpid(info->pid, &status, 0);                
    while (WIFSTOPPED(status))                 
    {                       
     ptrace(PTRACE_GETREGS, info->pid, NULL, info->regs);          
     ptr = ptrace(PTRACE_PEEKDATA, info->pid, info->regs->rip);        
     if (((ptr & 0x000000ff) == 0xe8)) // Opcode for call                
     {                      
      call++;                    
     }                      
     else if (((ptr & 0x000000ff) == 0xc3) // Opcodes for rets         
       || ((ptr & 0x000000ff) == 0xc2)             
       || ((ptr & 0x000000ff) == 0xca)             
       || ((ptr & 0x000000ff) == 0xcb))             
     {                      
      ret++;                    
     }                      
     ptrace(PTRACE_SINGLESTEP, info->pid, 0, 0);            
     waitpid(info->pid, &status, 0);               
    }                       
    printf("Calls: %i\nRets: %i\nDiff: %i\n", call, ret, call - ret);            
    return (0);                     
} 

C'è la mia uscita:

Calls: 656 
Rets: 666 
Diff: -10 

Perché non c'è lo stesso numero di rets e chiamate? Mi mancano alcuni codici opzionali? Esistono funzioni che non ritornano?

+0

BTW non si _parse_ qui, ma si preferisce _trace_. –

risposta

4

È ad esempio perdere chiamate indirette come

callq *(<expr>) 

che utilizzano altri codici operativi. Le routine di inizializzazione standard libc ne fanno uso. A seconda dell'espressione sono possibili diversi codici opzionali: due esempi:

ff d0     callq *%rax 
41 ff 14 dc    callq *(%r12,%rbx,8) 

Probabilmente non è facile ottenerli tutti. Forse sarebbe più facile e più pulito decodificare le istruzioni con una libreria come libbfd e libopcodes

+2

Inoltre, tecnicamente non è necessario associare 'ret' e' call' anche se è una buona idea farlo. Nel codice a 32 bit, ad esempio 'call next; successivo: pop eax' è un idioma comune per ottenere l'attuale 'eip'. È meglio considerarlo come una funzione corretta, ma non sempre è fatto. – Jester