2016-04-26 4 views
6

私はptraceで実行可能ファイルからすべての呼び出しとRetsを解析しようとします。 x64opcodeに準拠して、のオペコードが見つかりました:0xe8の場合Rets:0xc3、0xc2、0xca、0xcbコールを解析し、ptraceでRetを返します。

私はそれらを解析して以来、私は呼び出しよりRetsを多く見つけました。

私はトレースプログラムがあります:

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

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

私のトレーサーがあります:

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);                     
} 

私の出力があります:

Calls: 656 
Rets: 666 
Diff: -10 

なぜ同じ数のがありませんretsおよびは、? いくつかのオペコードがありませんか? 戻ってこない関数はありますか?例えば

+0

ここでは_parse_ではなく_trace_です。 –

答えて

4

あなたは

他のオペコードを使用
callq *(<expr>) 

のような間接的な呼び出しを欠場します。 Libcの標準初期化ルーチンはこれらを利用しています。表現に応じて、いくつかのオペコードが可能です.2つの例があります。

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

おそらくそれらをすべて取得するのは簡単ではありません。おそらくlibbfdやlibopcodesのようなライブラリを使って命令を解読する方が簡単で洗練されたものになるでしょう。

+2

また、技術的には、 'ret'と' call'をペアにする必要はありませんが、そうすることをお勧めします。 32ビットのコードでは 'call next; next:pop eax'は、現在の 'eip'を得るための共通のイディオムです。それを適切な関数に分解する方が良いですが、必ずしもそうではありません。 – Jester

関連する問題